Compare commits

..

384 Commits

Author SHA1 Message Date
drh 2b041fb97a Provide SQLITE_U8TEXT_ONLY and SQLITE_U8TEXT_STDIO compile-time options
to the sqlite3_stdio.c module.

FossilOrigin-Name: f31588520e3f45b50dcaa9eecab17f52ebb56bb53d0f9bdb88cc596d1a156353
2024-09-26 19:16:20 +00:00
drh b7ceffdadf Fix shell test cases to account for recent additions to the ".help" output.
FossilOrigin-Name: 54c22bc6165affbea0d1166a0912d19939300ccc4ae33a6b2ed8c510ab61c574
2024-09-26 01:29:22 +00:00
drh 66b3ed318b Always show HTML table headers in ".www" output mode.
FossilOrigin-Name: 660ca5ce6600d897cc2b00b9d39e5d993c1c0e71ec0d5dc706246c053a163281
2024-09-25 16:11:27 +00:00
drh 878db7b099 Add the --plain option to the ".www" dot-command.
FossilOrigin-Name: a9209519f612e66cfe11c89e70efd8285a0185ac0d3e5795846aafbd05d7a21f
2024-09-25 15:55:52 +00:00
drh 7119a6c16b Have the zipfile and fileio extensions use sqlite3_stdio.c when it is
available - such as when those extensions are preloaded into the CLI.

FossilOrigin-Name: 74bbb2b2b4507d9acbd91209a2ce341968e9ff64f3aebe9e817bfe488d39ae03
2024-09-25 15:26:37 +00:00
drh 95f35b64da Redirect timer output just like any other text.
FossilOrigin-Name: 3b5ae21074958788b23ccf449e52fbbad1f81779e07a6ca62ad8395f88a37286
2024-09-25 14:09:47 +00:00
drh 62d96919f6 Improvements to ".www" and ".output -w" so that text that is not part of
query output is shown using <pre>.

FossilOrigin-Name: f8ef65c52305b2180ec56760f5762ac5638584cd504c79d57e86f61736901aa4
2024-09-25 13:56:05 +00:00
drh 2a9254cf2c Add the "www" output mode that include <table> in the HTML output.
Add the ".www" command and the "-w" option to ".once".

FossilOrigin-Name: b06fd9e6bcce09f12c994dc34f329a8d267ea0601bb07c9b00903c5017d55d42
2024-09-25 13:29:03 +00:00
drh 9e59c06fb1 Always include a UTF-8 BOM at the beginning of the output CSV when using
the ".excel" command on Windows, as the actual Excel program requires the
BOM in order to work correctly.

FossilOrigin-Name: 04727fc00207325a76a5d5f20549c00232810ac727dedb70bc9e8112e60b3f56
2024-09-25 12:56:44 +00:00
drh 853520ddbf Fix stray fputs() calls in the CLI.
FossilOrigin-Name: 1ee3fa0f0e87a61b5700abd56547c4acefe999317b0d53d66d890d9e09d8b7d9
2024-09-25 11:38:00 +00:00
drh 38b4158aba Use sqlite3_fgets() instead of fgetc() to end the startup debugging pause
in the CLI.

FossilOrigin-Name: 869b3c05e852a797b5801a81d30a1f7955c31afad0274327f7af2284b555f23a
2024-09-25 11:27:59 +00:00
drh 8f1f9ef09f Merge trunk enhancements, and especially the zero- and double-width character
processing for columnar outputs into the cli-stdlib branch.

FossilOrigin-Name: d6262a4bcd7b0334b23ae4d194ca2bce7c6554ee6c678666b24c830e4c14a467
2024-09-25 09:43:05 +00:00
drh 8cd30e3f5b In the CLI, for columnar output formats, try to account for the presence of
zero-width and double-width characters in the output and adjust column widths
accordingly.

FossilOrigin-Name: 9592b9ba3ad7a842cdd4c4010da278485a6fdec7e811bda01ebe640162a8c3b6
2024-09-25 09:39:11 +00:00
drh f4382b2415 Improvements to comments on data structures and subroutines.
FossilOrigin-Name: b217e3004b58af0e777726bdd652b999ad41815261299ef4ce8f8d2f6b0afe8d
2024-09-25 09:33:14 +00:00
drh 18e2ace468 Fix over-length lines in the shell source code.
FossilOrigin-Name: f3fdf76a0d3abeb5202f2b6f26318815396da7df680073955bde60b13f84e797
2024-09-24 19:47:12 +00:00
drh 697c3fb25b Fix error messages in the shell.
FossilOrigin-Name: aeef82e974c24071e3211588001a92c7f122fbaf02d9dcf7fa5aaf30d2729f64
2024-09-24 19:19:53 +00:00
drh 63558eae54 Get fiddle working again on this branch.
FossilOrigin-Name: 0f228317c6ea1388d82df46f44c166b2aa9be63361ff9b81569ebee63c930f2e
2024-09-24 18:01:50 +00:00
drh 6ba175f0c8 Port sqlite3_analyzer.exe to use sqlite3_stdio.
FossilOrigin-Name: 7c1c1226d803dbaf8e75085b1cc2aad88aef4c3168288e587c8c736633d09054
2024-09-24 17:49:06 +00:00
drh a55901a27c Port sqldiff over to use sqlite3_stdio.
FossilOrigin-Name: 18f784c47d4252bc3696a7e084a1afb9f51f006cf2021292f2103531b8235226
2024-09-24 17:40:54 +00:00
drh 0be2dd9a1b Get output redirection working again in the CLI.
FossilOrigin-Name: 086034c3508d95e4f620c5e0580fae770e85410b0c8bd94f600fc0fd25088947
2024-09-24 16:09:50 +00:00
dan 29057f3d18 Fix a memory leak in sqlite3expert.c introduced by [f1d76c86].
FossilOrigin-Name: 42bb941584a1ac922ee6b0b6ecadce71c9259555563cf49913a6f820f3f9b887
2024-09-24 15:11:34 +00:00
drh 57b32ef924 Add the sqlite3_stdio.h library for Windows console I/O.
FossilOrigin-Name: fcd0ecffc9889f8c855ea340f075ec42cdca482df82d6e67dc9c32613e8d5846
2024-09-24 13:46:32 +00:00
dan 3c90b86372 Avoid an error in sqlite3expert if the database has existing indexes on expressions.
FossilOrigin-Name: f1d76c8636866424fe0b57d8814b8bb1a0ed4e2ca1b75d8e308d4b962ad8dc3b
2024-09-24 11:26:21 +00:00
drh 4e34558f1b Use _wfopen() instead of fopen() on Windows in the CLI.
FossilOrigin-Name: 21a8cac5e9a0d5ead29ca1114be7520d182348f7e2e2e2416852b827d7e09f21
2024-09-24 10:30:07 +00:00
drh 118ac6a7ad Always use fputws() for output to a Windows command-line prompt.
FossilOrigin-Name: 33950a8c3f3e48e5107fe56647da05147aa84f9c3eccbe7c8671f5b502ebb70b
2024-09-24 09:51:53 +00:00
drh 7d24e6b080 Remove an ALWAYS() that can sometimes be false, with wildly incorrect SQL
inputs.  dbsqlfuzz 707afcf73930de2624cdeca0ad1f0deea982dfea

FossilOrigin-Name: 766cf5535b9f51decd88c1736b988def929a90f68eb6a52bcaa21bb321586a08
2024-09-24 00:53:27 +00:00
drh 415acd09d7 In the CLI, when displaying results in a columnar format, take into account
zero-width and double-width Unicode characters.

FossilOrigin-Name: 47cfad71eddc6fc4414ff853ee172da72527620eee743721806072c6e0a80caa
2024-09-24 00:01:47 +00:00
drh 1d9db01065 CLI uses only lib-c for I/O on Windows. No calls to Win32. Works on Win11,
at least.  Reads and writes unicode to/from the console and UTF-8 to/from files.
Prototype code only - must testing and additional work required.

FossilOrigin-Name: 5c54530d5a0a4125a1ba44f22537c4f63d5e5708f347c43cbac3e1832c4335da
2024-09-23 20:23:43 +00:00
dan 253695caf3 Fix a couple of problems with the sessions streaming interfaces.
FossilOrigin-Name: 9a1fc8d36b5b262f9d17a4743b4b9bb54510cf257d2d9778ebc42d5224856b1e
2024-09-23 19:32:06 +00:00
drh 5e419c1048 Add the run-fuzzcheck target to the MSVC makefile.
FossilOrigin-Name: 2e5194407a1b34dd0659c350ea8098bfef7b3f11aa5b2a07ecd2bce5582655a2
2024-09-21 17:27:47 +00:00
drh 38f2c5f81c If the database filename pointer passed to sqlite3_open(), change it
into ":memory:".

FossilOrigin-Name: 62e11a3a78edf9853b74d6495ccd8ae9ac1966c7d78eb3682cf2d5885e3740ec
2024-09-21 15:57:06 +00:00
drh 8a894cd804 Fix comment typo in the fileio.c extension. No changes to code.
FossilOrigin-Name: bf2c5b368ac094e048ca33a5e9175fe6a1fb5e2b1e392935eb29388e8999c40b
2024-09-20 17:41:05 +00:00
drh 7f0e0c7dbf New assert()s to help verify union access. No logic changes. Testing and
validation code only.

FossilOrigin-Name: b7b64c53f5d7f6b405ee3f1f1be1d84230aa79db5a502c8ad78d3e524f4384fb
2024-09-20 12:58:15 +00:00
drh db467f5777 Fix harmless compiler warning in the vfstrace extension.
FossilOrigin-Name: c8b4d092a22d87f1231424c8e3fa6a02f17fb965cb2a931621e1b51f4d215de7
2024-09-19 15:44:41 +00:00
drh f8305e4616 Improved rebustness to malformed UTF-16 inputs to sqlite3_prepare16_v2().
FossilOrigin-Name: 7b3a517b3e16ea487ca77a2c88a0c11d737de366524fc911aa1bdd6bfb7ad148
2024-09-19 13:39:06 +00:00
mistachkin 8513eb6ba8 Remove a stray newline.
FossilOrigin-Name: 77f587dc3bbc784e8884c1b56b53fa90bbd76f4bd121bd572ab529a2b9796e57
2024-09-19 00:05:18 +00:00
drh 0e8cbd5e78 Improvements to the scope of valueFromFunction().
FossilOrigin-Name: a0f39419cb5bdfa42ab2978cf3819e3d7821212996571f8251d2efbeaa26c603
2024-09-18 16:33:07 +00:00
dan 704561f346 Fix the preupdate hook so that it works when the "old.*" row has a column with a non-NULL default value that was added by ALTER TABLE ADD COLUMN after the current record was created.
FossilOrigin-Name: 6a8c687904e92f00c1a5f768947545d2920ab9025bf8649adb0ea8053f5aec4e
2024-09-18 15:52:05 +00:00
drh ae2a4acf8d Fix sqlite3-rsync so that it recognizes drive-letters on the front of pathnames
in Windows, and does not misinterpret them as hostnames.

FossilOrigin-Name: 54a3bbd5781f76bd73f5276b632d1107312f7a789134910793262317edd8359c
2024-09-18 15:38:05 +00:00
dan 38b31a93b3 Fix the preupdate hook so that it works when the "old.*" row has a column with a non-NULL default value that was added by ALTER TABLE ADD COLUMN after the current record was created.
FossilOrigin-Name: 00a398cf900179aa5a8aab09fe4a671d99e7a31583282848ef39390f2ef246eb
2024-09-18 15:02:27 +00:00
drh eaa50b8660 Fix harmless static analyzer warning in sqlite3-rsync.
FossilOrigin-Name: a63e412b6b2939422ecfa99d91fccb7a9c61e1533bb0db20ff12f3815ef41a2c
2024-09-17 22:57:08 +00:00
drh 87dce45f96 Add assert() statements to some of the sqlite3_bind() APIs that help human
readers and static analyzers, both, reason about the code and verify that it
is memory safe.

FossilOrigin-Name: 97528788145b83a1486dbaf09326ebedbc07bd0b47a57cdff773885b0b984604
2024-09-17 21:42:04 +00:00
drh ff60709d68 In sqlite3-rsync, do not allow the '/' character to appear anywhere in the
USER@HOST: prefix to one of the argument databases.

FossilOrigin-Name: 6089a90463dcb3ba8e1584cfc5e2528fbc131311c6df7834fb41a5614a8ca9e8
2024-09-17 10:36:33 +00:00
drh 3b204ec8bb Fix a typo in an error message in sqlite3-rsync.
FossilOrigin-Name: 3f25d6c8eac25de4afff486b134a339bc06404ddaed15b46db48c6770535b1e6
2024-09-16 20:53:52 +00:00
drh 61e3067529 Cleanup the sqlite3-rsync executable as part of "make clean"
FossilOrigin-Name: 8c5e481b49d86d97fefa345d0c1b96c050846ef9fc51d8b9dd203ee35afd6f6d
2024-09-16 14:11:14 +00:00
drh d70fbffc1a In sqlite3-rsync,
open the replica database using ATTACH since the sqlite3_dbpage virtual table
is technically a part of "main".  This avoids locking problems.

FossilOrigin-Name: 39c56c836a8ae52c5b42cc0d04b92f7c0e6889a03c4fdffd301209383b7c1f87
2024-09-16 10:58:11 +00:00
drh f8cafd7b11 Improved error message in sqlite3-rsync if the SQL statement for ORIGIN_TXN
fails.

FossilOrigin-Name: 73bde71ed10f52b851e220de35519d5fb7e65a932437ab82a194faff490b7930
2024-09-16 09:12:11 +00:00
drh a95620c141 Provide more opportunity for the remote side in sqlite3-rsync to send error
messages back to the local side.  Be sure to invoke pclose2() when done.

FossilOrigin-Name: 23a63505152ff995e4ce0963dc4ab9f76ed55da7e7f5e1b85a2577473642e3ad
2024-09-15 18:37:34 +00:00
drh d87a4f8bdd Merge subsequent changes to sqlite-rsync that were accidentally missed by
the prior check-in.

FossilOrigin-Name: 50762ba0783a04e0dcd9456a1ae17d875b0a9272f2f09854a23d9d5253761e9f
2024-09-14 16:52:45 +00:00
drh dbff02abc5 Enhancements to sqlite_dbpage() so that it accepts INSERT statements that can
extend or truncate the database.  Add the sqlite3-rsync utility program that
make a copy of a live database over SSH.

FossilOrigin-Name: b7a8ce4c8c5fc6a3b4744d412d96f99d2452eb4086ad84472511da3b4d6afec6
2024-09-14 16:39:02 +00:00
stephan 11e1defc8f CLI arg handling robustness improvements.
FossilOrigin-Name: 129aca54f6b791c222b51f3eb01569e1e569269860e153b005140eb65af378b9
2024-09-14 16:30:01 +00:00
drh 3d56d59adc Add the --version option.
FossilOrigin-Name: 9961334c8007e7cb6ae55885075b74acddc4fa701b359cf67e0f3c237d7eba4a
2024-09-14 16:28:38 +00:00
drh 7154803d4c New debugging options: --logfile, --errorfile, --remote-errorfile.
If page 1 changes, always send it last.

FossilOrigin-Name: 2d8cd76691554578e987ce682cf0c42c083711dd1511a178148978182ef43ba2
2024-09-14 16:03:16 +00:00
drh df9b488799 Always show the -v traffic message even if there are multiple -v options.
FossilOrigin-Name: fc05a5b7f77cdbfcc659d49eb09569a64a172362cb90199e2861028085178f10
2024-09-14 11:38:46 +00:00
drh 15e05eab32 Add the --logfile FILE option for debugging.
FossilOrigin-Name: 30e1b92d5663e24d2f325f2bab35f81b55848ef39d15688e40b9005269626303
2024-09-14 11:23:57 +00:00
drh 9d3047bd0d Improved error messages coming out of sqlite3-rsync.
FossilOrigin-Name: 452fb6de3984c3cb10d30b51dcdb2574578ca128a0c519b2bd43df0bdd343083
2024-09-14 10:59:32 +00:00
drh 2b30518804 Make the output from sqlite3-rsync with a single -v option the same as it
is with regular rsync.  Only show the SSH command with two or more -v options,
or if there is an error in popen2().

FossilOrigin-Name: 105ec44b470318fc9ff1773027c4064343f224068c9b6e71c5618f18f7dfcc3f
2024-09-14 10:48:05 +00:00
drh 33f0a3ed13 Merge sqlite_dbpage fixes into the sqlite3-rsync branch.
FossilOrigin-Name: dff76b7a3436031ea5a61b8a44ddfa1d40ea20c983f3d34a8501cd7074db68b8
2024-09-13 23:41:16 +00:00
drh 762946b236 Bug fix in the enhanced sqlite_dbpage for when truncating two or more
ATTACH-ed databases within the same transaction.

FossilOrigin-Name: 6aa9c8e79b440c6419e65990d9ceba8f00a6f975455138cf2aa82b113daec825
2024-09-13 21:47:57 +00:00
drh 8550e4a9f8 Fix harmless compiler warning on Windows.
FossilOrigin-Name: 86e0219d977c493ac19d00c3ddcf560eb317d506c7cf6e4ef17e92daa91e1762
2024-09-13 16:12:54 +00:00
larrybr 99f50dd219 Close the db as sqlite3_analyzer exits. (See [forum:af384c2315d9718a|forum post, "sqlite3_analyzer not closing WAL-mode db cleanly" ].)
FossilOrigin-Name: 94ceac98845e31249b656dcdb8a58f456b9212dc83968ea333852a66d72a0dae
2024-09-13 16:10:04 +00:00
drh 7316b6c072 Improved informational output from sqlite3-rsync.
FossilOrigin-Name: e55e3e8ec2fe3a9190872d999cee55c85bde92667040cc166233faaa2fa34266
2024-09-13 13:53:20 +00:00
drh d61d934f9b Preveious check-in was actually doing an 8-round KeccakF1600. This one
corrects that to just 6 rounds.

FossilOrigin-Name: 3c36f5814f25483586c4fd49ef2fe5c7c0ff8c59672b1622c92061ec0ba8547a
2024-09-13 12:35:04 +00:00
drh d0d3182fa8 Change the hash algorithm from SHA1 to a 6-round KeccakF1600 with a rate
of 160.  This uses about 1/3rd fewer CPU cycles.

FossilOrigin-Name: 96c7f47a8f59e5078bd296979421c1b57fbcb7be261f8a7a0b1d22a4b5914db0
2024-09-13 12:28:11 +00:00
drh e92f8e565b Further enhancement to PTRMAP display in showdb: Show the details of invalid
entries that are within the range of the database file.  Continue to ignore
invalid entries beyond the end of the database file.

FossilOrigin-Name: 4cad385b90eaca2d90e3375e473472145af4134160b81097a8535d06638c2e4a
2024-09-13 11:14:10 +00:00
drh 5c6dc45a10 Better initialization of new database files in sqlite3-rsync.
FossilOrigin-Name: 75d5a8eb3d4ece06900109ad4022ba2a3e82de2f0acb012e3a02bfb4326bfa6d
2024-09-12 23:30:29 +00:00
drh 74c8e234cd Enhancement to the "showdb" utility such that the "ptrmap" command shows
PTRMAP entries that extend off the end of the database, as long as they
appear to be well-formatted.

FossilOrigin-Name: a9f95fe5ce90ab9864165e603f3a34013c3c98d03f1db689996f4a32086e2ed6
2024-09-12 21:58:31 +00:00
stephan 5735921b0f Add RSYNC_OPT to the sqlite3-rsync build flags.
FossilOrigin-Name: b2a3497e5525dd33faf70961107a0529f476735fef756953c66e105747271c6d
2024-09-12 21:03:11 +00:00
stephan 6677cfeda7 Port some of the shell's CLI flag-handling code into sqlite3-rsync to make the arg handling more robust.
FossilOrigin-Name: 53fb9b11807ff7accd8cd41f9cb6516d2503f161ea976940437a1d3aae868665
2024-09-12 18:15:28 +00:00
drh 40b831851e Replica must be in writable_schema mode.
FossilOrigin-Name: e385525793c7d74ce8ee139c9d6cfc1248834754598f3fd45b22b9426ff106ee
2024-09-12 17:06:02 +00:00
drh 6df1de1c73 Improved --commcheck. Add the infoMsg() function which is useful for
debugging.

FossilOrigin-Name: b979d02ffd1370d8840328bce06c76c224f0fc1fb54b47d6c904547580a820a1
2024-09-12 16:54:34 +00:00
drh 0b8c8c861b Pass the names of both the origin and the replica databases to the remote
side, so that if the remote is the replica, it will have access to the
origin database name in case the replica name is really a directory.

FossilOrigin-Name: 435c30171d3c6073b7aaf5cc11cc4813f6a2d225ae6dce1b0e478f0cd5a0b532
2024-09-12 15:51:56 +00:00
drh f7c96ee98b Add a protocol version number to the first message, and give the two sides
an opportunity to negotiate a suitable protocol number, for future
compatibility.  Send the page size as a power-of-two.

FossilOrigin-Name: df0623aae1154281157409f62d6d3fb3ce41829281d53bc55868ce44b3d36883
2024-09-12 15:36:34 +00:00
drh 165daef043 Add sha1() functions to the CLI. Fix sha1b() such that it actually returns
a BLOB.

FossilOrigin-Name: fe65821a3b912f061026e6fd7174be26897010e6b474e2780350cac60faebaad
2024-09-12 14:43:05 +00:00
drh f1fb5ce10f Improved debugging output.
FossilOrigin-Name: 80461e0d724963aaf2646005298f1194c5f1c4c9ae41c1085d4d137ed485bd9f
2024-09-12 12:04:53 +00:00
drh dc3bec34a6 Progress on the sqlite3-rsync utility. This is an incremental check-in. It
does compile, but it does not work.

FossilOrigin-Name: fa06977b6db7fa745720561ec0b10570cf7e71598dc7a7c5ee650640e5bdf6f5
2024-09-11 17:02:44 +00:00
drh 2a4a4ec408 Disable the debug-use-only functions sqlite3_mutex_held() and
sqlite3_mutex_notheld() when compiling with TSAN in as much as those
routines cause TSAN to complain.  Response to
[https://issues.chromium.org/issues/41427446].

FossilOrigin-Name: db702dd78500a0839b0b2810a580d3634df49275470787b170973a86b73826d3
2024-09-11 12:17:26 +00:00
drh 79254dc363 Improved SSH infrastructure. The foundation is now in place to begin working
on the actual sync protocol.  Still experimental.  Still a work in progress.

FossilOrigin-Name: 9a1a95f523a96303aad57e2422c2b51ea7e125f5490f32f7a2929d49b6c69ef8
2024-09-10 22:14:18 +00:00
dan 0c8144ab4f Alternative implementation of fts5 locale=1 feature that allows blobs to be stored in indexed columns of fts5 locale=1 tables.
FossilOrigin-Name: 198305de92ebba7045d8ec7d2de98511f3b00924f808a3811f061dca47b01ec7
2024-09-10 20:32:36 +00:00
dan 27119c56bd Remove a stray "breakpoint" from a test script.
FossilOrigin-Name: 7d87a27a01311153ddee122cedecedc3bcc331618dc2ab1da397a3b257dc21cf
2024-09-10 18:38:47 +00:00
drh a9c8f7cf34 Initial infrastructure for the sqlite3-rsync utility. Prototype only.
Does not work.

FossilOrigin-Name: 397b2d37b7a6619b0c1eee201065585d03496f94786b21540f613e4716d56612
2024-09-10 17:05:12 +00:00
dan 923423c16f Fix a test in fts3corrupt4.test that would fail if SQLITE_ENABLE_FTS5 was not defined.
FossilOrigin-Name: 437849c80851da842b5c4fd37d5c147f821abc541e9b4d6f9000c12983548844
2024-09-10 16:40:08 +00:00
dan 7a41b48cf9 Alternative implementation of fts5 locale=1 feature that allows blobs to be stored in indexed columns of fts5 locale=1 tables.
FossilOrigin-Name: 55c5c119a0a77fac2c9f46d718ef78c0f33ed3520e10c240cf5bf1801e0586ee
2024-09-10 16:19:31 +00:00
drh 38b26d82e6 Add the ability for sqlite_dbpage to truncate the database file by writing
a NULL page.  Experimental.

FossilOrigin-Name: eb3c89ee2e4c5425be75deaf46a06a9cd8b210c695b918dd63a78f930c6e6b63
2024-09-10 12:09:03 +00:00
dan cd889c7a88 Fix an OOM-handling problem affecting locale=1 fts5 tables.
FossilOrigin-Name: d8103684f660ff9b3186d0f89afb113ca580bd16f0bf413ed8a9434236b54426
2024-09-09 19:12:57 +00:00
drh 882aba4090 Generalize the sqlite3_dbpage virtual table so that it is able to write
new pages onto the end of the database file using INSERT.

FossilOrigin-Name: fe0d67e72d4228661c021f227bfc0d5ddb1b726db0f36c7221ead8dd8bd1dc73
2024-09-09 18:45:58 +00:00
drh 9c2f068ebd Move the vfstrace extension out of src/ and into ext/misc/. Make it a
standard part of the CLI.  Improve its output.  Also fix some unrelated
comment typos.

FossilOrigin-Name: 123cb1f579daec3ed092fe9dd1bc0d3250f2b56d4cda1efa92af139029e112e2
2024-09-09 15:39:40 +00:00
drh dbab768d07 Fix dependencies in makefiles to include ext/misc/vfstrace.c as necessary.
Improved xFileControl() output from vfstrace.c.

FossilOrigin-Name: e8f2d6313075c92fdeebcdfd8b50f43e9d45225890b2ef6b77148a766a42e940
2024-09-09 15:33:37 +00:00
drh a40f6eb80e Fix harmless compiler warnings in the vfstrace.c extension.
FossilOrigin-Name: f23954e604bf4da45f07194b54a4fe1c83002ab65d6c6f0ac095e88baba18547
2024-09-09 15:19:26 +00:00
drh a8cf79e322 Fix harmless compiler warnings in FTS5.
FossilOrigin-Name: aa75e701de61fe63ec15c35d70e53e950ff73b0dcb0d871dd8721412f3af297a
2024-09-09 15:12:21 +00:00
drh 5600adf1b1 Move the vfstrace extension out of src/ over into ext/misc/ where it belongs.
Make it part of the standard build for the CLI.  Bring some of the vfstrace
output up-to-date.

FossilOrigin-Name: 055b97de8d2397987d72dbab1cde78ece2d1c066e95042b4ed6b7b36b2cf9006
2024-09-09 14:50:23 +00:00
dan cf25c16a54 Fix a problem with fts5 locale=1 tables and UPDATE statements that may affect more than one row.
FossilOrigin-Name: 70e42f941c0778a04b82655409c7caf4c1039589f7e43a8ec1e736ea8f931b26
2024-09-07 16:22:22 +00:00
drh 8755e695c5 Fix an off-by-one error in the routines that bind the special $test_TTT and
$int_NNN parameters for fuzz testing.  Fix to testing logic only - no changes
to the SQLite core.

FossilOrigin-Name: 6206b90a4ec3f05e3bbb4844e71569bbde7df237550569e6419ff7c3146505dc
2024-09-07 16:04:04 +00:00
dan f1c750e4ca Add tests for an fts5 NEAR() expression with a single argument phrase.
FossilOrigin-Name: e319d43bfd5ee4ed92b93531b239af4d1be0a8215b2a06c3532122ff2c7b6a7c
2024-09-06 20:12:59 +00:00
stephan 6946a7fa50 Resolve the "No rule to make target '0'" error when building with --disable-tcl.
FossilOrigin-Name: d94541ae76b5d8b69f5524f10dcccc0814283f438a03f553848ed631a1983633
2024-09-06 15:01:00 +00:00
drh bc97630313 Fix a harmless stray carriage-return character.
FossilOrigin-Name: 84a6c5f975de36ba93b888e01cc5188717b5644ab8384beb8fd8906bdfc8e227
2024-09-06 14:01:48 +00:00
drh c43d16d69a In testrunner.tcl, correctly capture and display information about the
system under test:  hostname, OS, pointer size, byte-order.

FossilOrigin-Name: ec75cfc5d4b69e4aed64d17748cac15cd62a759a1cbe7feaa4580ad8346b0b95
2024-09-06 13:13:25 +00:00
drh deb6a60a84 Fix harmless compiler warnings.
FossilOrigin-Name: 60fb8ee153ec293b6b3a4170dafa305e4c16af575aced72daef46116d8dc2bb6
2024-09-06 11:21:53 +00:00
drh c4e84b7295 A testcase() macro added to help ensure that the fix to the omit-noop-join
optimization from yesterday does not regress.

FossilOrigin-Name: 224628b1039b996499e0d806fc0215f175da6f1059eb1b9ac491ac11126971ab
2024-09-06 10:35:36 +00:00
drh 56a0480540 Clarification and simplification to the README.md file and to the instructions
for building on Windows.

FossilOrigin-Name: f69ef1a37b2778bdf73ee7e3b3edd74f7344ab8e5eedbedc22203c782e521f5b
2024-09-06 09:49:13 +00:00
drh dc181d41d5 Fix a testrunner status reporting problem introduced by [aa5f10f21dbfb24e].
FossilOrigin-Name: d20c65c3b4256a662ebf7ed024b7b7adaceca90358f58111dc645da322000794
2024-09-05 23:40:13 +00:00
drh 934e796e43 Ensure that the WhereInfo.revMask bitmap is adjusted when tables are removed
from the FROM clause by the Omit-Noop-Join optimization of
[0cd82ee9a8413cf1].  Fix for the issue described by
[forum:/forum/8a1e467e905b8d27|format post 8a1e467e905b8d27].

FossilOrigin-Name: 22ca5a2ffb89ccb5f337993b5a95e27c449c39014284156eabc33da012a8759c
2024-09-05 23:22:55 +00:00
drh 6ffcdb1856 Update notes on build procedures in the README.md file.
FossilOrigin-Name: 1d12744fe7cc294994e53e1ffe72799d0321dd5c1ef031213f083e200918fee5
2024-09-05 15:55:04 +00:00
drh 4987c5c3c2 Testrunner.tcl enhancements: (1) Attempt to build the SQLite tcl extension
if it is not already available.  (2) testrunner target "devtest" is added as
an alias for "mdevtest".  (3) Try to keep summary information at the end of
a test below 80-characters per line.  (4) Update the Makefile.in so that
the "clean" target removes the tcl extension built by item 1 above.

FossilOrigin-Name: aa5f10f21dbfb24ee54ca96bfb7b013ae29e26fec05b80681f19cc63d9face49
2024-09-05 15:28:15 +00:00
drh 21e7816e65 Enhance testrunner.tcl to keep track of the platform and SQLite version
as reported by individual test cases and to report that information in the
summary at the end of each test run.

FossilOrigin-Name: 80ebb7c7e686cd936ac834f2258f585a7004762593e0bc859ecd75d6fb0badfd
2024-09-05 12:06:45 +00:00
drh 6aedd6d9fc Faster implementation of the aggregate_test_counts procedure inside of
testrunner.tcl.

FossilOrigin-Name: a01d869520329fb9e786cdc65f359785a95d19d289e4c6b844c758d6e5385aaf
2024-09-05 11:46:43 +00:00
drh 7bd230cf4d Make the default TCLDIR be C:\Tcl in the Makefile.msc.
FossilOrigin-Name: c2c0a9176ae7291a0b72f3d048a2ef5716c325b9f693cdc5eada552e0c881a9d
2024-09-04 18:51:59 +00:00
drh bb4d2edf10 Fix a bug in the parsing of some corner-case JSON PATH strings that contain
escaped double-quotes.

FossilOrigin-Name: 60ac55c4b76355aaf7cbde38bf1f6082ff5612bf4ffc49ab69d00fd4e3d64e64
2024-09-04 16:01:44 +00:00
drh 109025c0a4 Put a proper shebang at the start of the testrunner.tcl script and make the
script executable.

FossilOrigin-Name: c0c6e9abebf76358625f30a179658319b260baba6eded2a4c5ad356143e36f97
2024-09-04 13:42:19 +00:00
drh 3c72072a6f Make extra efforts to delete the over-size directory names created by
the win32longpath.test module.

FossilOrigin-Name: 3c8035ed3f023fb31f65f298fb9ce19d4fa7a5511bd90877b27969f5f0892472
2024-09-04 13:09:58 +00:00
drh c81ab76cd9 Add the "joblist" command to testrunner.tcl
FossilOrigin-Name: f64469f4806d4d5d7103c171a37a542c7aab9db09a226bccd8411e9ccd55353d
2024-09-04 11:22:47 +00:00
drh fd486258a0 Enhance the "errors" command in testrunner.tcl so that it accepts the
"-s" or "--summary" argument to see a list of failed jobs, and so that
an additional argument is a GLOB pattern that restricts the output to
jobs whose names match that pattern.

FossilOrigin-Name: dcbebe30f594a99e23b5ccd8d199b92118204a3e52e75c78d98c394601252e81
2024-09-03 16:04:34 +00:00
drh 940cdc94f3 Fix ext/consio so that it works correctly with SQLITE_USE_ONLY_WIN32.
FossilOrigin-Name: efc6f3d7e92a25f440fb8d392daf325af5ca7dca104a5bb4bd59f7df93af53b0
2024-09-03 14:15:57 +00:00
drh 23a16c8387 In testrunner.tcl, compile the Windows Default configuration using
SQLITE_ENABLE_STMT_SCANSTATUS.

FossilOrigin-Name: 49e8b1635f29d9fd0dc2ef6e312fd4129f2283f68e9423d95ff9b55077688ad7
2024-09-03 14:00:36 +00:00
drh e6e49bfef2 Fix harmless compiler warnings in the percentile extension.
FossilOrigin-Name: c5557f281c6294b6db6682349d245feac7c6ce7f4f61356f486afdf186c566c4
2024-09-03 12:41:21 +00:00
drh 06638117bb In testrunner.tcl, allow setting njob to zero, which causes no new jobs
to be launched and for the process to shut down once all current jobs are
completed.

FossilOrigin-Name: 0ef65fd4ba17def4c13986365b3af300c4024725af4bc314845d1af8be568ab4
2024-09-03 10:53:32 +00:00
larrybr 22cd1eec5a Cause cfGets() (under SQLITE_USE_ONLY_WIN32) to better emulate fgets().
FossilOrigin-Name: 2d783524d1671d988ebb1b21c83de99c9f335963b6c20cf4df612f58c13da913
2024-09-03 02:09:13 +00:00
drh 7c6f2880aa Fix possible NULL pointer dereference following OOM in the new error reporting
logic of the percentile extension.

FossilOrigin-Name: 7891a266c4425722ae8b9231397ef9e42e2432be9e6b70632dfaf9ff15300d2c
2024-09-02 21:59:31 +00:00
dan 70989b6f59 Fix a technically undefined signed integer overflow in fts5.
FossilOrigin-Name: e6bec37ea1ca51e1d048941ce4c5211d8fc5c5e3556a1441f9c79b036843f9e3
2024-09-02 18:41:59 +00:00
drh ef7c692baf Make the percential extension easier to incorporate as a built-in on Windows
applications.

FossilOrigin-Name: 831e2be4117dc7f5113f66d3e484ca34e4405444ac7b0def12ee9a00608d40da
2024-09-02 17:27:10 +00:00
drh da52f11250 Remove some debug/test code from percentile. Make the extension easier to
statically link.

FossilOrigin-Name: 6e5f146e274b210749dd8923a2da56905eb098b5a66699ff9130e3e51b1ff662
2024-09-02 14:46:56 +00:00
drh 7a29505e57 Enhance the percentile extension to support percentile_cont() and
percentile_disc().  Add support for ordered-set aggregate notation in 
the parser when compiling with SQLITE_ENABLE_ORDERED_SET_AGGREGATES.  A
new function property SQLITE_SELFORDER1 must appear on any aggregate function
that wants to take advantage of the ordered-set aggregate notation.

FossilOrigin-Name: 557bd245ef24af15da1374762bbeb9b8b0241da06e604efdf00d567a9ed09216
2024-09-02 12:07:37 +00:00
drh d281889ac8 Improved error messages on percentile functions. More tests cases for
percentile and for ordered-set aggregates.

FossilOrigin-Name: e1bca168e70335fa2f9537632fd16e374c566a564fab4974c0b8f61cb63d08ce
2024-09-02 11:17:04 +00:00
drh a955ec806a Change the name of the enabling compile-time macro to
SQLITE_ENABLE_ORDERED_SET_AGGREGATES.

FossilOrigin-Name: 3b1cdddf8339cc339ec74cd8be2bfa42e62b500048a444eb9e5d9817bc4702ae
2024-09-02 09:40:37 +00:00
drh b5df31d15f More internal documentation improvements.
FossilOrigin-Name: 8b91b74931c36e1955ef933a07d8ec40c8b54c882efe7084d179168867c5244f
2024-09-01 23:56:14 +00:00
drh b9a6e42a55 Improved documentation of recent enhancements to the percentile extension.
FossilOrigin-Name: 51e7b4c9cf19a5986432a76c5fd30cef715c170a403d7b4304a8c5888c445a91
2024-09-01 23:47:20 +00:00
drh 1c30df3598 The WITHIN GROUP (ORDER BY ...) syntax is now a compile-time option:
SQLITE_ENABLE_ORDERED_SET_FUNCS.  There is no increment in the code size
if the option is omitted.

FossilOrigin-Name: c9367e2532d653738af27c4d92810eb648a9e12f72d7223017c87cb0dddc6804
2024-09-01 23:27:34 +00:00
drh ca447020ae Implement percentile_cont() and percentile_disc().
FossilOrigin-Name: b1a93f67d6b21df6fe3247c9333fead61dd425574f66ea3eb06b80c2b06f616a
2024-09-01 20:24:24 +00:00
drh 7aa01a0ffc No prepare-time penality for ordered-set aggregates for applications that
do not use them.

FossilOrigin-Name: e070c16d2183312e416ff6af770346041e4d3836c4db2c9ea6049f63fb0eaa07
2024-09-01 19:19:26 +00:00
drh 5d5d6194c9 Merge fixes from trunk into the ordere-set-agg branch.
FossilOrigin-Name: 7528ddcfdf155116353266e00e6408c526e29f04cb00ca2d9e84b105329b17c0
2024-09-01 18:57:52 +00:00
drh c97ad9b4e1 Improved sort function in the percentile extension.
FossilOrigin-Name: 9f84e8d59bcda642e732565e840f6a880a01b2fc65af2651248f6a8a6e1cb65a
2024-09-01 18:54:31 +00:00
drh 41155d8885 Fix to the quicksort algorithm in the percentile extension.
FossilOrigin-Name: 54313f74b24c46f1afa1ff082ef569fa46938527095be358015e7047e17702ac
2024-09-01 10:52:20 +00:00
drh df2d14b86e Add error checking: Do not allow functions other than those in the
percentile extension to use the ordered-set aggregate notation.

FossilOrigin-Name: 317d901429303340290334dbe7680a36339df0a50b586e3f71b6c5e5eba6d411
2024-08-31 22:22:24 +00:00
drh a239ece378 Demonstration of how ordered-set aggregates might be parsed and integrated
into the existing parse tree, should we decide to support them.

FossilOrigin-Name: ef9777890001ba0122d3add799795e118fd87243f42731ab84d4748b67605647
2024-08-31 20:09:37 +00:00
drh c1042cd133 Include percentile() and merge() in the fuzzcheck test utility.
FossilOrigin-Name: d1d0942a947803d45a1fd9068f3518cf412178b6b9bafcb82db44c52d5820c11
2024-08-31 19:24:17 +00:00
drh 65b1244781 Omit the percentile_cont() function added by [095c22e62248f8ef] (and not yet
released) since its usage conflicts with the PG percentile_cont() function.

FossilOrigin-Name: 3fe0a852978f3f1218e37a58f0d3b54016d4116a3301aa32efa7c4c12c767755
2024-08-31 18:35:10 +00:00
drh 49af3dfbf4 Allow percentile() and median() to act as window functions.
FossilOrigin-Name: 94cf96af8fee55449080655bddf81cbf5c078a02d7bb5dd7e4903b36f83a8c07
2024-08-31 18:08:31 +00:00
drh a5315a6ece Still more test cases.
FossilOrigin-Name: f09904608195dac38172b0dd4dcab3190f33c116d468beff27f913a7433b400e
2024-08-31 17:50:06 +00:00
drh f138110dfd Add more test cases.
FossilOrigin-Name: 0d0e5456793b4bef673ebc7fcc1c393a6d3c817363d948ddfe06d60eab56dc24
2024-08-31 17:27:55 +00:00
drh ad8ec9db63 Avoid unnecessary sort operations when running one of the percentile
aggregates as a window function.

FossilOrigin-Name: 5d311536211eb1e3c887ceb7e6516d3900e6eebbccc8c445dd43cdd556182728
2024-08-31 16:55:14 +00:00
drh 129767958a Test cases added.
FossilOrigin-Name: 25e68229843cc84978955817285550085d1306ba4ce3b0517dd00e5d05b9ae0a
2024-08-31 15:02:07 +00:00
drh 90fa4c7b2c Enhance the percentile() and median() extension functions so that they can be
window functions.

FossilOrigin-Name: 4d0e3df4b9c609755977b8a462126242d2be1310c0122a8d4ba76d98d32a7230
2024-08-31 14:31:17 +00:00
drh 3196c349d1 Do not fail the omittest if ICU libraries are not installed.
FossilOrigin-Name: ddc55efd2d59df3f20743b0533550436da945453c069025a3f871d28d40e13d4
2024-08-30 17:33:25 +00:00
drh 0337b9a628 New makefile target: "tidy". The "tidy" target removes all build products
be leaves behind test results.  The "clean" target has been enhanced to do a
better job.  The tool/omittest.tcl script is rewritten to work on the
configure-generated Makefile and to require no arguments.

FossilOrigin-Name: e48add02695a41b26a04e7942b5333e2bf4dc5598e363367aea3a4690982667d
2024-08-30 16:51:41 +00:00
drh 6cb12337b9 A couple of #defines so that the build work with SQLITE_OMIT_FLOATING_POINT.
FossilOrigin-Name: be768f80c703ac1645251ccbac83e07b3ea4cc231c8ea7e66374a4f78361f10b
2024-08-30 16:43:36 +00:00
drh c589d5ab06 Rework the tool/omittest.tcl script so that it works with the
configure-generated Makefile, and requires no arguments.
Update the configure-generated Makefile with a new "tidy" target which
is like "clean" except that is preserves test logs.  Use "make tidy" to
force everything to be recompiled from scratch without destroying logs.

FossilOrigin-Name: 99491df19d68df1f0515bd5ec9240ef3dd6e0fa38a6c837a38a16a873f8e2cbb
2024-08-30 16:24:49 +00:00
drh 28db1a68ba Improvements to "make clean" on unix.
FossilOrigin-Name: a1d775f07528192b09566ff1546b067ffbee0db5812e424e6b7f3cc33a67dc83
2024-08-30 12:10:28 +00:00
drh 11397ce104 In the testrunner.tcl status report, try to provide a rough estimate of
the time remaining.

FossilOrigin-Name: 90bc616d20e8c247691c45de2a28d41c1632b21152dc34253eefc179a90ab31f
2024-08-30 01:11:19 +00:00
drh 494ba30c9b Sync the autoconf/Makefile.msc with the main ./Makefile.msc
FossilOrigin-Name: 9de47c3611ca05e03a661807a06c6c5c0b5c6548ea7a8d73cb63832d2dff9d0e
2024-08-29 23:32:16 +00:00
drh 6a18c9e06a All makefiles are responsive to OPTIONS=... command-line arguments, and add
the RHS value of OPTIONS= to builds and to lemon and other build steps that
might respond to -D or -U options.

FossilOrigin-Name: 854b3776ee1fcaa5931e3a0ed104978ca350d218e553586d1c40c2420e1be498
2024-08-29 18:32:56 +00:00
dan ccd34894e1 Fix a case where the BTCF_AtLast flag was being left set incorrectly. This was causing obscure window function queries to fail.
FossilOrigin-Name: e042eb024738a83eed92cd2dfac3d2a50d2589715a3d81b1a494564dd7d8e7fa
2024-08-29 16:27:57 +00:00
drh c1547d1f7a Do not allow sqlite3_blob_open() to work on a any table that contains
generated columns, even columns of the table which are not generated themselves,
because such columns might be part of the expression of a STORED column.
This restriction could be relaxed some, but that would be a lot of code
for something that nobody ever uses.

FossilOrigin-Name: 6e84947123339f0ea2b7dabc6134a621eed09317f81647f15870ed50a0f7d1bc
2024-08-28 19:13:16 +00:00
dan 50ca8af6f2 Fix a dropped error code in fts5.
FossilOrigin-Name: df55502e4f412e5b1daccf82f11fa4eb932047d9972dcd16e36be00cf09f78e1
2024-08-28 15:54:46 +00:00
drh 8db3fc5488 Update the README.md file to recommend running "devtest" instead of "mdevtest".
FossilOrigin-Name: eb016f66ea2c7ebacf8c57495843db3414602d062e4a430f2cc603c88b10c3f9
2024-08-28 13:55:46 +00:00
drh ba5994b181 Maybe [7420b13238da4e6b] was not such a good idea. Restore "make test" so
that it works as before - running a single-threaded test over the source tree
with options specified by ./configure and similar.  Instead, change the
"make devtest" target so that runs the automated multi-threaded tests on 
a standard configuration.

FossilOrigin-Name: dc9fee980d4f4b5a569628702e52cef9e5d8e6c69c2b84546dce47e3e514775e
2024-08-28 13:51:51 +00:00
drh 3341f5ce85 Minor wording change on testrunner output.
FossilOrigin-Name: 115e68597957a9ee80de7f554ee3768c992051687c8f07eaf3a9fcaab7efd44e
2024-08-28 13:34:20 +00:00
drh d6b56d65a8 Update the "make test" target so that it is really just "mdevtest" with
"srctree-check" and "sourcetest".

FossilOrigin-Name: 7420b13238da4e6bfb1589eaf3cfd842fe3c4b0f3b6a3b49c24cd70589bf4809
2024-08-28 12:10:51 +00:00
drh 4f2f91bf08 Further improvements to the status display in order to maximum the amount of
information shown on the limited screen realestate available when running
via "watch" or in continuous monitoring mode.  All details are still shown
when doing a stand-alone "status".

FossilOrigin-Name: 557a2c65f5ae1d8cb1858c17da0fe64fbfba83d787cfb7f2f21582960a8b9eac
2024-08-28 11:03:58 +00:00
drh 242e064978 Only limit the number of failures reported by testrunner status if using
VT100 cursor movement.  For a straight-up "status" command, show everything.

FossilOrigin-Name: 791237e0f4b67f0197ae11e966554edeade0c443289d2ade00470d23bf5e8ec8
2024-08-28 10:36:18 +00:00
drh 4a90f81a6d In the testrunner status display, limit the number of reported failed jobs
to avoid overflowing the terminal when there are many failures.

FossilOrigin-Name: ffeaa4d5d73871cbdf1ef70b9845d921ebdb96e964d232661a5048cab7d744ed
2024-08-28 10:25:44 +00:00
drh a88d61824d Disable shell test cases that require virtual tables when testfixture is
built using SQLITE_OMIT_VIRTUALTABLE.

FossilOrigin-Name: 8c73d54fd1e250fcd7f30741cfbd169af9aaecc2096c0c8a9486abaa064d69af
2024-08-28 09:47:29 +00:00
drh af43eddc23 Reenable SQLITE_OMIT_VIRTUALTABLE on the Device-One alignment for testrunner.
FossilOrigin-Name: 8f2cb357634ec0b5aef14f3d967e76db236f8899f3201efc80c264f548cc1b0b
2024-08-28 09:31:17 +00:00
drh b5b4ca2a11 Changes to the way "release" tests were constructed in [d03d35eebaf82709]
were incorrect.  Fixed here.  Also enhance --explain to chose permutation
configurations and so that PATTERNS on the the command line can match
against permutation configurations.

FossilOrigin-Name: 1f962ffc9e956a9d6311ed9c02fea13c0fe056283ee2c650a2312a258808b3b3
2024-08-27 22:28:03 +00:00
drh c3c645ef46 Improvements to --status overwrite in testrunner.
FossilOrigin-Name: 26372762ab1451eb95d29367f5b2534bde616a37e5e757e72ba2cfe42571d180
2024-08-27 21:44:45 +00:00
dan f5a9b58c8b Avoid reading the structure record from within the fts5 xConnect method.
FossilOrigin-Name: 6a6ce343b249e269229867b2c2f107a49ac8a8f24ad66801718ef01159655319
2024-08-27 20:37:30 +00:00
drh ce018f5bb3 Further minor improvements and tweaks to the testrunner --status display.
FossilOrigin-Name: 7d1ccc6dfc9abe053baaf39f68e9fb14001f5032a52b85fe1e4b752e48317536
2024-08-27 19:49:51 +00:00
drh 1a7cfbebb0 Fix typo in the previous check-in. Ensure that --status header lines do not
overflow and wrap.

FossilOrigin-Name: 2eaea67495fd9961b7145d829789889bf1d8fa7a834d40d1be43e7c74c233bc2
2024-08-27 19:48:19 +00:00
drh db05c66a16 In testrunner, when doing the --status updates to the screen, be sure to
overwrite dead text at the end of each line with spaces.

FossilOrigin-Name: 7c195f132cb48ee44124eb4af3532937493429f7c45f6ac611f7a9b128799ad7
2024-08-27 19:43:21 +00:00
drh 71475478a1 Further improvement to the status display in testrunner.tcl. Show the
number of errors and the number of test cases on the status summary.

FossilOrigin-Name: dbc1ac8692feccde271eaca78f2833c8bb7bf620088c8f975692d6ae2c8ba53a
2024-08-27 19:28:21 +00:00
dan c8edf07ca7 Modify the implementation of "wrapper" tokenizers to make them more robust in the case where the database connection is closed before the tokenizers are deleted.
FossilOrigin-Name: 7c0001d6eb43f89144eb84d9e30f575a3feed401d685a0d1f260692e419b2df2
2024-08-27 19:27:40 +00:00
drh d9bc2bb638 Improvements to testrunner.tcl: Show elapse time in MM:SS or HH:MM:SS.
Keep track of the total number of tests and the total number of errors
and report those values on a summary line at the end.

FossilOrigin-Name: 40b232924c973f8d94605946fff75acbe120d90634a2eaf38bd31649e9f1390b
2024-08-27 19:17:29 +00:00
dan 3c39f1f5d6 Add test code to drop an fts5 table with corrupt records in its shadow tables.
FossilOrigin-Name: ca21c942c30a3dbff0e7d118e105b847d80b5388c74d19c2eeea71581f8f40b8
2024-08-27 18:25:04 +00:00
drh dac0d0b310 Updates to testrunner: (1) Omit all testing of User-Auth.
(2) Automatically add the "*" wildcard before and after all pattern
arguments.  (3) Build the sqlite3 CLI for release tests.

FossilOrigin-Name: d03d35eebaf82709414c87cfa6abc9d2baf8d7e64c2627bad0fd5bbda3e78d60
2024-08-27 17:38:26 +00:00
drh 4a972bc1b8 Merge the SQLITE_USE_ONLY_WIN32 flag for consio into trunk.
FossilOrigin-Name: e9b03b082dcf141695140a6c2c50bf0dc577c3d64ab76f81dd22f0084eca26d6
2024-08-27 14:35:54 +00:00
drh 8aa9135f2c Only avoid all C-runtime I/O if the SQLITE_USE_ONLY_WIN32 flag is defined.
FossilOrigin-Name: 164b1e1962aa1e16bdf52e9e86d4cf9c9e09220c0821932ac8e390e82074185f
2024-08-27 14:25:52 +00:00
drh fcd65efcf1 Merge all the latests trunk enhancements into the win-dupe-crt-fio branch.
FossilOrigin-Name: 2d52db98f47fbcda0622c034b21c2fb19bf4345b88c5c565ae9e6f7128642e43
2024-08-27 13:57:43 +00:00
dan c013fa50db Changes to documentation comments in fts5.h.
FossilOrigin-Name: 886545a8d0e9cbf4911ecf747da0ea8aad702d79cb065dad01a04aa4f51da12b
2024-08-26 19:08:54 +00:00
drh 1321ea5010 Randomize the name of the attached database used to do VACUUM.
FossilOrigin-Name: 0f4e65d73a2b95932f36768c0d9925a2d265d9b395b886d8e492d1d519b2093c
2024-08-26 17:35:32 +00:00
stephan 87ebadbf4e shell.c.in: use eputz/oputz() instead of eputf/oputf() where appropriate to avoid compilation errors in -std=c99 mode (namely wasm builds).
FossilOrigin-Name: 9ef8317faebc29d016bdf2e8c678fb21ca2cfa95272f1f18b461fcaf0e220ac5
2024-08-25 11:59:29 +00:00
drh cc902fd25e Fix harmless compiler warnings in fts5V2toV1Tokenize().
FossilOrigin-Name: df65d00f104f31741056686f2ba41ecb192c552012bffb17c2a8b5d4db058328
2024-08-24 20:05:59 +00:00
drh 306a8dcf3e Fix compiler warnings in the CLI detected by MSVC.
FossilOrigin-Name: 23ae505cbfde6dfd1dbb2216cf76c1e316b49f2ca84491a1aae28ad33f7777a9
2024-08-24 20:01:05 +00:00
drh 838d2d3078 Improved help message for the --enable-test-status configuration option.
Fix the build for when that option is omitted.

FossilOrigin-Name: b404a5fe3f0532f6d56b5e65c44a59379c17d175c21ac69a1f2ba8aadf453313
2024-08-24 19:06:52 +00:00
drh 1d5a12e6a5 New ./configure option --enable-test-status causes testrunner.tcl to be
run with the --status option for targets like mdevtest and releasetest.

FossilOrigin-Name: 9ca8513c26e54c97f2d3c6105c42144100044727f6fb4c28048f7cd7270dd35e
2024-08-24 19:02:33 +00:00
drh f9eff9052d Remove a term from an assert() that is no longer relevant.
FossilOrigin-Name: 8b4766252b80075354a6b1406c5430fe999a6490aa3e079893fcc682d88734f7
2024-08-24 18:42:39 +00:00
dan 58b08d7702 Avoid a stack overflow that could be caused by a recursively defined WINDOW() with a strategically embedded error.
FossilOrigin-Name: bada54bd6bf54190e40aa721b77081015957d204c7b6a9fdbe8c67bcf20798f8
2024-08-24 15:54:15 +00:00
drh 27095fc4a5 Ensure that the WhereLoop.u.btree.pOrderBy field added by the
order-by-subquery optimization [7a0cdc7edb704a88] is correctly
initialized.  dbsqlfuzz 437be171a98687082a31ea6efc2fd5c5d64481c8.

FossilOrigin-Name: b75f8b2252aefe7bb96fa237205a1a9dc88c46d9ec09bca7407e6c636b203e7e
2024-08-24 11:48:19 +00:00
stephan 7766c9943e Eliminate use of strcpy() in shell.c.in to squelch an unwarranted link-time warning on OpenBSD.
FossilOrigin-Name: 32e9bf7f972144eacbb2580151220bc4fc1cbcc8bcf586ffd8e10762abf75c7e
2024-08-23 21:20:50 +00:00
dan 789da35848 Fix a problem in the ext/fts5/extract_api_docs.tcl script.
FossilOrigin-Name: 9a9d0f6301faefe324261f03543023ffb6a90823349c6946abb0df2f69b31f96
2024-08-23 17:40:29 +00:00
dan 8d4edd0d67 Add fts5 auxiliary function fts5_get_locale(). For querying the locale of a stored value.
FossilOrigin-Name: 396f720f36a937145ac727c2750acfd26e4eda350b46d648d82a7e9985545a9f
2024-08-23 15:18:02 +00:00
drh 5804da0218 Enhance the generate_series() table-valued function such that it is able to
recognize equality and inequality constraints on the "value" column and
optimize its operating accordingly.

FossilOrigin-Name: d50b784807333c5461a2d027778c746c799285b95bb1952f142b317ea2846460
2024-08-22 18:12:10 +00:00
drh d55ab84451 Add the SQLITE_INDEX_SCAN_HEX bit to the sqlite3_index_info.idxFlags bitmask.
When set, this bit causes the EXPLAIN QUERY PLAN output to show the idxNum
value in hex rather than in decimal.  This is purely a debugging aid.

FossilOrigin-Name: 6c00e88ebdb41d6317bb8758825521614dedc2e6e6289ff415c5f0406eed815b
2024-08-22 16:22:08 +00:00
drh 889ce8ee90 Add SQLITE_TESTCTRL_GETOPT. Use it to implement improvements to the
".testctrl opt" dot-command in the CLI, and similar enhancements to TH3.

FossilOrigin-Name: 6500baa9914b08ce19c361a69f19a80e5d800fcb82579d1c1e03601c7a664338
2024-08-21 20:25:31 +00:00
drh be1fdbd272 Add the new SQLITE_TESTCTRL_OPTGET that retrieves the current optimization
setting.  Use this in the CLI to provide symbolic fine-grain control
over optimization settings using the ".testctrl opt" dot-command.

FossilOrigin-Name: 0ea4e1e8fc689cb1af3a8d21dd6af9d483115412b414e85e8a42480f50d65af2
2024-08-21 18:57:55 +00:00
drh 9904d824b8 Improved comments on byte-code subroutine calls to materialize subqueries.
Should not affect production builds.

FossilOrigin-Name: 6b024c85ef856e26cddac8ad862e16909b5149c3e3efb4e73ba54c97291f1cc4
2024-08-21 17:38:50 +00:00
stephan 5b5625f679 README.md: a markup link fix and use the canonical URL for Fossil.
FossilOrigin-Name: c49bfee6b878bd96adfc852fdc76e98bf81e2fb82be8325672fbc7af04e7dffa
2024-08-21 13:57:30 +00:00
drh 59b171172f Updates and enhancements to the README.md file. No code changes.
FossilOrigin-Name: 3161b8028916bff9a13a04bfb1996bce7e1274a3c403fc58f4d798afd30c528f
2024-08-21 13:44:40 +00:00
drh 4cc86b6e92 Add code comments for a "table-of-contents" and various milestone marks in
the 1300+ line long sqlite3Select() function, to help improve readiability
and maintainability.  Comment changes only - no functional changes.

FossilOrigin-Name: 00cfbb9fa5136e6a7847da4e4ab30d320ca79c22acda9db2030e558d59b8c744
2024-08-21 12:01:46 +00:00
drh 91937a6961 Fix a minor typo in a comment.
FossilOrigin-Name: 92c80af1129051c9eded8df170730ad6366b4f7715dead34c4364c8149d0dce9
2024-08-21 10:37:59 +00:00
drh 01972f55fe Improvements to treetrace output for subqueries. Debug code only.
FossilOrigin-Name: 0a835d18d9063b17a1d506fd989ebcf7f0d76593978a3bd5981be59618335f21
2024-08-21 10:32:00 +00:00
stephan fb7d0c3c01 De-duplicate some error-output code in shell.c.in as part of tracking down the cause of [forum:5647ca2af1|forum post 5647ca2af1].
FossilOrigin-Name: fd5904495e0c775174f9380bc6877fb9def3d30dec1c9315979ad4503a18d70b
2024-08-21 09:56:45 +00:00
drh 8c58fd78c3 Remove incorrect assert() statements in the SrcItem invariant validator.
dbsqlfuzz 7f908865436ce531b0ace55c97a1c71d05c4e76c.

FossilOrigin-Name: 81a1ede38823b8d50e221ecb6ce52a05d82a856099002a71d9f1ac561a587f05
2024-08-21 07:38:14 +00:00
drh 5648d717b1 Refactor the SrcItem object to move fields associated with subqueries out
into a separate object named Subquery.  This reduces the size of the SrcItem
object by about 1/3rd and provides improved performance.

FossilOrigin-Name: 484bcd75bc95491d8540c791c1c4d40d996cb465839564662e14f98739699bf1
2024-08-20 23:11:28 +00:00
drh a0651b3707 Fix a name resolution issue with CTEs.
FossilOrigin-Name: 4fa8235dd59cd683d6c6c97bfe181a9637be7c054d435323c903b9dbd74aff02
2024-08-20 22:44:40 +00:00
drh bb36d55e63 Fix minor comment issues.
FossilOrigin-Name: c1bbed19f4348ec31c3cb4723eaa8f1554bb58ef4de7feb3a0f39612785f13d5
2024-08-20 22:05:01 +00:00
drh 0766cbf511 Remove unreachable code.
FossilOrigin-Name: 17699329aa8e234c6793a38db5ca05def9395b287bcc8bc05493b824327edb59
2024-08-20 20:01:21 +00:00
drh 692c160360 Tighter checking of access constraints on union members in SrcItem.
Improved invariant checking.

FossilOrigin-Name: fd72d3400a8fe5747f494eee81654698acee350bb95b9db269e87d857af03492
2024-08-20 19:09:59 +00:00
drh ff176231da Fix some stray SrcItem field name fixes.
FossilOrigin-Name: bc5f5ce59e1e4323422bda7d002310923f927a03b4fd42749bf04f6c9853956b
2024-08-20 17:41:44 +00:00
drh 27c680cc69 Fix a memory leak so that now all dev tests (including TH3) are passing.
FossilOrigin-Name: 3995c45fff0e4bd10bcf49cc16eb1050216426723c63ba56d3ae5ba738c34019
2024-08-20 17:24:42 +00:00
drh ff4ad29d05 Memory issues fixes so that mdevtest now passes.
FossilOrigin-Name: b249516f6a6650808e035ec219e762bf24dcb7c32a6235984b995d08d07d35d8
2024-08-20 16:50:21 +00:00
drh 781163aa9d When the database encoding is UTF-16LE and the GLOB optimization is used,
it is ok to use the range search over an index, but it is not ok to
disable the actual GLOB function call.

FossilOrigin-Name: 3399698376761ab8c422f8ea02bfa2759afb606f08bedbd1cf7eee834229a9aa
2024-08-20 14:12:16 +00:00
drh 6ad4e9fd2a Fix for the UTF-16LE problem reporte by
[forum:/forumpost/dc7e1b7527e84343|forum post dc7e1b7527e84343].  Because of
the unexpected ordering of characters using the default collation (memcmp()
order) in UTF-16LE, the LIKE/GLOB optimization restricts its attention to
the pattern prefix that is all ASCII, which is the common case.

FossilOrigin-Name: a5797ebdea423afc3d2d3bd8adaf1575d33a01f594c0c315afcb1499f1718e9b
2024-08-20 12:09:55 +00:00
drh 1c8ed5fa43 Earlier error detection while processing complex aggregate
queries.  dbsqlfuzz 5242c2f07f4aa031aa3c80461f18e9b7619ede9b

FossilOrigin-Name: 70f4973078ffc72f4ff247234e6f8e695b40803c3e7c9ed12050d97195728352
2024-08-19 23:43:08 +00:00
drh 1521ca4c20 Refactor the SrcItem object so that information about subqueries is stored
in a separately allocated Subquery object.  This reduces the memory requirements
for SrcItem and makes the code run faster.  It also provides an expansion path
for subquery processing that does not burden simple queries.  The current
checking mostly works, but there are still issues that need to be tracked
down and fixed.

FossilOrigin-Name: 8ff5dda8448d7e1a533d7f27db2573ce68fa9956b9d9847ced45e83c1f06bab0
2024-08-19 22:48:30 +00:00
dan 127812e645 Update some comments that are processed into the fts5.html webpage.
FossilOrigin-Name: 3e06ab218bbd1ed75a24afb44e8df9ce84e9fc24701428cb8b3459760f44006d
2024-08-19 20:35:30 +00:00
dan 18557fdeb5 Add the fts5_locale() function and related functionality to fts5.
FossilOrigin-Name: b9632900100bdbc913f83bfb03b32585cf07a192b9a7f26b9bebc7d91e63a610
2024-08-19 14:33:39 +00:00
drh 922cf3e2e4 Fix leap-year handling for dates prior to 0400-03-01.
[forum:/forumpost/eaa0a09786c6368b|Forum post eaa0a09786c6368b].

FossilOrigin-Name: 474b7e34b83bc5e85854bc3b386f31ff39b390549d89b94921f33bbc5b658d1d
2024-08-19 14:20:18 +00:00
drh 5a18c1f9cd New date/time test cases to validate ancient dates.
FossilOrigin-Name: 82719074f090d9d0a0b9baea0dee7b1dd40a272e3f3e45043d4a640c07989d5d
2024-08-19 13:53:49 +00:00
drh aa2258e35b Attempt to fix date/time calculations for days earlier than 0400-03-01.
See [forum:/forumpost/eaa0a09786c6368b|forum thread eaa0a09786c6368b].

FossilOrigin-Name: 00cae11fffaf50e2133915e851d41098d00b6b1458e1438bcb6664e1411d8498
2024-08-19 12:54:12 +00:00
dan f5b1c3da36 Merge trunk changes into this branch.
FossilOrigin-Name: 6787603bd0d8117e41e6b572c0d7cada0f6d7266a4ff2ad79f9471b9beb28a9e
2024-08-19 10:40:08 +00:00
dan dd9a7e4540 Fix a problem with detail=none, content='' tables.
FossilOrigin-Name: 4b8070816ada3f269d53c9cee20669f59e19a23c31c8509fc397c21dd097ec9f
2024-08-18 14:46:13 +00:00
drh 901b671455 Automatically disable directory fsync when compiling for AIX.
FossilOrigin-Name: 8d170e07e20c21a5bb97fdc8c2d01d92178f5fe740e60d203e4621747cfce33e
2024-08-18 09:53:37 +00:00
drh b204b6aa7b Give unique names to fields in the SrcItem object, to facilitate analysis of
how those fields are used using "grep".

FossilOrigin-Name: 9f5aeef3cbc2c95267c8f7bf60d5c66971a76789669fb0e8f853273ff6f616f2
2024-08-17 23:23:23 +00:00
drh 8797bd695f Reduce the size of the SrcItem object by combining fields into a union.
FossilOrigin-Name: a4c59ac3c6ec979c25b544d29e47b8e39f6439c098eed8f84b3bd506c9adf047
2024-08-17 19:46:49 +00:00
dan 6c796631fc Fix a broken assert() in fts5_storage.c.
FossilOrigin-Name: 01116e32797e1b127ba79059d890fbe5075eee2b6e3ce4468e82862b0fc3aa46
2024-08-17 19:40:15 +00:00
dan 408a34925d Merge trunk changes into this branch.
FossilOrigin-Name: 6a8ff9ba5e71d817489093d8dff0a8d77365b4222773b941accbd58558d24379
2024-08-17 19:11:09 +00:00
dan ef2401f669 Tests to improve coverage of fts5_expr.c.
FossilOrigin-Name: f4b839e5265700b1a89066d1b6e0d0d010852a69c5da3d75d2c41624dbf3c0af
2024-08-17 19:07:13 +00:00
dan b651084713 Add tests to restore coverage of fts5_tokenizer.c.
FossilOrigin-Name: 8f9257361b05e368bf433e56d0698923b0f97d12e7c0ad7760aaab6746c0e467
2024-08-17 17:22:49 +00:00
drh 21363ac78d Adjust Makefile.in so that it outputs a slightly better error message on an
attempt to build something that requires TCL libraries when HAVE_TCL is false.

FossilOrigin-Name: a4043cbeb8a08fca2fdd2ea703e030d3a5574cc6002292ecc6f0e88c116472a3
2024-08-17 16:17:16 +00:00
drh f87a54ab41 Adjust the "configure" script so that it just disables the ability to
run tests rather than erroring out if tclsh is unable to recommend a
suitable tclConfig.sh.

FossilOrigin-Name: 793ff83d09bea165c8cedc978afd3fcfb1a4cee894c5914aa1d92416afce963d
2024-08-17 15:52:21 +00:00
dan 52d0310256 Fix a typo in an "ifdef" that broke SQLITE_OMIT_ANALYZE builds.
FossilOrigin-Name: c09da26cb6f772a18c595ff0eb55d8345a377c3ef5ed02a5e539ffdbe9d07f85
2024-08-17 14:59:26 +00:00
dan 342984075b Add tests to restore coverage of fts5_config.c.
FossilOrigin-Name: 9d971b31df7ad4d68eb348f95d8f996071cf87d41c47033bde3fcc4dba732e06
2024-08-16 19:05:47 +00:00
drh 65a46af7ae If a subquery has an ORDER BY clause and that ordering is helpfile in
satisfying the ORDER BY or GROUP BY of the outer query without doing an
extra sort, then omit or reduce the sort in the outer query.  Call
this the "order-by-subquery optimization".

FossilOrigin-Name: 7a0cdc7edb704a88a77b748cd28f6e00c49849cc2c1af838b95b34232ecc21f9
2024-08-16 18:51:46 +00:00
dan f0f240c0d8 Add tests to restore coverage of fts5_storage.c.
FossilOrigin-Name: 38841881a08f4d75c2dfcbc1b2b45e311d7dda1287780f8ba1c8388f7adc1629
2024-08-16 17:54:00 +00:00
dan db79dd1f88 Add tests to restore coverage of fts5_main.c.
FossilOrigin-Name: 681edd08ab7024ddcd6447a64d8aad581b47b039481b697d91d26e6c6660f373
2024-08-16 16:20:43 +00:00
drh b8123415b2 Ensure that memory allocations in ANALYZE are always 8-byte aligned in order
to satisfy a new assert() added by [539e4f661767ef90].

FossilOrigin-Name: a1915cbdeccac2ed49fb8a9733abf2c6239396e3174fed2ff275f66b606c48b6
2024-08-16 15:35:20 +00:00
drh 2ed4f5016a Fix handling of COLLATE. Add test cases for the same. Code cleanup for
improved understandability and maintainability.

FossilOrigin-Name: 41a41c173a9d15d94f23d73a5c04bfb1616cb9223bc81d41808f9b4d00817fbf
2024-08-16 11:26:21 +00:00
drh 42f997d768 Bug fix in the subquery ORDER BY propagator.
FossilOrigin-Name: 5a9a3b8af7ac0aa1c04ad2d735e341c92d67952acb9a1d30217c0471e92cd468
2024-08-16 02:19:17 +00:00
drh 743188642d Improvements to the subquery ORDER BY decision algorithm. Fewer false-negatives.
FossilOrigin-Name: b82421e3f5811946e9d60b845fc882b6ea5c53c648695654c6900754427bf9bf
2024-08-16 00:37:54 +00:00
drh 235b5d0ac5 If a subquery is materialized due to an ORDER BY and that ordering is useful
in helping to satisfy the ORDER BY or GROUP BY in the order query without
doing an extra sort, then omit the extra sort.

FossilOrigin-Name: 2fbb4dc2327ee435cb2b7a4adcddf5a9cee6dff7de96e2ecb761166427b5ddea
2024-08-15 23:38:52 +00:00
dan 41ebf965cd Extra tests.
FossilOrigin-Name: fb257540d32ced4a5fe0759d3ad9c1b36fd2b7d64d93cb0a0ecdb48355a68b7a
2024-08-15 20:33:05 +00:00
dan 189c41221d Further tests and fixes for this branch.
FossilOrigin-Name: d27985245a0e8c0d6b04323c98b26b6a8fb4e489fa8f5f3234252c7c198f23c8
2024-08-15 18:50:13 +00:00
drh 7c5a829025 Improved help message for --disable-tcl on the configure script.
FossilOrigin-Name: 96e6cfb211f7f1aab50f997f4bc61dfb9701beb720c59bc413a4285c1ae5e20d
2024-08-15 15:31:46 +00:00
drh 3f138e1d8f Reinstate the --disable-tcl option on ./configure.
[forum:/forumpost/845d4a57becc7f3c|Forum thread 845d4a57becc7f3c].

FossilOrigin-Name: de927016aadd7ee55d947134e3540907a3ea5ab4015034c5d088e3a84905d98a
2024-08-15 15:23:33 +00:00
stephan ff7200e75b Doc typo correction reported in the forum.
FossilOrigin-Name: 48900a867cc4b6d733d2a3533a553af3dfadf96d3ef7ddf4c72bd432e7bf0f76
2024-08-14 20:00:03 +00:00
drh 78f9ba9774 Improved documentation for the sha3() SQL functions in the shathree.c
extension in ext/misc.

FossilOrigin-Name: 0ce609103eb35cfa26d9b6fa1769679be7e2b9032c37cc8c00a194fe355b06a4
2024-08-14 17:58:46 +00:00
dan 8ff952773d Fix an assert() in fts5 that might fail with an expression like "... NOT ''".
FossilOrigin-Name: 317c91edfc69d1d47e233bb6ac13934241742fda1ba03a88fd51bdf98fcbc463
2024-08-14 14:26:02 +00:00
dan a7384e0de2 More tests for the new code on this branch.
FossilOrigin-Name: 00792e807f1dde750e6ac9f9b0095cf60b9fa6ff7cf4b14440600a21de2ee61a
2024-08-13 21:15:43 +00:00
drh 797fcb8433 Add the sha3_agg() aggregate to the shathree extension.
FossilOrigin-Name: c4d7f9996ce4f5f6d08d83fc3abdb81b6825cfb556318f90c6896736a1da5175
2024-08-13 21:04:00 +00:00
dan 7dad9b4297 Add tests and fix minor issues with the code on this branch.
FossilOrigin-Name: def5243a7b4f1d50427ba607d31332db2d6ac34b181b0cbd2ed4911064f5637a
2024-08-13 15:04:00 +00:00
dan 3e38aa0821 Add extra documentation comments to fts5_main.c.
FossilOrigin-Name: 1a7a9bd3f6a2b9347720f7f0386399e7f14b428500acf07d7c55b9dde1ec233a
2024-08-12 18:39:13 +00:00
dan a4a8e91022 Fix problem with some fts5 aux function APIs with (locale=, detail=none/column) tables.
FossilOrigin-Name: bf116dec6fb20cce69099cb8c031b0de511195482919a99ccfb3c498e9bf8125
2024-08-12 17:28:13 +00:00
dan 10e54e365a Fix further issues to do with fts5 locale support.
FossilOrigin-Name: e626123580065986f7df50b6140f00048944becce179b9391fbf09f97ac55485
2024-08-12 17:03:37 +00:00
dan 29d5e43ad4 Update the porter tokenizer to use locales.
FossilOrigin-Name: 3291ce3a3359a80e51e4546a3d7a187cbe4c7530fca6632f0bb2728525efe212
2024-08-12 11:46:09 +00:00
dan 1286677773 Update the auxiliary function API to include xTokenize_x2() instead of xSetLocale().
FossilOrigin-Name: f7d56a1f2149f0da117167db62e2c28ec337e8da3403873b64cdfc6a951e2e8e
2024-08-12 11:13:56 +00:00
drh 8c411f7fce Resolve parameters Bind $int_N and $test_T in fuzzcheck inputs.
FossilOrigin-Name: 9c10664416274df6f8da53ddd86f6356c9704ad798fd4034d2784ae433c1c056
2024-08-12 09:49:02 +00:00
dan 9b118de9d5 Merge trunk changes into this branch.
FossilOrigin-Name: b243007525a825b3daf8aa9bb2d3088efb853bd8b7c9ea3c0924fde193eb5c44
2024-08-10 20:03:01 +00:00
dan 195ef6baca Prevent the fts5 xPhraseNext() or xPhraseFirst() APIs from returning an out-of-range column number, even if the database is corrupt.
FossilOrigin-Name: d4014c87ba9b011a6a04c2bf85879b668dc762ebcbbfb50a2f8a417ce594ef88
2024-08-10 19:57:28 +00:00
dan 7978910f85 Fix an uninitialized variable in fts5_tcl.c.
FossilOrigin-Name: 924d3467cebd71ac8dfef8225965d71eda82ef1f0b43508af5b7ea78e2099cf3
2024-08-10 19:18:19 +00:00
dan ff6ab9dd2b Update the fts5_tokenizer_v2 API so that the locale is passed as parameter to xTokenize(), instead of via a separate call to xSetLocale().
FossilOrigin-Name: 03e63ed24e7a08817341e59b075ae2d4e3f7a5e5b37e0e6138359d5fd29a5e9e
2024-08-10 18:59:36 +00:00
drh 5af9fd53f4 Revision to check-in [d9f726ade6b258f8] so that OOM and other unrelated failures
are not overridden by a syntax error in the tokenizer spec.

FossilOrigin-Name: 3778b2a9ca1cc12a88ef6c32a1ee7c58a0a829ed9715a3d32a225d377d7527ef
2024-08-10 15:46:57 +00:00
drh 4a9a5cbbe9 Fix harmless compiler warning related to the TCL8-to-TCL9 transition. This
change in testing code only and is not relevante to the core SQLite.

FossilOrigin-Name: c86ef65545485eae6aca23b4582e8115d4edfdd6084afa77858e11b21aa270f6
2024-08-10 15:05:22 +00:00
drh 6010980914 Fix behavior change in the offset() SQL function introduced by
check-in [f0b671183f44d0ae].

FossilOrigin-Name: c2ac17f183082d6388336338b8d5c0b334095e5f77a27bc08419431f37471d22
2024-08-10 14:53:21 +00:00
drh fe4ed96006 Enhancements to covering-index prediction. In particular, avoid the
false-positive prediction described by
[forum:/forumpost/e60e4c295d22f8ce|forum post e60e4c295d22f8ce].
Add early detection of over-prediction of covering-indexes so that
sqlite3_prepare() will return an error rather than just generate bad
bytecode.

FossilOrigin-Name: f0b671183f44d0ae294956e7651a1653f47bd6219f9636872d15993f30f28dfb
2024-08-10 10:05:22 +00:00
drh 4098aa5d19 Add an assert() to fix a harmless compiler warning in the recovery
extension.

FossilOrigin-Name: 2502339339f3c831966479a400c2b1a531fb4d990b1776b4dc4870cf734c3fcd
2024-08-10 09:56:36 +00:00
drh 555aaa432c Fix a few minor TCL9 compatibilities issues.
FossilOrigin-Name: 69eed19914ef52bc0101f4ae1c7b242df4ee28675b3581e1f4d60a35494f9f76
2024-08-09 22:48:11 +00:00
dan 5eba4281b0 Ensure tokenizers registered with xCreateTokenizer_v2() can be accessed using xFindTokenizer(), and that those registered with xCreateTokenizer() work with xFindTokenizer_v2().
FossilOrigin-Name: a3ef7d47b582a66a85ebe802ab40114f77289d6b44a4b375ea7858c60f59b27f
2024-08-09 20:59:50 +00:00
drh c5900bfd59 Import the second ALTER TABLE fix from trunk.
FossilOrigin-Name: 1de3e5883613ff6093203720f3cdcf6b3a3e626c99735284fae95a438e1ce24f
2024-08-09 18:53:02 +00:00
drh c60c928717 Fix another instance where ALTER TABLE was returning SQLITE_INTERNAL instead
of SQLITE_ERROR one malformed input.

FossilOrigin-Name: b416756320dfb46ad72b843a7fbf18807d3fd1966251c320de626280b5238a5c
2024-08-09 18:42:01 +00:00
drh 8f924f0530 Merge the error code fix from trunk.
FossilOrigin-Name: 81dfb8cd5d59ecf974018b03175ddabd11366d2aca0211dc982f7e14ff314d4d
2024-08-09 18:22:20 +00:00
drh 610a5bafe2 Fix the internal routine sqlite3ResolveExprListNames() so that it returns
SQLITE_OK or SQLITE_ERROR instead of WRC_Continue or WRC_Abort.  Without this
fix, some times of obscure syntax errors end up returning SQLITE_INTERNAL
rather than SQLITE_ERROR.

FossilOrigin-Name: 9052187efd1f78abd9b285ac94269a3ba4d65b6aa74c9fa34002ee0628c83919
2024-08-09 18:18:11 +00:00
drh 8bc2647e0c Do not attempt to use a covering index based purely on columns-used
when doing an UPDATE or DELETE of a WITHOUT ROWID table.  Raise an
SQLITE_INTERNAL error if there is ever a situation where a table reference
cannot be converted into an index reference when the query planner thinks
that a covering index is appropriate.

FossilOrigin-Name: fae39ae9320c0f4fcc2e3b3baf0a4170ba2b9a04634a0a1fa41dd4918a74b106
2024-08-09 17:09:18 +00:00
drh 1107b4b9cf Bind the new debug parameters in fuzzinvariants.c.
FossilOrigin-Name: 7e1dc263051cf50db04643d1a2aa9f91559b2b121859b750ce4446012d5f3c3e
2024-08-09 12:35:27 +00:00
stephan caa7a62591 Remove unused static var cBadGroup from ext/consio/console_io.c to resolve a compiler warning reported in the fossil forum. This is a build fix, not a functional change.
FossilOrigin-Name: fa047c3ea7a03d76afd6a11f58ef7b84c653f583ed795e0de5be2a6b986e558e
2024-08-09 12:19:11 +00:00
dan 0c8c9a64b3 Ensure sqlite3expert.c unregisters any SQL user-functions it registers with the database handle before returning.
FossilOrigin-Name: 123b154ce3b6fee1bbf483704812bd6f8538966f9687520b4470d700f0270719
2024-08-08 15:26:11 +00:00
dan 679f5d458e Add assert() statements and reorganize code slightly in fts3 and fts5 to make it easier to follow.
FossilOrigin-Name: 797b0a13fd7a42b0a48ecbf0cd1961aa932da3e9c9ccffd903a3a4d963d0cc54
2024-08-08 15:07:27 +00:00
drh 1193e4679d Do not let the number of terms on a VALUES clause be limited by
SQLITE_LIMIT_COMPOUND_SELECT, even if the VALUES clause contains elements
that appear to be variables due to the use of double-quoted string literals.
[https://issues.chromium.org/issues/358174302|Chromium issue 358174302].

FossilOrigin-Name: 670beb133eb203065a75022f0c6db7c605a4e0e22c8ef6d6b4724be2663ff3dc
2024-08-08 14:45:50 +00:00
drh 35c6f58dce Back out the --memory option to ".parameter init" in the CLI, as the
capability is no longer needed for testing due to the new "$int_N" and
"$text_T" automatic bindings, and the "init --memory" is hence just
added complication.

FossilOrigin-Name: 3b1b0c141993eb0f8749f54ea40d6014f9bdccbe0fdb3ccccad971a0baea8d3c
2024-08-08 12:14:07 +00:00
drh 6e7a0c2d86 In the CLI, recognize magic parameter names "$int_NNN" and "$text_TTT" and
bind them with integer value NNN and text value TTT respectively.  Intended
for testing and debugging use only.

FossilOrigin-Name: a929cdb00ff74d77cdf55087d32abf53578f7127b36276f89b64ccbef1d4a9a4
2024-08-08 12:08:36 +00:00
stephan 5529ec74da Move a misplaced va_end, as reported in [forum:702c79e9da|forum post 702c79e9da].
FossilOrigin-Name: daa25fb35fd7bdd482d51214439f38b0b9a7df93f689a2b3d30a113daa9f2a1a
2024-08-08 10:51:56 +00:00
drh 6d02d2647b Add the --memory option to the ".parameter init" CLI command. When present,
the --memory option causes the sqlite_parameters table to be created in a
completely independent :memory: database.  This can be done to avoid
parameter binding queries from being affected by debug settings such as
".wheretrace", ".treetrace", "PRAGMA vdbe_addoptrace=on", and similar.

FossilOrigin-Name: 4e69dce2093b75b7db4fbdca4953b664b907be15d991ed352ea1d87c64fbf9d2
2024-08-08 10:10:38 +00:00
dan 5cd01c30b4 Fix a broken assert in fts5_expr.c.
FossilOrigin-Name: 08cc5488404d068e59378b82988460793710df43ec21b4a83a794b497abd035f
2024-08-07 21:20:08 +00:00
drh c76520c5b9 Add a new assert() to help static analyzers understand that a pointer is
never NULL.

FossilOrigin-Name: 433f2b942ee6f79d50ebe9b08fa3ea8162db6a10ce9d80e2bc193124baa1b083
2024-08-07 15:17:37 +00:00
drh 92d317f787 Fix a harmless compiler warning in an assert().
FossilOrigin-Name: 5e4c9a74b2efa74ace67f644fb6bb37e07f5982f8faaca9463e3daa50b0469d7
2024-08-07 14:54:54 +00:00
drh eaa560f3fc Remove unused test cases from FTS5, as they interfere with "grep".
FossilOrigin-Name: 048a71bae48aacdfc91e59330db4d4b3d663f00665f51a7110ea82e0508758ec
2024-08-06 23:09:37 +00:00
drh e9b919d550 Improved robustness of parsing of tokenize= arguments in FTS5.
[forum:/forumpost/171bcc2bcd|Forum post 171bcc2bcd].

FossilOrigin-Name: d9f726ade6b258f8723f90d0b04a4682e885e30939eb29773913e4dfc8e85503
2024-08-06 22:49:01 +00:00
drh 210f6f89be Improvements to ./configure that will hopefully break fewer builds.
FossilOrigin-Name: 769e32a69b7b7c04225afa0371f139b2ed29aaee5a7a4159a30d600ed9f25c57
2024-08-06 20:00:10 +00:00
drh 575a7b85f5 Change the AggInfoColumnReg() and AggInfoFuncReg() macros for
compilers that cannot parse empty elements of a comma expression.
[forum:/forumpost/8fd21998dc|Forum post 8fd21998dc].

FossilOrigin-Name: 533a6251f188805363f0e39613ea03b1bfd758eaea00e0855803238585bdfec7
2024-08-06 10:29:41 +00:00
drh f2b21a5f57 Restore legacy "tcl_install" makefile target, as an interim measure until
I can figure out what is going on.

FossilOrigin-Name: 931ad7d9e3aedb6d466fffc0af1f8d6b20d57a35dec644f28585f3e84f22d1ce
2024-08-04 10:13:01 +00:00
drh 3a799b3e4e Fix to the previous checkin: The colUsed parameter should have high-order bit
set if any of the 64-th or greater columns of the virtual table is used.  The
lower 63 bits of colUsed always show the usage of the first 63 columns of the
virtual table.

FossilOrigin-Name: 90ac8457750ace1d76d7bc957af7877e86e6301bb07361e19beaf5c7b3b6085a
2024-08-03 23:00:17 +00:00
drh 133f930e61 Ensure that the sqlite3_index_info.colUsed mask always includes the PK fields of WITHOUT ROWID virtual tables.
FossilOrigin-Name: ff4ac279b02190cc2107b0b110806dd7abcea47a6589d827b5ee39d4b80fb719
2024-08-03 21:45:46 +00:00
dan 5c85ddc3d7 Fix a typo in [c327c0c0] preventing the shell tool from running ".dump" scripts that feature virtual tables.
FossilOrigin-Name: 10e97abb878debb67410902ea1af4df75a9ced1e38fec710b1796c5143aff48e
2024-08-03 18:58:25 +00:00
dan 0a83dac31c Ensure the sqlite3_index_info.colUsed mask always includes the PK fields of WITHOUT ROWID vtabs in cases where they may be used.
FossilOrigin-Name: c327c0c02cfefdba373cfb15933a9cdfddb578b6582f2ce7c08929203743ffe9
2024-08-03 18:45:48 +00:00
drh 4a36d30493 Add the --status option to the test runs using testrunner.tcl. Only works
on Unix platforms.  The "exec" command appears to interfere with VT100
escape codes on windows.

FossilOrigin-Name: 94015cda4ceb4292ceceadb951fe5d9cb3e4e20403719b7254ad094a5b749ab3
2024-08-03 15:55:25 +00:00
dan e317e7f4b4 Change things so that locale=1 is required to write fts5_locale() values to an fts5 table, and so that blobs may not be stored in indexed (i.e. not UNINDEXED) columns of these tables.
FossilOrigin-Name: c98ccc12169419b8b27ead89ef0665de40320277c5daa748b80869337419e43e
2024-08-02 21:06:13 +00:00
drh 8517b7d2b6 Make sure the input buffer is big enough for an memcpy() when doing the
restore autodetection in the shell.

FossilOrigin-Name: 1637d29d518b3b4534a1b4c0dc0eddcb770f6f71763e4177812a3e79b97d2365
2024-08-02 18:20:10 +00:00
drh b2d590c5f9 Add the "-d SECS" option to the "status" command of testrunner.tcl
FossilOrigin-Name: 2151ea31632f7aa363c7d4b7205e1174a45d710783a8efad8176049d356cfc70
2024-08-02 17:36:34 +00:00
drh dcea6335c7 New MSVC makefile targets: tclextension, tclextension-install,
tclextension-uninstall, and tclextension-list.

FossilOrigin-Name: c38734f57509c50dd28029738dd602600950703b773d9b7b60fdb1dcb06e8fd8
2024-08-02 15:28:40 +00:00
drh 9e88d4bb8a Fix typo in a progress message in the builttclext.tcl script.
FossilOrigin-Name: 5e7c94645632b736e805428ff4c135666ab525fac99c29c12d5127b06f39fc6e
2024-08-02 13:56:55 +00:00
drh eb48fddac7 Fix problems in the configure/Makefile system caused by recent enhancements
and report by [forum:/forumpost/242ebd0c81|forum post 242ebd0c81].

FossilOrigin-Name: a59319fe4adc094381c46e490289b3e0cda8f804edaea6984571c47a68a23eef
2024-08-02 11:32:28 +00:00
drh 698386ca2c New configuration option: --with-tclsh=FILE. New makefile targets:
tclextension, tclextension-install, tclextension-uninstall,
tclextension-list.

FossilOrigin-Name: 888284d1d47269e66e23627e2519cd2cf83ef65a777a679af20c288453f092e2
2024-08-02 00:59:32 +00:00
drh ea9a25e500 Previous Makefile.in change broke the tclextension-install target.
FossilOrigin-Name: 7748367c78a1f480ec9e892ba77652e3c31a4b387b89221ae584891818804851
2024-08-02 00:56:31 +00:00
drh 0c059b598d Continuing refinements of the tclextension-install makefile target.
FossilOrigin-Name: 871c20a848e0e9b7f3d5661bd076fde16e9ec1e445a7ee657ef267978988ad56
2024-08-02 00:51:52 +00:00
drh 490661fd96 Extra robustness for the SQLite Tcl Extension builder, so that it works
on Debian Linux.

FossilOrigin-Name: 2f0738daaff48c51a60f063af6e453443bd7eedf6936daab325b2a36927c7a2b
2024-08-02 00:19:59 +00:00
drh bb99e73ef5 Simplification the ./configure script. Carry Makefile CFLAGS and OPTS through
into builttclext.tcl.  Fix a bug in tclsqlite.c introduced by the previous
check-in.

FossilOrigin-Name: 72a80aa0abb121a23f8cc1eb1af04ba06c733a7a40c06f1fe9e62f2a0a26ca6e
2024-08-01 23:30:29 +00:00
drh 58c5a95c07 Add the tclextension-list makefile target. The the makefile running on Mac.
FossilOrigin-Name: 2f667cc8e54167342e17e63e1a017388365ebf4cd379f9c16c12e4603b34a326
2024-08-01 23:00:37 +00:00
drh 1bed50d424 New makefile targets: tclextension-install and tclextension-uninstall. Seem
to work on Linux.

FossilOrigin-Name: 534f8344abbda78e841edafe84c27ea8b1dfdecb9ab51271772a7f7264ef5b8c
2024-08-01 20:26:22 +00:00
drh 24b1d7a0c8 Work on a TCL script that will compile and install the TCL extension.
Works on Linux only, so far.  This is an incremental check-in.

FossilOrigin-Name: 58babd2aa4b5c9c70e1169cdf09f05eb95d7b13f50bb2ec0e487182288172678
2024-08-01 20:18:10 +00:00
drh 91db27aff5 Clean up and restructure the TCL configuration sections in autoconf.
The new --with-tclsh=FILE option lets you select the specific tclsh
that you want to run.

FossilOrigin-Name: 8fafc679d91e857602fbbe203144ca98242246660ede5a49c5fec8aaff571151
2024-08-01 18:10:00 +00:00
dan f971c15b1f Clarify the role of Fts5Storage.pSavedRow in the new feature on this branch.
FossilOrigin-Name: e8a61d5c48073fdd4d99d0b6fc70469b37af009f281336a44e3789e7eeed820d
2024-08-01 17:15:17 +00:00
drh a51de65758 Include a test case summary in the output of "errors" in testrunner.tcl.
FossilOrigin-Name: 173df1478e89996126e172656e35da8026d4ef145b2341ef56213f00ade14f48
2024-08-01 14:43:27 +00:00
drh 5cc7f4b580 Add the "errors" command to testrunner.tcl.
FossilOrigin-Name: 03b7f99229cfcffde024915e6812d75ae11318db9dc93a00838e4588a79b1243
2024-08-01 14:16:36 +00:00
drh a1291e79d3 Fix the tclsqlite.c TCL interface module so that it works with both Tcl8 and
Tcl9.  Make changes across the TCL-based test harness to enable SQLite to
be tested with either Tcl8 or Tcl9.  Get the --with-tcl= argument on the
configure script working. Testing changes only - no changes to the SQLite core.
I believe the previous merge attempt didn't work because of errors in the
merge itself, not because of faults in the code.  Trying again...

FossilOrigin-Name: ea9d88f9ca3399bca83bf03893689a927b73e481604b94527e42de43f103eb46
2024-07-31 22:36:14 +00:00
drh b030bc6980 testrunner.db should be in WAL mode for improved concurrency while running
"watch sqlite3 test/testrunner.tcl status".

FossilOrigin-Name: f23ad0979865f3c11a3dbd0598ee7c4e2eabeaf1863d000fc0242e18890a4a11
2024-07-31 22:26:04 +00:00
drh 5addf9f111 Make the #include section of tclsqlite.c the same as tclsqlite.h.
FossilOrigin-Name: 2afadbeb124d6d7bb81d473379269014ebd8601f98f231e2218f54350a2e5fd3
2024-07-31 22:25:25 +00:00
drh d888e79bb8 Fix typo in testrunner.tcl for the "status" command that was causing it
to fail if any errors were seen.

FossilOrigin-Name: 8327c5ed535c57c4082211a50bfb1c32ea5d5fe1cf71f37798d8b58e88948ac2
2024-07-31 22:17:26 +00:00
drh 3f91c05e5d Use <tcl.h> instead of "tcl.h" to include the TCL interface.
FossilOrigin-Name: 4e32d4aed7c487ee9ed39a7e4486c2989a01781a3edbe9cdce52c6ed357f6366
2024-07-31 21:59:29 +00:00
drh 47ce12d239 Fix the tclsqlite.c TCL interface module so that it works with both Tcl8 and
Tcl9.  Make changes across the TCL-based test harness to enable SQLite to
be tested with either Tcl8 or Tcl9.  Get the --with-tcl= argument on the
configure script working.  Testing changes only - no changes to the SQLite core.

FossilOrigin-Name: 2a04b1bea12b0b4c3387d675f487337533ac0813248f70085398485e4cacd691
2024-07-31 21:46:46 +00:00
dan 5bd8cc7dd5 Fix various problems with the code on this branch.
FossilOrigin-Name: 8bd4ae7e95c7b6ce34db5ea705dc136e742a22f333d0e7370b485ebd736b5ec2
2024-07-31 20:49:00 +00:00
drh ed1b616f4a More tweaks to testfixture-implemented TCL commands to make them safe for Tcl9.
FossilOrigin-Name: 67897ca97d8c98e119a498a3adb39548a579e12ee477e9dd74e9564a6f5e4c2b
2024-07-31 19:57:22 +00:00
drh a7382d3523 Under Tcl9, the %x format letter truncates to 32-bits. Must use %llx in order
to get a 64-bit rendering.

FossilOrigin-Name: a3044e0ae65c099d76bf04536e223e70d89971688627c342252951f6c65f49d1
2024-07-31 19:56:14 +00:00
drh 15fef79a29 Fixes to testfixture routines needed to test snapshots.
FossilOrigin-Name: 66f61c3b35383b2575774d309043a722cc87a53d03518d339d6dbdcf342adc93
2024-07-31 17:15:24 +00:00
drh ff79000f28 Fix a typo in testrunner_data.tcl that prevented --with-tcl specifications
from being carried through into sub-builds.  Adjust test cases to account
for new floating-point differences discovered when --with-tcl was fixed.

FossilOrigin-Name: b8f81351914deac99b14be6bb5e4096c1efed9bdb057750825760f09dae04656
2024-07-31 16:37:02 +00:00
dan 8e3042b565 Add missing documentation for new features to fts5.h.
FossilOrigin-Name: fa0da3b28e411affd45a918d6b7faba49f744ca8b4adf3cd5ce6609bb630499e
2024-07-31 15:46:41 +00:00
drh ad2bcef112 Remove obsolete testfixture TCL commands formerly required by Windows
but now handled by Tcl itself.  Update tests case accordingly.

FossilOrigin-Name: 4f065fb638b24b33283518af8ad55f28a49cfac4086fa5e4568e2f3a6814962d
2024-07-31 15:04:37 +00:00
drh 3f80dbd51e Fix problems uncovered while testing Tcl9 on Windows.
FossilOrigin-Name: d5523c77fd0bcdc8344971a116d6ce9657f2b6daddeb7d936cd7607163a36744
2024-07-31 13:00:18 +00:00
drh 096c22ad5e Minor adjustments to get Tcl9-based testing working on Macs.
FossilOrigin-Name: 066c8672ee85a6ce972de38fcd3793fc2c1ef4f21c3de2379746d0ff18df8dc0
2024-07-31 12:19:16 +00:00
drh d3b58968a9 Adjust the configure script so that the --with-tcl option is used to
find the appropriate tclsh.

FossilOrigin-Name: 6fb9e37c751cd1a411c77f792794e1abafa5c40ad4dda8d433600d44d525a97c
2024-07-31 11:42:47 +00:00
drh f15c80d80f Patch to testrunner.tcl so that it works with Tcl9's pedantic UTF-8 checking.
FossilOrigin-Name: 8d4a23d32dc16b115153e6e100ba3ba15273c3e37310e8a1b4bace885c5383a8
2024-07-31 11:12:13 +00:00
drh e388fc7367 Fixes to tclsqlite.c to facilitate TEA installs.
FossilOrigin-Name: 7157c3c910565c9385a028793a0c0106c5064ab6a8a6efbe29dd1f1cdb2bd48d
2024-07-31 10:59:19 +00:00
dan c97cdbe523 Merge latest changes from trunk into this branch.
FossilOrigin-Name: ff64939ec8399949393f1029fa6d514892fbf2bf1498545300cc5e120b9622a5
2024-07-31 10:52:38 +00:00
drh 4400b0ac45 Fix a problem with strictly conforming UTF8 in shell1.test.
FossilOrigin-Name: 8ee187f98d310e1e7cf6c3fdf000c19e98a9f11e01436c3c407df04da79aa7c0
2024-07-31 02:01:19 +00:00
drh 3bad3d6964 Adjust a few tests that don't work even with the new floating point
comparison routine.

FossilOrigin-Name: 895125a4895099df7c3841ca7c34697ba17fd667bddbc2fd7148f7aa9d6d2b9d
2024-07-31 01:53:48 +00:00
drh f504cc761b Implement a new comparison routine to compare text renderings of
floating point values.  This gets the number of failures down to just 5.
But the routine needs work, and probably refactoring.

FossilOrigin-Name: 71f2ee5db01150707401804b136641170e7ed44760fccec20de19184e4d0a840
2024-07-31 01:45:14 +00:00
dan 9015b8822d Fix cases surrounding blob values being stored in locale=1 fts5 tables.
FossilOrigin-Name: ae435aff1785d5832821c19dc88ccf6c496a7ff55be80276b31e5c9abee723db
2024-07-30 20:39:58 +00:00
drh 262addd9ab All tests in "make test" now pass with Tcl9, except for about 198 cases where
the error involves small differences in the rendering to floating point
values.

FossilOrigin-Name: 8e27f5326c69aa4fb6f3f1f42668ab1b08140ab0a614ac4a9d94679c8fb9734e
2024-07-30 20:39:05 +00:00
drh a28a784ef4 More adjustments to the incrblob channel: Apparently you need to wait
until the close2Proc is called with a flag of 0 before actually shutting
down the channel.

FossilOrigin-Name: fa549a5507b5f805b469b4360c11155aa9d22043f01f6d9428bf44d0f2351eb0
2024-07-30 18:49:20 +00:00
drh 15669d302d Adjustments to test cases for session so that they work with Tcl9.
FossilOrigin-Name: d417415b967e62d41667e14ebf5455932ebf38d218a941f13878f0aba6d19bc8
2024-07-30 18:42:31 +00:00
drh 1c2ad465c6 Tcl_ChannelType implementations for Tcl9 apparently require that
wideSeekProc be implemented.  Also adjust minor test script issues for
fts5 tests so that they can be run sequentially and so that they do not
depend on the specific floating point output formats generated by Tcl.

FossilOrigin-Name: 19fda979c5dc1a385ed3f8ab8df34388c1acfc7ff951fe1b183a79186bd20cdb
2024-07-30 18:15:59 +00:00
drh 780187f090 Get rid of "-encoding binary" across all test cases, as that is no longer
supported in Tcl9.  Use "-translation binary" instead.

FossilOrigin-Name: e0d9670dd98a22d2e22aac8ba8720787a05e280e18ec9b2d4323f947c83718f5
2024-07-30 17:09:51 +00:00
drh 3302bf4dbd Use the SQLite format() function to format floating point values for test
results, to avoid inconsistences in TCL versions.

FossilOrigin-Name: 6a63c472190dafb36582c116c925bbcbe48c3a2f3217fc1ffcb64a733b0151e1
2024-07-30 16:59:33 +00:00
drh 1631c64f78 Fix the incrblob channel so that partial close works with Tcl9.
FossilOrigin-Name: d54ec2de78c2aed12be643e59a30b6827fe4728a0ab6504dd64ee9116e5f885a
2024-07-30 16:51:51 +00:00
dan 8174305e17 Update the highlight() and snippet() functions to use locales when available.
FossilOrigin-Name: 569ae56a673a2e101fac7003a1cb41c7a02a515adf55bd1e1f2a03c19eb2b085
2024-07-30 15:55:51 +00:00
drh 064b681e9b First attempt at getting the build to work with Tcl 9.0.
FossilOrigin-Name: 6e5bb48a74d63fb8c30528f0005d1763cd2dbb882abf86baf1565721e6bfcf84
2024-07-30 15:49:02 +00:00
dan 8f14c45197 Fix xColumnText() and xColumnSize() APIs. Add xColumnLocale() and xTokenizeSetLocale().
FossilOrigin-Name: 14006711d83d098e665c540b978b0e29aa8f458da1c2c8e9c2baf2ad5ebd502c
2024-07-29 20:31:17 +00:00
dan b4afecc626 Fix a couple of asan problems on this branch.
FossilOrigin-Name: 4e3e529313c86b42d5f1ba113d0714d1545bc6641e09e4537d622057f0352989
2024-07-29 15:00:11 +00:00
drh 07f215ad9e Fix documentation typo.
[forum:/forumpost/993cb82402|Forum post 993cb82402]

FossilOrigin-Name: 86de4e755e37dc1cbcbd59018927aa87ff49fc15f706a36187631d8f14075c12
2024-07-27 20:28:13 +00:00
dan 53bef48fbe Ensure that an fts5 UPDATE does not strip the locale from columns that it does not write to.
FossilOrigin-Name: 69205264debd829573b1c777a5a493cfeb6083c4cdec106b1f819989f859ac75
2024-07-27 19:46:10 +00:00
dan 2ec78c0e4b Add the fts5_locale() function, and begin adding the related functionality to fts5.
FossilOrigin-Name: 8839ef7cfb49239e7f1c4812a53a93a672827c88d6921408b1d5062b352c87cc
2024-07-26 20:50:33 +00:00
stephan b16c2980b3 wasm minimal build: strip authorizers and JSON support (saves approx 35kb). Strip vtab support from the JS bits but cannot yet strip it from the C bits because that requires a custom-configured sqlite3.c.
FossilOrigin-Name: eb64d106551718467e0f6c6b53695410bf4c566901008e4cda8580d0f7efa7b0
2024-07-24 23:58:28 +00:00
stephan fe225745fc Restructuring of the wasm build to support an experimental 'minimal' build mode which elides all non-core APIs.
FossilOrigin-Name: ee2191f7302210100fa0b29ace8156531ad995bf61aa2642e526e0901d0c6862
2024-07-24 22:07:18 +00:00
drh 4f2144dac0 Add the percentile extension to the CLI by default.
FossilOrigin-Name: bcc31846964102385d5a21eb5e85d7db153b155e76b4e2847c9453d3d0e1af04
2024-07-24 13:53:51 +00:00
drh b18d851119 Add the percentile_cont(Y,P) variant of percentile() to the percentile
extension.

FossilOrigin-Name: 095c22e62248f8ef50cd8531171827f50a7bdd4fc1128bf0e616a3eb2dce980e
2024-07-24 13:41:09 +00:00
stephan 4eabec5b18 JNI SQLTester: fix --new command to force-replace db if it already exists. Add no-op impls for --stmt-cache and --jsonglob commands.
FossilOrigin-Name: f1185dc349d076a6b8ea22f9b5cd527bfd60e9afd55eaec754c0e2b4d7edd5d4
2024-07-24 12:12:11 +00:00
drh 171c944345 Enhance the percentile() extension function to include the median()
variant.  Update the implementation to implement its own sorting
algorithm, so that the extension no longer depends on qsort().

FossilOrigin-Name: 6e31b1bab1f014933c671a12a5930c1e88d611cfe68d389e9ce888bd8842addd
2024-07-23 16:23:46 +00:00
stephan 8bd5ff4f32 Doc typo fix. No code changes.
FossilOrigin-Name: 8d558ad25bfbdea04de87616d4e3f664b5749a7d23643d1a0238e991b4bb337e
2024-07-22 21:46:55 +00:00
stephan faf10c521f Move a block of JS code which was inadvertently (and harmlessly) moved in the previous checkin. Clarify the semantics of an internal-use-only API. Add another WAL-related JS test.
FossilOrigin-Name: 6cd9f55a975b5237efee8776efce7e7836b41905ca750f82be3b90aa04c1dff2
2024-07-22 21:21:25 +00:00
stephan 71e2bdb2b4 OPFS VFSes: remove the on-open() pragma calls, as those (A) already reflected the build-time default settings and (B) they made it illegal to run locking_mode=exclusive, which is a requirement for WAL mode without shared memory. Modify part of the test suite to demonstrate that the SAHPool VFS can run in WAL mode so long as locking_mode=exclusive is used.
FossilOrigin-Name: 19cd8e2b056d7842ee39afb7160c901c9dc55a5bac8049cb0b5246210f6b920d
2024-07-22 20:58:51 +00:00
stephan 04416ddc51 wasm build: resolve a circular dep and do some minor tidying up.
FossilOrigin-Name: 9df3f1f24c6346dc94695bf533501c54379bb6e3cf492b67dda8a64a6a1eb495
2024-07-22 19:52:02 +00:00
drh 6326e30f86 Fixes to TreeView debugging output for VALUES clauses.
FossilOrigin-Name: b6aed8bcb06edc7f0221fd707d5adc227856fe62dbcaae5ffe1fb4faa5c542e1
2024-07-21 23:34:52 +00:00
drh c855df67a4 Improved debugging output when using PRAGMA vdbe_addoptrace:
Show the range of opcodes being checked for Column-to-Copy conversion.

FossilOrigin-Name: 2c122026db979a099a3d1a14ae1e01a0a64a559905ea414b2d80ed7dc3e04846
2024-07-21 23:10:55 +00:00
dan aecfb0a3b3 Fix an oversized allocation in sqlite3ExprCodeIN().
FossilOrigin-Name: d7be326a80e7b3aa8fd6e5e059c04e6ad3feaffcb20b1e3c251d7195ddc1be8b
2024-07-20 16:11:12 +00:00
stephan f73912694b Minor typo fixes in test-script-interpreter.md.
FossilOrigin-Name: bf54b26092ded2e6acc779acfb960364f05c665c7626c38ffae61caae5636184
2024-07-18 19:17:29 +00:00
drh d109de8f84 Fix a problem in FTS5 where it reports the wrong error code following an OOM.
FossilOrigin-Name: 0c1cc4071edcd3e465779bbb17ea3ee6ddaa7c93c4fde55e5f3e07aa4b45783b
2024-07-18 18:44:44 +00:00
dan 9d82438dcb Fixes for platforms with 32-bit pointers that require 64-bit values to be aligned.
FossilOrigin-Name: 539e4f661767ef90aef8d995f1f75fd5f550703bba1517cd3caff84a4afe2b37
2024-07-17 18:38:34 +00:00
dan a592883d87 Add extra assert() statements to the fixes on this branch.
FossilOrigin-Name: 81b6360050eea95e4367de1b41b5864a640b4d1c5c8fc3bea3b96ed770cb0325
2024-07-17 16:27:36 +00:00
stephan 1ffd7ed54f Slight doc touchup for [af41a1e6fc8b36e9bf65] based on feedback. No code changes.
FossilOrigin-Name: be7b1fc0c5d8cda971b471dfcb4637212bfff4f42b1e074077a381cc493d877a
2024-07-15 10:11:21 +00:00
stephan a0a1fb876f Improve one of the JS test cases.
FossilOrigin-Name: 3767d8bef2dfa661b56c1bfaa4695e32ce26874154e4a322f0d599c257c6fc70
2024-07-13 18:16:40 +00:00
dan 7acf972c59 Fixes for platforms with 32-bit pointers that require 64-bit values to be aligned.
FossilOrigin-Name: 2212d7488ed4ec2839ffa45cb9567056b36519434834634e4ecc441c330694d7
2024-07-13 16:53:56 +00:00
stephan 441993200e Add JS binding for sqlite3_column_decltype().
FossilOrigin-Name: 5252d292b14f6ed99b09f6330b19effd488c2b23ff6ea33311321a065d3f6ce2
2024-07-13 15:42:30 +00:00
stephan 7052c67c36 JS doc touchups. No code changes.
FossilOrigin-Name: a8e240495ff7e0cd38301ef2de215a7cc10fea832311bd19ca2592858ee4e6ff
2024-07-13 15:21:35 +00:00
stephan 55a4bea72a Add JS bindings for sqlite3_stmt_busy() and sqlite3_stmt_explain().
FossilOrigin-Name: b772edfb44143107d4993bde600d0f4c45184f29a4deee403105c64748c36523
2024-07-13 14:07:47 +00:00
stephan 0b9efaffd7 Add missing sqlite3_bind_parameter_name() binding to JS.
FossilOrigin-Name: 6dcfcc7e1c0772b11aec750bb75899a5c8e452735ecf5028c001fbaa7aa6fda0
2024-07-13 13:22:32 +00:00
stephan 6f9b37b35b Add JS bindings and tests for sqlite3_interrupted(), is_interrupted(), and db_readonly().
FossilOrigin-Name: 5589ba5651d80479ae555429340fc74390ff07d3e05ba770bb7d82490211e00d
2024-07-13 12:50:42 +00:00
stephan c636e124df Remove a stray/harmless duplicate wasm function export entry.
FossilOrigin-Name: 5402e4fb1cbd7a2c3dee6ebfb492a076d05daa66f747d18602338874405829df
2024-07-13 11:47:44 +00:00
stephan db8939f481 Add several convenience links to the OPFS VFS concurrency tester app for launching it with various combinations of options.
FossilOrigin-Name: 397d6a18f173a46b60a867fc45611045c76316d6602a3df8b4dc4ba45e1348ce
2024-07-13 01:40:36 +00:00
stephan bdc4ffacec Add an option to the opfs-sahpool VFS which tells it to ignore a previous init failure and retry, as an opt-in workaround for a browser quirk which occasionally denies OPFS access on the first attempt and permits it on subsequent attempts. This resolves [https://github.com/sqlite/sqlite-wasm/issues/79|issue #79 of the npm distribution].
FossilOrigin-Name: fbf3948a4ba27c6ebf55b24e7463b20026439f04d1974bafe78df5c5bc958f59
2024-07-13 01:02:57 +00:00
stephan 2e32cbc4a5 sqldiff: fail if the 2nd db argument cannot be opened read-only.
FossilOrigin-Name: e8b33525fc2b4d609a7be9acc43fbc66638effaa7b092b48568ded6c53c4f4db
2024-07-12 14:41:16 +00:00
stephan be3778dee2 Work around a difficult-to-trigger Atomics API message-passing quirk in the OPFS VFS which appears in rare instances in some browsers when running high I/O loads. This resolves [https://github.com/sqlite/sqlite-wasm/issues/12 | issue #12 of the npm distribution].
FossilOrigin-Name: af41a1e6fc8b36e9bf65a5bb0154e1ce7eb99903cb5a3e4779322527c29d8780
2024-07-12 13:49:54 +00:00
stephan 74d5faec93 sqldiff: if the first db argument does not exist, fail instead of creating an empty db. Resolving that for the second argument is trickier, as discussed in [forum:ec2d429e32 | forum post ec2d429e32].
FossilOrigin-Name: 0547ccf776c6054732437bffb8b2fe2ed5194ef817c2593f8cec4a3e2b749720
2024-07-12 13:45:15 +00:00
stephan 20ff50ad10 Remove the timing and counter metrics from the OPFS VFS, as they're long-since unused so are just wasted CPU cycles.
FossilOrigin-Name: 67c035c34fb916e66bfe115a132660771e8fa2921e6d46756975c5df3ebcd73c
2024-07-11 14:07:46 +00:00
stephan 9b183a234c Add some docs explaining [64f4f3cd878b1a72].
FossilOrigin-Name: 4fdf9a322fccf7d68b03d07a42a526f18f951e2e19228b7d41e01121b667cc86
2024-07-11 12:57:58 +00:00
stephan d3bb31b931 Proposed workaround for the "errant op" case in the OPFS VFS, as discussed in [https://github.com/sqlite/sqlite-wasm/issues/12 | issue #12 of the npm distribution].
FossilOrigin-Name: 64f4f3cd878b1a723caa0cd54b21f10fdb27d4e2ecb19fc233cbc8dd9d06f259
2024-07-11 12:36:28 +00:00
larrybr 3a39c44c21 Fix a few compiler gripes.
FossilOrigin-Name: 2e74a938f771a889dd8c49648b5a125ff748835ba1925388cc6b379a0abde9ac
2024-01-10 20:13:38 +00:00
larrybr 20728a599e For CLI shell and other utilities, optionally avoid C runtime file I/O on Windows in favor of WIN32 calls, while nominally preserving FILE* API interfaces. (a WIP, awaiting build and testing)
FossilOrigin-Name: 6be68be17927e72b1f1c4b93e781b7e9235876b3ad9512fe168e5b9d0b7b763a
2024-01-10 05:52:02 +00:00
286 changed files with 14027 additions and 4676 deletions
+127 -60
View File
@@ -83,9 +83,13 @@ TEMP_STORE = -DSQLITE_TEMP_STORE=@TEMP_STORE@
# based on configuration. (-DSQLITE_OMIT*, -DSQLITE_ENABLE*).
# The same set of OMIT and ENABLE flags should be passed to the
# LEMON parser generator and the mkkeywordhash tool as well.
OPT_FEATURE_FLAGS = @OPT_FEATURE_FLAGS@
#
# Add OPTIONS=... on the command line to append additional options
# to the OPT_FEATURE_FLAGS.
#
OPT_FEATURE_FLAGS = @OPT_FEATURE_FLAGS@ $(OPTIONS)
TCC += $(OPT_FEATURE_FLAGS)
TCC += $(OPT_FEATURE_FLAGS)
# Add in any optional parameters specified on the make commane line
# ie. make "OPTS=-DSQLITE_ENABLE_FOO=1 -DSQLITE_OMIT_FOO=1".
@@ -117,14 +121,15 @@ HAVE_TCL = @HAVE_TCL@
#
TCLSH_CMD = @TCLSH_CMD@
# Additional options when running tests using testrunner.tcl
# This is usually either blank, or else --status
#
TSTRNNR_OPTS = @TSTRNNR_OPTS@
# Where do we want to install the tcl plugin
#
TCLLIBDIR = @TCLLIBDIR@
# The suffix used on shared libraries. Ex: ".dll", ".so", ".dylib"
#
SHLIB_SUFFIX = @TCL_SHLIB_SUFFIX@
# If gcov support was enabled by the configure script, add the appropriate
# flags here. It's not always as easy as just having the user add the right
# CFLAGS / LDFLAGS, because libtool wants to use CFLAGS when linking, which
@@ -645,6 +650,7 @@ FUZZCHECK_SRC += $(TOP)/test/fuzzinvariants.c
FUZZCHECK_SRC += $(TOP)/ext/recover/dbdata.c
FUZZCHECK_SRC += $(TOP)/ext/recover/sqlite3recover.c
FUZZCHECK_SRC += $(TOP)/test/vt02.c
FUZZCHECK_SRC += $(TOP)/ext/misc/percentile.c
FUZZCHECK_SRC += $(TOP)/ext/misc/randomjson.c
DBFUZZ_OPT =
ST_OPT = -DSQLITE_OS_KV_OPTIONAL
@@ -655,11 +661,16 @@ SQLITE3_SHELL_TARGET_ = sqlite3$(TEXE)
SQLITE3_SHELL_TARGET_1 =
SQLITE3_SHELL_TARGET = $(SQLITE3_SHELL_TARGET_@HAVE_WASI_SDK@)
# Use $(libtclsqlite3.la_$(HAVE_TCL)) to resolve to either
# libtclsqlite3.la or an empty value.
libtclsqlite3.la_0 =
libtclsqlite3.la_1 = libtclsqlite3.la
# This is the default Makefile target. The objects listed here
# are what get build when you type just "make" with no arguments.
#
all: sqlite3.h libsqlite3.la $(SQLITE3_SHELL_TARGET) \
$(HAVE_TCL:1=libtclsqlite3.la)
$(libtclsqlite3.la_$(HAVE_TCL))
Makefile: $(TOP)/Makefile.in
./config.status
@@ -683,12 +694,26 @@ sqlite3$(TEXE): shell.c sqlite3.c
shell.c sqlite3.c \
$(LIBREADLINE) $(TLIBS) -rpath "$(libdir)"
sqldiff$(TEXE): $(TOP)/tool/sqldiff.c sqlite3.lo sqlite3.h
$(LTLINK) -o $@ $(TOP)/tool/sqldiff.c sqlite3.lo $(TLIBS)
sqldiff$(TEXE): $(TOP)/tool/sqldiff.c $(TOP)/ext/misc/sqlite3_stdio.h sqlite3.lo sqlite3.h
$(LTLINK) -I$(TOP)/ext/misc -o $@ $(TOP)/tool/sqldiff.c sqlite3.lo $(TLIBS)
dbhash$(TEXE): $(TOP)/tool/dbhash.c sqlite3.lo sqlite3.h
$(LTLINK) -o $@ $(TOP)/tool/dbhash.c sqlite3.lo $(TLIBS)
RSYNC_SRC = \
$(TOP)/tool/sqlite3-rsync.c \
sqlite3.c
RSYNC_OPT = \
-DSQLITE_ENABLE_DBPAGE_VTAB \
-USQLITE_THREADSAFE \
-DSQLITE_THREADSAFE=0 \
-DSQLITE_OMIT_LOAD_EXTENSION \
-DSQLITE_OMIT_DEPRECATED
sqlite3-rsync$(TEXE): $(RSYNC_SRC)
$(TCC) -o $@ $(RSYNC_OPT) $(RSYNC_SRC) $(TLIBS)
scrub$(TEXE): $(TOP)/ext/misc/scrub.c sqlite3.lo
$(LTLINK) -o $@ -I. -DSCRUB_STANDALONE \
$(TOP)/ext/misc/scrub.c sqlite3.lo $(TLIBS)
@@ -800,6 +825,10 @@ has_tclsh85:
sh $(TOP)/tool/cktclsh.sh 8.5 $(TCLSH_CMD)
touch has_tclsh85
has_tclconfig:
@ if test x"$(HAVE_TCL)" != "x1"; then echo 'ERROR: Requires access to "tclConfig.sh" which "configure" was not able to locate'; exit 1; fi
touch has_tclconfig
# This target creates a directory named "tsrc" and fills it with
# copies of all of the C source code and header files needed to
@@ -1122,7 +1151,7 @@ tclsqlite-shell.lo: $(TOP)/src/tclsqlite.c $(HDR)
tclsqlite-stubs.lo: $(TOP)/src/tclsqlite.c $(HDR)
$(LTCOMPILE) -DUSE_TCL_STUBS=1 -o $@ -c $(TOP)/src/tclsqlite.c
tclsqlite3$(TEXE): tclsqlite-shell.lo libsqlite3.la
tclsqlite3$(TEXE): has_tclconfig tclsqlite-shell.lo libsqlite3.la
$(LTLINK) -o $@ tclsqlite-shell.lo \
libsqlite3.la $(LIBTCL)
@@ -1158,8 +1187,6 @@ keywordhash.h: $(TOP)/tool/mkkeywordhash.c
# Source and header files that shell.c depends on
SHELL_DEP = \
$(TOP)/src/shell.c.in \
$(TOP)/ext/consio/console_io.c \
$(TOP)/ext/consio/console_io.h \
$(TOP)/ext/expert/sqlite3expert.c \
$(TOP)/ext/expert/sqlite3expert.h \
$(TOP)/ext/intck/sqlite3intck.c \
@@ -1173,11 +1200,16 @@ SHELL_DEP = \
$(TOP)/ext/misc/ieee754.c \
$(TOP)/ext/misc/memtrace.c \
$(TOP)/ext/misc/pcachetrace.c \
$(TOP)/ext/misc/percentile.c \
$(TOP)/ext/misc/regexp.c \
$(TOP)/ext/misc/series.c \
$(TOP)/ext/misc/sha1.c \
$(TOP)/ext/misc/shathree.c \
$(TOP)/ext/misc/sqlar.c \
$(TOP)/ext/misc/sqlite3_stdio.c \
$(TOP)/ext/misc/sqlite3_stdio.h \
$(TOP)/ext/misc/uint.c \
$(TOP)/ext/misc/vfstrace.c \
$(TOP)/ext/misc/zipfile.c \
$(TOP)/ext/recover/dbdata.c \
$(TOP)/ext/recover/sqlite3recover.c \
@@ -1309,7 +1341,7 @@ TESTFIXTURE_SRC1 = sqlite3.c
TESTFIXTURE_SRC = $(TESTSRC) $(TOP)/src/tclsqlite.c
TESTFIXTURE_SRC += $(TESTFIXTURE_SRC$(USE_AMALGAMATION))
testfixture$(TEXE): has_tclsh85 $(TESTFIXTURE_SRC)
testfixture$(TEXE): has_tclconfig has_tclsh85 $(TESTFIXTURE_SRC)
$(LTLINK) -DSQLITE_NO_SYNC=1 $(TEMP_STORE) $(TESTFIXTURE_FLAGS) \
-o $@ $(TESTFIXTURE_SRC) $(LIBTCL) $(TLIBS)
@@ -1358,15 +1390,20 @@ tcltest: ./testfixture$(TEXE)
testrunner: testfixture$(TEXE)
./testfixture$(TEXE) $(TOP)/test/testrunner.tcl
# Runs both fuzztest and testrunner, consecutively.
# This is the testing target preferred by the core SQLite developers.
# It runs tests under a standard configuration, regardless of how
# ./configure was run. The devs run "make devtest" prior to each
# check-in, at a minimum. Probably other tests too, but at least this
# one.
#
devtest: srctree-check testfixture$(TEXE) fuzztest testrunner
devtest: srctree-check sourcetest
$(TCLSH_CMD) $(TOP)/test/testrunner.tcl mdevtest $(TSTRNNR_OPTS)
mdevtest: srctree-check has_tclsh85
$(TCLSH_CMD) $(TOP)/test/testrunner.tcl mdevtest
$(TCLSH_CMD) $(TOP)/test/testrunner.tcl mdevtest $(TSTRNNR_OPTS)
sdevtest: has_tclsh85
$(TCLSH_CMD) $(TOP)/test/testrunner.tcl sdevtest
$(TCLSH_CMD) $(TOP)/test/testrunner.tcl sdevtest $(TSTRNNR_OPTS)
# Validate that various generated files in the source tree
# are up-to-date.
@@ -1376,16 +1413,19 @@ srctree-check: $(TOP)/tool/srctree-check.tcl
# Testing for a release
#
releasetest: srctree-check testfixture$(TEXE)
./testfixture$(TEXE) $(TOP)/test/testrunner.tcl release
releasetest: srctree-check has_tclsh85 verify-source
$(TCLSH_CMD) $(TOP)/test/testrunner.tcl release $(TSTRNNR_OPTS)
# Minimal testing that runs in less than 3 minutes
#
quicktest: ./testfixture$(TEXE)
./testfixture$(TEXE) $(TOP)/test/extraquick.test $(TESTOPTS)
# This is the common case. Run many tests that do not take too long,
# including fuzzcheck, sqlite3_analyzer, and sqldiff tests.
# Try to run tests on whatever options are specified by the
# ./configure. The developers seldom use this target. Instead
# they use "make devtest" which runs tests on a standard set of
# options regardless of how SQLite is configured. This "test"
# target is provided for legacy only.
#
test: srctree-check fuzztest sourcetest $(TESTPROGS) tcltest
@@ -1402,19 +1442,19 @@ valgrindtest: $(TESTPROGS) valgrindfuzz
smoketest: $(TESTPROGS) fuzzcheck$(TEXE)
./testfixture$(TEXE) $(TOP)/test/main.test $(TESTOPTS)
shelltest: $(TESTPROGS)
./testfixture$(TEXT) $(TOP)/test/permutations.test shell
shelltest:
$(TCLSH_CMD) $(TOP)/test/testrunner.tcl release shell
sqlite3_analyzer.c: sqlite3.c $(TOP)/src/tclsqlite.c $(TOP)/tool/spaceanal.tcl $(TOP)/tool/mkccode.tcl $(TOP)/tool/sqlite3_analyzer.c.in has_tclsh85
$(TCLSH_CMD) $(TOP)/tool/mkccode.tcl $(TOP)/tool/sqlite3_analyzer.c.in >sqlite3_analyzer.c
sqlite3_analyzer$(TEXE): sqlite3_analyzer.c
sqlite3_analyzer$(TEXE): has_tclconfig sqlite3_analyzer.c
$(LTLINK) sqlite3_analyzer.c -o $@ $(LIBTCL) $(TLIBS)
sqltclsh.c: sqlite3.c $(TOP)/src/tclsqlite.c $(TOP)/tool/sqltclsh.tcl $(TOP)/ext/misc/appendvfs.c $(TOP)/tool/mkccode.tcl $(TOP)/tool/sqltclsh.c.in has_tclsh85
$(TCLSH_CMD) $(TOP)/tool/mkccode.tcl $(TOP)/tool/sqltclsh.c.in >sqltclsh.c
sqltclsh$(TEXE): sqltclsh.c
sqltclsh$(TEXE): has_tclconfig sqltclsh.c
$(LTLINK) sqltclsh.c -o $@ $(LIBTCL) $(TLIBS)
sqlite3_expert$(TEXE): $(TOP)/ext/expert/sqlite3expert.h $(TOP)/ext/expert/sqlite3expert.c $(TOP)/ext/expert/expert.c sqlite3.c
@@ -1433,7 +1473,7 @@ CHECKER_DEPS =\
sqlite3_checker.c: $(CHECKER_DEPS) has_tclsh85
$(TCLSH_CMD) $(TOP)/tool/mkccode.tcl $(TOP)/ext/repair/sqlite3_checker.c.in >$@
sqlite3_checker$(TEXE): sqlite3_checker.c
sqlite3_checker$(TEXE): has_tclconfig sqlite3_checker.c
$(LTLINK) sqlite3_checker.c -o $@ $(LIBTCL) $(TLIBS)
dbdump$(TEXE): $(TOP)/ext/misc/dbdump.c sqlite3.lo
@@ -1547,7 +1587,12 @@ lib_install: libsqlite3.la
$(INSTALL) -d $(DESTDIR)$(libdir)
$(LTINSTALL) libsqlite3.la $(DESTDIR)$(libdir)
install: sqlite3$(TEXE) lib_install sqlite3.h sqlite3.pc ${HAVE_TCL:1=tcl_install}
# Use $(tcl_install_$(HAVE_TCL)) to resolve to either tcl_install or
# an empty value.
tcl_install_0 =
tcl_install_1 = tcl_install
install: sqlite3$(TEXE) lib_install sqlite3.h sqlite3.pc $(tcl_install_$(HAVE_TCL))
$(INSTALL) -d $(DESTDIR)$(bindir)
$(LTINSTALL) sqlite3$(TEXE) $(DESTDIR)$(bindir)
$(INSTALL) -d $(DESTDIR)$(includedir)
@@ -1558,49 +1603,71 @@ install: sqlite3$(TEXE) lib_install sqlite3.h sqlite3.pc ${HAVE_TCL:1=tcl_instal
pkgIndex.tcl:
echo 'package ifneeded sqlite3 $(RELEASE) [list load [file join $$dir libtclsqlite3[info sharedlibextension]] sqlite3]' > $@
tcl_install: lib_install libtclsqlite3.la pkgIndex.tcl
$(INSTALL) -d $(DESTDIR)$(TCLLIBDIR)
$(LTINSTALL) libtclsqlite3.la $(DESTDIR)$(TCLLIBDIR)
rm -f $(DESTDIR)$(TCLLIBDIR)/libtclsqlite3.la $(DESTDIR)$(TCLLIBDIR)/libtclsqlite3.a
$(INSTALL) -m 0644 pkgIndex.tcl $(DESTDIR)$(TCLLIBDIR)
clean:
rm -f *.lo *.la *.o sqlite3$(TEXE) libsqlite3.la
rm -f sqlite3.h opcodes.*
rm -rf .libs .deps
rm -f lemon$(BEXE) lempar.c parse.* sqlite*.tar.gz
rm -f mkkeywordhash$(BEXE) keywordhash.h
rm -f mksourceid$(BEXE)
rm -f *.da *.bb *.bbg gmon.out
rm -rf tsrc .target_source
rm -f tclsqlite3$(TEXE)
rm -f testfixture$(TEXE) test.db
# Build the SQLite TCL extension in a way that make it compatible
# with whatever version of TCL is running as $TCLSH_CMD, possibly defined
# by --with-tclsh=
#
tclextension: tclsqlite3.c
$(TCLSH_CMD) $(TOP)/tool/buildtclext.tcl --build-only --cc $(CC) $(CFLAGS) $(OPT_FEATURE_FLAGS) $(OPTS)
# Install the SQLite TCL extension in a way that is appropriate for $TCLSH_CMD
# to find it.
#
tclextension-install: tclsqlite3.c
$(TCLSH_CMD) $(TOP)/tool/buildtclext.tcl --cc $(CC) $(CFLAGS) $(OPT_FEATURE_FLAGS) $(OPTS)
# Install the SQLite TCL extension that is used by $TCLSH_CMD
#
tclextension-uninstall:
$(TCLSH_CMD) $(TOP)/tool/buildtclext.tcl --uninstall
# List all installed the SQLite TCL extension that is are accessible
# by $TCLSH_CMD, included prior versions.
#
tclextension-list:
$(TCLSH_CMD) $(TOP)/tool/buildtclext.tcl --info
# Remove build products sufficient so that subsequent makes will recompile
# everything from scratch. Do not remove:
#
# * test results and test logs
# * output from ./configure
#
tidy:
rm -f *.lo *.la *.o *.c *.da *.bb *.bbg gmon.* *.rws sqlite3$(TEXE)
rm -f fts5.h keywordhash.h opcodes.h sqlite3.h sqlite3ext.h sqlite3session.h
rm -rf .libs .deps tsrc .target_source
rm -f lemon$(BEXE) sqlite*.tar.gz
rm -f mkkeywordhash$(BEXE) mksourceid$(BEXE)
rm -f parse.* fts5parse.*
rm -f tclsqlite3$(TEXE) $(TESTPROGS)
rm -f LogEst$(TEXE) fts3view$(TEXE) rollback-test$(TEXE) showdb$(TEXE)
rm -f showjournal$(TEXE) showstat4$(TEXE) showwal$(TEXE) speedtest1$(TEXE)
rm -f wordcount$(TEXE) changeset$(TEXE)
rm -f version-info$(TEXT)
rm -f sqlite3.dll sqlite3.lib sqlite3.exp sqlite3.def
rm -f sqlite3.c
rm -f sqlite3rc.h
rm -f shell.c sqlite3ext.h
rm -f sqlite3_analyzer$(TEXE) sqlite3_analyzer.c
rm -f sqlite-*-output.vsix
rm -f mptester mptester.exe
rm -f rbu rbu.exe
rm -f srcck1 srcck1.exe
rm -f fuzzershell fuzzershell.exe
rm -f fuzzcheck fuzzcheck.exe
rm -f sqldiff sqldiff.exe
rm -f dbhash dbhash.exe
rm -f fts5.* fts5parse.*
rm -f threadtest5
rm -f src-verify
rm -f custom.rws
rm -f has_tclsh84 has_tclsh85
rm -f wordcount$(TEXE) changeset$(TEXE) version-info$(TEXE)
rm -f *.dll *.lib *.exp *.def *.pc *.vsix *.so *.dylib pkgIndex.tcl
rm -f sqlite3_analyzer$(TEXE) sqlite3-rsync$(TEXE)
rm -f mptester$(TEXE) rbu$(TEXE) srcck1$(TEXE)
rm -f fuzzershell$(TEXE) fuzzcheck$(TEXE) sqldiff$(TEXE) dbhash$(TEXE)
rm -f threadtest5$(TEXE)
rm -f src-verify has_tclsh*
# Removes build products and test logs. Retains ./configure outputs.
#
clean: tidy
rm -rf omittest* testrunner* testdir*
# Clean up everything. No exceptions.
#
distclean: clean
rm -f sqlite_cfg.h config.log config.status libtool Makefile sqlite3.pc \
$(TESTPROGS)
rm -f sqlite_cfg.h config.log config.status Makefile $(LIBTOOL)
#
# Windows section
+71 -12
View File
@@ -379,6 +379,7 @@ SQLITE_TCL_DEP =
# the Windows platform.
#
!IFNDEF OPT_FEATURE_FLAGS
OPT_FEATURE_FLAGS = $(OPT_XTRA)
!IF $(MINIMAL_AMALGAMATION)==0
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_FTS3=1
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_FTS5=1
@@ -392,6 +393,14 @@ OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_BYTECODE_VTAB=1
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_COLUMN_METADATA=1
!ENDIF
# Additional feature-options above and beyond what are normally used can be
# be added using OPTIONS=.... on the command-line. These values are
# appended to the OPT_FEATURE_FLAGS variable.
#
!IFDEF OPTIONS
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) $(OPTIONS)
!ENDIF
# Should the session extension be enabled? If so, add compilation options
# to enable it.
#
@@ -929,7 +938,7 @@ TCLSUFFIX =
!ENDIF
!IFNDEF TCLDIR
TCLDIR = $(TOP)\compat\tcl
TCLDIR = C:\Tcl
!ENDIF
!IFNDEF TCLINCDIR
@@ -1758,6 +1767,7 @@ FUZZCHECK_SRC = $(FUZZCHECK_SRC) $(TOP)\test\fuzzinvariants.c
FUZZCHECK_SRC = $(FUZZCHECK_SRC) $(TOP)\test\vt02.c
FUZZCHECK_SRC = $(FUZZCHECK_SRC) $(TOP)\ext\recover\dbdata.c
FUZZCHECK_SRC = $(FUZZCHECK_SRC) $(TOP)\ext\recover\sqlite3recover.c
FUZZCHECK_SRC = $(FUZZCHECK_SRC) $(TOP)\ext\misc\percentile.c
FUZZCHECK_SRC = $(FUZZCHECK_SRC) $(TOP)\ext\misc\randomjson.c
OSSSHELL_SRC = $(TOP)\test\ossshell.c $(TOP)\test\ossfuzz.c
@@ -1820,6 +1830,19 @@ pkgIndex.tcl: $(TOP)\VERSION
$(SQLITE3TCLDLL): libtclsqlite3.lib $(LIBRESOBJS) tclsqlite3.def pkgIndex.tcl
$(LD) $(LDFLAGS) $(LTLINKOPTS) $(LTLIBPATHS) /DLL /DEF:tclsqlite3.def /OUT:$@ libtclsqlite3.lib $(LIBRESOBJS) $(LTLIBS) $(TLIBS)
tclextension: $(SQLITE3TCLDLL)
tclextension-install: $(SQLITE3TCLDLL)
$(TCLSH_CMD) $(TOP)\tool\buildtclext.tcl --install-only
tclextension-uninstall:
$(TCLSH_CMD) $(TOP)\tool\buildtclext.tcl --uninstall
tclextension-list:
$(TCLSH_CMD) $(TOP)\tool\buildtclext.tcl --info
# <</mark>>
$(SQLITE3DLL): $(LIBOBJ) $(LIBRESOBJS) $(CORE_LINK_DEP)
@@ -1838,12 +1861,25 @@ $(SQLITE3EXE): shell.c $(SHELL_CORE_DEP) $(LIBRESOBJS) $(SHELL_CORE_SRC) $(SQLIT
/link $(SQLITE3EXEPDB) $(LDFLAGS) $(LTLINKOPTS) $(SHELL_LINK_OPTS) $(LTLIBPATHS) $(LIBRESOBJS) $(LIBREADLINE) $(LTLIBS) $(TLIBS)
# <<mark>>
sqldiff.exe: $(TOP)\tool\sqldiff.c $(TOP)\ext\consio\console_io.h $(TOP)\ext\consio\console_io.c $(SQLITE3C) $(SQLITE3H) $(LIBRESOBJS)
$(LTLINK) $(NO_WARN) -I$(TOP)\ext\consio $(TOP)\tool\sqldiff.c $(TOP)\ext\consio\console_io.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS) $(LIBRESOBJS)
sqldiff.exe: $(TOP)\tool\sqldiff.c $(TOP)\ext\misc\sqlite3_stdio.h $(TOP)\ext\misc\sqlite3_stdio.c $(SQLITE3C) $(SQLITE3H) $(LIBRESOBJS)
$(LTLINK) $(NO_WARN) -I$(TOP)\ext\misc $(TOP)\tool\sqldiff.c $(TOP)\ext\misc\sqlite3_stdio.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS) $(LIBRESOBJS)
dbhash.exe: $(TOP)\tool\dbhash.c $(SQLITE3C) $(SQLITE3H)
$(LTLINK) $(NO_WARN) $(TOP)\tool\dbhash.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS)
RSYNC_SRC = \
$(TOP)\tool\sqlite3-rsync.c \
$(SQLITE3C)
RSYNC_OPT = \
-DSQLITE_ENABLE_DBPAGE_VTAB \
-DSQLITE_THREADSAFE=0 \
-DSQLITE_OMIT_LOAD_EXTENSION \
-DSQLITE_OMIT_DEPRECATED
sqlite3-rsync.exe: $(RSYNC_SRC) $(LIBRESOBJS)
$(LTLINK) $(RSYNC_OPT) $(NO_WARN) $(RSYNC_SRC) /link $(LDFLAGS) $(LTLINKOPTS) $(LIBRESOBJS)
scrub.exe: $(TOP)\ext\misc\scrub.c $(SQLITE3C) $(SQLITE3H)
$(LTLINK) $(NO_WARN) -DSCRUB_STANDALONE=1 $(TOP)\ext\misc\scrub.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS)
@@ -1871,6 +1907,10 @@ fuzzcheck.exe: $(FUZZCHECK_SRC) $(SQLITE3C) $(SQLITE3H)
fuzzcheck-asan.exe: $(FUZZCHECK_SRC) $(SQLITE3C) $(SQLITE3H)
$(LTLINK) $(NO_WARN) /fsanitize=address $(FUZZCHECK_OPTS) $(FUZZCHECK_SRC) $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS)
run-fuzzcheck: fuzzcheck.exe fuzzcheck-asan.exe
fuzzcheck --spinner $(FUZZDB)
fuzzcheck-asan --spinner $(FUZZDB)
ossshell.exe: $(OSSSHELL_SRC) $(SQLITE3C) $(SQLITE3H)
$(LTLINK) $(NO_WARN) $(FUZZCHECK_OPTS) $(OSSSHELL_SRC) $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS)
@@ -2276,8 +2316,6 @@ keywordhash.h: $(TOP)\tool\mkkeywordhash.c mkkeywordhash.exe
# Source and header files that shell.c depends on
SHELL_DEP = \
$(TOP)\src\shell.c.in \
$(TOP)\ext\consio\console_io.c \
$(TOP)\ext\consio\console_io.h \
$(TOP)\ext\expert\sqlite3expert.c \
$(TOP)\ext\expert\sqlite3expert.h \
$(TOP)\ext\intck\sqlite3intck.c \
@@ -2291,11 +2329,16 @@ SHELL_DEP = \
$(TOP)\ext\misc\ieee754.c \
$(TOP)\ext\misc\memtrace.c \
$(TOP)\ext\misc\pcachetrace.c \
$(TOP)\ext\misc\percentile.c \
$(TOP)\ext\misc\regexp.c \
$(TOP)\ext\misc\series.c \
$(TOP)\ext\misc\sha1.c \
$(TOP)\ext\misc\shathree.c \
$(TOP)\ext\misc\sqlar.c \
$(TOP)\ext\misc\sqlite3_stdio.c \
$(TOP)\ext\misc\sqlite3_stdio.h \
$(TOP)\ext\misc\uint.c \
$(TOP)\ext\misc\vfstrace.c \
$(TOP)\ext\misc\zipfile.c \
$(TOP)\ext\recover\dbdata.c \
$(TOP)\ext\recover\sqlite3recover.c \
@@ -2522,6 +2565,13 @@ queryplantest: testfixture.exe shell
fuzztest: fuzzcheck.exe
.\fuzzcheck.exe $(FUZZDATA)
# Legacy testing target for third-party integrators. The SQLite
# developers seldom use this target themselves. Instead
# they use "nmake /f Makefile.msc devtest" which runs tests on
# a standard set of options
#
test: $(TESTPROGS) sourcetest fuzztest tcltest
# Minimal testing that runs in less than 3 minutes (on a fast machine)
#
quicktest: testfixture.exe sourcetest
@@ -2531,7 +2581,6 @@ quicktest: testfixture.exe sourcetest
# This is the common case. Run many tests that do not take too long,
# including fuzzcheck, sqlite3_analyzer, and sqldiff tests.
#
test: $(TESTPROGS) sourcetest fuzztest tcltest
# The veryquick.test TCL tests.
#
@@ -2545,17 +2594,27 @@ tcltest: testfixture.exe
testrunner: testfixture.exe
.\testfixture.exe $(TOP)\test\testrunner.tcl
# Runs both fuzztest and testrunner, consecutively.
# This is the testing target preferred by the core SQLite developers.
# It runs tests under a standard configuration. The devs run
# "nmake /f Makefile.msc devtest" prior to each check-in, at a minimum.
# Probably other tests too, but at least this one.
#
devtest: testfixture.exe fuzztest testrunner
devtest: srctree-check sourcetest
$(TCLSH_CMD) $(TOP)\test\testrunner.tcl mdevtest
mdevtest:
$(TCLSH_CMD) $(TOP)\test\testrunner.tcl mdevtest
# Validate that various generated files in the source tree
# are up-to-date.
#
srctree-check: $(TOP)\tool\srctree-check.tcl
$(TCLSH_CMD) $(TOP)\tool\srctree-check.tcl
# Testing for a release
#
releasetest: testfixture.exe
testfixture.exe $(TOP)\test\testrunner.tcl release
releasetest:
$(TCLSH_CMD) $(TOP)\test\testrunner.tcl release
smoketest: $(TESTPROGS)
@@ -2565,7 +2624,7 @@ smoketest: $(TESTPROGS)
shelltest: $(TESTPROGS)
.\testfixture.exe $(TOP)\test\permutations.test shell
sqlite3_analyzer.c: $(SQLITE3C) $(SQLITE3H) $(TOP)\src\tclsqlite.c $(TOP)\tool\spaceanal.tcl $(TOP)\tool\mkccode.tcl $(TOP)\tool\sqlite3_analyzer.c.in $(TOP)\ext\consio\console_io.h $(TOP)\ext\consio\console_io.c $(SQLITE_TCL_DEP)
sqlite3_analyzer.c: $(SQLITE3C) $(SQLITE3H) $(TOP)\src\tclsqlite.c $(TOP)\tool\spaceanal.tcl $(TOP)\tool\mkccode.tcl $(TOP)\tool\sqlite3_analyzer.c.in $(TOP)\ext\misc\sqlite3_stdio.h $(TOP)\ext\misc\sqlite3_stdio.c $(SQLITE_TCL_DEP)
$(TCLSH_CMD) $(TOP)\tool\mkccode.tcl $(TOP)\tool\sqlite3_analyzer.c.in > $@
sqlite3_analyzer.exe: sqlite3_analyzer.c $(LIBRESOBJS)
@@ -2720,7 +2779,7 @@ clean:
del /Q sqlite3.c sqlite3-*.c sqlite3.h 2>NUL
del /Q sqlite3rc.h 2>NUL
del /Q shell.c sqlite3ext.h sqlite3session.h 2>NUL
del /Q sqlite3_analyzer.exe sqlite3_analyzer.c 2>NUL
del /Q sqlite3_analyzer.exe sqlite3_analyzer.c sqlite3-rsync.exe 2>NUL
del /Q sqlite-*-output.vsix 2>NUL
del /Q fuzzershell.exe fuzzcheck.exe sqldiff.exe dbhash.exe 2>NUL
del /Q sqltclsh.* 2>NUL
+131 -58
View File
@@ -1,14 +1,19 @@
<h1 align="center">SQLite Source Repository</h1>
This repository contains the complete source code for the
[SQLite database engine](https://sqlite.org/). Some test scripts
are also included. However, many other test scripts
[SQLite database engine](https://sqlite.org/), including
many test scripts. However, other test scripts
and most of the documentation are managed separately.
See the [on-line documentation](https://sqlite.org/) for more information
about what SQLite is and how it works from a user's perspective. This
README file is about the source code that goes into building SQLite,
not about how SQLite is used.
## Version Control
SQLite sources are managed using
[Fossil](https://www.fossil-scm.org/), a distributed version control system
[Fossil](https://fossil-scm.org/), a distributed version control system
that was specifically designed and written to support SQLite development.
The [Fossil repository](https://sqlite.org/src/timeline) contains the urtext.
@@ -68,24 +73,26 @@ archives or [SQLite archives](https://sqlite.org/cli.html#sqlar) as follows:
then click on the "Tarball" or "ZIP Archive" links on the information
page.
If you do want to use Fossil to check out the source tree,
To access sources directly using [Fossil](https://fossil-scm.org/home),
first install Fossil version 2.0 or later.
(Source tarballs and precompiled binaries available
[here](https://www.fossil-scm.org/fossil/uv/download.html). Fossil is
Source tarballs and precompiled binaries available at
<https://fossil-scm.org/home/uv/download.html>. Fossil is
a stand-alone program. To install, simply download or build the single
executable file and put that file someplace on your $PATH.)
executable file and put that file someplace on your $PATH.
Then run commands like this:
mkdir -p ~/sqlite ~/Fossils
mkdir -p ~/sqlite
cd ~/sqlite
fossil clone https://www.sqlite.org/src ~/Fossils/sqlite.fossil
fossil open ~/Fossils/sqlite.fossil
fossil open https://sqlite.org/src
After setting up a repository using the steps above, you can always
update to the latest version using:
The "fossil open" command will take two or three minutes. Afterwards,
you can do fast, bandwidth-efficient updates to the whatever versions
of SQLite you like. Some examples:
fossil update trunk ;# latest trunk check-in
fossil update release ;# latest official release
fossil update trunk ;# latest trunk check-in
fossil update release ;# latest official release
fossil update trunk:2024-01-01 ;# First trunk check-in after 2024-01-01
fossil update version-3.39.0 ;# Version 3.39.0
Or type "fossil ui" to get a web-based user interface.
@@ -99,15 +106,42 @@ script found at the root of the source tree. Then run "make".
For example:
tar xzf sqlite.tar.gz ;# Unpack the source tree into "sqlite"
mkdir bld ;# Build will occur in a sibling directory
cd bld ;# Change to the build directory
../sqlite/configure ;# Run the configure script
make ;# Builds the "sqlite3" command-line tool
make sqlite3.c ;# Build the "amalgamation" source file
make devtest ;# Run some tests (requires Tcl)
apt install gcc make tcl-dev ;# Make sure you have all the necessary build tools
tar xzf sqlite.tar.gz ;# Unpack the source tree into "sqlite"
mkdir bld ;# Build will occur in a sibling directory
cd bld ;# Change to the build directory
../sqlite/configure ;# Run the configure script
make sqlite3 ;# Builds the "sqlite3" command-line tool
make sqlite3.c ;# Build the "amalgamation" source file
make sqldiff ;# Builds the "sqldiff" command-line tool
# Makefile targets below this point require tcl-dev
make tclextension-install ;# Build and install the SQLite TCL extension
make devtest ;# Run development tests
make releasetest ;# Run full release tests
make sqlite3_analyzer ;# Builds the "sqlite3_analyzer" tool
See the makefile for additional targets.
See the makefile for additional targets. For debugging builds, the
core developers typically run "configure" with options like this:
../sqlite/configure --enable-all --enable-debug CFLAGS='-O0 -g'
For release builds, the core developers usually do:
../sqlite/configure --enable-all
Almost all makefile targets require a "tclsh" TCL interpreter version 8.6 or
later. The "tclextension-install" target and the test targets that follow
all require TCL development libraries too. ("apt install tcl-dev"). It is
helpful, but is not required, to install the SQLite TCL extension (the
"tclextension-install" target) prior to running tests. The "releasetest"
target has additional requiremenst, such as "valgrind".
On "make" command-lines, one can add "OPTIONS=..." to specify additional
compile-time options over and above those set by ./configure. For example,
to compile with the SQLITE_OMIT_DEPRECATED compile-time option, one could say:
./configure --enable-all
make OPTIONS=-DSQLITE_OMIT_DEPRECATED sqlite3
The configure script uses autoconf 2.61 and libtool. If the configure
script does not work out for you, there is a generic makefile named
@@ -117,7 +151,7 @@ show what changes are needed.
## Compiling for Windows Using MSVC
On Windows, all applicable build products can be compiled with MSVC.
On Windows, everything can be compiled with MSVC.
You will also need a working installation of TCL.
See the [compile-for-windows.md](doc/compile-for-windows.md) document for
additional information about how to install MSVC and TCL and configure your
@@ -128,48 +162,72 @@ TCL library, using a command like this:
set TCLDIR=c:\Tcl
SQLite uses "tclsh.exe" as part of the build process, and so that utility
program will need to be somewhere on your %PATH%. The finished SQLite library
does not contain any TCL code, but it does use TCL to help with the build process
and to run tests.
SQLite uses "tclsh.exe" as part of the build process, and so that
program will need to be somewhere on your %PATH%. SQLite itself
does not contain any TCL code, but it does use TCL to help with the
build process and to run tests. You may need to install TCL development
libraries in order to successfully complete some makefile targets.
It is helpful, but is not required, to install the SQLite TCL extension
(the "tclextension-install" target) prior to running tests.
Build using Makefile.msc. Example:
nmake /f Makefile.msc
nmake /f Makefile.msc sqlite3.exe
nmake /f Makefile.msc sqlite3.c
nmake /f Makefile.msc sqldiff.exe
# Makefile targets below this point require TCL development libraries
nmake /f Makefile.msc tclextension-install
nmake /f Makefile.msc devtest
nmake /f Makefile.msc releasetest
nmake /f Makefile.msc sqlite3_analyzer.exe
There are many other makefile targets. See comments in Makefile.msc for
details.
## Source Code Tour
As with the unix Makefile, the OPTIONS=... argument can be passed on the nmake
command-line to enable new compile-time options. For example:
Most of the core source files are in the **src/** subdirectory. The
**src/** folder also contains files used to build the "testfixture" test
harness. The names of the source files used by "testfixture" all begin
with "test".
The **src/** also contains the "shell.c" file
which is the main program for the "sqlite3.exe"
[command-line shell](https://sqlite.org/cli.html) and
the "tclsqlite.c" file which implements the
[Tcl bindings](https://sqlite.org/tclsqlite.html) for SQLite.
(Historical note: SQLite began as a Tcl
extension and only later escaped to the wild as an independent library.)
nmake /f Makefile.msc OPTIONS=-DSQLITE_OMIT_DEPRECATED sqlite3.exe
Test scripts and programs are found in the **test/** subdirectory.
Additional test code is found in other source repositories.
See [How SQLite Is Tested](https://www.sqlite.org/testing.html) for
additional information.
## Source Tree Map
The **ext/** subdirectory contains code for extensions. The
Full-text search engine is in **ext/fts3**. The R-Tree engine is in
**ext/rtree**. The **ext/misc** subdirectory contains a number of
smaller, single-file extensions, such as a REGEXP operator.
* **src/** - This directory contains the primary source code for the
SQLite core. For historical reasons, C-code used for testing is
also found here. Source files intended for testing begin with "`test`".
The `tclsqlite3.c` and `tclsqlite3.h` files are the TCL interface
for SQLite and are also not part of the core.
The **tool/** subdirectory contains various scripts and programs used
for building generated source code files or for testing or for generating
accessory programs such as "sqlite3_analyzer(.exe)".
* **test/** - This directory and its subdirectories contains code used
for testing. Files that end in "`.test`" are TCL scripts that run
tests using an augmented TCL interpreter named "testfixture". Use
a command like "`make testfixture`" (unix) or
"`nmake /f Makefile.msc testfixture.exe`" (windows) to build that
augmented TCL interpreter, then run individual tests using commands like
"`testfixture test/main.test`". This test/ subdirectory also contains
additional C code modules and scripts for other kinds of testing.
* **tool/** - This directory contains programs and scripts used to
build some of the machine-generated code that goes into the SQLite
core, as well as to build and run tests and perform diagnostics.
The source code to [the Lemon parser generator](./doc/lemon.html) is
found here. There are also TCL scripts used to build and/or transform
source code files. For example, the tool/mksqlite3h.tcl script reads
the src/sqlite.h.in file and uses it as a template to construct
the deliverable "sqlite3.h" file that defines the SQLite interface.
* **ext/** - Various extensions to SQLite are found under this
directory. For example, the FTS5 subsystem is in "ext/fts5/".
Some of these extensions (ex: FTS3/4, FTS5, RTREE) might get built
into the SQLite amalgamation, but not all of them. The
"ext/misc/" subdirectory contains an assortment of one-file extensions,
many of which are omitted from the SQLite core, but which are included
in the [SQLite CLI](https://sqlite.org/cli.html).
* **doc/** - Some documentation files about SQLite internals are found
here. Note, however, that the primary documentation designed for
application developers and users of SQLite is in a completely separate
repository. Note also that the primary API documentation is derived
from specially constructed comments in the src/sqlite.h.in file.
### Generated Source Code Files
@@ -252,31 +310,37 @@ individual source file exceeds 32K lines in length.
SQLite is modular in design.
See the [architectural description](https://www.sqlite.org/arch.html)
for details. Other documents that are useful in
(helping to understand how SQLite works include the
helping to understand how SQLite works include the
[file format](https://www.sqlite.org/fileformat2.html) description,
the [virtual machine](https://www.sqlite.org/opcode.html) that runs
prepared statements, the description of
[how transactions work](https://www.sqlite.org/atomiccommit.html), and
the [overview of the query planner](https://www.sqlite.org/optoverview.html).
Years of effort have gone into optimizing SQLite, both
Decades of effort have gone into optimizing SQLite, both
for small size and high performance. And optimizations tend to result in
complex code. So there is a lot of complexity in the current SQLite
implementation. It will not be the easiest library in the world to hack.
Key files:
### Key source code files
* **sqlite.h.in** - This file defines the public interface to the SQLite
library. Readers will need to be familiar with this interface before
trying to understand how the library works internally.
trying to understand how the library works internally. This file is
really a template that is transformed into the "sqlite3.h" deliverable
using a script invoked by the makefile.
* **sqliteInt.h** - this header file defines many of the data objects
used internally by SQLite. In addition to "sqliteInt.h", some
subsystems have their own header files.
subsystems inside of sQLite have their own header files. These internal
interfaces are not for use by applications. They can and do change
from one release of SQLite to the next.
* **parse.y** - This file describes the LALR(1) grammar that SQLite uses
to parse SQL statements, and the actions that are taken at each step
in the parsing process.
in the parsing process. The file is processed by the
[Lemon Parser Generator](./doc/lemon.html) to produce the actual C code
used for parsing.
* **vdbe.c** - This file implements the virtual machine that runs
prepared statements. There are various helper files whose names
@@ -319,6 +383,11 @@ Key files:
(and some other test programs too) is built and run when you type
"make test".
* **VERSION**, **manifest**, and **manifest.uuid** - These files define
the current SQLite version number. The "VERSION" file is human generated,
but the "manifest" and "manifest.uuid" files are automatically generated
by the [Fossil version control system](https://fossil-scm.org/).
There are many other source files. Each has a succinct header comment that
describes its purpose and role within the larger system.
@@ -336,7 +405,7 @@ The `manifest.uuid` file should contain the SHA3-256 hash of the
`manifest` file. If all of the above hash comparisons are correct, then
you can be confident that your source tree is authentic and unadulterated.
Details on the format for the `manifest` files are available
[on the Fossil website](https://fossil-scm.org/fossil/doc/trunk/www/fileformat.wiki#manifest).
[on the Fossil website](https://fossil-scm.org/home/doc/trunk/www/fileformat.wiki#manifest).
The process of checking source code authenticity is automated by the
makefile:
@@ -357,3 +426,7 @@ The main SQLite website is [https://sqlite.org/](https://sqlite.org/)
with geographically distributed backups at
[https://www2.sqlite.org/](https://www2.sqlite.org) and
[https://www3.sqlite.org/](https://www3.sqlite.org).
Contact the SQLite developers through the
[SQLite Forum](https://sqlite.org/forum/). In an emergency, you
can send private email to the lead developer at drh at sqlite dot org.
+9
View File
@@ -301,6 +301,7 @@ SQLITE3EXEPDB = /pdb:sqlite3sh.pdb
# the Windows platform.
#
!IFNDEF OPT_FEATURE_FLAGS
OPT_FEATURE_FLAGS = $(OPT_XTRA)
!IF $(MINIMAL_AMALGAMATION)==0
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_FTS3=1
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_FTS5=1
@@ -314,6 +315,14 @@ OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_BYTECODE_VTAB=1
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_COLUMN_METADATA=1
!ENDIF
# Additional feature-options above and beyond what are normally used can be
# be added using OPTIONS=.... on the command-line. These values are
# appended to the OPT_FEATURE_FLAGS variable.
#
!IFDEF OPTIONS
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) $(OPTIONS)
!ENDIF
# Should the session extension be enabled? If so, add compilation options
# to enable it.
#
+1 -1
View File
@@ -4064,4 +4064,4 @@ AC_DEFUN([TEA_ZIPFS_SUPPORT], [
# Local Variables:
# mode: autoconf
# End:
# End:
-1
View File
@@ -708,4 +708,3 @@ TK_INCLUDES = -I"$(_TKDIR)\generic" -I"$(_TKDIR)\win" -I"$(_TKDIR)\xlib"
!message *** Link options '$(LINKERFLAGS)'
!endif
Vendored
+159 -244
View File
@@ -781,18 +781,6 @@ TARGET_HAVE_EDITLINE
TARGET_HAVE_READLINE
TARGET_READLINE_INC
TARGET_READLINE_LIBS
HAVE_TCL
TCL_SHLIB_SUFFIX
TCL_STUB_LIB_SPEC
TCL_STUB_LIB_FLAG
TCL_STUB_LIB_FILE
TCL_LIB_SPEC
TCL_LIB_FLAG
TCL_LIB_FILE
TCL_INCLUDE_SPEC
TCL_SRC_DIR
TCL_BIN_DIR
TCL_VERSION
TARGET_EXEEXT
SQLITE_OS_WIN
SQLITE_OS_UNIX
@@ -805,7 +793,12 @@ HAVE_WASI_SDK
RELEASE
VERSION
program_prefix
TSTRNNR_OPTS
TCLLIBDIR
HAVE_TCL
TCL_STUB_LIB_SPEC
TCL_LIB_SPEC
TCL_INCLUDE_SPEC
TCLSH_CMD
INSTALL_DATA
INSTALL_SCRIPT
@@ -894,12 +887,14 @@ enable_fast_install
with_gnu_ld
enable_libtool_lock
enable_largefile
with_tclsh
with_tcl
enable_tcl
enable_test_status
with_wasi_sdk
enable_threadsafe
enable_releasemode
enable_tempstore
enable_tcl
with_tcl
enable_editline
enable_readline
with_readline_lib
@@ -1551,11 +1546,13 @@ Optional Features:
optimize for fast installation [default=yes]
--disable-libtool-lock avoid locking (might break parallel builds)
--disable-largefile omit support for large files
--disable-tcl omit building accessory programs that require
TCL-dev
--enable-test-status Full-screen status of tests
--disable-threadsafe Disable mutexing
--enable-releasemode Support libtool link to release mode
--enable-tempstore Use an in-ram database for temporary tables
(never,no,yes,always)
--disable-tcl do not build TCL extension
--enable-editline enable BSD editline support
--disable-readline disable readline support
--enable-debug enable debugging & verbose explain
@@ -1583,10 +1580,10 @@ Optional Packages:
--with-pic try to use only PIC/non-PIC objects [default=use
both]
--with-gnu-ld assume the C compiler uses GNU ld [default=no]
--with-tclsh=PATHNAME full pathname of a tclsh to use
--with-tcl=DIR directory containing (tclConfig.sh)
--with-wasi-sdk=DIR directory containing the WASI SDK. Triggers
cross-compile to WASM.
--with-tcl=DIR directory containing tcl configuration
(tclConfig.sh)
--with-readline-lib specify readline library
--with-readline-inc specify readline include paths
--with-linenoise=DIR source directory for linenoise library
@@ -3945,13 +3942,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:3948: $ac_compile\"" >&5)
(eval echo "\"\$as_me:3945: $ac_compile\"" >&5)
(eval "$ac_compile" 2>conftest.err)
cat conftest.err >&5
(eval echo "\"\$as_me:3951: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
(eval echo "\"\$as_me:3948: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
(eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
cat conftest.err >&5
(eval echo "\"\$as_me:3954: output\"" >&5)
(eval echo "\"\$as_me:3951: output\"" >&5)
cat conftest.out >&5
if $GREP 'External.*some_variable' conftest.out > /dev/null; then
lt_cv_nm_interface="MS dumpbin"
@@ -5157,7 +5154,7 @@ ia64-*-hpux*)
;;
*-*-irix6*)
# Find out which ABI we are using.
echo '#line 5160 "configure"' > conftest.$ac_ext
echo '#line 5157 "configure"' > conftest.$ac_ext
if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
(eval $ac_compile) 2>&5
ac_status=$?
@@ -6682,11 +6679,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:6685: $lt_compile\"" >&5)
(eval echo "\"\$as_me:6682: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
echo "$as_me:6689: \$? = $ac_status" >&5
echo "$as_me:6686: \$? = $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.
@@ -7021,11 +7018,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:7024: $lt_compile\"" >&5)
(eval echo "\"\$as_me:7021: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
echo "$as_me:7028: \$? = $ac_status" >&5
echo "$as_me:7025: \$? = $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.
@@ -7126,11 +7123,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:7129: $lt_compile\"" >&5)
(eval echo "\"\$as_me:7126: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
echo "$as_me:7133: \$? = $ac_status" >&5
echo "$as_me:7130: \$? = $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
@@ -7181,11 +7178,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:7184: $lt_compile\"" >&5)
(eval echo "\"\$as_me:7181: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
echo "$as_me:7188: \$? = $ac_status" >&5
echo "$as_me:7185: \$? = $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
@@ -9561,7 +9558,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
#line 9564 "configure"
#line 9561 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -9657,7 +9654,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
#line 9660 "configure"
#line 9657 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -10314,11 +10311,31 @@ done
USE_AMALGAMATION=1
#########
# See whether we can run specific tclsh versions known to work well;
# if not, then we fall back to plain tclsh.
# TODO: try other versions before falling back?
# Figure out all the name of a working tclsh and parameters needed to compile against Tcl.
# The --with-tcl= and/or --with-tclsh= configuration arguments might be useful for this.
#
for ac_prog in tclsh8.7 tclsh8.6 tclsh8.5 tclsh
# Check whether --with-tclsh was given.
if test "${with_tclsh+set}" = set; then :
withval=$with_tclsh;
fi
# Check whether --with-tcl was given.
if test "${with_tcl+set}" = set; then :
withval=$with_tcl;
fi
# Check whether --enable-tcl was given.
if test "${enable_tcl+set}" = set; then :
enableval=$enable_tcl; use_tcl=$enableval
else
use_tcl=yes
fi
original_use_tcl=${use_tcl}
if test x"${with_tclsh}" == x -a x"${with_tcl}" == x; then
for ac_prog in tclsh8.6 tclsh tclsh9.0
do
# Extract the first word of "$ac_prog", so it can be a program name with args.
set dummy $ac_prog; ac_word=$2
@@ -10361,10 +10378,99 @@ fi
done
test -n "$TCLSH_CMD" || TCLSH_CMD="none"
with_tclsh=${TCLSH_CMD}
fi
if test x"${with_tclsh}" != x -a x"${with_tclsh}" != xnone; then
TCLSH_CMD=${with_tclsh}
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: using tclsh at \"$TCLSH_CMD\"" >&5
$as_echo "using tclsh at \"$TCLSH_CMD\"" >&6; }
if test x"${use_tcl}" = "xyes"; then
with_tcl=`${with_tclsh} <${srcdir}/tool/find_tclconfig.tcl`
if test x"${with_tcl}" != x; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $TCLSH_CMD recommends the tclConfig.sh at ${with_tcl}" >&5
$as_echo "$TCLSH_CMD recommends the tclConfig.sh at ${with_tcl}" >&6; }
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $TCLSH_CMD is unable to recommend a tclConfig.sh" >&5
$as_echo "$as_me: WARNING: $TCLSH_CMD is unable to recommend a tclConfig.sh" >&2;}
use_tcl=no
fi
fi
fi
if test x"${use_tcl}" = "xyes"; then
if test x"${with_tcl}" != x; then
if test -r ${with_tcl}/tclConfig.sh; then
tclconfig="${with_tcl}/tclConfig.sh"
else
for i in tcl8.6 tcl9.0 lib; do
if test -r ${with_tcl}/$i/tclConfig.sh; then
tclconfig=${with_tcl}/$i/tclConfig.sh
break
fi
done
fi
if test ! -r "${tclconfig}"; then
as_fn_error $? "no tclConfig.sh file found under ${with_tcl}" "$LINENO" 5
fi
else
# If we have not yet found a tclConfig.sh file, look in $libdir whic is
# set automatically by autoconf or by the --prefix command-line option.
# See https://sqlite.org/forum/forumpost/e04e693439a22457
libdir=${prefix}/lib
if test -r ${libdir}/tclConfig.sh; then
tclconfig=${libdir}/tclConfig.sh
else
for i in tcl8.6 tcl9.0 lib; do
if test -r ${libdir}/$i/tclConfig.sh; then
tclconfig=${libdir}/$i/tclConfig.sh
break
fi
done
fi
if test ! -r "${tclconfig}"; then
as_fn_error $? "cannot find a usable tclConfig.sh file.
Use --with-tcl=DIR to specify a directory where tclConfig.sh can be found.
SQLite does not use TCL internally, but TCL is required to build SQLite
from canonical sources and TCL is required for testing." "$LINENO" 5
fi
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: loading TCL configuration from ${tclconfig}" >&5
$as_echo "loading TCL configuration from ${tclconfig}" >&6; }
. ${tclconfig}
# There are lots of other configuration variables that are provided by the
# tclConfig.sh file and that could be included here. But as of right now,
# TCL_LIB_SPEC is the only what that the Makefile uses.
HAVE_TCL=1
elif test x"${original_use_tcl}" = "xno"; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: unable to run tests because of --disable-tcl" >&5
$as_echo "unable to run tests because of --disable-tcl" >&6; }
HAVE_TCL=0
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: unable to run tests because no tclConfig.sh file could be located" >&5
$as_echo "unable to run tests because no tclConfig.sh file could be located" >&6; }
HAVE_TCL=0
fi
if test x"$TCLSH_CMD" == x; then
TCLSH_CMD=${TCL_EXEC_PREFIX}/bin/tclsh${TCL_VERSION}
if test ! -x ${TCLSH_CMD}; then
TCLSH_CMD_2=${TCL_EXEC_PREFIX}/bin/tclsh
if test ! -x ${TCLSH_CMD_2}; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cannot find a usable tclsh at either ${TCLSH_CMD} or ${TCLSH_CMD_2}" >&5
$as_echo "$as_me: WARNING: cannot find a usable tclsh at either ${TCLSH_CMD} or ${TCLSH_CMD_2}" >&2;}
TCLSH_CMD=none
else
TCLSH_CMD=${TCLSH_CMD_2}
fi
fi
fi
if test "$TCLSH_CMD" = "none"; then
# If we can't find a local tclsh, then building the amalgamation will fail.
# We act as though --disable-amalgamation has been used.
echo "Warning: can't find tclsh - defaulting to non-amalgamation build."
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Warning: can't find tclsh - defaulting to non-amalgamation build." >&5
$as_echo "$as_me: WARNING: Warning: can't find tclsh - defaulting to non-amalgamation build." >&2;}
USE_AMALGAMATION=0
TCLSH_CMD="tclsh"
fi
@@ -10372,7 +10478,6 @@ fi
if test "x${TCLLIBDIR+set}" != "xset" ; then
TCLLIBDIR='$(libdir)'
for i in `echo 'puts stdout $auto_path' | ${TCLSH_CMD}` ; do
if test -d $i ; then
TCLLIBDIR=$i
@@ -10382,6 +10487,23 @@ if test "x${TCLLIBDIR+set}" != "xset" ; then
TCLLIBDIR="${TCLLIBDIR}/sqlite3"
fi
#########
# Set up options for running tests.
#
# Check whether --enable-test-status was given.
if test "${enable_test_status+set}" = set; then :
enableval=$enable_test_status; use_vt100=$enableval
else
use_vt100=no
fi
if test $use_vt100 != no; then
TSTRNNR_OPTS=--status
else
TSTRNNR_OPTS=
fi
#########
# Set up an appropriate program prefix
@@ -10769,213 +10891,6 @@ fi
##########
# Figure out all the parameters needed to compile against Tcl.
#
# This code is derived from the SC_PATH_TCLCONFIG and SC_LOAD_TCLCONFIG
# macros in the in the tcl.m4 file of the standard TCL distribution.
# Those macros could not be used directly since we have to make some
# minor changes to accomodate systems that do not have TCL installed.
#
# Check whether --enable-tcl was given.
if test "${enable_tcl+set}" = set; then :
enableval=$enable_tcl; use_tcl=$enableval
else
use_tcl=yes
fi
if test "${use_tcl}" = "yes" ; then
# Check whether --with-tcl was given.
if test "${with_tcl+set}" = set; then :
withval=$with_tcl; with_tclconfig=${withval}
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for Tcl configuration" >&5
$as_echo_n "checking for Tcl configuration... " >&6; }
if ${ac_cv_c_tclconfig+:} false; then :
$as_echo_n "(cached) " >&6
else
# First check to see if --with-tcl was specified.
if test x"${with_tclconfig}" != x ; then
if test -f "${with_tclconfig}/tclConfig.sh" ; then
ac_cv_c_tclconfig=`(cd ${with_tclconfig}; pwd)`
else
as_fn_error $? "${with_tclconfig} directory doesn't contain tclConfig.sh" "$LINENO" 5
fi
fi
# Start autosearch by asking tclsh
if test x"${ac_cv_c_tclconfig}" = x ; then
if test x"$cross_compiling" = xno; then
for i in `echo 'puts stdout $auto_path' | ${TCLSH_CMD}`
do
if test -f "$i/tclConfig.sh" ; then
ac_cv_c_tclconfig="$i"
break
fi
done
fi
fi
# On ubuntu 14.10, $auto_path on tclsh is not quite correct.
# So try again after applying corrections.
if test x"${ac_cv_c_tclconfig}" = x ; then
if test x"$cross_compiling" = xno; then
for i in `echo 'puts stdout $auto_path' | ${TCLSH_CMD} | sed 's,/tcltk/tcl,/tcl,g'`
do
if test -f "$i/tclConfig.sh" ; then
ac_cv_c_tclconfig="$i"
break
fi
done
fi
fi
# Recent versions of Xcode on Macs hid the tclConfig.sh file
# in a strange place.
if test x"${ac_cv_c_tclconfig}" = x ; then
if test x"$cross_compiling" = xno; then
for i in /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX*.sdk/usr/lib
do
if test -f "$i/tclConfig.sh" ; then
ac_cv_c_tclconfig="$i"
break
fi
done
fi
fi
# then check for a private Tcl installation
if test x"${ac_cv_c_tclconfig}" = x ; then
for i in \
../tcl \
`ls -dr ../tcl[8-9].[0-9].[0-9]* 2>/dev/null` \
`ls -dr ../tcl[8-9].[0-9] 2>/dev/null` \
`ls -dr ../tcl[8-9].[0-9]* 2>/dev/null` \
../../tcl \
`ls -dr ../../tcl[8-9].[0-9].[0-9]* 2>/dev/null` \
`ls -dr ../../tcl[8-9].[0-9] 2>/dev/null` \
`ls -dr ../../tcl[8-9].[0-9]* 2>/dev/null` \
../../../tcl \
`ls -dr ../../../tcl[8-9].[0-9].[0-9]* 2>/dev/null` \
`ls -dr ../../../tcl[8-9].[0-9] 2>/dev/null` \
`ls -dr ../../../tcl[8-9].[0-9]* 2>/dev/null`
do
if test -f "$i/unix/tclConfig.sh" ; then
ac_cv_c_tclconfig=`(cd $i/unix; pwd)`
break
fi
done
fi
# check in a few common install locations
if test x"${ac_cv_c_tclconfig}" = x ; then
for i in \
`ls -d ${libdir} 2>/dev/null` \
`ls -d /usr/local/lib 2>/dev/null` \
`ls -d /usr/contrib/lib 2>/dev/null` \
`ls -d /usr/lib 2>/dev/null`
do
if test -f "$i/tclConfig.sh" ; then
ac_cv_c_tclconfig=`(cd $i; pwd)`
break
fi
done
fi
# check in a few other private locations
if test x"${ac_cv_c_tclconfig}" = x ; then
for i in \
${srcdir}/../tcl \
`ls -dr ${srcdir}/../tcl[8-9].[0-9].[0-9]* 2>/dev/null` \
`ls -dr ${srcdir}/../tcl[8-9].[0-9] 2>/dev/null` \
`ls -dr ${srcdir}/../tcl[8-9].[0-9]* 2>/dev/null`
do
if test -f "$i/unix/tclConfig.sh" ; then
ac_cv_c_tclconfig=`(cd $i/unix; pwd)`
break
fi
done
fi
fi
if test x"${ac_cv_c_tclconfig}" = x ; then
use_tcl=no
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Can't find Tcl configuration definitions" >&5
$as_echo "$as_me: WARNING: Can't find Tcl configuration definitions" >&2;}
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: *** Without Tcl the regression tests cannot be executed ***" >&5
$as_echo "$as_me: WARNING: *** Without Tcl the regression tests cannot be executed ***" >&2;}
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: *** Consider using --with-tcl=... to define location of Tcl ***" >&5
$as_echo "$as_me: WARNING: *** Consider using --with-tcl=... to define location of Tcl ***" >&2;}
else
TCL_BIN_DIR=${ac_cv_c_tclconfig}
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: found $TCL_BIN_DIR/tclConfig.sh" >&5
$as_echo "found $TCL_BIN_DIR/tclConfig.sh" >&6; }
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for existence of $TCL_BIN_DIR/tclConfig.sh" >&5
$as_echo_n "checking for existence of $TCL_BIN_DIR/tclConfig.sh... " >&6; }
if test -f "$TCL_BIN_DIR/tclConfig.sh" ; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: loading" >&5
$as_echo "loading" >&6; }
. $TCL_BIN_DIR/tclConfig.sh
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: file not found" >&5
$as_echo "file not found" >&6; }
fi
#
# If the TCL_BIN_DIR is the build directory (not the install directory),
# then set the common variable name to the value of the build variables.
# For example, the variable TCL_LIB_SPEC will be set to the value
# of TCL_BUILD_LIB_SPEC. An extension should make use of TCL_LIB_SPEC
# instead of TCL_BUILD_LIB_SPEC since it will work with both an
# installed and uninstalled version of Tcl.
#
if test -f $TCL_BIN_DIR/Makefile ; then
TCL_LIB_SPEC=${TCL_BUILD_LIB_SPEC}
TCL_STUB_LIB_SPEC=${TCL_BUILD_STUB_LIB_SPEC}
TCL_STUB_LIB_PATH=${TCL_BUILD_STUB_LIB_PATH}
fi
#
# eval is required to do the TCL_DBGX substitution
#
eval "TCL_LIB_FILE=\"${TCL_LIB_FILE}\""
eval "TCL_LIB_FLAG=\"${TCL_LIB_FLAG}\""
eval "TCL_LIB_SPEC=\"${TCL_LIB_SPEC}\""
eval "TCL_STUB_LIB_FILE=\"${TCL_STUB_LIB_FILE}\""
eval "TCL_STUB_LIB_FLAG=\"${TCL_STUB_LIB_FLAG}\""
eval "TCL_STUB_LIB_SPEC=\"${TCL_STUB_LIB_SPEC}\""
fi
fi
if test "${use_tcl}" = "no" ; then
HAVE_TCL=""
else
HAVE_TCL=1
fi
##########
# Figure out what C libraries are required to compile programs
# that use "readline()" library.
+104 -191
View File
@@ -116,15 +116,101 @@ AC_CHECK_FUNCS([fdatasync gmtime_r isnan localtime_r localtime_s malloc_usable_s
USE_AMALGAMATION=1
#########
# See whether we can run specific tclsh versions known to work well;
# if not, then we fall back to plain tclsh.
# TODO: try other versions before falling back?
#
AC_CHECK_PROGS(TCLSH_CMD, [tclsh8.7 tclsh8.6 tclsh8.5 tclsh], none)
# Figure out all the name of a working tclsh and parameters needed to compile against Tcl.
# The --with-tcl= and/or --with-tclsh= configuration arguments might be useful for this.
#
AC_ARG_WITH(tclsh, AS_HELP_STRING([--with-tclsh=PATHNAME],[full pathname of a tclsh to use]))
AC_ARG_WITH(tcl, AS_HELP_STRING([--with-tcl=DIR],[directory containing (tclConfig.sh)]))
AC_ARG_ENABLE(tcl, AS_HELP_STRING([--disable-tcl],[omit building accessory programs that require TCL-dev]),
[use_tcl=$enableval],[use_tcl=yes])
original_use_tcl=${use_tcl}
if test x"${with_tclsh}" == x -a x"${with_tcl}" == x; then
AC_CHECK_PROGS(TCLSH_CMD, [tclsh8.6 tclsh tclsh9.0],none)
with_tclsh=${TCLSH_CMD}
fi
if test x"${with_tclsh}" != x -a x"${with_tclsh}" != xnone; then
TCLSH_CMD=${with_tclsh}
AC_MSG_RESULT([using tclsh at "$TCLSH_CMD"])
if test x"${use_tcl}" = "xyes"; then
with_tcl=`${with_tclsh} <${srcdir}/tool/find_tclconfig.tcl`
if test x"${with_tcl}" != x; then
AC_MSG_RESULT([$TCLSH_CMD recommends the tclConfig.sh at ${with_tcl}])
else
AC_MSG_WARN([$TCLSH_CMD is unable to recommend a tclConfig.sh])
use_tcl=no
fi
fi
fi
if test x"${use_tcl}" = "xyes"; then
if test x"${with_tcl}" != x; then
if test -r ${with_tcl}/tclConfig.sh; then
tclconfig="${with_tcl}/tclConfig.sh"
else
for i in tcl8.6 tcl9.0 lib; do
if test -r ${with_tcl}/$i/tclConfig.sh; then
tclconfig=${with_tcl}/$i/tclConfig.sh
break
fi
done
fi
if test ! -r "${tclconfig}"; then
AC_MSG_ERROR([no tclConfig.sh file found under ${with_tcl}])
fi
else
# If we have not yet found a tclConfig.sh file, look in $libdir whic is
# set automatically by autoconf or by the --prefix command-line option.
# See https://sqlite.org/forum/forumpost/e04e693439a22457
libdir=${prefix}/lib
if test -r ${libdir}/tclConfig.sh; then
tclconfig=${libdir}/tclConfig.sh
else
for i in tcl8.6 tcl9.0 lib; do
if test -r ${libdir}/$i/tclConfig.sh; then
tclconfig=${libdir}/$i/tclConfig.sh
break
fi
done
fi
if test ! -r "${tclconfig}"; then
AC_MSG_ERROR([cannot find a usable tclConfig.sh file.
Use --with-tcl=DIR to specify a directory where tclConfig.sh can be found.
SQLite does not use TCL internally, but TCL is required to build SQLite
from canonical sources and TCL is required for testing.])
fi
fi
AC_MSG_RESULT([loading TCL configuration from ${tclconfig}])
. ${tclconfig}
AC_SUBST(TCL_INCLUDE_SPEC)
AC_SUBST(TCL_LIB_SPEC)
AC_SUBST(TCL_STUB_LIB_SPEC)
# There are lots of other configuration variables that are provided by the
# tclConfig.sh file and that could be included here. But as of right now,
# TCL_LIB_SPEC is the only what that the Makefile uses.
HAVE_TCL=1
elif test x"${original_use_tcl}" = "xno"; then
AC_MSG_RESULT([unable to run tests because of --disable-tcl])
HAVE_TCL=0
else
AC_MSG_RESULT([unable to run tests because no tclConfig.sh file could be located])
HAVE_TCL=0
fi
AC_SUBST(HAVE_TCL)
if test x"$TCLSH_CMD" == x; then
TCLSH_CMD=${TCL_EXEC_PREFIX}/bin/tclsh${TCL_VERSION}
if test ! -x ${TCLSH_CMD}; then
TCLSH_CMD_2=${TCL_EXEC_PREFIX}/bin/tclsh
if test ! -x ${TCLSH_CMD_2}; then
AC_MSG_WARN([cannot find a usable tclsh at either ${TCLSH_CMD} or ${TCLSH_CMD_2}])
TCLSH_CMD=none
else
TCLSH_CMD=${TCLSH_CMD_2}
fi
fi
fi
if test "$TCLSH_CMD" = "none"; then
# If we can't find a local tclsh, then building the amalgamation will fail.
# We act as though --disable-amalgamation has been used.
echo "Warning: can't find tclsh - defaulting to non-amalgamation build."
AC_MSG_WARN([Warning: can't find tclsh - defaulting to non-amalgamation build.])
USE_AMALGAMATION=0
TCLSH_CMD="tclsh"
fi
@@ -132,7 +218,6 @@ AC_SUBST(TCLSH_CMD)
AC_ARG_VAR([TCLLIBDIR], [Where to install tcl plugin])
if test "x${TCLLIBDIR+set}" != "xset" ; then
TCLLIBDIR='$(libdir)'
for i in `echo 'puts stdout $auto_path' | ${TCLSH_CMD}` ; do
if test -d $i ; then
TCLLIBDIR=$i
@@ -142,6 +227,18 @@ if test "x${TCLLIBDIR+set}" != "xset" ; then
TCLLIBDIR="${TCLLIBDIR}/sqlite3"
fi
#########
# Set up options for running tests.
#
AC_ARG_ENABLE(test-status, AS_HELP_STRING([--enable-test-status],[Full-screen status of tests]),
[use_vt100=$enableval],[use_vt100=no])
if test $use_vt100 != no; then
TSTRNNR_OPTS=--status
else
TSTRNNR_OPTS=
fi
AC_SUBST(TSTRNNR_OPTS)
#########
# Set up an appropriate program prefix
@@ -339,190 +436,6 @@ AC_SUBST(SQLITE_OS_UNIX)
AC_SUBST(SQLITE_OS_WIN)
AC_SUBST(TARGET_EXEEXT)
##########
# Figure out all the parameters needed to compile against Tcl.
#
# This code is derived from the SC_PATH_TCLCONFIG and SC_LOAD_TCLCONFIG
# macros in the in the tcl.m4 file of the standard TCL distribution.
# Those macros could not be used directly since we have to make some
# minor changes to accomodate systems that do not have TCL installed.
#
AC_ARG_ENABLE(tcl, AS_HELP_STRING([--disable-tcl],[do not build TCL extension]),
[use_tcl=$enableval],[use_tcl=yes])
if test "${use_tcl}" = "yes" ; then
AC_ARG_WITH(tcl, AS_HELP_STRING([--with-tcl=DIR],[directory containing tcl configuration (tclConfig.sh)]), with_tclconfig=${withval})
AC_MSG_CHECKING([for Tcl configuration])
AC_CACHE_VAL(ac_cv_c_tclconfig,[
# First check to see if --with-tcl was specified.
if test x"${with_tclconfig}" != x ; then
if test -f "${with_tclconfig}/tclConfig.sh" ; then
ac_cv_c_tclconfig=`(cd ${with_tclconfig}; pwd)`
else
AC_MSG_ERROR([${with_tclconfig} directory doesn't contain tclConfig.sh])
fi
fi
# Start autosearch by asking tclsh
if test x"${ac_cv_c_tclconfig}" = x ; then
if test x"$cross_compiling" = xno; then
for i in `echo 'puts stdout $auto_path' | ${TCLSH_CMD}`
do
if test -f "$i/tclConfig.sh" ; then
ac_cv_c_tclconfig="$i"
break
fi
done
fi
fi
# On ubuntu 14.10, $auto_path on tclsh is not quite correct.
# So try again after applying corrections.
if test x"${ac_cv_c_tclconfig}" = x ; then
if test x"$cross_compiling" = xno; then
for i in `echo 'puts stdout $auto_path' | ${TCLSH_CMD} | sed 's,/tcltk/tcl,/tcl,g'`
do
if test -f "$i/tclConfig.sh" ; then
ac_cv_c_tclconfig="$i"
break
fi
done
fi
fi
# Recent versions of Xcode on Macs hid the tclConfig.sh file
# in a strange place.
if test x"${ac_cv_c_tclconfig}" = x ; then
if test x"$cross_compiling" = xno; then
for i in /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX*.sdk/usr/lib
do
if test -f "$i/tclConfig.sh" ; then
ac_cv_c_tclconfig="$i"
break
fi
done
fi
fi
# then check for a private Tcl installation
if test x"${ac_cv_c_tclconfig}" = x ; then
for i in \
../tcl \
`ls -dr ../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \
`ls -dr ../tcl[[8-9]].[[0-9]] 2>/dev/null` \
`ls -dr ../tcl[[8-9]].[[0-9]]* 2>/dev/null` \
../../tcl \
`ls -dr ../../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \
`ls -dr ../../tcl[[8-9]].[[0-9]] 2>/dev/null` \
`ls -dr ../../tcl[[8-9]].[[0-9]]* 2>/dev/null` \
../../../tcl \
`ls -dr ../../../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \
`ls -dr ../../../tcl[[8-9]].[[0-9]] 2>/dev/null` \
`ls -dr ../../../tcl[[8-9]].[[0-9]]* 2>/dev/null`
do
if test -f "$i/unix/tclConfig.sh" ; then
ac_cv_c_tclconfig=`(cd $i/unix; pwd)`
break
fi
done
fi
# check in a few common install locations
if test x"${ac_cv_c_tclconfig}" = x ; then
for i in \
`ls -d ${libdir} 2>/dev/null` \
`ls -d /usr/local/lib 2>/dev/null` \
`ls -d /usr/contrib/lib 2>/dev/null` \
`ls -d /usr/lib 2>/dev/null`
do
if test -f "$i/tclConfig.sh" ; then
ac_cv_c_tclconfig=`(cd $i; pwd)`
break
fi
done
fi
# check in a few other private locations
if test x"${ac_cv_c_tclconfig}" = x ; then
for i in \
${srcdir}/../tcl \
`ls -dr ${srcdir}/../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \
`ls -dr ${srcdir}/../tcl[[8-9]].[[0-9]] 2>/dev/null` \
`ls -dr ${srcdir}/../tcl[[8-9]].[[0-9]]* 2>/dev/null`
do
if test -f "$i/unix/tclConfig.sh" ; then
ac_cv_c_tclconfig=`(cd $i/unix; pwd)`
break
fi
done
fi
])
if test x"${ac_cv_c_tclconfig}" = x ; then
use_tcl=no
AC_MSG_WARN(Can't find Tcl configuration definitions)
AC_MSG_WARN(*** Without Tcl the regression tests cannot be executed ***)
AC_MSG_WARN(*** Consider using --with-tcl=... to define location of Tcl ***)
else
TCL_BIN_DIR=${ac_cv_c_tclconfig}
AC_MSG_RESULT(found $TCL_BIN_DIR/tclConfig.sh)
AC_MSG_CHECKING([for existence of $TCL_BIN_DIR/tclConfig.sh])
if test -f "$TCL_BIN_DIR/tclConfig.sh" ; then
AC_MSG_RESULT([loading])
. $TCL_BIN_DIR/tclConfig.sh
else
AC_MSG_RESULT([file not found])
fi
#
# If the TCL_BIN_DIR is the build directory (not the install directory),
# then set the common variable name to the value of the build variables.
# For example, the variable TCL_LIB_SPEC will be set to the value
# of TCL_BUILD_LIB_SPEC. An extension should make use of TCL_LIB_SPEC
# instead of TCL_BUILD_LIB_SPEC since it will work with both an
# installed and uninstalled version of Tcl.
#
if test -f $TCL_BIN_DIR/Makefile ; then
TCL_LIB_SPEC=${TCL_BUILD_LIB_SPEC}
TCL_STUB_LIB_SPEC=${TCL_BUILD_STUB_LIB_SPEC}
TCL_STUB_LIB_PATH=${TCL_BUILD_STUB_LIB_PATH}
fi
#
# eval is required to do the TCL_DBGX substitution
#
eval "TCL_LIB_FILE=\"${TCL_LIB_FILE}\""
eval "TCL_LIB_FLAG=\"${TCL_LIB_FLAG}\""
eval "TCL_LIB_SPEC=\"${TCL_LIB_SPEC}\""
eval "TCL_STUB_LIB_FILE=\"${TCL_STUB_LIB_FILE}\""
eval "TCL_STUB_LIB_FLAG=\"${TCL_STUB_LIB_FLAG}\""
eval "TCL_STUB_LIB_SPEC=\"${TCL_STUB_LIB_SPEC}\""
AC_SUBST(TCL_VERSION)
AC_SUBST(TCL_BIN_DIR)
AC_SUBST(TCL_SRC_DIR)
AC_SUBST(TCL_INCLUDE_SPEC)
AC_SUBST(TCL_LIB_FILE)
AC_SUBST(TCL_LIB_FLAG)
AC_SUBST(TCL_LIB_SPEC)
AC_SUBST(TCL_STUB_LIB_FILE)
AC_SUBST(TCL_STUB_LIB_FLAG)
AC_SUBST(TCL_STUB_LIB_SPEC)
AC_SUBST(TCL_SHLIB_SUFFIX)
fi
fi
if test "${use_tcl}" = "no" ; then
HAVE_TCL=""
else
HAVE_TCL=1
fi
AC_SUBST(HAVE_TCL)
##########
# Figure out what C libraries are required to compile programs
# that use "readline()" library.
+12 -1
View File
@@ -57,11 +57,22 @@ canonical source on a new Windows 11 PC, as of 2023-11-01:
<ul>
<li> `nmake /f makefile.msc`
<li> `nmake /f makefile.msc sqlite3.c`
<li> `nmake /f makefile.msc sqlite3.exe`
<li> `nmake /f makefile.msc sqldiff.exe`
<li> `nmake /f makefile.msc tclextension-install`
<li> `nmake /f makefile.msc devtest`
<li> `nmake /f makefile.msc releasetest`
<li> `nmake /f makefile.msc sqlite3.exe`
<li> `nmake /f makefile.msc sqlite3_analyzer.exe`
</ul>
It is not required that you run the "tclextension-install" target prior to
running tests. However, the tests will run more smoothly if you do.
The version of SQLite used for the TCL extension does *not* need to
correspond to the version of SQLite under test. So you can install the
SQLite TCL extension once, and then use it to test many different versions
of SQLite.
7. For a debugging build of the CLI, where the ".treetrace" and ".wheretrace"
commands work, add the DEBUG=3 argument to nmake. Like this:
<ul>
+89 -7
View File
@@ -53,11 +53,6 @@
# define CIO_WIN_WC_XLATE 0 /* Not exposing translation routines at all */
#endif
#if CIO_WIN_WC_XLATE
/* Character used to represent a known-incomplete UTF-8 char group () */
static WCHAR cBadGroup = 0xfffd;
#endif
#if CIO_WIN_WC_XLATE
static HANDLE handleOfFile(FILE *pf){
int fileDesc = _fileno(pf);
@@ -600,6 +595,93 @@ oPutbUtf8(const char *cBuf, int nAccept){
# endif
}
/*
** Flush the given output stream. Return non-zero for success, else 0.
*/
#if !defined(SQLITE_CIO_NO_FLUSH) && !defined(SQLITE_CIO_NO_SETMODE)
SQLITE_INTERNAL_LINKAGE int
fFlushBuffer(FILE *pfOut){
# if CIO_WIN_WC_XLATE && !defined(SHELL_OMIT_FIO_DUPE)
return FlushFileBuffers(handleOfFile(pfOut))? 1 : 0;
# else
return fflush(pfOut);
# endif
}
#endif
#if CIO_WIN_WC_XLATE \
&& !defined(SHELL_OMIT_FIO_DUPE) \
&& defined(SQLITE_USE_ONLY_WIN32)
static struct FileAltIds {
int fd;
HANDLE fh;
} altIdsOfFile(FILE *pf){
struct FileAltIds rv = { _fileno(pf) };
union { intptr_t osfh; HANDLE fh; } fid = {
(rv.fd>=0)? _get_osfhandle(rv.fd) : (intptr_t)INVALID_HANDLE_VALUE
};
rv.fh = fid.fh;
return rv;
}
SQLITE_INTERNAL_LINKAGE size_t
cfWrite(const void *buf, size_t osz, size_t ocnt, FILE *pf){
size_t rv = 0;
struct FileAltIds fai = altIdsOfFile(pf);
int fmode = _setmode(fai.fd, _O_BINARY);
_setmode(fai.fd, fmode);
while( rv < ocnt ){
size_t nbo = osz;
while( nbo > 0 ){
DWORD dwno = (nbo>(1L<<24))? 1L<<24 : (DWORD)nbo;
BOOL wrc = TRUE;
BOOL genCR = (fmode & _O_TEXT)!=0;
if( genCR ){
const char *pnl = (const char*)memchr(buf, '\n', nbo);
if( pnl ) nbo = pnl - (const char*)buf;
else genCR = 0;
}
if( dwno>0 ) wrc = WriteFile(fai.fh, buf, dwno, 0,0);
if( genCR && wrc ){
wrc = WriteFile(fai.fh, "\r\n", 2, 0,0);
++dwno; /* Skip over the LF */
}
if( !wrc ) return rv;
buf = (const char*)buf + dwno;
nbo += dwno;
}
++rv;
}
return rv;
}
/* An fgets() equivalent, using Win32 file API for actual input.
** Input ends when given buffer is filled or a newline is read.
** If the FILE object is in text mode, swallows 0x0D. (ASCII CR)
*/
SQLITE_INTERNAL_LINKAGE char *
cfGets(char *cBuf, int n, FILE *pf){
int nci = 0;
struct FileAltIds fai = altIdsOfFile(pf);
int fmode = _setmode(fai.fd, _O_BINARY);
BOOL eatCR = (fmode & _O_TEXT)!=0;
_setmode(fai.fd, fmode);
while( nci < n-1 ){
DWORD nr;
if( !ReadFile(fai.fh, cBuf+nci, 1, &nr, 0) || nr==0 ) break;
if( nr>0 && (!eatCR || cBuf[nci]!='\r') ){
nci += nr;
if( cBuf[nci-nr]=='\n' ) break;
}
}
if( nci < n ) cBuf[nci] = 0;
return (nci>0)? cBuf : 0;
}
# else
# define cfWrite(b,os,no,f) fwrite(b,os,no,f)
# define cfGets(b,n,f) fgets(b,n,f)
# endif
# ifdef CONSIO_EPUTB
SQLITE_INTERNAL_LINKAGE int
ePutbUtf8(const char *cBuf, int nAccept){
@@ -611,7 +693,7 @@ ePutbUtf8(const char *cBuf, int nAccept){
return conZstrEmit(ppst, cBuf, nAccept);
}else {
# endif
return (int)fwrite(cBuf, 1, nAccept, pfErr);
return (int)cfWrite(cBuf, 1, nAccept, pfErr);
# if CIO_WIN_WC_XLATE
}
# endif
@@ -677,7 +759,7 @@ SQLITE_INTERNAL_LINKAGE char* fGetsUtf8(char *cBuf, int ncMax, FILE *pfIn){
# endif
}else{
# endif
return fgets(cBuf, ncMax, pfIn);
return cfGets(cBuf, ncMax, pfIn);
# if CIO_WIN_WC_XLATE
}
# endif
+11 -4
View File
@@ -176,12 +176,19 @@ SQLITE_INTERNAL_LINKAGE int
ePutbUtf8(const char *cBuf, int nAccept);
#endif
/*
** Flush the given output stream. Return non-zero for success, else 0.
*/
#if !defined(SQLITE_CIO_NO_FLUSH) && !defined(SQLITE_CIO_NO_SETMODE)
SQLITE_INTERNAL_LINKAGE int
fFlushBuffer(FILE *pfOut);
#endif
/*
** Collect input like fgets(...) with special provisions for input
** from the console on platforms that require same. Defers to the
** C library fgets() when input is not from the console. Newline
** translation may be done as set by set{Binary,Text}Mode(). As a
** convenience, pfIn==NULL is treated as stdin.
** from the console on such platforms as require same. Newline
** translation may be done as set by set{Binary,Text}Mode().
** As a convenience, pfIn==NULL is treated as stdin.
*/
SQLITE_INTERNAL_LINKAGE char* fGetsUtf8(char *cBuf, int ncMax, FILE *pfIn);
/* Like fGetsUtf8 except stream is always the designated input. */
+23
View File
@@ -428,6 +428,8 @@ do_execsql_test 5.0 {
WITH s(i) AS ( VALUES(1) UNION ALL SELECT i+1 FROM s WHERE i<100)
INSERT INTO t2 SELECT (i-1)/20, (i-1)/5 FROM s;
CREATE INDEX i1 ON t1( lower(a) );
}
do_candidates_test 5.1 {
SELECT * FROM t1,t2 WHERE (b=? OR a=?) AND (c=? OR d=?)
@@ -457,6 +459,7 @@ do_execsql_test 5.3 {
ANALYZE;
SELECT * FROM sqlite_stat1 ORDER BY 1, 2;
} {
t1 i1 {100 50}
t1 t1_idx_00000061 {100 50}
t1 t1_idx_00000062 {100 20}
t1 t1_idx_000123a7 {100 50 17}
@@ -465,6 +468,13 @@ do_execsql_test 5.3 {
t2 t2_idx_0001295b {100 20 5}
}
do_catchsql_test 5.4 {
SELECT sqlite_expert_rem(123, 123);
} {1 {no such function: sqlite_expert_rem}}
do_catchsql_test 5.5 {
SELECT sqlite_expert_sample();
} {1 {no such function: sqlite_expert_sample}}
if 0 {
do_test expert1-6.0 {
catchcmd :memory: {
@@ -484,4 +494,17 @@ USE TEMP B-TREE FOR ORDER BY
}}
}
do_execsql_test 6.0 {
CREATE TABLE x1(a, b, c, d);
CREATE INDEX x1ab ON x1(a, lower(b));
CREATE INDEX x1dcba ON x1(d, b+c, a);
}
do_candidates_test 6.1 {
SELECT * FROM x1 WHERE b=? ORDER BY a;
} {
CREATE INDEX x1_idx_0001267f ON x1(b, a);
CREATE INDEX x1_idx_00000062 ON x1(b);
}
finish_test
+18 -8
View File
@@ -626,7 +626,7 @@ static int expertFilter(
pCsr->pData = 0;
if( rc==SQLITE_OK ){
rc = idxPrintfPrepareStmt(pExpert->db, &pCsr->pData, &pVtab->base.zErrMsg,
"SELECT * FROM main.%Q WHERE sample()", pVtab->pTab->zName
"SELECT * FROM main.%Q WHERE sqlite_expert_sample()", pVtab->pTab->zName
);
}
@@ -1500,7 +1500,7 @@ struct IdxRemCtx {
};
/*
** Implementation of scalar function rem().
** Implementation of scalar function sqlite_expert_rem().
*/
static void idxRemFunc(
sqlite3_context *pCtx,
@@ -1513,7 +1513,7 @@ static void idxRemFunc(
assert( argc==2 );
iSlot = sqlite3_value_int(argv[0]);
assert( iSlot<=p->nSlot );
assert( iSlot<p->nSlot );
pSlot = &p->aSlot[iSlot];
switch( pSlot->eType ){
@@ -1623,8 +1623,15 @@ static int idxPopulateOneStat1(
const char *zComma = zCols==0 ? "" : ", ";
const char *zName = (const char*)sqlite3_column_text(pIndexXInfo, 0);
const char *zColl = (const char*)sqlite3_column_text(pIndexXInfo, 1);
if( zName==0 ){
/* This index contains an expression. Ignore it. */
sqlite3_free(zCols);
sqlite3_free(zOrder);
return sqlite3_reset(pIndexXInfo);
}
zCols = idxAppendText(&rc, zCols,
"%sx.%Q IS rem(%d, x.%Q) COLLATE %s", zComma, zName, nCol, zName, zColl
"%sx.%Q IS sqlite_expert_rem(%d, x.%Q) COLLATE %s",
zComma, zName, nCol, zName, zColl
);
zOrder = idxAppendText(&rc, zOrder, "%s%d", zComma, ++nCol);
}
@@ -1757,13 +1764,13 @@ static int idxPopulateStat1(sqlite3expert *p, char **pzErr){
if( rc==SQLITE_OK ){
sqlite3 *dbrem = (p->iSample==100 ? p->db : p->dbv);
rc = sqlite3_create_function(
dbrem, "rem", 2, SQLITE_UTF8, (void*)pCtx, idxRemFunc, 0, 0
rc = sqlite3_create_function(dbrem, "sqlite_expert_rem",
2, SQLITE_UTF8, (void*)pCtx, idxRemFunc, 0, 0
);
}
if( rc==SQLITE_OK ){
rc = sqlite3_create_function(
p->db, "sample", 0, SQLITE_UTF8, (void*)&samplectx, idxSampleFunc, 0, 0
rc = sqlite3_create_function(p->db, "sqlite_expert_sample",
0, SQLITE_UTF8, (void*)&samplectx, idxSampleFunc, 0, 0
);
}
@@ -1815,6 +1822,9 @@ static int idxPopulateStat1(sqlite3expert *p, char **pzErr){
rc = sqlite3_exec(p->dbm, "ANALYZE sqlite_schema", 0, 0, 0);
}
sqlite3_create_function(p->db, "sqlite_expert_rem", 2, SQLITE_UTF8, 0,0,0,0);
sqlite3_create_function(p->db, "sqlite_expert_sample", 0,SQLITE_UTF8,0,0,0,0);
sqlite3_exec(p->db, "DROP TABLE IF EXISTS temp."UNIQUE_TABLE_NAME,0,0,0);
return rc;
}
+1 -9
View File
@@ -16,15 +16,7 @@
#include "sqlite3expert.h"
#include <assert.h>
#include <string.h>
#if defined(INCLUDE_SQLITE_TCL_H)
# include "sqlite_tcl.h"
#else
# include "tcl.h"
# ifndef SQLITE_TCLAPI
# define SQLITE_TCLAPI
# endif
#endif
#include "tclsqlite.h"
#ifndef SQLITE_OMIT_VIRTUALTABLE
+1
View File
@@ -398,6 +398,7 @@ static int fts3SnippetNextCandidate(SnippetIter *pIter){
return 1;
}
assert( pIter->nSnippet>=0 );
pIter->iCurrent = iStart = iEnd - pIter->nSnippet + 1;
for(i=0; i<pIter->nPhrase; i++){
SnippetPhrase *pPhrase = &pIter->aPhrase[i];
+12 -4
View File
@@ -78,6 +78,8 @@ static int fts3termConnectMethod(
iIndex = atoi(argv[4]);
argc--;
}
*ppVtab = 0;
/* The user should specify a single argument - the name of an fts3 table. */
if( argc!=4 ){
@@ -95,12 +97,17 @@ static int fts3termConnectMethod(
rc = sqlite3_declare_vtab(db, FTS3_TERMS_SCHEMA);
if( rc!=SQLITE_OK ) return rc;
nByte = sizeof(Fts3termTable) + sizeof(Fts3Table) + nDb + nFts3 + 2;
p = (Fts3termTable *)sqlite3_malloc64(nByte);
nByte = sizeof(Fts3termTable);
p = (Fts3termTable *)sqlite3Fts3MallocZero(nByte);
if( !p ) return SQLITE_NOMEM;
memset(p, 0, (size_t)nByte);
p->pFts3Tab = (Fts3Table *)&p[1];
p->pFts3Tab = (Fts3Table*)sqlite3Fts3MallocZero(
sizeof(Fts3Table) + nDb + nFts3 + 2
);
if( p->pFts3Tab==0 ){
sqlite3_free(p);
return SQLITE_NOMEM;
}
p->pFts3Tab->zDb = (char *)&p->pFts3Tab[1];
p->pFts3Tab->zName = &p->pFts3Tab->zDb[nDb+1];
p->pFts3Tab->db = db;
@@ -130,6 +137,7 @@ static int fts3termDisconnectMethod(sqlite3_vtab *pVtab){
sqlite3_finalize(pFts3->aStmt[i]);
}
sqlite3_free(pFts3->zSegmentsTbl);
sqlite3_free(pFts3);
sqlite3_free(p);
return SQLITE_OK;
}
+13 -16
View File
@@ -18,14 +18,7 @@
** that the sqlite3_tokenizer_module.xLanguage() method is invoked correctly.
*/
#if defined(INCLUDE_SQLITE_TCL_H)
# include "sqlite_tcl.h"
#else
# include "tcl.h"
# ifndef SQLITE_TCLAPI
# define SQLITE_TCLAPI
# endif
#endif
#include "tclsqlite.h"
#include <string.h>
#include <assert.h>
@@ -167,7 +160,8 @@ static int SQLITE_TCLAPI fts3_near_match_cmd(
Tcl_Obj *pPhrasecount = 0;
Tcl_Obj **apExprToken;
int nExprToken;
Tcl_Size nExprToken;
Tcl_Size nn;
UNUSED_PARAMETER(clientData);
@@ -201,23 +195,25 @@ static int SQLITE_TCLAPI fts3_near_match_cmd(
}
}
rc = Tcl_ListObjGetElements(interp, objv[1], &doc.nToken, &apDocToken);
rc = Tcl_ListObjGetElements(interp, objv[1], &nn, &apDocToken);
doc.nToken = (int)nn;
if( rc!=TCL_OK ) goto near_match_out;
doc.aToken = (NearToken *)ckalloc(doc.nToken*sizeof(NearToken));
for(ii=0; ii<doc.nToken; ii++){
doc.aToken[ii].z = Tcl_GetStringFromObj(apDocToken[ii], &doc.aToken[ii].n);
doc.aToken[ii].z = Tcl_GetStringFromObj(apDocToken[ii], &nn);
doc.aToken[ii].n = (int)nn;
}
rc = Tcl_ListObjGetElements(interp, objv[2], &nExprToken, &apExprToken);
if( rc!=TCL_OK ) goto near_match_out;
nPhrase = (nExprToken + 1) / 2;
nPhrase = (int)(nExprToken + 1) / 2;
aPhrase = (NearPhrase *)ckalloc(nPhrase * sizeof(NearPhrase));
memset(aPhrase, 0, nPhrase * sizeof(NearPhrase));
for(ii=0; ii<nPhrase; ii++){
Tcl_Obj *pPhrase = apExprToken[ii*2];
Tcl_Obj **apToken;
int nToken;
Tcl_Size nToken;
int jj;
rc = Tcl_ListObjGetElements(interp, pPhrase, &nToken, &apToken);
@@ -227,11 +223,12 @@ static int SQLITE_TCLAPI fts3_near_match_cmd(
rc = TCL_ERROR;
goto near_match_out;
}
for(jj=0; jj<nToken; jj++){
for(jj=0; jj<(int)nToken; jj++){
NearToken *pT = &aPhrase[ii].aToken[jj];
pT->z = Tcl_GetStringFromObj(apToken[jj], &pT->n);
pT->z = Tcl_GetStringFromObj(apToken[jj], &nn);
pT->n = (int)nn;
}
aPhrase[ii].nToken = nToken;
aPhrase[ii].nToken = (int)nToken;
}
for(ii=1; ii<nPhrase; ii++){
Tcl_Obj *pNear = apExprToken[2*ii-1];
+1 -5
View File
@@ -226,11 +226,7 @@ int sqlite3Fts3InitTokenizer(
#ifdef SQLITE_TEST
#if defined(INCLUDE_SQLITE_TCL_H)
# include "sqlite_tcl.h"
#else
# include "tcl.h"
#endif
#include "tclsqlite.h"
#include <string.h>
/*
+3
View File
@@ -628,6 +628,9 @@ proc print_categories {lMap} {
$caseP
$caseS
$caseZ
default:
return 1;
}
return 0;
}
+5 -2
View File
@@ -82,7 +82,7 @@ proc get_struct_docs {data names} {
set current_doc ""
}
set subject n/a
regexp {^ *([[:alpha:]]*)} $line -> subject
regexp {^ *([[:alnum:]_]*)} $line -> subject
if {[lsearch $names $subject]>=0} {
set current_header $subject
} else {
@@ -108,8 +108,11 @@ proc get_tokenizer_docs {data} {
append res "<dt><b>$line</b></dt><dd><p style=margin-top:0>\n"
continue
}
if {[regexp {FTS5_TOKENIZER} $line]} {
set line </dl><p>
}
if {[regexp {SYNONYM SUPPORT} $line]} {
set line "</dl><h3>Synonym Support</h3>"
set line "<h3>Synonym Support</h3>"
}
if {[string trim $line] == ""} {
append res "<p>\n"
+115 -4
View File
@@ -308,9 +308,32 @@ struct Fts5PhraseIter {
**
** This API can be quite slow if used with an FTS5 table created with the
** "detail=none" or "detail=column" option.
**
** xColumnLocale(pFts5, iIdx, pzLocale, pnLocale)
** If parameter iCol is less than zero, or greater than or equal to the
** number of columns in the table, SQLITE_RANGE is returned.
**
** Otherwise, this function attempts to retrieve the locale associated
** with column iCol of the current row. Usually, there is no associated
** locale, and output parameters (*pzLocale) and (*pnLocale) are set
** to NULL and 0, respectively. However, if the fts5_locale() function
** was used to associate a locale with the value when it was inserted
** into the fts5 table, then (*pzLocale) is set to point to a nul-terminated
** buffer containing the name of the locale in utf-8 encoding. (*pnLocale)
** is set to the size in bytes of the buffer, not including the
** nul-terminator.
**
** If successful, SQLITE_OK is returned. Or, if an error occurs, an
** SQLite error code is returned. The final value of the output parameters
** is undefined in this case.
**
** xTokenize_v2:
** Tokenize text using the tokenizer belonging to the FTS5 table. This
** API is the same as the xTokenize() API, except that it allows a tokenizer
** locale to be specified.
*/
struct Fts5ExtensionApi {
int iVersion; /* Currently always set to 3 */
int iVersion; /* Currently always set to 4 */
void *(*xUserData)(Fts5Context*);
@@ -352,6 +375,15 @@ struct Fts5ExtensionApi {
const char **ppToken, int *pnToken
);
int (*xInstToken)(Fts5Context*, int iIdx, int iToken, const char**, int*);
/* Below this point are iVersion>=4 only */
int (*xColumnLocale)(Fts5Context*, int iCol, const char **pz, int *pn);
int (*xTokenize_v2)(Fts5Context*,
const char *pText, int nText, /* Text to tokenize */
const char *pLocale, int nLocale, /* Locale to pass to tokenizer */
void *pCtx, /* Context passed to xToken() */
int (*xToken)(void*, int, const char*, int, int, int) /* Callback */
);
};
/*
@@ -364,6 +396,7 @@ struct Fts5ExtensionApi {
** Applications may also register custom tokenizer types. A tokenizer
** is registered by providing fts5 with a populated instance of the
** following structure. All structure methods must be defined, setting
**
** any member of the fts5_tokenizer struct to NULL leads to undefined
** behaviour. The structure methods are expected to function as follows:
**
@@ -372,7 +405,7 @@ struct Fts5ExtensionApi {
** A tokenizer instance is required to actually tokenize text.
**
** The first argument passed to this function is a copy of the (void*)
** pointer provided by the application when the fts5_tokenizer object
** pointer provided by the application when the fts5_tokenizer_v2 object
** was registered with FTS5 (the third argument to xCreateTokenizer()).
** The second and third arguments are an array of nul-terminated strings
** containing the tokenizer arguments, if any, specified following the
@@ -396,7 +429,7 @@ struct Fts5ExtensionApi {
** argument passed to this function is a pointer to an Fts5Tokenizer object
** returned by an earlier call to xCreate().
**
** The second argument indicates the reason that FTS5 is requesting
** The third argument indicates the reason that FTS5 is requesting
** tokenization of the supplied text. This is always one of the following
** four values:
**
@@ -420,6 +453,13 @@ struct Fts5ExtensionApi {
** on a columnsize=0 database.
** </ul>
**
** The sixth and seventh arguments passed to xTokenize() - pLocale and
** nLocale - are a pointer to a buffer containing the locale to use for
** tokenization (e.g. "en_US") and its size in bytes, respectively. The
** pLocale buffer is not nul-terminated. pLocale may be passed NULL (in
** which case nLocale is always 0) to indicate that the tokenizer should
** use its default locale.
**
** For each token in the input string, the supplied callback xToken() must
** be invoked. The first argument to it should be a copy of the pointer
** passed as the second argument to xTokenize(). The third and fourth
@@ -443,6 +483,30 @@ struct Fts5ExtensionApi {
** may abandon the tokenization and return any error code other than
** SQLITE_OK or SQLITE_DONE.
**
** If the tokenizer is registered using an fts5_tokenizer_v2 object,
** then the xTokenize() method has two additional arguments - pLocale
** and nLocale. These specify the locale that the tokenizer should use
** for the current request. If pLocale and nLocale are both 0, then the
** tokenizer should use its default locale. Otherwise, pLocale points to
** an nLocale byte buffer containing the name of the locale to use as utf-8
** text. pLocale is not nul-terminated.
**
** FTS5_TOKENIZER
**
** There is also an fts5_tokenizer object. This is an older, deprecated,
** version of fts5_tokenizer_v2. It is similar except that:
**
** <ul>
** <li> There is no "iVersion" field, and
** <li> The xTokenize() method does not take a locale argument.
** </ul>
**
** Legacy fts5_tokenizer tokenizers must be registered using the
** legacy xCreateTokenizer() function, instead of xCreateTokenizer_v2().
**
** Tokenizer implementations registered using either API may be retrieved
** using both xFindTokenizer() and xFindTokenizer_v2().
**
** SYNONYM SUPPORT
**
** Custom tokenizers may also support synonyms. Consider a case in which a
@@ -551,6 +615,33 @@ struct Fts5ExtensionApi {
** inefficient.
*/
typedef struct Fts5Tokenizer Fts5Tokenizer;
typedef struct fts5_tokenizer_v2 fts5_tokenizer_v2;
struct fts5_tokenizer_v2 {
int iVersion; /* Currently always 2 */
int (*xCreate)(void*, const char **azArg, int nArg, Fts5Tokenizer **ppOut);
void (*xDelete)(Fts5Tokenizer*);
int (*xTokenize)(Fts5Tokenizer*,
void *pCtx,
int flags, /* Mask of FTS5_TOKENIZE_* flags */
const char *pText, int nText,
const char *pLocale, int nLocale,
int (*xToken)(
void *pCtx, /* Copy of 2nd argument to xTokenize() */
int tflags, /* Mask of FTS5_TOKEN_* flags */
const char *pToken, /* Pointer to buffer containing token */
int nToken, /* Size of token in bytes */
int iStart, /* Byte offset of token within input text */
int iEnd /* Byte offset of end of token within input text */
)
);
};
/*
** New code should use the fts5_tokenizer_v2 type to define tokenizer
** implementations. The following type is included for legacy applications
** that still use it.
*/
typedef struct fts5_tokenizer fts5_tokenizer;
struct fts5_tokenizer {
int (*xCreate)(void*, const char **azArg, int nArg, Fts5Tokenizer **ppOut);
@@ -570,6 +661,7 @@ struct fts5_tokenizer {
);
};
/* Flags that may be passed as the third argument to xTokenize() */
#define FTS5_TOKENIZE_QUERY 0x0001
#define FTS5_TOKENIZE_PREFIX 0x0002
@@ -589,7 +681,7 @@ struct fts5_tokenizer {
*/
typedef struct fts5_api fts5_api;
struct fts5_api {
int iVersion; /* Currently always set to 2 */
int iVersion; /* Currently always set to 3 */
/* Create a new tokenizer */
int (*xCreateTokenizer)(
@@ -616,6 +708,25 @@ struct fts5_api {
fts5_extension_function xFunction,
void (*xDestroy)(void*)
);
/* APIs below this point are only available if iVersion>=3 */
/* Create a new tokenizer */
int (*xCreateTokenizer_v2)(
fts5_api *pApi,
const char *zName,
void *pUserData,
fts5_tokenizer_v2 *pTokenizer,
void (*xDestroy)(void*)
);
/* Find an existing tokenizer */
int (*xFindTokenizer_v2)(
fts5_api *pApi,
const char *zName,
void **ppUserData,
fts5_tokenizer_v2 **ppTokenizer
);
};
/*
+39 -3
View File
@@ -59,6 +59,22 @@ typedef sqlite3_uint64 u64;
# define LARGEST_INT64 (0xffffffff|(((i64)0x7fffffff)<<32))
# define SMALLEST_INT64 (((i64)-1) - LARGEST_INT64)
/* The uptr type is an unsigned integer large enough to hold a pointer
*/
#if defined(HAVE_STDINT_H)
typedef uintptr_t uptr;
#elif SQLITE_PTRSIZE==4
typedef u32 uptr;
#else
typedef u64 uptr;
#endif
#ifdef SQLITE_4_BYTE_ALIGNED_MALLOC
# define EIGHT_BYTE_ALIGNMENT(X) ((((uptr)(X) - (uptr)0)&3)==0)
#else
# define EIGHT_BYTE_ALIGNMENT(X) ((((uptr)(X) - (uptr)0)&7)==0)
#endif
#endif
/* Truncate very long tokens to this many bytes. Hard limit is
@@ -146,10 +162,13 @@ typedef struct Fts5TokenizerConfig Fts5TokenizerConfig;
struct Fts5TokenizerConfig {
Fts5Tokenizer *pTok;
fts5_tokenizer *pTokApi;
fts5_tokenizer_v2 *pApi2;
fts5_tokenizer *pApi1;
const char **azArg;
int nArg;
int ePattern; /* FTS_PATTERN_XXX constant */
const char *pLocale; /* Current locale to use */
int nLocale; /* Size of pLocale in bytes */
};
/*
@@ -190,6 +209,8 @@ struct Fts5TokenizerConfig {
**
** INSERT INTO tbl(tbl, rank) VALUES('prefix-index', $bPrefixIndex);
**
** bLocale:
** Set to true if locale=1 was specified when the table was created.
*/
struct Fts5Config {
sqlite3 *db; /* Database handle */
@@ -207,10 +228,12 @@ struct Fts5Config {
char *zContentRowid; /* "content_rowid=" option value */
int bColumnsize; /* "columnsize=" option value (dflt==1) */
int bTokendata; /* "tokendata=" option value (dflt==0) */
int bLocale; /* "locale=" option value (dflt==0) */
int eDetail; /* FTS5_DETAIL_XXX value */
char *zContentExprlist;
Fts5TokenizerConfig t;
int bLock; /* True when table is preparing statement */
/* Values loaded from the %_config table */
int iVersion; /* fts5 file format 'version' */
@@ -276,6 +299,8 @@ int sqlite3Fts5ConfigSetValue(Fts5Config*, const char*, sqlite3_value*, int*);
int sqlite3Fts5ConfigParseRank(const char*, char**, char**);
void sqlite3Fts5ConfigErrmsg(Fts5Config *pConfig, const char *zFmt, ...);
/*
** End of interface to code in fts5_config.c.
**************************************************************************/
@@ -320,7 +345,7 @@ char *sqlite3Fts5Mprintf(int *pRc, const char *zFmt, ...);
void sqlite3Fts5Put32(u8*, int);
int sqlite3Fts5Get32(const u8*);
#define FTS5_POS2COLUMN(iPos) (int)(iPos >> 32)
#define FTS5_POS2COLUMN(iPos) (int)((iPos >> 32) & 0x7FFFFFFF)
#define FTS5_POS2OFFSET(iPos) (int)(iPos & 0x7FFFFFFF)
typedef struct Fts5PoslistReader Fts5PoslistReader;
@@ -611,6 +636,14 @@ Fts5Table *sqlite3Fts5TableFromCsrid(Fts5Global*, i64);
int sqlite3Fts5FlushToDisk(Fts5Table*);
void sqlite3Fts5ClearLocale(Fts5Config *pConfig);
void sqlite3Fts5SetLocale(Fts5Config *pConfig, const char *pLoc, int nLoc);
int sqlite3Fts5IsLocaleValue(Fts5Config *pConfig, sqlite3_value *pVal);
int sqlite3Fts5DecodeLocaleValue(sqlite3_value *pVal,
const char **ppText, int *pnText, const char **ppLoc, int *pnLoc
);
/*
** End of interface to code in fts5.c.
**************************************************************************/
@@ -690,7 +723,7 @@ int sqlite3Fts5StorageRename(Fts5Storage*, const char *zName);
int sqlite3Fts5DropAll(Fts5Config*);
int sqlite3Fts5CreateTable(Fts5Config*, const char*, const char*, int, char **);
int sqlite3Fts5StorageDelete(Fts5Storage *p, i64, sqlite3_value**);
int sqlite3Fts5StorageDelete(Fts5Storage *p, i64, sqlite3_value**, int);
int sqlite3Fts5StorageContentInsert(Fts5Storage *p, sqlite3_value**, i64*);
int sqlite3Fts5StorageIndexInsert(Fts5Storage *p, sqlite3_value**, i64);
@@ -716,6 +749,9 @@ int sqlite3Fts5StorageOptimize(Fts5Storage *p);
int sqlite3Fts5StorageMerge(Fts5Storage *p, int nMerge);
int sqlite3Fts5StorageReset(Fts5Storage *p);
void sqlite3Fts5StorageReleaseDeleteRow(Fts5Storage*);
int sqlite3Fts5StorageFindDeleteRow(Fts5Storage *p, i64 iDel);
/*
** End of interface to code in fts5_storage.c.
**************************************************************************/
+75 -7
View File
@@ -226,6 +226,7 @@ static int fts5HighlightCb(
return rc;
}
/*
** Implementation of highlight() function.
*/
@@ -256,12 +257,19 @@ static void fts5HighlightFunction(
sqlite3_result_text(pCtx, "", -1, SQLITE_STATIC);
rc = SQLITE_OK;
}else if( ctx.zIn ){
const char *pLoc = 0; /* Locale of column iCol */
int nLoc = 0; /* Size of pLoc in bytes */
if( rc==SQLITE_OK ){
rc = fts5CInstIterInit(pApi, pFts, iCol, &ctx.iter);
}
if( rc==SQLITE_OK ){
rc = pApi->xTokenize(pFts, ctx.zIn, ctx.nIn, (void*)&ctx,fts5HighlightCb);
rc = pApi->xColumnLocale(pFts, iCol, &pLoc, &nLoc);
}
if( rc==SQLITE_OK ){
rc = pApi->xTokenize_v2(
pFts, ctx.zIn, ctx.nIn, pLoc, nLoc, (void*)&ctx, fts5HighlightCb
);
}
if( ctx.bOpen ){
fts5HighlightAppend(&rc, &ctx, ctx.zClose, -1);
@@ -458,6 +466,8 @@ static void fts5SnippetFunction(
memset(&sFinder, 0, sizeof(Fts5SFinder));
for(i=0; i<nCol; i++){
if( iCol<0 || iCol==i ){
const char *pLoc = 0; /* Locale of column iCol */
int nLoc = 0; /* Size of pLoc in bytes */
int nDoc;
int nDocsize;
int ii;
@@ -465,8 +475,10 @@ static void fts5SnippetFunction(
sFinder.nFirst = 0;
rc = pApi->xColumnText(pFts, i, &sFinder.zDoc, &nDoc);
if( rc!=SQLITE_OK ) break;
rc = pApi->xTokenize(pFts,
sFinder.zDoc, nDoc, (void*)&sFinder,fts5SentenceFinderCb
rc = pApi->xColumnLocale(pFts, i, &pLoc, &nLoc);
if( rc!=SQLITE_OK ) break;
rc = pApi->xTokenize_v2(pFts,
sFinder.zDoc, nDoc, pLoc, nLoc, (void*)&sFinder, fts5SentenceFinderCb
);
if( rc!=SQLITE_OK ) break;
rc = pApi->xColumnSize(pFts, i, &nDocsize);
@@ -524,6 +536,9 @@ static void fts5SnippetFunction(
rc = pApi->xColumnSize(pFts, iBestCol, &nColSize);
}
if( ctx.zIn ){
const char *pLoc = 0; /* Locale of column iBestCol */
int nLoc = 0; /* Bytes in pLoc */
if( rc==SQLITE_OK ){
rc = fts5CInstIterInit(pApi, pFts, iBestCol, &ctx.iter);
}
@@ -542,7 +557,12 @@ static void fts5SnippetFunction(
}
if( rc==SQLITE_OK ){
rc = pApi->xTokenize(pFts, ctx.zIn, ctx.nIn, (void*)&ctx,fts5HighlightCb);
rc = pApi->xColumnLocale(pFts, iBestCol, &pLoc, &nLoc);
}
if( rc==SQLITE_OK ){
rc = pApi->xTokenize_v2(
pFts, ctx.zIn, ctx.nIn, pLoc, nLoc, (void*)&ctx,fts5HighlightCb
);
}
if( ctx.bOpen ){
fts5HighlightAppend(&rc, &ctx, ctx.zClose, -1);
@@ -726,6 +746,53 @@ static void fts5Bm25Function(
}
}
/*
** Implementation of fts5_get_locale() function.
*/
static void fts5GetLocaleFunction(
const Fts5ExtensionApi *pApi, /* API offered by current FTS version */
Fts5Context *pFts, /* First arg to pass to pApi functions */
sqlite3_context *pCtx, /* Context for returning result/error */
int nVal, /* Number of values in apVal[] array */
sqlite3_value **apVal /* Array of trailing arguments */
){
int iCol = 0;
int eType = 0;
int rc = SQLITE_OK;
const char *zLocale = 0;
int nLocale = 0;
/* xColumnLocale() must be available */
assert( pApi->iVersion>=4 );
if( nVal!=1 ){
const char *z = "wrong number of arguments to function fts5_get_locale()";
sqlite3_result_error(pCtx, z, -1);
return;
}
eType = sqlite3_value_numeric_type(apVal[0]);
if( eType!=SQLITE_INTEGER ){
const char *z = "non-integer argument passed to function fts5_get_locale()";
sqlite3_result_error(pCtx, z, -1);
return;
}
iCol = sqlite3_value_int(apVal[0]);
if( iCol<0 || iCol>=pApi->xColumnCount(pFts) ){
sqlite3_result_error_code(pCtx, SQLITE_RANGE);
return;
}
rc = pApi->xColumnLocale(pFts, iCol, &zLocale, &nLocale);
if( rc!=SQLITE_OK ){
sqlite3_result_error_code(pCtx, rc);
return;
}
sqlite3_result_text(pCtx, zLocale, nLocale, SQLITE_TRANSIENT);
}
int sqlite3Fts5AuxInit(fts5_api *pApi){
struct Builtin {
const char *zFunc; /* Function name (nul-terminated) */
@@ -733,9 +800,10 @@ int sqlite3Fts5AuxInit(fts5_api *pApi){
fts5_extension_function xFunc;/* Callback function */
void (*xDestroy)(void*); /* Destructor function */
} aBuiltin [] = {
{ "snippet", 0, fts5SnippetFunction, 0 },
{ "highlight", 0, fts5HighlightFunction, 0 },
{ "bm25", 0, fts5Bm25Function, 0 },
{ "snippet", 0, fts5SnippetFunction, 0 },
{ "highlight", 0, fts5HighlightFunction, 0 },
{ "bm25", 0, fts5Bm25Function, 0 },
{ "fts5_get_locale", 0, fts5GetLocaleFunction, 0 },
};
int rc = SQLITE_OK; /* Return code */
int i; /* To iterate through builtin functions */
+60 -11
View File
@@ -380,6 +380,16 @@ static int fts5ConfigParseSpecial(
return rc;
}
if( sqlite3_strnicmp("locale", zCmd, nCmd)==0 ){
if( (zArg[0]!='0' && zArg[0]!='1') || zArg[1]!='\0' ){
*pzErr = sqlite3_mprintf("malformed locale=... directive");
rc = SQLITE_ERROR;
}else{
pConfig->bLocale = (zArg[0]=='1');
}
return rc;
}
if( sqlite3_strnicmp("detail", zCmd, nCmd)==0 ){
const Fts5Enum aDetail[] = {
{ "none", FTS5_DETAIL_NONE },
@@ -506,6 +516,15 @@ static int fts5ConfigMakeExprlist(Fts5Config *p){
}
}
}
if( p->eContent==FTS5_CONTENT_NORMAL && p->bLocale ){
for(i=0; i<p->nCol; i++){
if( p->abUnindexed[i]==0 ){
sqlite3Fts5BufferAppendPrintf(&rc, &buf, ", T.l%d", i);
}else{
sqlite3Fts5BufferAppendPrintf(&rc, &buf, ", NULL");
}
}
}
assert( p->zContentExprlist==0 );
p->zContentExprlist = (char*)buf.p;
@@ -669,7 +688,11 @@ void sqlite3Fts5ConfigFree(Fts5Config *pConfig){
if( pConfig ){
int i;
if( pConfig->t.pTok ){
pConfig->t.pTokApi->xDelete(pConfig->t.pTok);
if( pConfig->t.pApi1 ){
pConfig->t.pApi1->xDelete(pConfig->t.pTok);
}else{
pConfig->t.pApi2->xDelete(pConfig->t.pTok);
}
}
sqlite3_free((char*)pConfig->t.azArg);
sqlite3_free(pConfig->zDb);
@@ -752,9 +775,15 @@ int sqlite3Fts5Tokenize(
rc = sqlite3Fts5LoadTokenizer(pConfig);
}
if( rc==SQLITE_OK ){
rc = pConfig->t.pTokApi->xTokenize(
pConfig->t.pTok, pCtx, flags, pText, nText, xToken
);
if( pConfig->t.pApi1 ){
rc = pConfig->t.pApi1->xTokenize(
pConfig->t.pTok, pCtx, flags, pText, nText, xToken
);
}else{
rc = pConfig->t.pApi2->xTokenize(pConfig->t.pTok, pCtx, flags,
pText, nText, pConfig->t.pLocale, pConfig->t.nLocale, xToken
);
}
}
}
return rc;
@@ -1011,13 +1040,10 @@ int sqlite3Fts5ConfigLoad(Fts5Config *pConfig, int iCookie){
&& iVersion!=FTS5_CURRENT_VERSION_SECUREDELETE
){
rc = SQLITE_ERROR;
if( pConfig->pzErrmsg ){
assert( 0==*pConfig->pzErrmsg );
*pConfig->pzErrmsg = sqlite3_mprintf("invalid fts5 file format "
"(found %d, expected %d or %d) - run 'rebuild'",
iVersion, FTS5_CURRENT_VERSION, FTS5_CURRENT_VERSION_SECUREDELETE
);
}
sqlite3Fts5ConfigErrmsg(pConfig, "invalid fts5 file format "
"(found %d, expected %d or %d) - run 'rebuild'",
iVersion, FTS5_CURRENT_VERSION, FTS5_CURRENT_VERSION_SECUREDELETE
);
}else{
pConfig->iVersion = iVersion;
}
@@ -1027,3 +1053,26 @@ int sqlite3Fts5ConfigLoad(Fts5Config *pConfig, int iCookie){
}
return rc;
}
/*
** Set (*pConfig->pzErrmsg) to point to an sqlite3_malloc()ed buffer
** containing the error message created using printf() style formatting
** string zFmt and its trailing arguments.
*/
void sqlite3Fts5ConfigErrmsg(Fts5Config *pConfig, const char *zFmt, ...){
va_list ap; /* ... printf arguments */
char *zMsg = 0;
va_start(ap, zFmt);
zMsg = sqlite3_vmprintf(zFmt, ap);
if( pConfig->pzErrmsg ){
assert( *pConfig->pzErrmsg==0 );
*pConfig->pzErrmsg = zMsg;
}else{
sqlite3_free(zMsg);
}
va_end(ap);
}
+20 -17
View File
@@ -54,7 +54,7 @@ struct Fts5Expr {
/*
** eType:
** Expression node type. Always one of:
** Expression node type. Usually one of:
**
** FTS5_AND (nChild, apChild valid)
** FTS5_OR (nChild, apChild valid)
@@ -62,6 +62,10 @@ struct Fts5Expr {
** FTS5_STRING (pNear valid)
** FTS5_TERM (pNear valid)
**
** An expression node with eType==0 may also exist. It always matches zero
** rows. This is created when a phrase containing no tokens is parsed.
** e.g. "".
**
** iHeight:
** Distance from this node to furthest leaf. This is always 0 for nodes
** of type FTS5_STRING and FTS5_TERM. For all other nodes it is one
@@ -282,11 +286,12 @@ int sqlite3Fts5ExprNew(
}while( sParse.rc==SQLITE_OK && t!=FTS5_EOF );
sqlite3Fts5ParserFree(pEngine, fts5ParseFree);
assert( sParse.pExpr || sParse.rc!=SQLITE_OK );
assert_expr_depth_ok(sParse.rc, sParse.pExpr);
/* If the LHS of the MATCH expression was a user column, apply the
** implicit column-filter. */
if( iCol<pConfig->nCol && sParse.pExpr && sParse.rc==SQLITE_OK ){
if( sParse.rc==SQLITE_OK && iCol<pConfig->nCol ){
int n = sizeof(Fts5Colset);
Fts5Colset *pColset = (Fts5Colset*)sqlite3Fts5MallocZero(&sParse.rc, n);
if( pColset ){
@@ -303,15 +308,7 @@ int sqlite3Fts5ExprNew(
sParse.rc = SQLITE_NOMEM;
sqlite3Fts5ParseNodeFree(sParse.pExpr);
}else{
if( !sParse.pExpr ){
const int nByte = sizeof(Fts5ExprNode);
pNew->pRoot = (Fts5ExprNode*)sqlite3Fts5MallocZero(&sParse.rc, nByte);
if( pNew->pRoot ){
pNew->pRoot->bEof = 1;
}
}else{
pNew->pRoot = sParse.pExpr;
}
pNew->pRoot = sParse.pExpr;
pNew->pIndex = 0;
pNew->pConfig = pConfig;
pNew->apExprPhrase = sParse.apPhrase;
@@ -1129,7 +1126,7 @@ static int fts5ExprNodeTest_STRING(
}
}else{
Fts5IndexIter *pIter = pPhrase->aTerm[j].pIter;
if( pIter->iRowid==iLast || pIter->bEof ) continue;
if( pIter->iRowid==iLast ) continue;
bMatch = 0;
if( fts5ExprAdvanceto(pIter, bDesc, &iLast, &rc, &pNode->bEof) ){
return rc;
@@ -1651,9 +1648,6 @@ Fts5ExprNearset *sqlite3Fts5ParseNearset(
Fts5ExprNearset *pRet = 0;
if( pParse->rc==SQLITE_OK ){
if( pPhrase==0 ){
return pNear;
}
if( pNear==0 ){
sqlite3_int64 nByte;
nByte = sizeof(Fts5ExprNearset) + SZALLOC * sizeof(Fts5ExprPhrase*);
@@ -2263,6 +2257,9 @@ static void fts5ExprAssignXNext(Fts5ExprNode *pNode){
}
}
/*
** Add pSub as a child of p.
*/
static void fts5ExprAddChildren(Fts5ExprNode *p, Fts5ExprNode *pSub){
int ii = p->nChild;
if( p->eType!=FTS5_NOT && pSub->eType==p->eType ){
@@ -2407,19 +2404,23 @@ Fts5ExprNode *sqlite3Fts5ParseNode(
"fts5: %s queries are not supported (detail!=full)",
pNear->nPhrase==1 ? "phrase": "NEAR"
);
sqlite3_free(pRet);
sqlite3Fts5ParseNodeFree(pRet);
pRet = 0;
pNear = 0;
assert( pLeft==0 && pRight==0 );
}
}
}else{
assert( pNear==0 );
fts5ExprAddChildren(pRet, pLeft);
fts5ExprAddChildren(pRet, pRight);
pLeft = pRight = 0;
if( pRet->iHeight>SQLITE_FTS5_MAX_EXPR_DEPTH ){
sqlite3Fts5ParseError(pParse,
"fts5 expression tree is too large (maximum depth %d)",
SQLITE_FTS5_MAX_EXPR_DEPTH
);
sqlite3_free(pRet);
sqlite3Fts5ParseNodeFree(pRet);
pRet = 0;
}
}
@@ -2457,6 +2458,7 @@ Fts5ExprNode *sqlite3Fts5ParseImplicitAnd(
assert( pRight->eType==FTS5_STRING
|| pRight->eType==FTS5_TERM
|| pRight->eType==FTS5_EOF
|| (pRight->eType==FTS5_AND && pParse->bPhraseToAnd)
);
if( pLeft->eType==FTS5_AND ){
@@ -3104,6 +3106,7 @@ static int fts5ExprCheckPoslists(Fts5ExprNode *pNode, i64 iRowid){
pNode->iRowid = iRowid;
pNode->bEof = 0;
switch( pNode->eType ){
case 0:
case FTS5_TERM:
case FTS5_STRING:
return (pNode->pNear->apPhrase[0]->poslist.n>0);
+5 -3
View File
@@ -831,11 +831,12 @@ static Fts5Data *fts5DataRead(Fts5Index *p, i64 iRowid){
if( rc==SQLITE_OK ){
u8 *aOut = 0; /* Read blob data into this buffer */
int nByte = sqlite3_blob_bytes(p->pReader);
sqlite3_int64 nAlloc = sizeof(Fts5Data) + nByte + FTS5_DATA_PADDING;
int szData = (sizeof(Fts5Data) + 7) & ~7;
sqlite3_int64 nAlloc = szData + nByte + FTS5_DATA_PADDING;
pRet = (Fts5Data*)sqlite3_malloc64(nAlloc);
if( pRet ){
pRet->nn = nByte;
aOut = pRet->p = (u8*)&pRet[1];
aOut = pRet->p = (u8*)pRet + szData;
}else{
rc = SQLITE_NOMEM;
}
@@ -858,6 +859,7 @@ static Fts5Data *fts5DataRead(Fts5Index *p, i64 iRowid){
}
assert( (pRet==0)==(p->rc!=SQLITE_OK) );
assert( pRet==0 || EIGHT_BYTE_ALIGNMENT( pRet->p ) );
return pRet;
}
@@ -2183,7 +2185,7 @@ static void fts5SegIterNext_None(
if( iOff<pIter->iEndofDoclist ){
/* Next entry is on the current page */
i64 iDelta;
u64 iDelta;
iOff += sqlite3Fts5GetVarint(&pIter->pLeaf->p[iOff], (u64*)&iDelta);
pIter->iLeafOffset = iOff;
pIter->iRowid += iDelta;
+779 -148
View File
File diff suppressed because it is too large Load Diff
+357 -92
View File
@@ -16,13 +16,40 @@
#include "fts5Int.h"
/*
** pSavedRow:
** SQL statement FTS5_STMT_LOOKUP2 is a copy of FTS5_STMT_LOOKUP, it
** does a by-rowid lookup to retrieve a single row from the %_content
** table or equivalent external-content table/view.
**
** However, FTS5_STMT_LOOKUP2 is only used when retrieving the original
** values for a row being UPDATEd. In that case, the SQL statement is
** not reset and pSavedRow is set to point at it. This is so that the
** insert operation that follows the delete may access the original
** row values for any new values for which sqlite3_value_nochange() returns
** true. i.e. if the user executes:
**
** CREATE VIRTUAL TABLE ft USING fts5(a, b, c, locale=1);
** ...
** UPDATE fts SET a=?, b=? WHERE rowid=?;
**
** then the value passed to the xUpdate() method of this table as the
** new.c value is an sqlite3_value_nochange() value. So in this case it
** must be read from the saved row stored in Fts5Storage.pSavedRow.
**
** This is necessary - using sqlite3_value_nochange() instead of just having
** SQLite pass the original value back via xUpdate() - so as not to discard
** any locale information associated with such values.
**
*/
struct Fts5Storage {
Fts5Config *pConfig;
Fts5Index *pIndex;
int bTotalsValid; /* True if nTotalRow/aTotalSize[] are valid */
i64 nTotalRow; /* Total number of rows in FTS table */
i64 *aTotalSize; /* Total sizes of each column */
sqlite3_stmt *aStmt[11];
sqlite3_stmt *pSavedRow;
sqlite3_stmt *aStmt[12];
};
@@ -36,14 +63,39 @@ struct Fts5Storage {
# error "FTS5_STMT_LOOKUP mismatch"
#endif
#define FTS5_STMT_INSERT_CONTENT 3
#define FTS5_STMT_REPLACE_CONTENT 4
#define FTS5_STMT_DELETE_CONTENT 5
#define FTS5_STMT_REPLACE_DOCSIZE 6
#define FTS5_STMT_DELETE_DOCSIZE 7
#define FTS5_STMT_LOOKUP_DOCSIZE 8
#define FTS5_STMT_REPLACE_CONFIG 9
#define FTS5_STMT_SCAN 10
#define FTS5_STMT_LOOKUP2 3
#define FTS5_STMT_INSERT_CONTENT 4
#define FTS5_STMT_REPLACE_CONTENT 5
#define FTS5_STMT_DELETE_CONTENT 6
#define FTS5_STMT_REPLACE_DOCSIZE 7
#define FTS5_STMT_DELETE_DOCSIZE 8
#define FTS5_STMT_LOOKUP_DOCSIZE 9
#define FTS5_STMT_REPLACE_CONFIG 10
#define FTS5_STMT_SCAN 11
/*
** Return a pointer to a buffer obtained from sqlite3_malloc() that contains
** nBind comma-separated question marks. e.g. if nBind is passed 5, this
** function returns "?,?,?,?,?".
**
** If *pRc is not SQLITE_OK when this function is called, it is a no-op and
** NULL is returned immediately. Or, if the attempt to malloc a buffer
** fails, then *pRc is set to SQLITE_NOMEM and NULL is returned. Otherwise,
** if it is SQLITE_OK when this function is called and the malloc() succeeds,
** *pRc is left unchanged.
*/
static char *fts5BindingsList(int *pRc, int nBind){
char *zBind = sqlite3Fts5MallocZero(pRc, 1 + nBind*2);
if( zBind ){
int ii;
for(ii=0; ii<nBind; ii++){
zBind[ii*2] = '?';
zBind[ii*2 + 1] = ',';
}
zBind[ii*2-1] = '\0';
}
return zBind;
}
/*
** Prepare the two insert statements - Fts5Storage.pInsertContent and
@@ -73,6 +125,7 @@ static int fts5StorageGetStmt(
"SELECT %s FROM %s T WHERE T.%Q >= ? AND T.%Q <= ? ORDER BY T.%Q ASC",
"SELECT %s FROM %s T WHERE T.%Q <= ? AND T.%Q >= ? ORDER BY T.%Q DESC",
"SELECT %s FROM %s T WHERE T.%Q=?", /* LOOKUP */
"SELECT %s FROM %s T WHERE T.%Q=?", /* LOOKUP2 */
"INSERT INTO %Q.'%q_content' VALUES(%s)", /* INSERT_CONTENT */
"REPLACE INTO %Q.'%q_content' VALUES(%s)", /* REPLACE_CONTENT */
@@ -88,6 +141,8 @@ static int fts5StorageGetStmt(
Fts5Config *pC = p->pConfig;
char *zSql = 0;
assert( ArraySize(azStmt)==ArraySize(p->aStmt) );
switch( eStmt ){
case FTS5_STMT_SCAN:
zSql = sqlite3_mprintf(azStmt[eStmt],
@@ -104,24 +159,26 @@ static int fts5StorageGetStmt(
break;
case FTS5_STMT_LOOKUP:
case FTS5_STMT_LOOKUP2:
zSql = sqlite3_mprintf(azStmt[eStmt],
pC->zContentExprlist, pC->zContent, pC->zContentRowid
);
break;
case FTS5_STMT_INSERT_CONTENT:
case FTS5_STMT_REPLACE_CONTENT: {
int nCol = pC->nCol + 1;
case FTS5_STMT_INSERT_CONTENT: {
int nCol = 0;
char *zBind;
int i;
zBind = sqlite3_malloc64(1 + nCol*2);
if( zBind ){
for(i=0; i<nCol; i++){
zBind[i*2] = '?';
zBind[i*2 + 1] = ',';
nCol = 1 + pC->nCol;
if( pC->bLocale ){
for(i=0; i<pC->nCol; i++){
if( pC->abUnindexed[i]==0 ) nCol++;
}
zBind[i*2-1] = '\0';
}
zBind = fts5BindingsList(&rc, nCol);
if( zBind ){
zSql = sqlite3_mprintf(azStmt[eStmt], pC->zDb, pC->zName, zBind);
sqlite3_free(zBind);
}
@@ -150,7 +207,7 @@ static int fts5StorageGetStmt(
rc = SQLITE_NOMEM;
}else{
int f = SQLITE_PREPARE_PERSISTENT;
if( eStmt>FTS5_STMT_LOOKUP ) f |= SQLITE_PREPARE_NO_VTAB;
if( eStmt>FTS5_STMT_LOOKUP2 ) f |= SQLITE_PREPARE_NO_VTAB;
p->pConfig->bLock++;
rc = sqlite3_prepare_v3(pC->db, zSql, -1, f, &p->aStmt[eStmt], 0);
p->pConfig->bLock--;
@@ -312,7 +369,7 @@ int sqlite3Fts5StorageOpen(
if( bCreate ){
if( pConfig->eContent==FTS5_CONTENT_NORMAL ){
int nDefn = 32 + pConfig->nCol*10;
char *zDefn = sqlite3_malloc64(32 + (sqlite3_int64)pConfig->nCol * 10);
char *zDefn = sqlite3_malloc64(32 + (sqlite3_int64)pConfig->nCol * 20);
if( zDefn==0 ){
rc = SQLITE_NOMEM;
}else{
@@ -324,6 +381,14 @@ int sqlite3Fts5StorageOpen(
sqlite3_snprintf(nDefn-iOff, &zDefn[iOff], ", c%d", i);
iOff += (int)strlen(&zDefn[iOff]);
}
if( pConfig->bLocale ){
for(i=0; i<pConfig->nCol; i++){
if( pConfig->abUnindexed[i]==0 ){
sqlite3_snprintf(nDefn-iOff, &zDefn[iOff], ", l%d", i);
iOff += (int)strlen(&zDefn[iOff]);
}
}
}
rc = sqlite3Fts5CreateTable(pConfig, "content", zDefn, 0, pzErr);
}
sqlite3_free(zDefn);
@@ -399,15 +464,49 @@ static int fts5StorageInsertCallback(
return sqlite3Fts5IndexWrite(pIdx, pCtx->iCol, pCtx->szCol-1, pToken, nToken);
}
/*
** This function is used as part of an UPDATE statement that modifies the
** rowid of a row. In that case, this function is called first to set
** Fts5Storage.pSavedRow to point to a statement that may be used to
** access the original values of the row being deleted - iDel.
**
** SQLITE_OK is returned if successful, or an SQLite error code otherwise.
** It is not considered an error if row iDel does not exist. In this case
** pSavedRow is not set and SQLITE_OK returned.
*/
int sqlite3Fts5StorageFindDeleteRow(Fts5Storage *p, i64 iDel){
int rc = SQLITE_OK;
sqlite3_stmt *pSeek = 0;
assert( p->pSavedRow==0 );
rc = fts5StorageGetStmt(p, FTS5_STMT_LOOKUP+1, &pSeek, 0);
if( rc==SQLITE_OK ){
sqlite3_bind_int64(pSeek, 1, iDel);
if( sqlite3_step(pSeek)!=SQLITE_ROW ){
rc = sqlite3_reset(pSeek);
}else{
p->pSavedRow = pSeek;
}
}
return rc;
}
/*
** If a row with rowid iDel is present in the %_content table, add the
** delete-markers to the FTS index necessary to delete it. Do not actually
** remove the %_content row at this time though.
**
** If parameter bSaveRow is true, then Fts5Storage.pSavedRow is left
** pointing to a statement (FTS5_STMT_LOOKUP2) that may be used to access
** the original values of the row being deleted. This is used by UPDATE
** statements.
*/
static int fts5StorageDeleteFromIndex(
Fts5Storage *p,
i64 iDel,
sqlite3_value **apVal
sqlite3_value **apVal,
int bSaveRow /* True to set pSavedRow */
){
Fts5Config *pConfig = p->pConfig;
sqlite3_stmt *pSeek = 0; /* SELECT to read row iDel from %_data */
@@ -416,12 +515,21 @@ static int fts5StorageDeleteFromIndex(
int iCol;
Fts5InsertCtx ctx;
assert( bSaveRow==0 || apVal==0 );
assert( bSaveRow==0 || bSaveRow==1 );
assert( FTS5_STMT_LOOKUP2==FTS5_STMT_LOOKUP+1 );
if( apVal==0 ){
rc = fts5StorageGetStmt(p, FTS5_STMT_LOOKUP, &pSeek, 0);
if( rc!=SQLITE_OK ) return rc;
sqlite3_bind_int64(pSeek, 1, iDel);
if( sqlite3_step(pSeek)!=SQLITE_ROW ){
return sqlite3_reset(pSeek);
if( p->pSavedRow && bSaveRow ){
pSeek = p->pSavedRow;
p->pSavedRow = 0;
}else{
rc = fts5StorageGetStmt(p, FTS5_STMT_LOOKUP+bSaveRow, &pSeek, 0);
if( rc!=SQLITE_OK ) return rc;
sqlite3_bind_int64(pSeek, 1, iDel);
if( sqlite3_step(pSeek)!=SQLITE_ROW ){
return sqlite3_reset(pSeek);
}
}
}
@@ -429,26 +537,42 @@ static int fts5StorageDeleteFromIndex(
ctx.iCol = -1;
for(iCol=1; rc==SQLITE_OK && iCol<=pConfig->nCol; iCol++){
if( pConfig->abUnindexed[iCol-1]==0 ){
const char *zText;
int nText;
sqlite3_value *pVal = 0;
const char *pText = 0;
int nText = 0;
const char *pLoc = 0;
int nLoc = 0;
assert( pSeek==0 || apVal==0 );
assert( pSeek!=0 || apVal!=0 );
if( pSeek ){
zText = (const char*)sqlite3_column_text(pSeek, iCol);
nText = sqlite3_column_bytes(pSeek, iCol);
}else if( ALWAYS(apVal) ){
zText = (const char*)sqlite3_value_text(apVal[iCol-1]);
nText = sqlite3_value_bytes(apVal[iCol-1]);
pVal = sqlite3_column_value(pSeek, iCol);
}else{
continue;
pVal = apVal[iCol-1];
}
ctx.szCol = 0;
rc = sqlite3Fts5Tokenize(pConfig, FTS5_TOKENIZE_DOCUMENT,
zText, nText, (void*)&ctx, fts5StorageInsertCallback
);
p->aTotalSize[iCol-1] -= (i64)ctx.szCol;
if( p->aTotalSize[iCol-1]<0 ){
rc = FTS5_CORRUPT;
if( pConfig->bLocale && sqlite3Fts5IsLocaleValue(pConfig, pVal) ){
rc = sqlite3Fts5DecodeLocaleValue(pVal, &pText, &nText, &pLoc, &nLoc);
}else{
pText = (const char*)sqlite3_value_text(pVal);
nText = sqlite3_value_bytes(pVal);
if( pConfig->bLocale && pSeek ){
pLoc = (const char*)sqlite3_column_text(pSeek, iCol + pConfig->nCol);
nLoc = sqlite3_column_bytes(pSeek, iCol + pConfig->nCol);
}
}
if( rc==SQLITE_OK ){
sqlite3Fts5SetLocale(pConfig, pLoc, nLoc);
ctx.szCol = 0;
rc = sqlite3Fts5Tokenize(pConfig, FTS5_TOKENIZE_DOCUMENT,
pText, nText, (void*)&ctx, fts5StorageInsertCallback
);
p->aTotalSize[iCol-1] -= (i64)ctx.szCol;
if( rc==SQLITE_OK && p->aTotalSize[iCol-1]<0 ){
rc = FTS5_CORRUPT;
}
sqlite3Fts5ClearLocale(pConfig);
}
}
}
@@ -458,11 +582,29 @@ static int fts5StorageDeleteFromIndex(
p->nTotalRow--;
}
rc2 = sqlite3_reset(pSeek);
if( rc==SQLITE_OK ) rc = rc2;
if( rc==SQLITE_OK && bSaveRow ){
assert( p->pSavedRow==0 );
p->pSavedRow = pSeek;
}else{
rc2 = sqlite3_reset(pSeek);
if( rc==SQLITE_OK ) rc = rc2;
}
return rc;
}
/*
** Reset any saved statement pSavedRow. Zero pSavedRow as well. This
** should be called by the xUpdate() method of the fts5 table before
** returning from any operation that may have set Fts5Storage.pSavedRow.
*/
void sqlite3Fts5StorageReleaseDeleteRow(Fts5Storage *pStorage){
assert( pStorage->pSavedRow==0
|| pStorage->pSavedRow==pStorage->aStmt[FTS5_STMT_LOOKUP2]
);
sqlite3_reset(pStorage->pSavedRow);
pStorage->pSavedRow = 0;
}
/*
** This function is called to process a DELETE on a contentless_delete=1
** table. It adds the tombstone required to delete the entry with rowid
@@ -519,12 +661,12 @@ static int fts5StorageInsertDocsize(
rc = sqlite3Fts5IndexGetOrigin(p->pIndex, &iOrigin);
sqlite3_bind_int64(pReplace, 3, iOrigin);
}
if( rc==SQLITE_OK ){
sqlite3_bind_blob(pReplace, 2, pBuf->p, pBuf->n, SQLITE_STATIC);
sqlite3_step(pReplace);
rc = sqlite3_reset(pReplace);
sqlite3_bind_null(pReplace, 2);
}
}
if( rc==SQLITE_OK ){
sqlite3_bind_blob(pReplace, 2, pBuf->p, pBuf->n, SQLITE_STATIC);
sqlite3_step(pReplace);
rc = sqlite3_reset(pReplace);
sqlite3_bind_null(pReplace, 2);
}
}
return rc;
@@ -578,7 +720,12 @@ static int fts5StorageSaveTotals(Fts5Storage *p){
/*
** Remove a row from the FTS table.
*/
int sqlite3Fts5StorageDelete(Fts5Storage *p, i64 iDel, sqlite3_value **apVal){
int sqlite3Fts5StorageDelete(
Fts5Storage *p, /* Storage object */
i64 iDel, /* Rowid to delete from table */
sqlite3_value **apVal, /* Optional - values to remove from index */
int bSaveRow /* If true, set pSavedRow for deleted row */
){
Fts5Config *pConfig = p->pConfig;
int rc;
sqlite3_stmt *pDel = 0;
@@ -595,7 +742,7 @@ int sqlite3Fts5StorageDelete(Fts5Storage *p, i64 iDel, sqlite3_value **apVal){
if( p->pConfig->bContentlessDelete ){
rc = fts5StorageContentlessDelete(p, iDel);
}else{
rc = fts5StorageDeleteFromIndex(p, iDel, apVal);
rc = fts5StorageDeleteFromIndex(p, iDel, apVal, bSaveRow);
}
}
@@ -684,14 +831,36 @@ int sqlite3Fts5StorageRebuild(Fts5Storage *p){
for(ctx.iCol=0; rc==SQLITE_OK && ctx.iCol<pConfig->nCol; ctx.iCol++){
ctx.szCol = 0;
if( pConfig->abUnindexed[ctx.iCol]==0 ){
const char *zText = (const char*)sqlite3_column_text(pScan, ctx.iCol+1);
int nText = sqlite3_column_bytes(pScan, ctx.iCol+1);
rc = sqlite3Fts5Tokenize(pConfig,
FTS5_TOKENIZE_DOCUMENT,
zText, nText,
(void*)&ctx,
fts5StorageInsertCallback
);
int nText = 0; /* Size of pText in bytes */
const char *pText = 0; /* Pointer to buffer containing text value */
int nLoc = 0; /* Size of pLoc in bytes */
const char *pLoc = 0; /* Pointer to buffer containing text value */
sqlite3_value *pVal = sqlite3_column_value(pScan, ctx.iCol+1);
if( pConfig->eContent==FTS5_CONTENT_EXTERNAL
&& sqlite3Fts5IsLocaleValue(pConfig, pVal)
){
rc = sqlite3Fts5DecodeLocaleValue(pVal, &pText, &nText, &pLoc, &nLoc);
}else{
pText = (const char*)sqlite3_value_text(pVal);
nText = sqlite3_value_bytes(pVal);
if( pConfig->bLocale ){
int iCol = ctx.iCol + 1 + pConfig->nCol;
pLoc = (const char*)sqlite3_column_text(pScan, iCol);
nLoc = sqlite3_column_bytes(pScan, iCol);
}
}
if( rc==SQLITE_OK ){
sqlite3Fts5SetLocale(pConfig, pLoc, nLoc);
rc = sqlite3Fts5Tokenize(pConfig,
FTS5_TOKENIZE_DOCUMENT,
pText, nText,
(void*)&ctx,
fts5StorageInsertCallback
);
sqlite3Fts5ClearLocale(pConfig);
}
}
sqlite3Fts5BufferAppendVarint(&rc, &buf, ctx.szCol);
p->aTotalSize[ctx.iCol] += (i64)ctx.szCol;
@@ -773,9 +942,49 @@ int sqlite3Fts5StorageContentInsert(
}else{
sqlite3_stmt *pInsert = 0; /* Statement to write %_content table */
int i; /* Counter variable */
int nIndexed = 0; /* Number indexed columns seen */
rc = fts5StorageGetStmt(p, FTS5_STMT_INSERT_CONTENT, &pInsert, 0);
for(i=1; rc==SQLITE_OK && i<=pConfig->nCol+1; i++){
rc = sqlite3_bind_value(pInsert, i, apVal[i]);
if( pInsert ) sqlite3_clear_bindings(pInsert);
/* Bind the rowid value */
sqlite3_bind_value(pInsert, 1, apVal[1]);
/* Loop through values for user-defined columns. i=2 is the leftmost
** user-defined column. As is column 1 of pSavedRow. */
for(i=2; rc==SQLITE_OK && i<=pConfig->nCol+1; i++){
int bUnindexed = pConfig->abUnindexed[i-2];
sqlite3_value *pVal = apVal[i];
nIndexed += !bUnindexed;
if( sqlite3_value_nochange(pVal) && p->pSavedRow ){
/* This is an UPDATE statement, and column (i-2) was not modified.
** Retrieve the value from Fts5Storage.pSavedRow instead. */
pVal = sqlite3_column_value(p->pSavedRow, i-1);
if( pConfig->bLocale && bUnindexed==0 ){
sqlite3_bind_value(pInsert, pConfig->nCol + 1 + nIndexed,
sqlite3_column_value(p->pSavedRow, pConfig->nCol + i - 1)
);
}
}else if( sqlite3Fts5IsLocaleValue(pConfig, pVal) ){
const char *pText = 0;
const char *pLoc = 0;
int nText = 0;
int nLoc = 0;
assert( pConfig->bLocale );
rc = sqlite3Fts5DecodeLocaleValue(pVal, &pText, &nText, &pLoc, &nLoc);
if( rc==SQLITE_OK ){
sqlite3_bind_text(pInsert, i, pText, nText, SQLITE_TRANSIENT);
if( bUnindexed==0 ){
int iLoc = pConfig->nCol + 1 + nIndexed;
sqlite3_bind_text(pInsert, iLoc, pLoc, nLoc, SQLITE_TRANSIENT);
}
}
continue;
}
rc = sqlite3_bind_value(pInsert, i, pVal);
}
if( rc==SQLITE_OK ){
sqlite3_step(pInsert);
@@ -810,14 +1019,38 @@ int sqlite3Fts5StorageIndexInsert(
for(ctx.iCol=0; rc==SQLITE_OK && ctx.iCol<pConfig->nCol; ctx.iCol++){
ctx.szCol = 0;
if( pConfig->abUnindexed[ctx.iCol]==0 ){
const char *zText = (const char*)sqlite3_value_text(apVal[ctx.iCol+2]);
int nText = sqlite3_value_bytes(apVal[ctx.iCol+2]);
rc = sqlite3Fts5Tokenize(pConfig,
FTS5_TOKENIZE_DOCUMENT,
zText, nText,
(void*)&ctx,
fts5StorageInsertCallback
);
int nText = 0; /* Size of pText in bytes */
const char *pText = 0; /* Pointer to buffer containing text value */
int nLoc = 0; /* Size of pText in bytes */
const char *pLoc = 0; /* Pointer to buffer containing text value */
sqlite3_value *pVal = apVal[ctx.iCol+2];
if( p->pSavedRow && sqlite3_value_nochange(pVal) ){
pVal = sqlite3_column_value(p->pSavedRow, ctx.iCol+1);
if( pConfig->eContent==FTS5_CONTENT_NORMAL && pConfig->bLocale ){
int iCol = ctx.iCol + 1 + pConfig->nCol;
pLoc = (const char*)sqlite3_column_text(p->pSavedRow, iCol);
nLoc = sqlite3_column_bytes(p->pSavedRow, iCol);
}
}else{
pVal = apVal[ctx.iCol+2];
}
if( pConfig->bLocale && sqlite3Fts5IsLocaleValue(pConfig, pVal) ){
rc = sqlite3Fts5DecodeLocaleValue(pVal, &pText, &nText, &pLoc, &nLoc);
}else{
pText = (const char*)sqlite3_value_text(pVal);
nText = sqlite3_value_bytes(pVal);
}
if( rc==SQLITE_OK ){
sqlite3Fts5SetLocale(pConfig, pLoc, nLoc);
rc = sqlite3Fts5Tokenize(pConfig,
FTS5_TOKENIZE_DOCUMENT, pText, nText, (void*)&ctx,
fts5StorageInsertCallback
);
sqlite3Fts5ClearLocale(pConfig);
}
}
sqlite3Fts5BufferAppendVarint(&rc, &buf, ctx.szCol);
p->aTotalSize[ctx.iCol] += (i64)ctx.szCol;
@@ -981,29 +1214,61 @@ int sqlite3Fts5StorageIntegrity(Fts5Storage *p, int iArg){
rc = sqlite3Fts5TermsetNew(&ctx.pTermset);
}
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;
if( pConfig->abUnindexed[i]==0 ){
const char *pText = 0;
int nText = 0;
const char *pLoc = 0;
int nLoc = 0;
sqlite3_value *pVal = sqlite3_column_value(pScan, i+1);
if( pConfig->eContent==FTS5_CONTENT_EXTERNAL
&& sqlite3Fts5IsLocaleValue(pConfig, pVal)
){
rc = sqlite3Fts5DecodeLocaleValue(
pVal, &pText, &nText, &pLoc, &nLoc
);
}else{
if( pConfig->eContent==FTS5_CONTENT_NORMAL && pConfig->bLocale ){
int iCol = i + 1 + pConfig->nCol;
pLoc = (const char*)sqlite3_column_text(pScan, iCol);
nLoc = sqlite3_column_bytes(pScan, iCol);
}
pText = (const char*)sqlite3_value_text(pVal);
nText = sqlite3_value_bytes(pVal);
}
ctx.iCol = i;
ctx.szCol = 0;
if( rc==SQLITE_OK && pConfig->eDetail==FTS5_DETAIL_COLUMNS ){
rc = sqlite3Fts5TermsetNew(&ctx.pTermset);
}
if( rc==SQLITE_OK ){
sqlite3Fts5SetLocale(pConfig, pLoc, nLoc);
rc = sqlite3Fts5Tokenize(pConfig,
FTS5_TOKENIZE_DOCUMENT,
pText, nText,
(void*)&ctx,
fts5StorageIntegrityCallback
);
sqlite3Fts5ClearLocale(pConfig);
}
/* If this is not a columnsize=0 database, check that the number
** of tokens in the value matches the aColSize[] value read from
** the %_docsize table. */
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);
+360 -54
View File
@@ -14,14 +14,7 @@
#ifdef SQLITE_TEST
#if defined(INCLUDE_SQLITE_TCL_H)
# include "sqlite_tcl.h"
#else
# include "tcl.h"
# ifndef SQLITE_TCLAPI
# define SQLITE_TCLAPI
# endif
#endif
#include "tclsqlite.h"
#ifdef SQLITE_ENABLE_FTS5
@@ -103,14 +96,14 @@ static int SQLITE_TCLAPI f5tDbAndApi(
rc = sqlite3_prepare_v2(db, "SELECT fts5(?1)", -1, &pStmt, 0);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, "error: ", sqlite3_errmsg(db), 0);
Tcl_AppendResult(interp, "error: ", sqlite3_errmsg(db), (char*)0);
return TCL_ERROR;
}
sqlite3_bind_pointer(pStmt, 1, (void*)&pApi, "fts5_api_ptr", 0);
sqlite3_step(pStmt);
if( sqlite3_finalize(pStmt)!=SQLITE_OK ){
Tcl_AppendResult(interp, "error: ", sqlite3_errmsg(db), 0);
Tcl_AppendResult(interp, "error: ", sqlite3_errmsg(db), (char*)0);
return TCL_ERROR;
}
@@ -247,6 +240,7 @@ static int SQLITE_TCLAPI xF5tApi(
{ "xQueryToken", 2, "IPHRASE ITERM" }, /* 18 */
{ "xInstToken", 2, "IDX ITERM" }, /* 19 */
{ "xColumnLocale", 1, "COL" }, /* 20 */
{ 0, 0, 0}
};
@@ -297,12 +291,12 @@ static int SQLITE_TCLAPI xF5tApi(
break;
}
CASE(3, "xTokenize") {
int nText;
Tcl_Size nText;
char *zText = Tcl_GetStringFromObj(objv[2], &nText);
F5tFunction ctx;
ctx.interp = interp;
ctx.pScript = objv[3];
rc = p->pApi->xTokenize(p->pFts, zText, nText, &ctx, xTokenizeCb);
rc = p->pApi->xTokenize(p->pFts, zText, (int)nText, &ctx, xTokenizeCb);
if( rc==SQLITE_OK ){
Tcl_ResetResult(interp);
}
@@ -398,7 +392,7 @@ static int SQLITE_TCLAPI xF5tApi(
CASE(12, "xSetAuxdata") {
F5tAuxData *pData = (F5tAuxData*)sqlite3_malloc(sizeof(F5tAuxData));
if( pData==0 ){
Tcl_AppendResult(interp, "out of memory", 0);
Tcl_AppendResult(interp, "out of memory", (char*)0);
return TCL_ERROR;
}
pData->pObj = objv[2];
@@ -458,7 +452,7 @@ static int SQLITE_TCLAPI xF5tApi(
rc = p->pApi->xPhraseFirst(p->pFts, iPhrase, &iter, &iCol, &iOff);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, sqlite3ErrName(rc), 0);
Tcl_AppendResult(interp, sqlite3ErrName(rc), (char*)0);
return TCL_ERROR;
}
for( ;iCol>=0; p->pApi->xPhraseNext(p->pFts, &iter, &iCol, &iOff) ){
@@ -535,6 +529,20 @@ static int SQLITE_TCLAPI xF5tApi(
break;
}
CASE(20, "xColumnLocale") {
const char *z = 0;
int n = 0;
int iCol;
if( Tcl_GetIntFromObj(interp, objv[2], &iCol) ){
return TCL_ERROR;
}
rc = p->pApi->xColumnLocale(p->pFts, iCol, &z, &n);
if( rc==SQLITE_OK && z ){
Tcl_SetObjResult(interp, Tcl_NewStringObj(z, n));
}
break;
}
default:
assert( 0 );
break;
@@ -605,15 +613,16 @@ static void xF5tFunction(
sqlite3_result_error(pCtx, Tcl_GetStringResult(p->interp), -1);
}else{
Tcl_Obj *pVar = Tcl_GetObjResult(p->interp);
int n;
const char *zType = (pVar->typePtr ? pVar->typePtr->name : "");
char c = zType[0];
if( c=='b' && strcmp(zType,"bytearray")==0 && pVar->bytes==0 ){
/* Only return a BLOB type if the Tcl variable is a bytearray and
** has no string representation. */
unsigned char *data = Tcl_GetByteArrayFromObj(pVar, &n);
sqlite3_result_blob(pCtx, data, n, SQLITE_TRANSIENT);
Tcl_Size nn;
unsigned char *data = Tcl_GetByteArrayFromObj(pVar, &nn);
sqlite3_result_blob(pCtx, data, (int)nn, SQLITE_TRANSIENT);
}else if( c=='b' && strcmp(zType,"boolean")==0 ){
int n;
Tcl_GetIntFromObj(0, pVar, &n);
sqlite3_result_int(pCtx, n);
}else if( c=='d' && strcmp(zType,"double")==0 ){
@@ -626,8 +635,9 @@ static void xF5tFunction(
Tcl_GetWideIntFromObj(0, pVar, &v);
sqlite3_result_int64(pCtx, v);
}else{
unsigned char *data = (unsigned char *)Tcl_GetStringFromObj(pVar, &n);
sqlite3_result_text(pCtx, (char *)data, n, SQLITE_TRANSIENT);
Tcl_Size nn;
unsigned char *data = (unsigned char *)Tcl_GetStringFromObj(pVar, &nn);
sqlite3_result_text(pCtx, (char*)data, (int)nn, SQLITE_TRANSIENT);
}
}
}
@@ -673,7 +683,7 @@ static int SQLITE_TCLAPI f5tCreateFunction(
pApi, zName, (void*)pCtx, xF5tFunction, xF5tDestroy
);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, "error: ", sqlite3_errmsg(db), 0);
Tcl_AppendResult(interp, "error: ", sqlite3_errmsg(db), (char*)0);
return TCL_ERROR;
}
@@ -720,7 +730,7 @@ static int SQLITE_TCLAPI f5tTokenize(
Tcl_Obj *CONST objv[]
){
char *zText;
int nText;
Tcl_Size nText;
sqlite3 *db = 0;
fts5_api *pApi = 0;
Fts5Tokenizer *pTok = 0;
@@ -729,7 +739,7 @@ static int SQLITE_TCLAPI f5tTokenize(
void *pUserdata;
int rc;
int nArg;
Tcl_Size nArg;
const char **azArg;
F5tTokenizeCtx ctx;
@@ -740,7 +750,7 @@ static int SQLITE_TCLAPI f5tTokenize(
if( objc==5 ){
char *zOpt = Tcl_GetString(objv[1]);
if( strcmp("-subst", zOpt) ){
Tcl_AppendResult(interp, "unrecognized option: ", zOpt, 0);
Tcl_AppendResult(interp, "unrecognized option: ", zOpt, (char*)0);
return TCL_ERROR;
}
}
@@ -749,7 +759,7 @@ static int SQLITE_TCLAPI f5tTokenize(
return TCL_ERROR;
}
if( nArg==0 ){
Tcl_AppendResult(interp, "no such tokenizer: ", 0);
Tcl_AppendResult(interp, "no such tokenizer: ", (char*)0);
Tcl_Free((void*)azArg);
return TCL_ERROR;
}
@@ -757,13 +767,13 @@ static int SQLITE_TCLAPI f5tTokenize(
rc = pApi->xFindTokenizer(pApi, azArg[0], &pUserdata, &tokenizer);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, "no such tokenizer: ", azArg[0], 0);
Tcl_AppendResult(interp, "no such tokenizer: ", azArg[0], (char*)0);
return TCL_ERROR;
}
rc = tokenizer.xCreate(pUserdata, &azArg[1], nArg-1, &pTok);
rc = tokenizer.xCreate(pUserdata, &azArg[1], (int)(nArg-1), &pTok);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, "error in tokenizer.xCreate()", 0);
Tcl_AppendResult(interp, "error in tokenizer.xCreate()", (char*)0);
return TCL_ERROR;
}
@@ -773,11 +783,11 @@ static int SQLITE_TCLAPI f5tTokenize(
ctx.pRet = pRet;
ctx.zInput = zText;
rc = tokenizer.xTokenize(
pTok, (void*)&ctx, FTS5_TOKENIZE_DOCUMENT, zText, nText, xTokenizeCb2
pTok, (void*)&ctx, FTS5_TOKENIZE_DOCUMENT, zText,(int)nText, xTokenizeCb2
);
tokenizer.xDelete(pTok);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, "error in tokenizer.xTokenize()", 0);
Tcl_AppendResult(interp, "error in tokenizer.xTokenize()", (char*)0);
Tcl_DecrRefCount(pRet);
return TCL_ERROR;
}
@@ -801,18 +811,32 @@ typedef struct F5tTokenizerInstance F5tTokenizerInstance;
struct F5tTokenizerContext {
void *pCtx;
int (*xToken)(void*, int, const char*, int, int, int);
F5tTokenizerInstance *pInst;
};
struct F5tTokenizerModule {
Tcl_Interp *interp;
Tcl_Obj *pScript;
void *pParentCtx;
fts5_tokenizer_v2 parent_v2;
fts5_tokenizer parent;
F5tTokenizerContext *pContext;
};
/*
** zLocale:
** Within a call to xTokenize_v2(), pLocale/nLocale store the locale
** passed to the call by fts5. This can be retrieved by a Tcl tokenize
** script using [sqlite3_fts5_locale].
*/
struct F5tTokenizerInstance {
Tcl_Interp *interp;
Tcl_Obj *pScript;
F5tTokenizerModule *pModule;
Fts5Tokenizer *pParent;
F5tTokenizerContext *pContext;
const char *pLocale;
int nLocale;
};
static int f5tTokenizerCreate(
@@ -821,11 +845,20 @@ static int f5tTokenizerCreate(
int nArg,
Fts5Tokenizer **ppOut
){
Fts5Tokenizer *pParent = 0;
F5tTokenizerModule *pMod = (F5tTokenizerModule*)pCtx;
Tcl_Obj *pEval;
int rc = TCL_OK;
int i;
assert( pMod->parent_v2.xCreate==0 || pMod->parent.xCreate==0 );
if( pMod->parent_v2.xCreate ){
rc = pMod->parent_v2.xCreate(pMod->pParentCtx, 0, 0, &pParent);
}
if( pMod->parent.xCreate ){
rc = pMod->parent.xCreate(pMod->pParentCtx, 0, 0, &pParent);
}
pEval = Tcl_DuplicateObj(pMod->pScript);
Tcl_IncrRefCount(pEval);
for(i=0; rc==TCL_OK && i<nArg; i++){
@@ -845,6 +878,8 @@ static int f5tTokenizerCreate(
pInst->interp = pMod->interp;
pInst->pScript = Tcl_GetObjResult(pMod->interp);
pInst->pContext = pMod->pContext;
pInst->pParent = pParent;
pInst->pModule = pMod;
Tcl_IncrRefCount(pInst->pScript);
*ppOut = (Fts5Tokenizer*)pInst;
}
@@ -855,11 +890,21 @@ static int f5tTokenizerCreate(
static void f5tTokenizerDelete(Fts5Tokenizer *p){
F5tTokenizerInstance *pInst = (F5tTokenizerInstance*)p;
Tcl_DecrRefCount(pInst->pScript);
ckfree((char *)pInst);
if( pInst ){
if( pInst->pParent ){
if( pInst->pModule->parent_v2.xDelete ){
pInst->pModule->parent_v2.xDelete(pInst->pParent);
}else{
pInst->pModule->parent.xDelete(pInst->pParent);
}
}
Tcl_DecrRefCount(pInst->pScript);
ckfree((char *)pInst);
}
}
static int f5tTokenizerTokenize(
static int f5tTokenizerReallyTokenize(
Fts5Tokenizer *p,
void *pCtx,
int flags,
@@ -867,6 +912,7 @@ static int f5tTokenizerTokenize(
int (*xToken)(void*, int, const char*, int, int, int)
){
F5tTokenizerInstance *pInst = (F5tTokenizerInstance*)p;
F5tTokenizerInstance *pOldInst = 0;
void *pOldCtx;
int (*xOldToken)(void*, int, const char*, int, int, int);
Tcl_Obj *pEval;
@@ -875,9 +921,11 @@ static int f5tTokenizerTokenize(
pOldCtx = pInst->pContext->pCtx;
xOldToken = pInst->pContext->xToken;
pOldInst = pInst->pContext->pInst;
pInst->pContext->pCtx = pCtx;
pInst->pContext->xToken = xToken;
pInst->pContext->pInst = pInst;
assert(
flags==FTS5_TOKENIZE_DOCUMENT
@@ -913,9 +961,105 @@ static int f5tTokenizerTokenize(
pInst->pContext->pCtx = pOldCtx;
pInst->pContext->xToken = xOldToken;
pInst->pContext->pInst = pOldInst;
return rc;
}
typedef struct CallbackCtx CallbackCtx;
struct CallbackCtx {
Fts5Tokenizer *p;
void *pCtx;
int flags;
int (*xToken)(void*, int, const char*, int, int, int);
};
static int f5tTokenizeCallback(
void *pCtx,
int tflags,
const char *z, int n,
int iStart, int iEnd
){
CallbackCtx *p = (CallbackCtx*)pCtx;
return f5tTokenizerReallyTokenize(p->p, p->pCtx, p->flags, z, n, p->xToken);
}
static int f5tTokenizerTokenize_v2(
Fts5Tokenizer *p,
void *pCtx,
int flags,
const char *pText, int nText,
const char *pLoc, int nLoc,
int (*xToken)(void*, int, const char*, int, int, int)
){
int rc = SQLITE_OK;
F5tTokenizerInstance *pInst = (F5tTokenizerInstance*)p;
pInst->pLocale = pLoc;
pInst->nLocale = nLoc;
if( pInst->pParent ){
CallbackCtx ctx;
ctx.p = p;
ctx.pCtx = pCtx;
ctx.flags = flags;
ctx.xToken = xToken;
if( pInst->pModule->parent_v2.xTokenize ){
rc = pInst->pModule->parent_v2.xTokenize(
pInst->pParent, (void*)&ctx, flags, pText, nText,
pLoc, nLoc, f5tTokenizeCallback
);
}else{
rc = pInst->pModule->parent.xTokenize(
pInst->pParent, (void*)&ctx, flags, pText, nText, f5tTokenizeCallback
);
}
}else{
rc = f5tTokenizerReallyTokenize(p, pCtx, flags, pText, nText, xToken);
}
pInst->pLocale = 0;
pInst->nLocale = 0;
return rc;
}
static int f5tTokenizerTokenize(
Fts5Tokenizer *p,
void *pCtx,
int flags,
const char *pText, int nText,
int (*xToken)(void*, int, const char*, int, int, int)
){
return f5tTokenizerTokenize_v2(p, pCtx, flags, pText, nText, 0, 0, xToken);
}
/*
** sqlite3_fts5_locale
*/
static int SQLITE_TCLAPI f5tTokenizerLocale(
void * clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
F5tTokenizerContext *p = (F5tTokenizerContext*)clientData;
if( objc!=1 ){
Tcl_WrongNumArgs(interp, 1, objv, "");
return TCL_ERROR;
}
if( p->xToken==0 ){
Tcl_AppendResult(interp,
"sqlite3_fts5_locale may only be used by tokenizer callback", (char*)0
);
return TCL_ERROR;
}
Tcl_SetObjResult(interp,
Tcl_NewStringObj(p->pInst->pLocale, p->pInst->nLocale)
);
return TCL_OK;
}
/*
** sqlite3_fts5_token ?-colocated? TEXT START END
*/
@@ -928,13 +1072,13 @@ static int SQLITE_TCLAPI f5tTokenizerReturn(
F5tTokenizerContext *p = (F5tTokenizerContext*)clientData;
int iStart;
int iEnd;
int nToken;
Tcl_Size nToken;
int tflags = 0;
char *zToken;
int rc;
if( objc==5 ){
int nArg;
Tcl_Size nArg;
char *zArg = Tcl_GetStringFromObj(objv[1], &nArg);
if( nArg<=10 && nArg>=2 && memcmp("-colocated", zArg, nArg)==0 ){
tflags |= FTS5_TOKEN_COLOCATED;
@@ -954,12 +1098,12 @@ static int SQLITE_TCLAPI f5tTokenizerReturn(
if( p->xToken==0 ){
Tcl_AppendResult(interp,
"sqlite3_fts5_token may only be used by tokenizer callback", 0
"sqlite3_fts5_token may only be used by tokenizer callback", (char*)0
);
return TCL_ERROR;
}
rc = p->xToken(p->pCtx, tflags, zToken, nToken, iStart, iEnd);
rc = p->xToken(p->pCtx, tflags, zToken, (int)nToken, iStart, iEnd);
Tcl_SetResult(interp, (char*)sqlite3ErrName(rc), TCL_VOLATILE);
return rc==SQLITE_OK ? TCL_OK : TCL_ERROR;
@@ -1001,32 +1145,112 @@ static int SQLITE_TCLAPI f5tCreateTokenizer(
fts5_api *pApi;
char *zName;
Tcl_Obj *pScript;
fts5_tokenizer t;
F5tTokenizerModule *pMod;
int rc;
int rc = SQLITE_OK;
int bV2 = 0; /* True to use _v2 API */
int iVersion = 2; /* Value for _v2.iVersion */
const char *zParent = 0; /* Name of parent tokenizer, if any */
int ii = 0;
if( objc!=4 ){
Tcl_WrongNumArgs(interp, 1, objv, "DB NAME SCRIPT");
if( objc<4 ){
Tcl_WrongNumArgs(interp, 1, objv, "?OPTIONS? DB NAME SCRIPT");
return TCL_ERROR;
}
if( f5tDbAndApi(interp, objv[1], &db, &pApi) ){
/* Parse any options. Set stack variables bV2 and zParent. */
for(ii=1; ii<objc-3; ii++){
int iOpt = 0;
const char *azOpt[] = { "-v2", "-parent", "-version", 0 };
if( Tcl_GetIndexFromObj(interp, objv[ii], azOpt, "OPTION", 0, &iOpt) ){
return TCL_ERROR;
}
switch( iOpt ){
case 0: /* -v2 */ {
bV2 = 1;
break;
}
case 1: /* -parent */ {
ii++;
if( ii==objc-3 ){
Tcl_AppendResult(
interp, "option requires an argument: -parent", (char*)0
);
return TCL_ERROR;
}
zParent = Tcl_GetString(objv[ii]);
break;
}
case 2: /* -version */ {
ii++;
if( ii==objc-3 ){
Tcl_AppendResult(
interp, "option requires an argument: -version", (char*)0
);
return TCL_ERROR;
}
if( Tcl_GetIntFromObj(interp, objv[ii], &iVersion) ){
return TCL_ERROR;
}
break;
}
default:
assert( 0 );
break;
}
}
if( f5tDbAndApi(interp, objv[objc-3], &db, &pApi) ){
return TCL_ERROR;
}
zName = Tcl_GetString(objv[2]);
pScript = objv[3];
t.xCreate = f5tTokenizerCreate;
t.xTokenize = f5tTokenizerTokenize;
t.xDelete = f5tTokenizerDelete;
zName = Tcl_GetString(objv[objc-2]);
pScript = objv[objc-1];
pMod = (F5tTokenizerModule*)ckalloc(sizeof(F5tTokenizerModule));
memset(pMod, 0, sizeof(F5tTokenizerModule));
pMod->interp = interp;
pMod->pScript = pScript;
pMod->pContext = pContext;
Tcl_IncrRefCount(pScript);
rc = pApi->xCreateTokenizer(pApi, zName, (void*)pMod, &t, f5tDelTokenizer);
pMod->pContext = pContext;
if( zParent ){
if( bV2 ){
fts5_tokenizer_v2 *pParent = 0;
rc = pApi->xFindTokenizer_v2(pApi, zParent, &pMod->pParentCtx, &pParent);
if( rc==SQLITE_OK ){
memcpy(&pMod->parent_v2, pParent, sizeof(fts5_tokenizer_v2));
pMod->parent_v2.xDelete(0);
}
}else{
rc = pApi->xFindTokenizer(pApi, zParent, &pMod->pParentCtx,&pMod->parent);
if( rc==SQLITE_OK ){
pMod->parent.xDelete(0);
}
}
}
if( rc==SQLITE_OK ){
void *pModCtx = (void*)pMod;
if( bV2==0 ){
fts5_tokenizer t;
t.xCreate = f5tTokenizerCreate;
t.xTokenize = f5tTokenizerTokenize;
t.xDelete = f5tTokenizerDelete;
rc = pApi->xCreateTokenizer(pApi, zName, pModCtx, &t, f5tDelTokenizer);
}else{
fts5_tokenizer_v2 t2;
memset(&t2, 0, sizeof(t2));
t2.iVersion = iVersion;
t2.xCreate = f5tTokenizerCreate;
t2.xTokenize = f5tTokenizerTokenize_v2;
t2.xDelete = f5tTokenizerDelete;
rc = pApi->xCreateTokenizer_v2(pApi, zName, pModCtx, &t2,f5tDelTokenizer);
}
}
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, "error in fts5_api.xCreateTokenizer()", 0);
Tcl_AppendResult(interp, (
bV2 ? "error in fts5_api.xCreateTokenizer_v2()"
: "error in fts5_api.xCreateTokenizer()"
), (char*)0);
return TCL_ERROR;
}
@@ -1083,7 +1307,7 @@ static int SQLITE_TCLAPI f5tTokenHash(
Tcl_Obj *CONST objv[]
){
char *z;
int n;
Tcl_Size n;
unsigned int iVal;
int nSlot;
@@ -1096,7 +1320,7 @@ static int SQLITE_TCLAPI f5tTokenHash(
}
z = Tcl_GetStringFromObj(objv[2], &n);
iVal = f5t_fts5HashKey(nSlot, z, n);
iVal = f5t_fts5HashKey(nSlot, z, (int)n);
Tcl_SetObjResult(interp, Tcl_NewIntObj(iVal));
return TCL_OK;
}
@@ -1316,12 +1540,92 @@ static int SQLITE_TCLAPI f5tRegisterOriginText(
Tcl_ResetResult(interp);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, "error: ", sqlite3_errmsg(db), 0);
Tcl_AppendResult(interp, "error: ", sqlite3_errmsg(db), (void*)0);
return TCL_ERROR;
}
return TCL_OK;
}
/*
** This function is used to DROP an fts5 table. It works even if the data
** structures fts5 stores within the database are corrupt, which sometimes
** prevents a straight "DROP TABLE" command from succeeding.
**
** The first parameter is the database handle to use for the DROP TABLE
** operation. The second is the name of the database to drop the fts5 table
** from (i.e. "main", "temp" or the name of an attached database). The
** third parameter is the name of the fts5 table to drop.
**
** SQLITE_OK is returned if the table is successfully dropped. Or, if an
** error occurs, an SQLite error code.
*/
static int sqlite3_fts5_drop_corrupt_table(
sqlite3 *db, /* Database handle */
const char *zDb, /* Database name ("main", "temp" etc.) */
const char *zTab /* Name of fts5 table to drop */
){
int rc = SQLITE_OK;
int bDef = 0;
rc = sqlite3_db_config(db, SQLITE_DBCONFIG_DEFENSIVE, -1, &bDef);
if( rc==SQLITE_OK ){
char *zScript = sqlite3_mprintf(
"DELETE FROM %Q.'%q_data';"
"DELETE FROM %Q.'%q_config';"
"INSERT INTO %Q.'%q_data' VALUES(10, X'0000000000');"
"INSERT INTO %Q.'%q_config' VALUES('version', 4);"
"DROP TABLE %Q.'%q';",
zDb, zTab, zDb, zTab, zDb, zTab, zDb, zTab, zDb, zTab
);
if( zScript==0 ){
rc = SQLITE_NOMEM;
}else{
if( bDef ) sqlite3_db_config(db, SQLITE_DBCONFIG_DEFENSIVE, 0, 0);
rc = sqlite3_exec(db, zScript, 0, 0, 0);
if( bDef ) sqlite3_db_config(db, SQLITE_DBCONFIG_DEFENSIVE, 1, 0);
sqlite3_free(zScript);
}
}
return rc;
}
/*
** sqlite3_fts5_drop_corrupt_table DB DATABASE TABLE
**
** Description...
*/
static int SQLITE_TCLAPI f5tDropCorruptTable(
void * clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
sqlite3 *db = 0;
const char *zDb = 0;
const char *zTab = 0;
int rc = SQLITE_OK;
if( objc!=4 ){
Tcl_WrongNumArgs(interp, 1, objv, "DB DATABASE TABLE");
return TCL_ERROR;
}
if( f5tDbPointer(interp, objv[1], &db) ){
return TCL_ERROR;
}
zDb = Tcl_GetString(objv[2]);
zTab = Tcl_GetString(objv[3]);
rc = sqlite3_fts5_drop_corrupt_table(db, zDb, zTab);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, "error: ", sqlite3_errmsg(db), (void*)0);
return TCL_ERROR;
}
return TCL_OK;
}
/*
** Entry point.
*/
@@ -1333,13 +1637,15 @@ int Fts5tcl_Init(Tcl_Interp *interp){
} aCmd[] = {
{ "sqlite3_fts5_create_tokenizer", f5tCreateTokenizer, 1 },
{ "sqlite3_fts5_token", f5tTokenizerReturn, 1 },
{ "sqlite3_fts5_locale", f5tTokenizerLocale, 1 },
{ "sqlite3_fts5_tokenize", f5tTokenize, 0 },
{ "sqlite3_fts5_create_function", f5tCreateFunction, 0 },
{ "sqlite3_fts5_may_be_corrupt", f5tMayBeCorrupt, 0 },
{ "sqlite3_fts5_token_hash", f5tTokenHash, 0 },
{ "sqlite3_fts5_register_matchinfo", f5tRegisterMatchinfo, 0 },
{ "sqlite3_fts5_register_fts5tokenize", f5tRegisterTok, 0 },
{ "sqlite3_fts5_register_origintext",f5tRegisterOriginText, 0 }
{ "sqlite3_fts5_register_origintext",f5tRegisterOriginText, 0 },
{ "sqlite3_fts5_drop_corrupt_table", f5tDropCorruptTable, 0 }
};
int i;
F5tTokenizerContext *pContext;
+56 -37
View File
@@ -386,7 +386,6 @@ static int fts5UnicodeCreate(
zCat = azArg[i+1];
}
}
if( rc==SQLITE_OK ){
rc = unicodeSetCategories(p, zCat);
}
@@ -416,7 +415,6 @@ static int fts5UnicodeCreate(
rc = SQLITE_ERROR;
}
}
}else{
rc = SQLITE_NOMEM;
}
@@ -555,7 +553,7 @@ static int fts5UnicodeTokenize(
typedef struct PorterTokenizer PorterTokenizer;
struct PorterTokenizer {
fts5_tokenizer tokenizer; /* Parent tokenizer module */
fts5_tokenizer_v2 tokenizer_v2; /* Parent tokenizer module */
Fts5Tokenizer *pTokenizer; /* Parent tokenizer instance */
char aBuf[FTS5_PORTER_MAX_TOKEN + 64];
};
@@ -567,7 +565,7 @@ static void fts5PorterDelete(Fts5Tokenizer *pTok){
if( pTok ){
PorterTokenizer *p = (PorterTokenizer*)pTok;
if( p->pTokenizer ){
p->tokenizer.xDelete(p->pTokenizer);
p->tokenizer_v2.xDelete(p->pTokenizer);
}
sqlite3_free(p);
}
@@ -586,6 +584,7 @@ static int fts5PorterCreate(
PorterTokenizer *pRet;
void *pUserdata = 0;
const char *zBase = "unicode61";
fts5_tokenizer_v2 *pV2 = 0;
if( nArg>0 ){
zBase = azArg[0];
@@ -594,14 +593,15 @@ static int fts5PorterCreate(
pRet = (PorterTokenizer*)sqlite3_malloc(sizeof(PorterTokenizer));
if( pRet ){
memset(pRet, 0, sizeof(PorterTokenizer));
rc = pApi->xFindTokenizer(pApi, zBase, &pUserdata, &pRet->tokenizer);
rc = pApi->xFindTokenizer_v2(pApi, zBase, &pUserdata, &pV2);
}else{
rc = SQLITE_NOMEM;
}
if( rc==SQLITE_OK ){
int nArg2 = (nArg>0 ? nArg-1 : 0);
const char **azArg2 = (nArg2 ? &azArg[1] : 0);
rc = pRet->tokenizer.xCreate(pUserdata, azArg2, nArg2, &pRet->pTokenizer);
const char **az2 = (nArg2 ? &azArg[1] : 0);
memcpy(&pRet->tokenizer_v2, pV2, sizeof(fts5_tokenizer_v2));
rc = pRet->tokenizer_v2.xCreate(pUserdata, az2, nArg2, &pRet->pTokenizer);
}
if( rc!=SQLITE_OK ){
@@ -1252,6 +1252,7 @@ static int fts5PorterTokenize(
void *pCtx,
int flags,
const char *pText, int nText,
const char *pLoc, int nLoc,
int (*xToken)(void*, int, const char*, int nToken, int iStart, int iEnd)
){
PorterTokenizer *p = (PorterTokenizer*)pTokenizer;
@@ -1259,8 +1260,8 @@ static int fts5PorterTokenize(
sCtx.xToken = xToken;
sCtx.pCtx = pCtx;
sCtx.aBuf = p->aBuf;
return p->tokenizer.xTokenize(
p->pTokenizer, (void*)&sCtx, flags, pText, nText, fts5PorterCb
return p->tokenizer_v2.xTokenize(
p->pTokenizer, (void*)&sCtx, flags, pText, nText, pLoc, nLoc, fts5PorterCb
);
}
@@ -1290,40 +1291,46 @@ static int fts5TriCreate(
Fts5Tokenizer **ppOut
){
int rc = SQLITE_OK;
TrigramTokenizer *pNew = (TrigramTokenizer*)sqlite3_malloc(sizeof(*pNew));
TrigramTokenizer *pNew = 0;
UNUSED_PARAM(pUnused);
if( pNew==0 ){
rc = SQLITE_NOMEM;
if( nArg%2 ){
rc = SQLITE_ERROR;
}else{
int i;
pNew->bFold = 1;
pNew->iFoldParam = 0;
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;
pNew = (TrigramTokenizer*)sqlite3_malloc(sizeof(*pNew));
if( pNew==0 ){
rc = SQLITE_NOMEM;
}else{
pNew->bFold = 1;
pNew->iFoldParam = 0;
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 if( 0==sqlite3_stricmp(azArg[i], "remove_diacritics") ){
if( (zArg[0]!='0' && zArg[0]!='1' && zArg[0]!='2') || zArg[1] ){
rc = SQLITE_ERROR;
}else{
pNew->iFoldParam = (zArg[0]!='0') ? 2 : 0;
}
}else{
pNew->bFold = (zArg[0]=='0');
}
}else if( 0==sqlite3_stricmp(azArg[i], "remove_diacritics") ){
if( (zArg[0]!='0' && zArg[0]!='1' && zArg[0]!='2') || zArg[1] ){
rc = SQLITE_ERROR;
}else{
pNew->iFoldParam = (zArg[0]!='0') ? 2 : 0;
}
}else{
}
if( pNew->iFoldParam!=0 && pNew->bFold==0 ){
rc = SQLITE_ERROR;
}
}
if( pNew->iFoldParam!=0 && pNew->bFold==0 ){
rc = SQLITE_ERROR;
}
if( rc!=SQLITE_OK ){
fts5TriDelete((Fts5Tokenizer*)pNew);
pNew = 0;
if( rc!=SQLITE_OK ){
fts5TriDelete((Fts5Tokenizer*)pNew);
pNew = 0;
}
}
}
*ppOut = (Fts5Tokenizer*)pNew;
@@ -1448,7 +1455,6 @@ int sqlite3Fts5TokenizerInit(fts5_api *pApi){
} aBuiltin[] = {
{ "unicode61", {fts5UnicodeCreate, fts5UnicodeDelete, fts5UnicodeTokenize}},
{ "ascii", {fts5AsciiCreate, fts5AsciiDelete, fts5AsciiTokenize }},
{ "porter", {fts5PorterCreate, fts5PorterDelete, fts5PorterTokenize }},
{ "trigram", {fts5TriCreate, fts5TriDelete, fts5TriTokenize}},
};
@@ -1463,6 +1469,19 @@ int sqlite3Fts5TokenizerInit(fts5_api *pApi){
0
);
}
if( rc==SQLITE_OK ){
fts5_tokenizer_v2 sPorter = {
2,
fts5PorterCreate,
fts5PorterDelete,
fts5PorterTokenize
};
rc = pApi->xCreateTokenizer_v2(pApi,
"porter",
(void*)pApi,
&sPorter,
0
);
}
return rc;
}
+3
View File
@@ -364,6 +364,9 @@ int sqlite3Fts5UnicodeCatParse(const char *zCat, u8 *aArray){
default: return 1; }
break;
default:
return 1;
}
return 0;
}
+18
View File
@@ -51,6 +51,10 @@ proc fts5_test_poslist2 {cmd} {
sort_poslist $res
}
proc fts5_test_insttoken {cmd iInst iToken} {
$cmd xInstToken $iInst $iToken
}
proc fts5_test_collist {cmd} {
set res [list]
@@ -78,6 +82,9 @@ proc fts5_test_columnsize {cmd} {
proc fts5_columntext {cmd iCol} {
$cmd xColumnText $iCol
}
proc fts5_columnlocale {cmd iCol} {
$cmd xColumnLocale $iCol
}
proc fts5_test_columntext {cmd} {
set res [list]
@@ -87,6 +94,14 @@ proc fts5_test_columntext {cmd} {
set res
}
proc fts5_test_columnlocale {cmd} {
set res [list]
for {set i 0} {$i < [$cmd xColumnCount]} {incr i} {
lappend res [$cmd xColumnLocale $i]
}
set res
}
proc fts5_test_columntotalsize {cmd} {
set res [list]
for {set i 0} {$i < [$cmd xColumnCount]} {incr i} {
@@ -165,10 +180,12 @@ proc fts5_aux_test_functions {db} {
foreach f {
fts5_test_columnsize
fts5_test_columntext
fts5_test_columnlocale
fts5_test_columntotalsize
fts5_test_poslist
fts5_test_poslist2
fts5_test_collist
fts5_test_insttoken
fts5_test_tokenize
fts5_test_rowcount
fts5_test_rowid
@@ -177,6 +194,7 @@ proc fts5_aux_test_functions {db} {
fts5_test_queryphrase
fts5_test_phrasecount
fts5_columntext
fts5_columnlocale
fts5_queryphrase
fts5_collist
} {
+2 -2
View File
@@ -440,7 +440,7 @@ do_execsql_test 16.1 {
proc funk {} {
db eval { UPDATE n1_config SET v=50 WHERE k='version' }
set fd [db incrblob main n1_data block 10]
fconfigure $fd -encoding binary -translation binary
fconfigure $fd -translation binary
# puts -nonewline $fd "\x44\x45"
close $fd
}
@@ -453,7 +453,7 @@ db func funk funk
# statement no longer fails.
#
do_catchsql_test 16.2 {
SELECT funk(), bm25(n1), funk() FROM n1 WHERE n1 MATCH 'a+b+c+d'
SELECT funk(), format('%g',bm25(n1)), funk() FROM n1 WHERE n1 MATCH 'a+b+c+d'
} {0 {{} -1e-06 {}}}
# {1 {SQL logic error}}
+11
View File
@@ -163,6 +163,17 @@ do_execsql_test 1.8.2 {
SELECT count(*) FROM t1 WHERE t1 MATCH 'x' AND rowid < 'text';
} {10000}
do_execsql_test 1.8.3 {
SELECT count(*) FROM t1 WHERE t1 MATCH 'x' AND rowid<5000 AND rowid < 'text';
} {4999}
do_execsql_test 1.8.4 {
SELECT count(*) FROM t1 WHERE t1 MATCH 'x' AND rowid>5000 AND rowid > 'text';
} {0}
do_catchsql_test 1.9 {
SELECT * FROM t1('*xy');
} {1 {unknown special query: xy}}
} ;# foreach_detail_mode
#db eval {SELECT rowid, fts5_decode(rowid, block) aS r FROM t1_data} {puts $r}
+10
View File
@@ -293,6 +293,16 @@ do_catchsql_test 4.4.4 {
SELECT *, rank FROM t3 WHERE t3 MATCH 'a' AND rank MATCH NULL
} {1 {parse error in rank function: }}
# Check that the second and subsequent rank= constraints are ignored.
#
do_catchsql_test 4.3.3 {
SELECT *, rank FROM t3
WHERE t3 MATCH 'a' AND
rank MATCH 'nosuch()' AND
rank MATCH 'rowidmod(3)'
ORDER BY rank ASC
} {1 {unable to use function MATCH in the requested context}}
} ;# foreach_detail_mode
+166
View File
@@ -0,0 +1,166 @@
# 2024 July 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.
#
#***********************************************************************
#
# This file verifies that:
#
# * blob values may be written to locale=0 tables.
#
# * blob values - other than fts5_locale() values - may not be written
# to locale=0 tables. This is an SQLITE_MISMATCH error
#
# * blob values may be returned by queries on the external-content table
# of a locale=0 table.
#
# * blob values not may be returned by queries on the external-content
# table of a locale=1 table, apart from fts5_locale() blobs. This is an
# SQLITE_MISMATCH error.
#
source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5blob
# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 {
finish_test
return
}
# Test that blobs may be stored in normal locale=0 tables.
#
foreach {tn enc} {
1 utf8
2 utf16
} {
reset_db
fts5_aux_test_functions db
execsql "PRAGMA encoding = $enc"
execsql "
CREATE VIRTUAL TABLE t1 USING fts5(x, y);
"
do_execsql_test 1.$tn.0 {
CREATE VIRTUAL TABLE tt USING fts5vocab('t1', 'instance');
INSERT INTO t1(rowid, x, y) VALUES(1, 555, X'0000000041424320444546');
INSERT INTO t1(rowid, x, y) VALUES(2, 666, X'41424300444546');
INSERT INTO t1(rowid, x, y) VALUES(3, 777, 'xyz');
}
do_execsql_test 1.$tn.1 {
SELECT rowid, quote(x), quote(y) FROM t1
} {
1 555 X'0000000041424320444546'
2 666 X'41424300444546'
3 777 'xyz'
}
do_execsql_test 1.$tn.2 {
DELETE FROM t1 WHERE rowid=2;
DELETE FROM t1 WHERE rowid=1;
}
do_execsql_test 1.$tn.3 {
PRAGMA integrity_check;
} {ok}
}
#--------------------------------------------------------------------------
# Test that a blob may be stored and retrieved in an unindexed column of
# a regular table with locale=1.
#
reset_db
do_execsql_test 2.0 {
CREATE VIRTUAL TABLE t1 USING fts5(x, y UNINDEXED, locale=1);
INSERT INTO t1(rowid, x, y) VALUES(12, 'twelve', X'0000000041424320444546');
}
do_execsql_test 2.1 {
select rowid, x, quote(y) FROM t1
} {
12 twelve X'0000000041424320444546'
}
#--------------------------------------------------------------------------
# Test that blobs may not be written to any type of table with locale=1
# set. Except, they may be written to UNINDEXED columns.
#
reset_db
do_execsql_test 3.0 {
CREATE TABLE t1(a, b);
CREATE VIRTUAL TABLE x1 USING fts5(a, b, locale=1);
CREATE VIRTUAL TABLE x2 USING fts5(a, b, locale=1, content=t2);
CREATE VIRTUAL TABLE x3 USING fts5(a, b, locale=1, content=);
}
do_catchsql_test 3.1 {
INSERT INTO x1(rowid, a, b) VALUES(113, 'hello world', X'123456');
} {0 {}}
do_catchsql_test 3.2 {
INSERT INTO x2(rowid, a, b) VALUES(113, 'hello world', X'123456');
} {0 {}}
do_catchsql_test 3.3 {
INSERT INTO x3(rowid, a, b) VALUES(113, 'hello world', X'123456');
} {0 {}}
#--------------------------------------------------------------------------
# Test that fts5_locale() values may not be written to any type of table
# without locale=1 set. Even to an UNINDEXED column.
#
reset_db
do_execsql_test 3.0 {
CREATE TABLE t1(a, b);
CREATE VIRTUAL TABLE x1 USING fts5(a, b);
CREATE VIRTUAL TABLE x2 USING fts5(a, b, content=t2);
CREATE VIRTUAL TABLE x3 USING fts5(a, b, content=);
CREATE VIRTUAL TABLE x4 USING fts5(a, b, c UNINDEXED);
}
do_catchsql_test 3.1 {
INSERT INTO x1(rowid, a, b)
VALUES(113, 'hello world', fts5_locale('en_AU', 'abc'));
} {1 {fts5_locale() requires locale=1}}
do_catchsql_test 3.2 {
INSERT INTO x2(rowid, a, b)
VALUES(113, 'hello world', fts5_locale('en_AU', 'abc'));
} {1 {fts5_locale() requires locale=1}}
do_catchsql_test 3.3 {
INSERT INTO x3(rowid, a, b)
VALUES(113, 'hello world', fts5_locale('en_AU', 'abc'));
} {1 {fts5_locale() requires locale=1}}
do_catchsql_test 3.4 {
INSERT INTO x4(rowid, a, b, c)
VALUES(113, 'hello world', 'yesno', fts5_locale('en_AU', 'abc'));
} {1 {fts5_locale() requires locale=1}}
#-------------------------------------------------------------------------
#
reset_db
do_execsql_test 4.0 {
CREATE VIRTUAL TABLE x1 USING fts5(x);
}
foreach {tn sql} {
1 { INSERT INTO x1(rowid, x) VALUES(4.5, 'abcd') }
2 { INSERT INTO x1(rowid, x) VALUES('xyz', 'abcd') }
3 { INSERT INTO x1(rowid, x) VALUES(X'001122', 'abcd') }
} {
do_catchsql_test 4.1.$tn $sql {1 {datatype mismatch}}
}
finish_test
+17
View File
@@ -55,5 +55,22 @@ do_execsql_test 1.5 {
SELECT * FROM t4t
} {สนามกีฬา 1 1}
#-------------------------------------------------------------------------
reset_db
do_execsql_test 2.0 "
CREATE VIRTUAL TABLE x1 USING fts5(c,
tokenize=\"unicode61 categories ' \t'\");
"
do_catchsql_test 2.1 "
CREATE VIRTUAL TABLE x2 USING fts5(c,
tokenize=\"unicode61 categories 'N*\t\tMYZ'\");
" {1 {error in tokenizer constructor}}
do_catchsql_test 2.2 "
CREATE VIRTUAL TABLE x2 USING fts5(c,
tokenize=\"unicode61 categories 'N*\t\tXYZ'\");
" {1 {error in tokenizer constructor}}
finish_test
+20
View File
@@ -267,4 +267,24 @@ do_execsql_test 8.2 {
SELECT rowid FROM ft('four');
} {}
#-------------------------------------------------------------------------
reset_db
do_execsql_test 9.0 {
CREATE VIRTUAL TABLE ft USING fts5(x, content='', contentless_delete=0);
INSERT INTO ft VALUES('hello world');
INSERT INTO ft VALUES('one two three');
}
do_catchsql_test 9.1 {
INSERT INTO ft(ft, rowid, x) VALUES('delete', 1, 'hello world');
} {0 {}}
do_catchsql_test 9.2 {
CREATE VIRTUAL TABLE ft2 USING fts5(x, content='', contentless_delete=2);
} {1 {malformed contentless_delete=... directive}}
do_catchsql_test 9.3 {
CREATE VIRTUAL TABLE ft2 USING fts5(x, content='', contentless_delete=11);
} {1 {malformed contentless_delete=... directive}}
finish_test
+1
View File
@@ -20,6 +20,7 @@ ifcapable !fts5 {
finish_test
return
}
unset -nocomplain res
do_execsql_test 1.0 {
CREATE VIRTUAL TABLE t1 USING fts5(a, b, c, content='', contentless_delete=1);
+21
View File
@@ -101,4 +101,25 @@ do_catchsql_test 3.1 {
SELECT * FROM t3 WHERE t3 MATCH 'o';
} {1 {fts5: missing row 3 from content table 'main'.'t3_content'}}
#--------------------------------------------------------------------
#
reset_db
do_execsql_test 4.0 {
CREATE VIRTUAL TABLE t2 USING fts5(x);
INSERT INTO t2 VALUES('one two three');
INSERT INTO t2 VALUES('four five six');
INSERT INTO t2 VALUES('seven eight nine');
INSERT INTO t2 VALUES('ten eleven twelve');
}
do_execsql_test 4.1 {
SELECT hex(block) FROM t2_data WHERE id=1;
} {040C}
do_execsql_test 4.2 {
UPDATE t2_data SET block = X'0402' WHERE id=1
}
breakpoint
do_catchsql_test 4.3 {
DELETE FROM t2 WHERE rowid=3
} {1 {database disk image is malformed}}
finish_test
+3 -2
View File
@@ -100,6 +100,7 @@ set lrowid [db one {SELECT max(rowid) FROM t1_data WHERE (rowid & $mask)=0}]
set nbyte [db one {SELECT length(block) FROM t1_data WHERE rowid=$lrowid}]
set all [db eval {SELECT rowid FROM t1}]
sqlite3_db_config db DEFENSIVE 0
unset -nocomplain res
for {set i [expr $nbyte-2]} {$i>=0} {incr i -1} {
do_execsql_test 2.$i.1 {
BEGIN;
@@ -152,7 +153,7 @@ foreach {tn hdr} {
execsql BEGIN
set fd [db incrblob main x3_data block $rowid]
fconfigure $fd -encoding binary -translation binary
fconfigure $fd -translation binary
set existing [read $fd [string length $hdr]]
seek $fd 0
puts -nonewline $fd $hdr
@@ -238,7 +239,7 @@ foreach {tn hdr} {
execsql BEGIN
set fd [db incrblob main x5_data block $rowid]
fconfigure $fd -encoding binary -translation binary
fconfigure $fd -translation binary
puts -nonewline $fd $hdr
close $fd
+170 -11
View File
@@ -680,11 +680,11 @@ do_test 12.0 {
do_catchsql_test 11.1 {
SELECT * FROM t1 WHERE t1 MATCH 'abandon';
} {1 {vtable constructor failed: t1}}
} {1 {database disk image is malformed}}
do_catchsql_test 11.2 {
INSERT INTO t1(t1, rank) VALUES('merge', 500);
} {1 {vtable constructor failed: t1}}
} {1 {database disk image is malformed}}
#-------------------------------------------------------------------------
#
@@ -1040,7 +1040,7 @@ do_test 16.0 {
do_catchsql_test 16.1 {
INSERT INTO t1(t1) VALUES('integrity-check');
} {1 {vtable constructor failed: t1}}
} {1 {database disk image is malformed}}
#--------------------------------------------------------------------------
reset_db
@@ -1126,7 +1126,7 @@ do_test 17.0 {
do_catchsql_test 17.1 {
SELECT * FROM t1 WHERE t1 MATCH 'abandon';
} {1 {vtable constructor failed: t1}}
} {1 {database disk image is malformed}}
#--------------------------------------------------------------------------
reset_db
@@ -1630,7 +1630,7 @@ do_test 20.0 {
do_catchsql_test 20.1 {
SELECT * FROM t1 WHERE t1 MATCH 'abandon';
} {1 {vtable constructor failed: t1}}
} {1 {database disk image is malformed}}
#-------------------------------------------------------------------------
reset_db
@@ -2100,7 +2100,7 @@ do_test 22.0 {
do_catchsql_test 22.1 {
INSERT INTO t1(t1) VALUES('optimize');
} {1 {vtable constructor failed: t1}}
} {1 {database disk image is malformed}}
#--------------------------------------------------------------------------
reset_db
@@ -3700,7 +3700,7 @@ do_catchsql_test 32.1 {
highlight(t1, 2, '[', ']')
FROM t1('g + h')
WHERE rank MATCH 'bm25(1.0, 1.0)' ORDER BY rank;
} {1 {vtable constructor failed: t1}}
} {1 {database disk image is malformed}}
do_catchsql_test 32.2 {
SELECT * FROM t3;
@@ -8958,7 +8958,6 @@ do_catchsql_test 61.2 {
SELECT * FROM t3 ORDER BY rowid;
} {/*malformed database schema*/}
breakpoint
#-------------------------------------------------------------------------
do_test 62.0 {
sqlite3 db {}
@@ -10768,6 +10767,7 @@ do_catchsql_test 73.1 {
reset_db
do_test 74.0 {
sqlite3 db {}
sqlite3_fts5_register_matchinfo db
db deserialize [decode_hexdb {
| size 106496 pagesize 4096 filename x.db
| page 1 offset 0
@@ -14587,14 +14587,19 @@ do_test 74.0 {
| end x.db
}]} {}
do_catchsql_test 74.1 {
SELECT rowid, quote(matchinfo(t1,'pxyb<s')) FROM t1 WHERE t1 MATCH 'e*';
do_catchsql_test 74.0.5 {
SELECT matchinfo(1,2);
} {1 {unable to use function matchinfo in the requested context}}
do_catchsql_test 74.1 {
SELECT rowid, quote(matchinfo(t1,'pxyb<s')) FROM t1 WHERE t1 MATCH 'e*';
} {1 {unrecognized matchinfo flag: <}}
#-------------------------------------------------------------------------
reset_db
do_test 75.0 {
sqlite3 db {}
sqlite3_fts5_register_matchinfo db
db deserialize [decode_hexdb {
| size 32768 pagesize 4096 filename crash-033d665d5caa8d.db
| page 1 offset 0
@@ -14791,7 +14796,7 @@ do_test 75.0 {
do_catchsql_test 75.1 {
SELECT rowid, quote(matchinfo(t1,'pcxybs')) FROM t1 WHERE t1 MATCH 'e*';
} {1 {unable to use function matchinfo in the requested context}}
} {1 {database disk image is malformed}}
#-------------------------------------------------------------------------
reset_db
@@ -15519,6 +15524,160 @@ do_catchsql_test 80.1 {
SELECT snippet(rowid, -1, '.', '..', '[', '(]'),snippet(rowid, -1, '.', '.', '', '(]'), highlight(t1, 29, 1 , '') FROM t1('g+ h') WHERE rank MATCH 'bm25(1.0, 10)' ORDER BY NOT (SELECT 1 FROM t1('g+ æ') WHERE rank MATCH 'bm25(1.0, 10)' ORDER BY rank);
} {1 {database disk image is malformed}}
#-------------------------------------------------------------------------
reset_db
do_test 81.0 {
sqlite3 db {}
db deserialize [decode_hexdb {
.open --hexdb
| size 40960 pagesize 4096 filename crash-44e8035a976422.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 0a .....@ ........
| 32: 00 00 00 00 00 00 00 00 00 00 00 0d 00 00 00 04 ................
| 48: 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 ................
| 96: 00 00 00 00 0d 00 00 00 0d 0b 6e 00 0f a3 0f 4c ..........n....L
| 112: 0e e1 0e 81 0e 24 0d cc 0d 72 0d 1b 0c b0 0c 50 .....$...r.....P
| 128: 0b f8 0b b3 0b 6e 00 00 00 00 00 00 00 00 00 00 .....n..........
| 2912: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 43 0d ..............C.
| 2928: 06 17 11 11 08 75 74 61 62 6c 65 74 34 74 34 43 .....utablet4t4C
| 2944: 52 45 41 54 45 20 56 49 52 54 55 41 4c 20 54 41 REATE VIRTUAL TA
| 2960: 42 4c 45 20 74 34 20 55 53 49 4e 47 20 66 74 73 BLE t4 USING fts
| 2976: 35 76 6f 63 61 62 28 27 74 32 27 2c 20 27 72 6f 5vocab('t2', 'ro
| 2992: 77 27 29 43 0c 06 17 11 11 08 75 74 61 62 6c 65 w')C......utable
| 3008: 74 33 74 33 43 52 45 41 54 45 20 56 49 52 54 55 t3t3CREATE VIRTU
| 3024: 41 4c 20 54 41 42 4c 45 20 74 33 20 55 53 49 4e AL TABLE t3 USIN
| 3040: 47 20 66 74 73 35 76 6f 63 61 62 28 27 74 31 27 G fts5vocab('t1'
| 3056: 2c 20 27 72 6f 77 27 29 56 0b 06 17 1f 1f 01 7d , 'row')V.......
| 3072: 74 61 62 6c 65 74 32 5f 63 6f 6e 66 69 67 74 32 tablet2_configt2
| 3088: 5f 63 6f 6e 66 69 67 0a 43 52 45 41 54 45 20 54 _config.CREATE T
| 3104: 41 42 4c 45 20 27 74 32 5f 63 6f 6e 66 69 67 27 ABLE 't2_config'
| 3120: 28 6b 20 50 52 49 4d 41 52 59 20 4b 45 59 2c 20 (k PRIMARY KEY,
| 3136: 76 29 20 57 49 54 48 4f 55 54 20 52 4f 57 49 44 v) WITHOUT ROWID
| 3152: 5e 0a 07 17 21 21 01 81 07 74 61 62 6c 65 74 32 ^...!!...tablet2
| 3168: 5f 63 6f 6e 74 65 6e 74 74 32 5f 63 6f 6e 74 65 _contentt2_conte
| 3184: 6e 74 09 43 52 45 41 54 45 20 54 41 42 4c 45 20 nt.CREATE TABLE
| 3200: 27 74 32 5f 63 6f 6e 74 65 6e 74 27 28 69 64 20 't2_content'(id
| 3216: 49 4e 54 45 47 45 52 20 50 52 49 4d 41 52 59 20 INTEGER PRIMARY
| 3232: 4b 45 59 2c 20 63 30 2c 20 63 31 2c 20 63 32 29 KEY, c0, c1, c2)
| 3248: 69 09 07 17 19 19 01 81 2d 74 61 62 6c 65 74 32 i.......-tablet2
| 3264: 5f 69 64 78 74 32 5f 69 64 78 08 43 52 45 41 54 _idxt2_idx.CREAT
| 3280: 45 20 54 41 42 4c 45 20 27 74 32 5f 69 64 78 27 E TABLE 't2_idx'
| 3296: 28 73 65 67 69 64 2c 20 74 65 72 6d 2c 20 70 67 (segid, term, pg
| 3312: 6e 6f 2c 20 50 52 49 4d 41 52 59 20 4b 45 59 28 no, PRIMARY KEY(
| 3328: 73 65 67 69 64 2c 20 74 65 72 6d 29 29 20 57 49 segid, term)) WI
| 3344: 54 48 4f 55 54 20 52 4f 57 49 44 55 08 07 17 1b THOUT ROWIDU....
| 3360: 1b 01 81 01 74 61 62 6c 65 74 32 5f 64 61 74 61 ....tablet2_data
| 3376: 74 32 5f 64 61 74 61 07 43 52 45 41 54 45 20 54 t2_data.CREATE T
| 3392: 41 42 4c 45 20 27 74 32 5f 64 61 74 61 27 28 69 ABLE 't2_data'(i
| 3408: 64 20 49 4e 54 45 47 45 52 20 50 52 49 4d 41 52 d INTEGER PRIMAR
| 3424: 59 20 4b 45 59 2c 20 62 6c 6f 63 6b 20 42 4c 4f Y KEY, block BLO
| 3440: 42 29 58 07 07 17 11 11 08 81 1d 74 61 62 6c 65 B)X........table
| 3456: 74 32 74 32 43 52 45 41 54 45 20 56 49 52 54 55 t2t2CREATE VIRTU
| 3472: 41 4c 20 54 41 42 4c 45 20 74 32 20 55 53 49 4e AL TABLE t2 USIN
| 3488: 47 20 66 74 73 35 28 27 61 27 2c 5b 62 5d 2c 22 G fts5('a',[b],.
| 3504: 63 22 2c 64 65 74 61 69 6c 3d 6e 6f 6e 65 2c 63 c.,detail=none,c
| 3520: 6f 6c 75 6d 6e 73 69 7a 65 3d 30 29 56 06 06 17 olumnsize=0)V...
| 3536: 1f 1f 01 7d 74 61 62 6c 65 74 31 5f 63 6f 6e 66 ....tablet1_conf
| 3552: 69 67 74 31 5f 63 6f 6e 66 69 67 06 43 52 45 41 igt1_config.CREA
| 3568: 54 45 20 54 41 42 4c 45 20 27 74 31 5f 63 6f 6e TE TABLE 't1_con
| 3584: 66 69 67 27 28 6b 20 50 52 49 4d 41 52 59 20 4b fig'(k PRIMARY K
| 3600: 45 59 2c 20 76 29 20 57 49 54 48 4f 55 54 20 52 EY, v) WITHOUT R
| 3616: 4f 57 49 44 5b 05 07 17 21 21 01 81 01 74 61 62 OWID[...!!...tab
| 3632: 6c 65 74 31 5f 64 6f 63 73 69 7a 65 74 31 5f 64 let1_docsizet1_d
| 3648: 6f 63 73 69 7a 65 05 43 52 45 41 54 45 20 54 41 ocsize.CREATE TA
| 3664: 42 4c 45 20 27 74 31 5f 64 6f 63 73 69 7a 65 27 BLE 't1_docsize'
| 3680: 28 69 64 20 49 4e 54 45 47 45 52 20 50 52 49 4d (id INTEGER PRIM
| 3696: 41 52 59 20 4b 45 59 2c 20 73 7a 20 42 4c 4f 42 ARY KEY, sz BLOB
| 3712: 29 5e 04 07 17 21 21 01 81 07 74 61 62 6c 65 74 )^...!!...tablet
| 3728: 31 5f 63 6f 6e 74 65 6e 74 74 31 5f 63 6f 6e 74 1_contentt1_cont
| 3744: 65 6e 74 04 43 52 45 41 54 45 20 54 41 42 4c 45 ent.CREATE TABLE
| 3760: 20 27 74 31 5f 63 6f 6e 74 65 6e 74 27 28 69 64 't1_content'(id
| 3776: 20 49 4e 54 45 47 45 52 20 50 52 49 4d 41 52 59 INTEGER PRIMARY
| 3792: 20 4b 45 59 2c 20 63 30 2c 20 63 31 2c 20 63 32 KEY, c0, c1, c2
| 3808: 29 69 03 07 17 19 19 01 81 2d 74 61 62 6c 65 74 )i.......-tablet
| 3824: 31 5f 69 64 78 74 31 5f 69 64 78 03 43 52 45 41 1_idxt1_idx.CREA
| 3840: 54 45 20 54 41 42 4c 45 20 27 74 31 5f 69 64 78 TE TABLE 't1_idx
| 3856: 27 28 73 65 67 69 64 2c 20 74 65 72 6d 2c 20 70 '(segid, term, p
| 3872: 67 6e 6f 2c 20 50 52 49 4d 41 52 59 20 4b 45 59 gno, PRIMARY KEY
| 3888: 28 73 65 67 69 64 2c 20 74 65 72 6d 29 29 20 57 (segid, term)) W
| 3904: 49 54 48 4f 55 54 20 52 4f 57 49 44 55 02 07 17 ITHOUT ROWIDU...
| 3920: 1b 1b 01 81 01 74 61 62 6c 65 74 31 5f 64 61 74 .....tablet1_dat
| 3936: 61 74 31 5f 64 61 74 61 02 43 52 45 41 54 45 20 at1_data.CREATE
| 3952: 54 41 42 4c 45 20 27 74 31 5f 64 61 74 61 27 28 TABLE 't1_data'(
| 3968: 69 64 20 49 4e 54 45 47 45 52 20 50 52 49 4d 41 id INTEGER PRIMA
| 3984: 52 59 20 4b 45 59 2c 20 62 6c 6f 63 6b 20 42 4c RY KEY, block BL
| 4000: 4f 42 29 5b 01 07 17 11 11 08 81 23 74 61 62 6c OB)[.......#tabl
| 4016: 65 74 31 74 31 43 52 45 41 54 45 20 56 49 52 54 et1t1CREATE VIRT
| 4032: 55 41 4c 20 54 41 42 4c 45 20 74 31 20 55 53 49 UAL TABLE t1 USI
| 4048: 4e 47 20 66 74 73 35 28 61 2c 62 20 75 6e 69 6e NG fts5(a,b unin
| 4064: 64 65 78 65 64 2c 63 2c 74 6f 6b 65 6e 69 7a 65 dexed,c,tokenize
| 4080: 3d 22 70 6f 72 74 65 72 20 61 73 63 69 69 22 29 =.porter ascii.)
| page 2 offset 4096
| 0: 0d 0f 68 00 05 0f 13 00 0f e6 0f 13 0f a8 0f 7c ..h............|
| 16: 0f 2a 00 00 00 00 00 00 00 00 00 00 00 00 00 00 .*..............
| 3856: 00 00 00 15 0a 03 00 30 00 00 00 00 01 03 03 00 .......0........
| 3872: 03 01 01 01 02 01 01 03 01 01 37 8c 80 80 80 80 ..........7.....
| 3888: 01 03 00 74 00 00 00 2e 02 30 61 03 02 02 01 01 ...t.....0a.....
| 3904: 62 03 02 03 01 01 63 03 02 04 01 01 67 03 06 01 b.....c.....g...
| 3920: 02 02 01 01 68 03 06 01 02 03 01 01 69 03 06 01 ....h.......i...
| 3936: 02 04 04 06 06 06 08 08 0f ef 00 14 2a 00 00 00 ............*...
| 3952: 00 01 02 02 00 02 01 01 01 02 01 01 25 88 80 80 ............%...
| 3968: 80 80 01 03 00 50 00 00 00 1f 02 30 67 02 08 02 .....P.....0g...
| 3984: 01 02 02 01 01 68 02 08 03 8d 02 03 01 01 6a 42 .....h........jB
| 4000: 08 04 01 02 04 04 09 09 37 84 80 80 80 80 01 03 ........7.......
| 4016: 00 74 00 00 00 2e 02 30 61 01 12 02 01 01 62 01 .t.....0a.....b.
| 4032: 02 03 01 01 63 01 02 04 01 01 67 01 06 01 02 02 ....c.....g.....
| 4048: 01 01 68 01 05 01 02 03 01 01 69 01 06 01 02 04 ..h.......i.....
| 4064: 04 06 06 06 08 08 07 01 03 00 14 03 09 00 09 00 ................
| 4080: 00 00 11 24 00 00 00 00 01 01 01 00 01 01 01 01 ...$............
| page 3 offset 8192
| 0: 0a 00 00 00 03 0f ec 00 0f fa 0f f3 0f ec 00 00 ................
| 4064: 00 00 00 00 00 00 00 00 00 00 00 00 06 04 01 0c ................
| 4080: 01 03 02 06 04 01 0c 01 02 02 05 04 09 0c 01 02 ................
| page 4 offset 12288
| 0: 0d 00 00 00 03 0f be 00 0f ea 00 00 00 00 00 00 ................
| 4016: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 14 03 ................
| 4032: 05 00 17 17 17 61 20 62 20 63 67 20 68 20 69 67 .....a b cg h ig
| 4048: 20 68 20 69 14 02 05 00 17 17 17 67 20 68 20 69 h i.......g h i
| 4064: 61 20 62 20 63 67 20 68 20 69 14 01 05 00 17 17 a b cg h i......
| 4080: 17 61 20 62 20 63 64 20 65 20 66 67 20 68 20 69 .a b cd e fg h i
| page 5 offset 16384
| 0: 0d 00 00 00 03 0f e8 00 0f f8 0f f0 0f e8 00 00 ................
| 4064: 00 00 00 00 00 00 00 00 06 03 03 00 12 03 00 03 ................
| 4080: 06 02 03 00 12 03 00 03 06 01 03 00 12 03 00 03 ................
| 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 9e 00 0f e6 0f ef 0f 9e 00 00 ................
| 3984: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 41 84 ..............A.
| 4000: 80 80 80 80 01 04 00 81 06 00 00 00 34 02 30 61 ............4.0a
| 4016: 01 01 01 01 01 62 01 01 01 01 01 63 01 01 01 01 .....b.....c....
| 4032: e6 64 01 01 01 65 01 01 01 66 01 01 01 67 01 01 .d...e...f...g..
| 4048: 01 01 01 68 01 01 01 01 01 69 01 01 01 04 06 06 ...h.....i......
| 4064: 06 04 04 04 06 06 07 01 03 00 14 03 09 09 09 0f ................
| 4080: 0a 03 00 24 00 00 00 00 01 01 01 00 01 01 01 01 ...$............
| page 8 offset 28672
| 0: 0a 00 00 00 01 0f fa 00 0f fa 00 00 00 00 00 00 ................
| 4080: 00 00 00 00 00 00 00 00 00 00 05 04 09 0c 01 02 ................
| page 9 offset 32768
| 0: 0d 00 00 00 03 0f be 00 0f ea 0f d4 0f be 00 00 ................
| 4016: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 14 03 ................
| 4032: 05 00 17 17 17 61 20 62 20 63 67 20 68 20 69 67 .....a b cg h ig
| 4048: 20 68 21 69 14 02 05 00 17 17 17 67 20 68 20 69 h!i.......g h i
| 4064: 61 20 62 20 63 67 20 68 20 69 14 01 05 00 17 17 a b cg h i......
| 4080: 17 61 20 62 20 63 64 20 65 20 66 67 20 68 20 69 .a b cd e fg h i
| page 10 offset 36864
| 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 crash-44e8035a976422.db
}]} {}
do_catchsql_test 81.2 {
UPDATE t1 SET b=zeroblob(299);
} {1 {database disk image is malformed}}
sqlite3_fts5_may_be_corrupt 0
finish_test
+94
View File
@@ -0,0 +1,94 @@
# 2024 Aug 28
#
# The author disclaims copyright to this source code. In place of
# a legal notice, here is a blessing:
#
# May you do good and not evil.
# May you find forgiveness for yourself and forgive others.
# May you share freely, never taking more than you give.
#
#***********************************************************************
#
source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5corrupt8
# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 {
finish_test
return
}
do_execsql_test 1.0 {
CREATE VIRTUAL TABLE t1 USING fts5(x);
}
do_execsql_test 1.1 {
UPDATE t1_data SET block='hello world' WHERE id=10
}
db close
sqlite3 db test.db
do_catchsql_test 1.2 {
SELECT * FROM t1
} {1 {database disk image is malformed}}
do_catchsql_test 1.3 {
DROP TABLE t1
} {0 {}}
do_execsql_test 1.4 {
SELECT * FROM sqlite_schema
}
do_execsql_test 2.0 {
CREATE VIRTUAL TABLE t1 USING fts5(x);
}
do_execsql_test 2.1 {
UPDATE t1_config SET v=555 WHERE k='version'
}
db close
sqlite3 db test.db
do_catchsql_test 2.2 {
SELECT * FROM t1
} {1 {invalid fts5 file format (found 555, expected 4 or 5) - run 'rebuild'}}
do_catchsql_test 2.3 {
DROP TABLE t1
} {1 {invalid fts5 file format (found 555, expected 4 or 5) - run 'rebuild'}}
do_test 2.4 {
sqlite3_fts5_drop_corrupt_table db main t1
} {}
do_execsql_test 2.5 {
SELECT * FROM sqlite_schema
}
do_execsql_test 3.0 {
CREATE VIRTUAL TABLE t1 USING fts5(x);
}
do_execsql_test 3.1 {
DELETE FROM t1_config;
}
db close
sqlite3 db test.db
do_catchsql_test 3.2 {
SELECT * FROM t1
} {1 {invalid fts5 file format (found 0, expected 4 or 5) - run 'rebuild'}}
do_catchsql_test 3.3 {
DROP TABLE t1
} {1 {invalid fts5 file format (found 0, expected 4 or 5) - run 'rebuild'}}
do_test 3.4 {
sqlite3_db_config db DEFENSIVE 1
} {1}
do_test 3.5 {
sqlite3_fts5_drop_corrupt_table db main t1
} {}
do_test 3.6 {
sqlite3_db_config db DEFENSIVE -1
} {1}
do_execsql_test 3.7 {
SELECT * FROM sqlite_schema
}
finish_test
+2 -2
View File
@@ -86,13 +86,13 @@ do_execsql_test 3.0 {
INSERT INTO e1 VALUES ('just a few words with a / inside');
}
do_execsql_test 3.1 {
SELECT rowid, bm25(e1) FROM e1 WHERE e1 MATCH '"just"' ORDER BY rank;
SELECT rowid, format('%g',bm25(e1)) FROM e1 WHERE e1 MATCH '"just"' ORDER BY rank;
} {1 -1e-06}
do_execsql_test 3.2 {
SELECT rowid FROM e1 WHERE e1 MATCH '"/" OR "just"'
} 1
do_execsql_test 3.3 {
SELECT rowid, bm25(e1) FROM e1 WHERE e1 MATCH '"/" OR "just"' ORDER BY rank;
SELECT rowid, format('%g',bm25(e1)) FROM e1 WHERE e1 MATCH '"/" OR "just"' ORDER BY rank;
} {1 -1e-06}
do_execsql_test 3.4 "
+52
View File
@@ -0,0 +1,52 @@
# 2024 August 8
#
# The author disclaims copyright to this source code. In place of
# a legal notice, here is a blessing:
#
# May you do good and not evil.
# May you find forgiveness for yourself and forgive others.
# May you share freely, never taking more than you give.
#
#*************************************************************************
# This file implements regression tests for SQLite library. The
# focus of this script is testing the FTS5 module.
#
source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5expr
# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 {
finish_test
return
}
do_execsql_test 1.0 {
CREATE VIRTUAL TABLE x1 USING fts5(a);
INSERT INTO x1(rowid, a) VALUES (113, 'fts5 expr test');
}
do_execsql_test 1.1 {
SELECT rowid FROM x1('expr');
} {113}
for {set ii 0} {$ii < 300} {incr ii} {
set expr "expr "
append expr [string repeat "NOT abcd " $ii]
if {$ii<257} {
set res {0 113}
} else {
set res {1 {fts5 expression tree is too large (maximum depth 256)}}
}
do_catchsql_test 1.1.$ii {
SELECT rowid FROM x1($expr)
} $res
}
do_execsql_test 1.2 {
SELECT rowid FROM x1 WHERE a MATCH '"..."'
} {}
finish_test
+1 -1
View File
@@ -90,7 +90,7 @@ set ::res [db eval {SELECT rowid, x1 FROM x1 WHERE x1 MATCH '*reads'}]
do_faultsim_test 4 -faults oom-* -body {
db eval {SELECT rowid, x, x1 FROM x1 WHERE x1 MATCH '*reads'}
} -test {
faultsim_test_result {0 {0 {} 3}}
faultsim_test_result {0 {0 {} 2}}
}
#-------------------------------------------------------------------------
+294
View File
@@ -0,0 +1,294 @@
# 2010 June 15
#
# The author disclaims copyright to this source code. In place of
# a legal notice, here is a blessing:
#
# May you do good and not evil.
# May you find forgiveness for yourself and forgive others.
# May you share freely, never taking more than you give.
#
#***********************************************************************
#
source [file join [file dirname [info script]] fts5_common.tcl]
source $testdir/malloc_common.tcl
set testprefix fts5faultI
# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 {
finish_test
return
}
set ::testprefix fts5faultI
do_execsql_test 1.0 {
PRAGMA encoding = utf16;
CREATE VIRTUAL TABLE t1 USING fts5(x, locale=1);
INSERT INTO t1 VALUES('origintext unicode61 ascii porter trigram');
}
faultsim_save_and_close
faultsim_restore_and_reopen
do_faultsim_test 1 -faults oom* -prep {
} -body {
execsql {
SELECT rowid FROM t1(fts5_locale('en_US', 'origintext'));
}
} -test {
faultsim_test_result {0 1}
}
do_faultsim_test 2 -faults oom* -prep {
faultsim_restore_and_reopen
execsql {
SELECT * FROM t1('ascii');
}
} -body {
execsql {
UPDATE t1 SET rowid=rowid+1;
}
} -test {
faultsim_test_result {0 {}}
}
fts5_aux_test_functions db
do_faultsim_test 3 -faults oom* -prep {
} -body {
execsql {
SELECT fts5_columnlocale(t1, 0) FROM t1('unicode*');
}
} -test {
faultsim_test_result {0 {{}}} {1 SQLITE_NOMEM}
}
#-------------------------------------------------------------------------
reset_db
do_execsql_test 4.0 {
CREATE VIRTUAL TABLE w1 USING fts5(a);
}
faultsim_save_and_close
do_faultsim_test 4 -faults oom* -prep {
faultsim_restore_and_reopen
execsql {
BEGIN;
INSERT INTO w1 VALUES('token token token');
}
} -body {
execsql {
INSERT INTO w1(w1, rank) VALUES('rank', 'bm25()');
}
} -test {
faultsim_test_result {0 {}}
}
do_faultsim_test 5 -faults oom* -prep {
faultsim_restore_and_reopen
execsql {
BEGIN;
INSERT INTO w1 VALUES('one');
SAVEPOINT one;
INSERT INTO w1 VALUES('two');
ROLLBACK TO one;
}
} -body {
execsql {
INSERT INTO w1 VALUES('string');
}
} -test {
faultsim_test_result {0 {}}
}
#-------------------------------------------------------------------------
reset_db
do_execsql_test 5.0 {
CREATE VIRTUAL TABLE w1 USING fts5(a);
INSERT INTO w1 VALUES('one two three');
}
fts5_aux_test_functions db
do_faultsim_test 5 -faults oom* -prep {
} -body {
execsql {
SELECT fts5_test_insttoken(w1, 0, 0) FROM w1('two');
}
} -test {
faultsim_test_result {0 two} {1 SQLITE_NOMEM}
}
#-------------------------------------------------------------------------
reset_db
do_execsql_test 6.0 {
CREATE VIRTUAL TABLE w1 USING fts5(a);
INSERT INTO w1 VALUES('one two three');
}
fts5_aux_test_functions db
faultsim_save_and_close
do_faultsim_test 6 -faults oom* -prep {
faultsim_restore_and_reopen
db eval {
BEGIN;
INSERT INTO w1 VALUES('four five six');
SAVEPOINT abc;
INSERT INTO w1 VALUES('seven eight nine');
SAVEPOINT def;
INSERT INTO w1 VALUES('ten eleven twelve');
}
} -body {
execsql {
RELEASE abc;
}
} -test {
faultsim_test_result {0 {}}
}
#-------------------------------------------------------------------------
reset_db
do_execsql_test 7.0 {
CREATE VIRTUAL TABLE w1 USING fts5(a);
INSERT INTO w1 VALUES('one two three');
INSERT INTO w1 VALUES('three two one');
DELETE FROM w1_content WHERE rowid=1;
}
faultsim_save_and_close
do_faultsim_test 7 -faults oom* -prep {
faultsim_restore_and_reopen
db eval { SELECT * FROM w1 }
} -body {
execsql {
PRAGMA integrity_check;
}
} -test {
}
#-------------------------------------------------------------------------
reset_db
fts5_tclnum_register db
fts5_aux_test_functions db
do_execsql_test 8.0 {
CREATE VIRTUAL TABLE ft USING fts5(
x, tokenize = "tclnum query", detail=columns
);
INSERT INTO ft VALUES('one two three i ii iii');
INSERT INTO ft VALUES('four five six iv v vi');
INSERT INTO ft VALUES('eight nine ten viii ix x');
} {}
do_faultsim_test 8.1 -faults oom* -prep {
} -body {
execsql {
SELECT fts5_test_collist (ft) FROM ft('one two');
}
} -test {
faultsim_test_result {0 {{0.0 1.0}}} {1 {SQL logic error}} {1 SQLITE_NOMEM}
}
do_faultsim_test 8.2 -faults oom* -prep {
} -body {
execsql {
SELECT rowid FROM ft('one two') ORDER BY rank;
}
} -test {
faultsim_test_result {0 1} {1 {SQL logic error}} {1 SQLITE_NOMEM}
}
#-------------------------------------------------------------------------
reset_db
do_execsql_test 9.0 {
CREATE VIRTUAL TABLE ft USING fts5(x);
INSERT INTO ft VALUES('one two three i ii iii');
INSERT INTO ft VALUES('four five six iv v vi');
INSERT INTO ft VALUES('eight nine ten viii ix x');
} {}
faultsim_save_and_close
do_faultsim_test 9.1 -faults oom* -prep {
faultsim_restore_and_reopen
} -body {
execsql {
UPDATE ft SET rowid=4 WHERE rowid=1
}
} -test {
faultsim_test_result {0 {}}
}
do_faultsim_test 9.2 -faults oom* -prep {
faultsim_restore_and_reopen
} -body {
execsql {
SELECT rowid FROM ft WHERE x MATCH 'one AND two AND three'
}
} -test {
faultsim_test_result {0 1}
}
#-------------------------------------------------------------------------
reset_db
do_execsql_test 10.0 {
CREATE VIRTUAL TABLE ft USING fts5(x, locale=1);
INSERT INTO ft VALUES(fts5_locale('hello', 'one two three i ii iii'));
INSERT INTO ft VALUES('four five six iv v vi');
INSERT INTO ft VALUES('eight nine ten viii ix x');
} {}
do_execsql_test 10.1 {
SELECT fts5_get_locale(ft, 0) FROM ft WHERE x MATCH 'one AND two AND three'
} {hello}
faultsim_save_and_close
do_faultsim_test 10.1 -faults oom* -prep {
faultsim_restore_and_reopen
} -body {
execsql {
SELECT fts5_get_locale(ft, 0) FROM ft WHERE x MATCH 'one AND two AND three'
}
} -test {
faultsim_test_result {0 hello}
}
breakpoint
faultsim_save_and_close
do_faultsim_test 10.2 -faults oom-t* -prep {
faultsim_restore_and_reopen
} -body {
execsql {
INSERT INTO ft VALUES(zeroblob(10000));
}
} -test {
faultsim_test_result {0 {}}
}
#-------------------------------------------------------------------------
reset_db
do_execsql_test 11.0 {
CREATE VIRTUAL TABLE f1 USING fts5(content);
CREATE TABLE g1(id, content);
INSERT INTO g1 VALUES(30000, 'a b c');
INSERT INTO g1 VALUES(40000, 'd e f');
}
faultsim_save_and_close
do_faultsim_test 11 -faults oom* -prep {
faultsim_restore_and_reopen
} -body {
execsql {
INSERT INTO f1(rowid, content) SELECT id, content FROM g1;
}
} -test {
faultsim_test_result {0 {}}
}
finish_test
+1
View File
@@ -22,6 +22,7 @@ do_execsql_test 1.0 {
CREATE VIRTUAL TABLE x1 USING fts5(a, b);
}
unset -nocomplain res
foreach {tn expr ok} {
1 {^abc} 1
2 {^abc + def} 1
+1
View File
@@ -153,6 +153,7 @@ do_execsql_test 5.3 {
INSERT INTO gg(gg) VALUES('integrity-check');
}
unset -nocomplain res
do_test 5.4.1 {
set ok 0
for {set i 0} {$i < 10000} {incr i} {
+56
View File
@@ -0,0 +1,56 @@
# 2024 September 3
#
# The author disclaims copyright to this source code. In place of
# a legal notice, here is a blessing:
#
# May you do good and not evil.
# May you find forgiveness for yourself and forgive others.
# May you share freely, never taking more than you give.
#
#***********************************************************************
#
# This file contains tests focused on the integrity-check procedure.
#
source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5integrity2
# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 {
finish_test
return
}
do_execsql_test 2.0 {
CREATE VIRTUAL TABLE t2 USING fts5(a, detail='none');
BEGIN;
INSERT INTO t2(rowid, a) VALUES(-1, 'hello world');
INSERT INTO t2(rowid, a) VALUES(9223372036854775807, 'hello world');
COMMIT;
}
do_execsql_test 2.1 {
SELECT rowid FROM t2('hello AND world');
} {-1 9223372036854775807}
#-------------------------------------------------------------------------
do_execsql_test 2.0 {
CREATE VIRTUAL TABLE t1 USING fts5(a, detail='none');
CREATE TABLE r1(r);
WITH c(x) AS (VALUES(1) UNION SELECT x<<1 FROM c)
INSERT INTO r1(r) SELECT -1-x FROM c;
INSERT INTO t1(rowid, a) SELECT r, 'abc' FROM r1;
}
do_execsql_test 2.1 {
PRAGMA integrity_check;
} {ok}
do_execsql_test 2.2 {
SELECT rowid FROM t1('abc') ORDER BY +rowid;
} [db eval {SELECT r FROM r1 ORDER BY r}]
finish_test
+1 -1
View File
@@ -33,6 +33,7 @@ proc progress_handler {args} {
return 0
}
unset -nocomplain res
foreach {tn sql} {
1 { INSERT INTO t1(rowid, a) VALUES(0, 'z z z z') }
2 { COMMIT }
@@ -64,4 +65,3 @@ foreach {tn sql} {
}
finish_test
+748
View File
@@ -0,0 +1,748 @@
# 2014 Dec 20
#
# The author disclaims copyright to this source code. In place of
# a legal notice, here is a blessing:
#
# May you do good and not evil.
# May you find forgiveness for yourself and forgive others.
# May you share freely, never taking more than you give.
#
#***********************************************************************
#
# Tests focusing on the built-in fts5 tokenizers.
#
source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5locale
# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 {
finish_test
return
}
proc transform_token {locale token} {
switch -- $locale {
reverse {
set ret ""
foreach c [split $token ""] {
set ret "$c$ret"
}
set token $ret
}
default {
# no-op
}
}
set token
}
proc tcl_create {args} { return "tcl_tokenize" }
proc tcl_tokenize {tflags text} {
set iToken 1
set bSkip 0
if {[sqlite3_fts5_locale]=="second"} { set bSkip 1 }
foreach {w iStart iEnd} [fts5_tokenize_split $text] {
incr iToken
if {(($iToken) % ($bSkip + 1))} continue
set w [transform_token [sqlite3_fts5_locale] $w]
sqlite3_fts5_token $w $iStart $iEnd
}
}
#-------------------------------------------------------------------------
# Check that queries can have a locale attached to them.
#
reset_db
sqlite3_fts5_create_tokenizer -v2 db tcl tcl_create
do_execsql_test 1.0 {
CREATE VIRTUAL TABLE t1 USING fts5(a, tokenize=tcl);
INSERT INTO t1 VALUES('abc');
INSERT INTO t1 VALUES('cba');
} {}
do_execsql_test 1.1 {
SELECT rowid, a FROM t1( fts5_locale('en_US', 'abc') );
} {1 abc}
do_execsql_test 1.2 {
SELECT rowid, a FROM t1( fts5_locale('reverse', 'abc') );
} {2 cba}
#-------------------------------------------------------------------------
# Test that the locale= option exists and seems to accept values. And
# that fts5_locale() values may only be inserted into an internal-content
# table if the locale=1 option was specified.
#
reset_db
sqlite3_fts5_create_tokenizer -v2 db tcl tcl_create
do_execsql_test 2.1 {
CREATE VIRTUAL TABLE b1 USING fts5(x, y, locale=1, tokenize=tcl);
CREATE VIRTUAL TABLE b2 USING fts5(x, y, locale=0, tokenize=tcl);
CREATE VIRTUAL TABLE ttt USING fts5vocab('b1', instance);
}
do_catchsql_test 2.2.1 {
CREATE VIRTUAL TABLE b3 USING fts5(x, y, locale=2);
} {1 {malformed locale=... directive}}
do_catchsql_test 2.2.2 {
CREATE VIRTUAL TABLE b3 USING fts5(x, y, locale=111);
} {1 {malformed locale=... directive}}
do_catchsql_test 2.3 {
INSERT INTO b1(b1, rank) VALUES('locale', 0);
} {1 {SQL logic error}}
do_execsql_test 2.4.1 {
INSERT INTO b1 VALUES('abc', 'one two three');
}
do_execsql_test 2.4.2 {
INSERT INTO b1 VALUES('def', fts5_locale('reverse', 'four five six'));
}
do_execsql_test 2.5 {
INSERT INTO b2 VALUES('abc', 'one two three');
}
do_catchsql_test 2.6 {
INSERT INTO b2 VALUES('def', fts5_locale('reverse', 'four five six'));
} {1 {fts5_locale() requires locale=1}}
do_execsql_test 2.7 { SELECT rowid FROM b1('one') } {1}
do_execsql_test 2.8 { SELECT rowid FROM b1('four') } {}
do_execsql_test 2.9 { SELECT rowid FROM b1('ruof') } 2
do_execsql_test 2.10 { SELECT rowid FROM b1(fts5_locale('reverse', 'five'))} 2
do_execsql_test 2.11 {
SELECT x, quote(y) FROM b1
} {
abc {'one two three'}
def {'four five six'}
}
do_execsql_test 2.12 { SELECT quote(y) FROM b1('ruof') } {
{'four five six'}
}
do_execsql_test 2.13 {
INSERT INTO b1(b1) VALUES('integrity-check');
}
do_execsql_test 2.14 {
INSERT INTO b1(b1) VALUES('rebuild');
}
do_execsql_test 2.15 {
INSERT INTO b1(b1) VALUES('integrity-check');
}
do_execsql_test 2.16 {
DELETE FROM b1 WHERE rowid=2
}
do_execsql_test 2.17 {
INSERT INTO b1(b1) VALUES('integrity-check');
}
do_execsql_test 2.18 {
INSERT INTO b1(rowid, x, y) VALUES(
test_setsubtype(45, 76), 'abc def', 'def abc'
);
}
#-------------------------------------------------------------------------
# Test the 'delete' command with contentless tables.
#
reset_db
sqlite3_fts5_create_tokenizer -v2 db tcl tcl_create
do_execsql_test 3.1 {
CREATE VIRTUAL TABLE c1 USING fts5(x, content=, tokenize=tcl, locale=1);
CREATE VIRTUAL TABLE c2 USING fts5vocab('c1', instance);
INSERT INTO c1 VALUES('hello world');
INSERT INTO c1 VALUES( fts5_locale('reverse', 'one two three') );
}
do_execsql_test 3.2 {
SELECT DISTINCT term FROM c2 ORDER BY 1
} {
eerht eno hello owt world
}
do_execsql_test 3.3 {
INSERT INTO c1(c1, rowid, x)
VALUES('delete', 2, fts5_locale('reverse', 'one two three') );
}
do_execsql_test 3.4 {
SELECT DISTINCT term FROM c2 ORDER BY 1
} {
hello world
}
#-------------------------------------------------------------------------
# Test that an UPDATE that updates a subset of the columns does not
# magically discard the locale from those columns not updated.
#
reset_db
sqlite3_fts5_create_tokenizer -v2 db tcl tcl_create
do_execsql_test 4.1 {
CREATE VIRTUAL TABLE d1 USING fts5(x, y, locale=1, tokenize=tcl);
CREATE VIRTUAL TABLE d2 USING fts5vocab('d1', instance);
INSERT INTO d1(rowid, x, y) VALUES(1, 'abc', 'def');
INSERT INTO d1(rowid, x, y) VALUES(2, 'ghi', fts5_locale('reverse', 'hello'));
}
do_execsql_test 4.2 {
SELECT DISTINCT term FROM d2 ORDER BY 1
} {
abc def ghi olleh
}
do_execsql_test 4.3 {
UPDATE d1 SET x='jkl' WHERE rowid=2;
}
do_execsql_test 4.4 {
SELECT DISTINCT term FROM d2 ORDER BY 1
} {
abc def jkl olleh
}
do_execsql_test 4.5 {
SELECT rowid, * FROM d1
} {
1 abc def
2 jkl hello
}
do_execsql_test 4.6 {
UPDATE d1 SET rowid=4 WHERE rowid=2
}
do_execsql_test 4.7 {
SELECT rowid, * FROM d1
} {
1 abc def
4 jkl hello
}
fts5_aux_test_functions db
do_execsql_test 4.8.1 {
SELECT fts5_test_columntext(d1) FROM d1('jkl')
} {{jkl hello}}
do_execsql_test 4.8.2 {
SELECT fts5_test_columntext(d1) FROM d1(fts5_locale('reverse', 'hello'))
} {{jkl hello}}
do_execsql_test 4.9 {
SELECT fts5_test_columnlocale(d1) FROM d1(fts5_locale('reverse', 'hello'))
} {{{} reverse}}
do_execsql_test 4.10 {
SELECT fts5_test_columnlocale(d1) FROM d1
} {
{{} {}}
{{} reverse}
}
#-------------------------------------------------------------------------
# Test that if an fts5_locale() value is written to an UNINDEXED
# column it is stored as text. This is so that blobs and other values
# can also be stored as is.
#
reset_db
sqlite3_fts5_create_tokenizer -v2 db tcl tcl_create
do_execsql_test 5.1 {
CREATE VIRTUAL TABLE t1 USING fts5(
x, y UNINDEXED, locale=1, tokenize=tcl
);
INSERT INTO t1(rowid, x, y) VALUES(111,
fts5_locale('reverse', 'one two three'),
fts5_locale('reverse', 'four five six')
);
}
do_execsql_test 5.2 {
SELECT rowid, x, y FROM t1
} {
111 {one two three} {four five six}
}
do_execsql_test 5.3 {
SELECT typeof(c0), typeof(c1), typeof(l0) FROM t1_content
} {
text text text
}
#-------------------------------------------------------------------------
foreach {tn opt} {
1 {}
2 {, columnsize=0}
} {
reset_db
sqlite3_fts5_create_tokenizer -v2 db tcl tcl_create
do_execsql_test 6.$tn.1 "
CREATE VIRTUAL TABLE y1 USING fts5(t, locale=1, tokenize=tcl $opt);
"
do_execsql_test 6.$tn.2 {
INSERT INTO y1(rowid, t) VALUES
(1, fts5_locale('second', 'the city of London')),
(2, fts5_locale('second', 'shall have all the old')),
(3, fts5_locale('second', 'Liberties and Customs')),
(4, fts5_locale('second', 'which it hath been used to have'));
}
fts5_aux_test_functions db
do_execsql_test 6.$tn.3 {
SELECT fts5_test_columnsize(y1) FROM y1
} {
2 3 2 4
}
do_execsql_test 6.$tn.4 {
SELECT rowid, fts5_test_columnsize(y1) FROM y1('shall');
} {
2 3
}
do_execsql_test 6.$tn.5 {
SELECT rowid, fts5_test_columnsize(y1) FROM y1('shall');
} {
2 3
}
do_execsql_test 6.$tn.6 {
SELECT rowid, fts5_test_columnsize(y1) FROM y1('have');
} {
4 4
}
do_execsql_test 6.$tn.7 {
SELECT rowid, highlight(y1, 0, '[', ']') FROM y1('have');
} {
4 {which it hath been used to [have]}
}
do_execsql_test 6.$tn.8 {
SELECT rowid,
highlight(y1, 0, '[', ']'),
snippet(y1, 0, '[', ']', '...', 10)
FROM y1('Liberties + Customs');
} {
3 {[Liberties and Customs]}
{[Liberties and Customs]}
}
}
#-------------------------------------------------------------------------
reset_db
do_execsql_test 6.0 {
CREATE VIRTUAL TABLE x1 USING fts5(x);
}
do_catchsql_test 6.1 {
INSERT INTO x1(rowid, x) VALUES(123, fts5_locale('en_AU', 'hello world'));
} {1 {fts5_locale() requires locale=1}}
do_execsql_test 6.2 {
SELECT typeof( fts5_locale(NULL, 'xyz') ), typeof( fts5_locale('', 'abc') );
} {text text}
#--------------------------------------------------------------------------
# Test that fts5_locale() works with external-content tables.
#
reset_db
sqlite3_fts5_create_tokenizer -v2 db tcl tcl_create
do_execsql_test 7.1 {
CREATE TABLE t1(ii INTEGER PRIMARY KEY, bb BLOB, tt TEXT, locale TEXT);
CREATE VIEW v1 AS
SELECT ii AS rowid, bb, fts5_locale(locale, tt) AS tt FROM t1;
CREATE VIRTUAL TABLE ft USING fts5(
bb, tt, locale=1, tokenize=tcl, content=v1
);
INSERT INTO t1 VALUES(1, NULL, 'one two three', NULL);
INSERT INTO t1 VALUES(2, '7800616263', 'four five six', 'reverse');
INSERT INTO t1 VALUES(3, '000000007800616263', 'seven eight nine', 'second');
}
do_execsql_test 7.2 {
INSERT INTO ft(ft) VALUES('rebuild');
INSERT INTO ft(ft) VALUES('integrity-check');
}
do_execsql_test 7.3 {
SELECT rowid, quote(bb), quote(tt) FROM ft
} {
1 NULL {'one two three'}
2 '7800616263' {'four five six'}
3 '000000007800616263' {'seven eight nine'}
}
do_execsql_test 7.4 { SELECT rowid FROM ft('six'); }
do_execsql_test 7.5 { SELECT rowid FROM ft(fts5_locale('reverse','six')); } 2
fts5_aux_test_functions db
do_execsql_test 7.6 {
SELECT fts5_test_columnlocale(ft) FROM ft;
} {
{{} {}} {{} reverse} {{} second}
}
#-------------------------------------------------------------------------
# Test that the porter tokenizer works with locales.
#
reset_db
sqlite3_fts5_create_tokenizer -v2 db tcl tcl_create
do_execsql_test 8.1 {
CREATE VIRTUAL TABLE ft USING fts5(tt, locale=1, tokenize="porter tcl");
CREATE VIRTUAL TABLE vocab USING fts5vocab('ft', instance);
INSERT INTO ft(rowid, tt) VALUES
(111, fts5_locale('second', 'the porter tokenizer is a wrapper tokenizer')),
(222, fts5_locale('reverse', 'This value may also be set'));
}
do_execsql_test 8.1 {
SELECT DISTINCT term FROM vocab ORDER BY 1
} {
a eb eulav osla sihT te the token yam
}
#-------------------------------------------------------------------------
# Test that position-lists (used by xInst, xPhraseFirst etc.) work with
# locales and modes other than detail=full.
#
foreach {tn detail} {
1 detail=full
2 detail=none
3 detail=column
} {
reset_db
sqlite3_fts5_create_tokenizer -v2 db tcl tcl_create
do_execsql_test 9.$tn.0 "
CREATE VIRTUAL TABLE ft USING fts5(tt, locale=1, tokenize=tcl, $detail);
"
do_execsql_test 9.$tn.1 {
CREATE VIRTUAL TABLE vocab USING fts5vocab('ft', instance);
INSERT INTO ft(rowid, tt) VALUES
(-1, fts5_locale('second', 'it is an ancient mariner'));
}
do_execsql_test 9.$tn.2 {
SELECT DISTINCT term FROM vocab
} {an it mariner}
do_execsql_test 9.$tn.3 {
SELECT highlight(ft, 0, '[', ']') FROM ft('mariner')
} {{it is an ancient [mariner]}}
}
#-------------------------------------------------------------------------
# Check some corrupt fts5_locale() blob formats are detected.
#
foreach_detail_mode $::testprefix {
reset_db
sqlite3_fts5_create_tokenizer -v2 db tcl tcl_create
fts5_aux_test_functions db
do_execsql_test 10.1 {
CREATE TABLE x1(ii INTEGER PRIMARY KEY, x);
CREATE VIRTUAL TABLE ft USING fts5(x,
content=x1, content_rowid=ii, locale=1, detail=%DETAIL%, columnsize=0
);
CREATE VIRTUAL TABLE ft2 USING fts5(
x, locale=1, detail=%DETAIL%, columnsize=0
);
}
foreach {tn v} {
1 X'001152'
2 X'0011223344'
3 X'00E0B2EB68656c6c6f'
4 X'00E0B2EB0068656c6c6f'
} {
do_execsql_test 10.2.$tn.0 { INSERT INTO ft(ft) VALUES('delete-all') }
do_execsql_test 10.2.$tn.1 { DELETE FROM x1; }
do_execsql_test 10.2.$tn.2 " INSERT INTO x1 VALUES(NULL, $v) "
do_catchsql_test 10.2.$tn.3 {
INSERT INTO ft(ft) VALUES('rebuild');
} {0 {}}
do_catchsql_test 10.2.$tn.4 "
SELECT * FROM ft( test_setsubtype($v, 76) );
" {1 {fts5: syntax error near ""}}
do_execsql_test 10.2.$tn.5 {
INSERT INTO ft(rowid, x) VALUES(1, 'hello world');
}
if {"%DETAIL%"=="full"} {
do_execsql_test 10.2.$tn.6 {
SELECT fts5_test_poslist(ft) FROM ft('world');
} {0.0.1}
do_execsql_test 10.2.$tn.7.1 {
SELECT fts5_test_columnsize(ft) FROM ft('world');
} {1}
do_execsql_test 10.2.$tn.7.2 {
SELECT fts5_test_columnlocale(ft) FROM ft('world');
} {{{}}}
}
do_catchsql_test 10.2.$tn.8 {
SELECT count(*) FROM ft('hello')
} {0 1}
do_catchsql_test 10.2.$tn.9 {
PRAGMA integrity_check;
} {0 ok}
do_execsql_test 10.2.$tn.10 {
DELETE FROM x1;
INSERT INTO x1(ii, x) VALUES(1, 'hello world');
}
do_catchsql_test 10.2.$tn.11 "
INSERT INTO ft(ft, rowid, x) VALUES('delete', 1, test_setsubtype($v,76) )
" {0 {}}
do_catchsql_test 10.2.$tn.12 "
INSERT INTO ft(rowid, x) VALUES(2, test_setsubtype($v,76) )
" {0 {}}
do_execsql_test 10.2.$tn.13 {
INSERT INTO ft2(rowid, x) VALUES(1, 'hello world');
}
do_execsql_test 10.2.$tn.14 "UPDATE ft2_content SET c0=$v"
do_catchsql_test 10.2.$tn.15 {
PRAGMA integrity_check;
} {0 {{malformed inverted index for FTS5 table main.ft2}}}
do_execsql_test 10.2.$tn.16 {
DELETE FROM ft2_content;
INSERT INTO ft2(ft2) VALUES('rebuild');
}
}
}
#-------------------------------------------------------------------------
#
reset_db
sqlite3_fts5_create_tokenizer -v2 db tcl tcl_create
fts5_aux_test_functions db
do_execsql_test 11.0 {
CREATE VIRTUAL TABLE x1 USING fts5(abc, locale=1);
INSERT INTO x1(rowid, abc) VALUES(123, fts5_locale('en_US', 'one two three'));
}
do_catchsql_test 11.1 {
SELECT fts5_columnlocale(x1, -1) FROM x1('two');
} {1 SQLITE_RANGE}
do_catchsql_test 11.2 {
SELECT fts5_columnlocale(x1, 1) FROM x1('two');
} {1 SQLITE_RANGE}
#-------------------------------------------------------------------------
#
reset_db
do_test 12.0 {
list [catch {
sqlite3_fts5_create_tokenizer -v2 -version 3 db tcl tcl_create
} msg] $msg
} {1 {error in fts5_api.xCreateTokenizer_v2()}}
#-------------------------------------------------------------------------
# Tests for auxiliary function fts5_get_locale().
#
reset_db
# Check that if the table does not support locale=1, fts5_get_locale()
# always returns NULL.
do_execsql_test 13.1.0 {
CREATE VIRTUAL TABLE nolocale USING fts5(a, b);
INSERT INTO nolocale VALUES('one two three', 'four five six');
INSERT INTO nolocale VALUES('three two one', 'seven eight nine');
}
do_execsql_test 13.1.1 {
SELECT fts5_get_locale(nolocale, 0) IS NULL FROM nolocale;
} {1 1}
do_execsql_test 13.1.2 {
SELECT fts5_get_locale(nolocale, 1) IS NULL FROM nolocale('one + two');
} {1}
do_execsql_test 13.1.3 {
SELECT fts5_get_locale(nolocale, 0) IS NULL FROM nolocale('one AND two');
} {1 1}
do_execsql_test 13.1.4 {
SELECT
fts5_get_locale(nolocale, 1) IS NULL
FROM nolocale('three AND two') ORDER BY rank
} {1 1}
do_catchsql_test 13.1.5 {
SELECT fts5_get_locale(nolocale, 2) IS NULL FROM nolocale('three AND two');
} {1 {column index out of range}}
do_catchsql_test 13.1.6 {
SELECT fts5_get_locale(nolocale, -1) IS NULL FROM nolocale('three AND two');
} {1 {column index out of range}}
do_catchsql_test 13.1.7 {
SELECT fts5_get_locale(nolocale) IS NULL FROM nolocale('three AND two');
} {1 {wrong number of arguments to function fts5_get_locale()}}
do_catchsql_test 13.1.8 {
SELECT fts5_get_locale(nolocale, 0, 0) IS NULL FROM nolocale('three AND two');
} {1 {wrong number of arguments to function fts5_get_locale()}}
do_catchsql_test 13.1.9 {
SELECT fts5_get_locale(nolocale, 'text') FROM nolocale('three AND two');
} {1 {non-integer argument passed to function fts5_get_locale()}}
# Check that if the table does support locale=1, fts5_get_locale()
# returns the locale of the identified row/column.
do_execsql_test 13.2.0 {
CREATE VIRTUAL TABLE ft USING fts5(a, b, locale=1);
INSERT INTO ft VALUES(
fts5_locale('th_TH', 'one two three'), 'four five six seven'
);
INSERT INTO ft VALUES(
'three two one', fts5_locale('en_AU', 'seven eight nine')
);
}
do_execsql_test 13.2.1 {
SELECT quote(fts5_get_locale(ft, 0)), quote(fts5_get_locale(ft, 1)) FROM ft
} { 'th_TH' NULL NULL 'en_AU' }
do_execsql_test 13.2.2 {
SELECT
quote(fts5_get_locale(ft, 0)), quote(fts5_get_locale(ft, 1))
FROM ft('one AND three')
} { 'th_TH' NULL NULL 'en_AU' }
do_execsql_test 13.2.3 {
SELECT
quote(fts5_get_locale(ft, 0)), quote(fts5_get_locale(ft, 1))
FROM ft('one AND three') ORDER BY rank
} { NULL 'en_AU' 'th_TH' NULL }
do_execsql_test 13.2.4 {
SELECT
quote(fts5_get_locale(ft, 0)), quote(fts5_get_locale(ft, 1))
FROM ft('one AND three') ORDER BY rowid
} { 'th_TH' NULL NULL 'en_AU' }
do_execsql_test 13.2.5 {
SELECT
quote(fts5_get_locale(ft, '0')), quote(fts5_get_locale(ft, 1))
FROM ft('one AND three') ORDER BY rowid
} { 'th_TH' NULL NULL 'en_AU' }
do_catchsql_test 13.2.6 {
SELECT
quote(fts5_get_locale(ft, '0.0')), quote(fts5_get_locale(ft, 1))
FROM ft('one AND three') ORDER BY rowid
} {1 {non-integer argument passed to function fts5_get_locale()}}
do_catchsql_test 13.2.7 {
SELECT
quote(fts5_get_locale(ft, 0.0)), quote(fts5_get_locale(ft, 1))
FROM ft('one AND three') ORDER BY rowid
} {1 {non-integer argument passed to function fts5_get_locale()}}
#-------------------------------------------------------------------------
# Check that UPDATE statements that may affect more than one row work.
#
reset_db
do_execsql_test 14.1 {
CREATE VIRTUAL TABLE ft USING fts5(a, b, locale=1);
}
do_execsql_test 14.2 {
INSERT INTO ft VALUES('hello', 'world');
}
do_execsql_test 14.3 {
UPDATE ft SET b = fts5_locale('en_AU', 'world');
}
do_execsql_test 14.4 {
INSERT INTO ft VALUES(X'abcd', X'1234');
} {}
do_execsql_test 14.5 {
SELECT quote(a), quote(b) FROM ft
} {'hello' 'world' X'ABCD' X'1234'}
do_execsql_test 14.6 {
DELETE FROM ft;
INSERT INTO ft VALUES(NULL, 'null');
INSERT INTO ft VALUES(123, 'int');
INSERT INTO ft VALUES(345.0, 'real');
INSERT INTO ft VALUES('abc', 'text');
INSERT INTO ft VALUES(fts5_locale('abc', 'def'), 'text');
SELECT a, typeof(a), b FROM ft
} {
{} null null
123 integer int
345.0 real real
abc text text
def text text
}
do_execsql_test 14.7 {
SELECT quote(c0), typeof(c0) FROM ft_content
} {
NULL null
123 integer
345.0 real
'abc' text
'def' text
}
#-------------------------------------------------------------------------
# Check that inserting UNINDEXED columns between indexed columns of a
# locale=1 table does not cause a problem.
#
reset_db
sqlite3_fts5_create_tokenizer -v2 db tcl tcl_create
fts5_aux_test_functions db
do_execsql_test 15.1 {
CREATE VIRTUAL TABLE ft USING fts5(a, b UNINDEXED, c, locale=1, tokenize=tcl);
}
do_execsql_test 15.2 {
INSERT INTO ft VALUES('one', 'two', 'three');
INSERT INTO ft VALUES('one', 'two', fts5_locale('loc', 'three'));
}
do_execsql_test 15.3 {
SELECT c2, l2 FROM ft_content
} {three {} three loc}
do_execsql_test 15.4 {
SELECT c, fts5_columnlocale(ft, 2) FROM ft
} {three {} three loc}
finish_test
+104 -5
View File
@@ -35,21 +35,21 @@ do_catchsql_test 1.1.2 {
do_catchsql_test 1.2.1 {
SELECT highlight(t1, 4, '<b>', '</b>') FROM t1('*id');
} {0 {{}}}
} {1 {no such cursor: 4}}
do_catchsql_test 1.2.2 {
SELECT a FROM t1
WHERE rank = (SELECT highlight(t1, 4, '<b>', '</b>') FROM t1('*id'));
} {0 {}}
} {1 {no such cursor: 6}}
do_catchsql_test 1.3.1 {
SELECT highlight(t1, 4, '<b>', '</b>') FROM t1('*reads');
} {1 {no such cursor: 2}}
} {1 {no such cursor: 0}}
do_catchsql_test 1.3.2 {
SELECT a FROM t1
WHERE rank = (SELECT highlight(t1, 4, '<b>', '</b>') FROM t1('*reads'));
} {1 {no such cursor: 2}}
} {1 {no such cursor: 0}}
db close
sqlite3 db test.db
@@ -57,7 +57,12 @@ sqlite3 db test.db
do_catchsql_test 1.3.3 {
SELECT a FROM t1
WHERE rank = (SELECT highlight(t1, 4, '<b>', '</b>') FROM t1('*reads'));
} {1 {no such cursor: 1}}
} {1 {no such cursor: 0}}
fts5_aux_test_functions db
do_catchsql_test 1.3.4 {
SELECT fts5_columntext(t1) FROM t1('*reads');
} {1 {no such cursor: 0}}
#-------------------------------------------------------------------------
reset_db
@@ -566,5 +571,99 @@ do_execsql_test 20.5 {
SELECT rowid FROM x1 WHERE x1 MATCH 'z' OR (x1 MATCH 'a' AND x1 MATCH 'd');
} {3 1}
#-------------------------------------------------------------------------
reset_db
do_execsql_test 21.0 {
CREATE TABLE t1(ii INTEGER, x TEXT, y TEXT);
CREATE VIRTUAL TABLE xyz USING fts5(content_rowid=ii, content=t1, x, y);
INSERT INTO t1 VALUES(1, 'one', 'i');
INSERT INTO t1 VALUES(2, 'two', 'ii');
INSERT INTO t1 VALUES(3, 'tree', 'iii');
INSERT INTO xyz(xyz) VALUES('rebuild');
}
do_execsql_test 21.1 {
UPDATE xyz SET y='TWO' WHERE rowid=2;
UPDATE t1 SET y='TWO' WHERE ii=2;
}
do_execsql_test 21.2 {
PRAGMA integrity_check
} {ok}
breakpoint
sqlite3_db_config db DEFENSIVE 1
do_execsql_test 21.3 {
CREATE TABLE xyz_notashadow(x, y);
DROP TABLE xyz_notashadow;
}
sqlite3_db_config db DEFENSIVE 0
#-------------------------------------------------------------------------
reset_db
do_execsql_test 22.0 {
SELECT fts5(NULL);
} {{}}
do_execsql_test 22.1 {
SELECT count(*) FROM (
SELECT fts5_source_id()
)
} {1}
execsql_pp {
SELECT fts5_source_id()
}
#-------------------------------------------------------------------------
reset_db
do_execsql_test 23.0 {
CREATE VIRTUAL TABLE x1 USING fts5(x);
INSERT INTO x1 VALUES('one + two + three');
INSERT INTO x1 VALUES('one + xyz + three');
INSERT INTO x1 VALUES('xyz + two + xyz');
}
do_execsql_test 23.1 {
SELECT rowid FROM x1('one + two + three');
} {1}
do_execsql_test 23.2 {
SELECT rowid FROM x1('^".." AND one');
} {}
do_execsql_test 23.3 {
SELECT rowid FROM x1('abc NEAR ".." NEAR def');
} {}
#-------------------------------------------------------------------------
reset_db
do_execsql_test 24.0 {
CREATE VIRTUAL TABLE t1 USING fts5(a, detail='none');
INSERT INTO t1(a) VALUES('a');
}
do_execsql_test 24.2 {
SELECT rank FROM ( SELECT rank FROM t1('a NOT "" NOT def') ) ORDER BY 1;
} {-1e-06}
do_execsql_test 24.3 {
SELECT rank FROM ( SELECT rank FROM t1('a NOT NOT def') ) ORDER BY 1;
} {-1e-06}
do_execsql_test 24.4 {
SELECT rank FROM ( SELECT rank FROM t1('a NOT "" NOT def') );
} {-1e-06}
#-------------------------------------------------------------------------
reset_db
fts5_aux_test_functions db
do_execsql_test 25.0 {
CREATE VIRTUAL TABLE t1 USING fts5(a, detail='none', content='');
INSERT INTO t1(a) VALUES('a b c');
}
do_execsql_test 25.0 {
SELECT fts5_test_poslist(t1) FROM t1('b') ORDER BY rank;
} {{}}
finish_test
+18 -2
View File
@@ -261,8 +261,8 @@ do_execsql_test 5.3 {
reset_db
sqlite3_fts5_register_origintext db
do_execsql_test 6.0 {
CREATE VIRTUAL TABLE ft USING fts5(
x, y, tokenize='origintext unicode61', detail=%DETAIL%
CREATE VIRTUAL TABLE ft USING fts5(
x, y, tokenize='origintext unicode61', detail=%DETAIL%, tokendata=0
);
INSERT INTO ft VALUES('One Two', 'Three two');
@@ -291,6 +291,22 @@ do_execsql_test 6.3 {
SELECT rowid, tokens(ft) FROM ft('Three*');
} {1 {{}} 2 {{}}}
fts5_aux_test_functions db
do_catchsql_test 6.4 {
SELECT fts5_test_insttoken(ft, -1, 0) FROM ft('one');
} {1 SQLITE_RANGE}
do_catchsql_test 6.5 {
SELECT fts5_test_insttoken(ft, 1, 0) FROM ft('one');
} {1 SQLITE_RANGE}
do_catchsql_test 6.6 {
CREATE VIRTUAL TABLE ft2 USING fts5(x, tokendata=2);
} {1 {malformed tokendata=... directive}}
do_catchsql_test 6.7 {
CREATE VIRTUAL TABLE ft2 USING fts5(x, content='', tokendata=11);
} {1 {malformed tokendata=... directive}}
}
finish_test
+11 -5
View File
@@ -93,15 +93,21 @@ foreach {tn cols tokens} {
10 {b} "i e"
11 {a} "i e"
} {
set fts "{$cols}:[join $tokens +]"
set where [list]
foreach c $cols { lappend where "pmatch($c, '$tokens')" }
set where [join $where " OR "]
set res [db eval "SELECT rowid FROM t3 WHERE $where"]
do_execsql_test "1.$tn.$fts->([llength $res] rows)" {
SELECT rowid FROM t3($fts)
} $res
foreach fts [list \
"{$cols}:[join $tokens +]" \
"{$cols}:NEAR([join $tokens +])" \
"{$cols}:NEAR([join $tokens +],1)" \
"{$cols}:NEAR([join $tokens +],111)" \
] {
set res [db eval "SELECT rowid FROM t3 WHERE $where"]
do_execsql_test "1.$tn.$fts->([llength $res] rows)" {
SELECT rowid FROM t3($fts)
} $res
}
}
do_execsql_test 2.0 {
+1
View File
@@ -29,6 +29,7 @@ do_execsql_test 1.0 {
# Run the 'optimize' command. Check that it does not disturb ongoing
# full-text queries.
#
unset -nocomplain lRowid
do_test 1.1 {
for {set i 1} {$i < 1000} {incr i} {
execsql { INSERT INTO f1 VALUES('a b c d e') }
+4
View File
@@ -58,6 +58,10 @@ do_execsql_test 2.1 {
pragma quick_check;
} {ok}
do_catchsql_test 2.2 {
INSERT INTO xyz(xyz, rank) VALUES('secure-delete', 'hello world');
} {1 {SQL logic error}}
+30 -1
View File
@@ -350,7 +350,7 @@ do_execsql_test 14.3 {
do_execsql_test 14.4 {
SELECT rowid, x, x1 FROM x1 WHERE x1 MATCH '*reads'
} {0 {} 3}
} {0 {} 2}
#-------------------------------------------------------------------------
reset_db
@@ -480,4 +480,33 @@ do_execsql_test 22.0 {
do_catchsql_test 22.1 {SELECT * FROM x1('')} {1 {fts5: syntax error near ""}}
do_catchsql_test 22.2 {SELECT * FROM x1(NULL)} {1 {fts5: syntax error near ""}}
#-------------------------------------------------------------------------
reset_db
do_execsql_test 23.0 {
CREATE VIRTUAL TABLE x1 USING fts5(x);
SELECT count(*) FROM x1_data;
} {2}
do_execsql_test 23.1 {
BEGIN;
INSERT INTO x1 VALUES('a b c d');
INSERT INTO x1 VALUES('a b c d');
INSERT INTO x1 VALUES('a b c d');
}
do_execsql_test 23.2 {
SELECT count(*) FROM x1_data;
} {2}
do_execsql_test 23.3 {
INSERT INTO x1(x1) VALUES('flush');
SELECT count(*) FROM x1_data;
} {3}
do_execsql_test 23.4 {
ROLLBACK;
SELECT count(*) FROM x1_data;
} {2}
finish_test
+20
View File
@@ -85,5 +85,25 @@ do_execsql_test 1.7 {
SELECT highlight(t1, 0, '>', '<') FROM t1('BB mess');
} {AAdont>BBmess<}
# 2024-08-06 https://sqlite.org/forum/forumpost/171bcc2bcd
# Error handling of tokenize= arguments.
#
foreach {n tkz} {
1 {ascii none}
2 {unicode61 none}
3 {porter none}
4 {trigram none}
5 {ascii none 0}
6 {unicode61 none 0}
7 {porter none 0}
8 {trigram none 0}
} {
db eval {DROP TABLE IF EXISTS t2;}
do_catchsql_test 2.$n "
DROP TABLE IF EXISTS t2;
CREATE VIRTUAL TABLE t2 USING fts5(a,b,c,tokenize='$tkz');
" {1 {error in tokenizer constructor}}
}
finish_test
+77
View File
@@ -0,0 +1,77 @@
# 2024 Aug 10
#
# 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 focusing on the built-in fts5 tokenizers.
#
source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5tokenizer3
# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 {
finish_test
return
}
proc get_sod {args} { return "split_on_dot" }
proc get_lowercase {args} { return "lowercase" }
proc lowercase {flags txt} {
set n [string length $txt]
sqlite3_fts5_token [string tolower $txt] 0 $n
return 0
}
proc split_on_dot {flags txt} {
set iOff 0
foreach t [split $txt "."] {
set n [string length $txt]
sqlite3_fts5_token $t $iOff [expr $iOff+$n]
incr iOff [expr {$n+1}]
}
return ""
}
foreach {tn script} {
1 {
sqlite3_fts5_create_tokenizer db lowercase get_lowercase
sqlite3_fts5_create_tokenizer -parent lowercase db split_on_dot get_sod
}
2 {
sqlite3_fts5_create_tokenizer -v2 db lowercase get_lowercase
sqlite3_fts5_create_tokenizer -parent lowercase db split_on_dot get_sod
}
3 {
sqlite3_fts5_create_tokenizer db lowercase get_lowercase
sqlite3_fts5_create_tokenizer -v2 -parent lowercase db split_on_dot get_sod
}
4 {
sqlite3_fts5_create_tokenizer -v2 db lowercase get_lowercase
sqlite3_fts5_create_tokenizer -v2 -parent lowercase db split_on_dot get_sod
}
} {
reset_db
eval $script
do_execsql_test 1.$tn.0 {
CREATE VIRTUAL TABLE t1 USING fts5(x, tokenize=split_on_dot);
CREATE VIRTUAL TABLE t1vocab USING fts5vocab(t1, instance);
INSERT INTO t1 VALUES('ABC.Def.ghi');
}
do_execsql_test 1.$tn.1 {
SELECT term FROM t1vocab ORDER BY 1
} {abc def ghi}
}
finish_test
+92 -1
View File
@@ -56,6 +56,7 @@ foreach {tn like res} {
7 {ABCDEFG%} 1
8 {%รุงเ%} 2
9 {%งเ%} 2
10 {%"งเ"%} {}
} {
do_execsql_test 1.3.$tn {
SELECT rowid FROM t1 WHERE y LIKE $like
@@ -69,6 +70,9 @@ do_execsql_test 2.0 {
INSERT INTO t1 VALUES('abcdefghijklm');
INSERT INTO t1 VALUES('กรุงเทพมหานคร');
}
do_catchsql_test 2.0.1 {
CREATE VIRTUAL TABLE t2 USING fts5(z, tokenize='trigram case_sensitive');
} {1 {error in tokenizer constructor}}
foreach {tn s res} {
1 abc "(abc)defghijklm"
@@ -197,6 +201,12 @@ do_eqp_test 6.3 {
do_eqp_test 6.4 {
SELECT * FROM ci1 WHERE x GLOB ?
} {VIRTUAL TABLE INDEX 0:G0}
do_eqp_test 6.5 {
SELECT * FROM ci1 WHERE x < ?
} {{SCAN ci1 VIRTUAL TABLE INDEX 0:}}
do_eqp_test 6.6 {
SELECT * FROM ci0 WHERE x < ?
} {{SCAN ci0 VIRTUAL TABLE INDEX 0:}}
reset_db
do_execsql_test 7.0 {
@@ -206,7 +216,7 @@ do_execsql_test 7.0 {
(20, "жираф.png"),
(30, "cat.png"),
(40, "кот.png"),
(50, "misic-🎵-.mp3");
(50, "misic-🎵-.mp3");
}
do_execsql_test 7.1 {
SELECT rowid FROM f WHERE +filename GLOB '*ир*';
@@ -253,4 +263,85 @@ do_execsql_test 8.3 {
{[abcde]}
}
#-------------------------------------------------------------------------
reset_db
do_execsql_test 9.0 {
CREATE VIRTUAL TABLE t1 USING fts5(
a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12,
tokenize=trigram
);
INSERT INTO t1(rowid, a12) VALUES(111, 'thats a tricky case though');
INSERT INTO t1(rowid, a12) VALUES(222, 'the query planner cannot do');
}
do_execsql_test 9.1 {
SELECT rowid FROM t1 WHERE a12 LIKE '%tricky%'
} {111}
do_execsql_test 9.2 {
SELECT rowid FROM t1 WHERE a12 LIKE '%tricky%' AND a12 LIKE '%case%'
} {111}
do_execsql_test 9.3 {
SELECT rowid FROM t1 WHERE a12 LIKE NULL
} {}
#-------------------------------------------------------------------------
reset_db
do_execsql_test 10.0 {
CREATE VIRTUAL TABLE t1 USING fts5(a, tokenize=trigram);
}
do_test 10.1 {
foreach {val} {
"abc \UFFjkl\UFF"
"abc \UFFFjkl\UFFF"
"abc \UFFFFjkl\UFFFF"
"abc \UFFFFFjkl\UFFFFF"
"\UFFjkl\UFF abc"
"\UFFFjkl\UFFF abc"
"\UFFFFjkl\UFFFF abc"
"\UFFFFFjkl\UFFFFF abc"
"\U10001jkl\U10001 abc"
} {
execsql { INSERT INTO t1 VALUES( $val ) }
}
} {}
do_test 10.2 {
foreach {val} {
X'E18000626320646566'
X'61EDA0806320646566'
X'61EDA0806320646566'
X'61EFBFBE6320646566'
X'76686920E18000626320646566'
X'7668692061EDA0806320646566'
X'7668692061EDA0806320646566'
X'7668692061EFBFBE6320646566'
} {
execsql " INSERT INTO t1 VALUES( $val ) "
}
} {}
do_test 10.3 {
set a [binary format c* {0x61 0xF7 0xBF 0xBF 0xBF 0x62}]
set b [binary format c* {0x61 0xF7 0xBF 0xBF 0xBF 0xBF 0x62}]
set c [binary format c* {0x61 0xF7 0xBF 0xBF 0xBF 0xBF 0xBF 0x62}]
set d [binary format c* {0x61 0xF7 0xBF 0xBF 0xBF 0xBF 0xBF 0xBF 0x62}]
execsql {
INSERT INTO t1 VALUES($a);
INSERT INTO t1 VALUES($b);
INSERT INTO t1 VALUES($c);
INSERT INTO t1 VALUES($d);
INSERT INTO t1 VALUES('abcd' || $a);
INSERT INTO t1 VALUES('abcd' || $b);
INSERT INTO t1 VALUES('abcd' || $c);
INSERT INTO t1 VALUES('abcd' || $d);
}
} {}
finish_test
+17
View File
@@ -21,6 +21,9 @@ do_execsql_test 1.0 "
INSERT INTO t1 VALUES('abc\u0303defghijklm');
INSERT INTO t1 VALUES('a\u0303b\u0303c\u0303defghijklm');
"
do_catchsql_test 1.0.1 {
CREATE VIRTUAL TABLE t2 USING fts5(z, tokenize='trigram remove_diacritics');
} {1 {error in tokenizer constructor}}
do_execsql_test 1.1 {
SELECT highlight(t1, 0, '(', ')') FROM t1('abc');
@@ -117,4 +120,18 @@ do_execsql_test 4.2 {
SELECT rowid FROM t4 WHERE z LIKE '%abc%'
} {1}
#-------------------------------------------------------------------------
reset_db
do_execsql_test 5.0 {
CREATE VIRTUAL TABLE t5 USING fts5(
c1, tokenize='trigram', detail='none'
);
INSERT INTO t5(rowid, c1) VALUES(1, 'abc_____xyx_yxz');
INSERT INTO t5(rowid, c1) VALUES(2, 'abc_____xyxz');
INSERT INTO t5(rowid, c1) VALUES(3, 'ac_____xyxz');
} {}
do_execsql_test 5.1 {
SELECT rowid FROM t5 WHERE c1 LIKE 'abc%xyxz'
} {2}
finish_test
+1
View File
@@ -60,6 +60,7 @@ do_execsql_test 2.1 "
# require 17 or more bits to store).
#
unset -nocomplain A B C D
set A [db one {SELECT char(0x1F75E)}] ;# Type So
set B [db one {SELECT char(0x1F5FD)}] ;# Type So
set C [db one {SELECT char(0x2F802)}] ;# Type Lo
+17 -112
View File
@@ -116,6 +116,7 @@ set docs [list {
connected by OR.
}]
unset -nocomplain map
set map(a) [list "\u00C4" "\u00E4"] ; # LATIN LETTER A WITH DIAERESIS
set map(e) [list "\u00CB" "\u00EB"] ; # LATIN LETTER E WITH DIAERESIS
set map(i) [list "\u00CF" "\u00EF"] ; # LATIN LETTER I WITH DIAERESIS
@@ -470,119 +471,23 @@ do_execsql_test 8.2.3 {
} {2 4}
#-------------------------------------------------------------------------
#
if 0 {
foreach {tn sql} {
1 {
CREATE VIRTUAL TABLE t5 USING fts4(tokenize=unicode61 [tokenchars= .]);
CREATE VIRTUAL TABLE t6 USING fts4(
tokenize=unicode61 [tokenchars=="] "tokenchars=[]");
CREATE VIRTUAL TABLE t7 USING fts4(tokenize=unicode61 [separators=x\xC4]);
}
2 {
CREATE VIRTUAL TABLE t5 USING fts4(tokenize=unicode61 "tokenchars= .");
CREATE VIRTUAL TABLE t6 USING fts4(tokenize=unicode61 "tokenchars=[=""]");
CREATE VIRTUAL TABLE t7 USING fts4(tokenize=unicode61 "separators=x\xC4");
}
3 {
CREATE VIRTUAL TABLE t5 USING fts4(tokenize=unicode61 'tokenchars= .');
CREATE VIRTUAL TABLE t6 USING fts4(tokenize=unicode61 'tokenchars=="[]');
CREATE VIRTUAL TABLE t7 USING fts4(tokenize=unicode61 'separators=x\xC4');
}
4 {
CREATE VIRTUAL TABLE t5 USING fts4(tokenize=unicode61 `tokenchars= .`);
CREATE VIRTUAL TABLE t6 USING fts4(tokenize=unicode61 `tokenchars=[="]`);
CREATE VIRTUAL TABLE t7 USING fts4(tokenize=unicode61 `separators=x\xC4`);
}
foreach {tn val bErr} {
1 0 0
2 1 0
3 2 0
4 3 1
5 11 1
} {
do_execsql_test 9.$tn.0 {
DROP TABLE IF EXISTS t5;
DROP TABLE IF EXISTS t5aux;
DROP TABLE IF EXISTS t6;
DROP TABLE IF EXISTS t6aux;
DROP TABLE IF EXISTS t7;
DROP TABLE IF EXISTS t7aux;
}
do_execsql_test 9.$tn.1 $sql
do_execsql_test 9.$tn.2 {
CREATE VIRTUAL TABLE t5aux USING fts4aux(t5);
INSERT INTO t5 VALUES('one two three/four.five.six');
SELECT * FROM t5aux;
} {
four.five.six * 1 1 four.five.six 0 1 1
{one two three} * 1 1 {one two three} 0 1 1
}
do_execsql_test 9.$tn.3 {
CREATE VIRTUAL TABLE t6aux USING fts4aux(t6);
INSERT INTO t6 VALUES('alpha=beta"gamma/delta[epsilon]zeta');
SELECT * FROM t6aux;
} {
{alpha=beta"gamma} * 1 1 {alpha=beta"gamma} 0 1 1
{delta[epsilon]zeta} * 1 1 {delta[epsilon]zeta} 0 1 1
}
do_execsql_test 9.$tn.4 {
CREATE VIRTUAL TABLE t7aux USING fts4aux(t7);
INSERT INTO t7 VALUES('alephxbeth\xC4gimel');
SELECT * FROM t7aux;
} {
aleph * 1 1 aleph 0 1 1
beth * 1 1 beth 0 1 1
gimel * 1 1 gimel 0 1 1
}
}
# Check that multiple options are handled correctly.
#
do_execsql_test 10.1 {
DROP TABLE IF EXISTS t1;
CREATE VIRTUAL TABLE t1 USING fts4(tokenize=unicode61
"tokenchars=xyz" "tokenchars=.=" "separators=.=" "separators=xy"
"separators=a" "separators=a" "tokenchars=a" "tokenchars=a"
);
INSERT INTO t1 VALUES('oneatwoxthreeyfour');
INSERT INTO t1 VALUES('a.single=word');
CREATE VIRTUAL TABLE t1aux USING fts4aux(t1);
SELECT * FROM t1aux;
} {
.single=word * 1 1 .single=word 0 1 1
four * 1 1 four 0 1 1
one * 1 1 one 0 1 1
three * 1 1 three 0 1 1
two * 1 1 two 0 1 1
}
# Test that case folding happens after tokenization, not before.
#
do_execsql_test 10.2 {
DROP TABLE IF EXISTS t2;
CREATE VIRTUAL TABLE t2 USING fts4(tokenize=unicode61 "separators=aB");
INSERT INTO t2 VALUES('oneatwoBthree');
INSERT INTO t2 VALUES('onebtwoAthree');
CREATE VIRTUAL TABLE t2aux USING fts4aux(t2);
SELECT * FROM t2aux;
} {
one * 1 1 one 0 1 1
onebtwoathree * 1 1 onebtwoathree 0 1 1
three * 1 1 three 0 1 1
two * 1 1 two 0 1 1
}
# Test that the tokenchars and separators options work with the
# fts3tokenize table.
#
do_execsql_test 11.1 {
CREATE VIRTUAL TABLE ft1 USING fts3tokenize(
"unicode61", "tokenchars=@.", "separators=1234567890"
);
SELECT token FROM ft1 WHERE input = 'berlin@street123sydney.road';
} {
berlin@street sydney.road
}
reset_db
set aRes(0) {0 {}}
set aRes(1) {1 {error in tokenizer constructor}}
set res $aRes($bErr)
do_catchsql_test 9.1.$tn "
CREATE VIRTUAL TABLE bl USING fts5(
s, tokenize='trigram remove_diacritics $val'
);
" $res
}
finish_test
+1
View File
@@ -513,6 +513,7 @@ do_execsql_test 10.5 {
INSERT INTO ft(a) VALUES('4 5 6');
}
unset -nocomplain x res
do_test 10.6 {
set res [list]
db eval { SELECT rowid FROM ft('4') } x {
+1 -7
View File
@@ -15,13 +15,7 @@
#include "sqlite3.h"
#include "sqlite3intck.h"
#if defined(INCLUDE_SQLITE_TCL_H)
# include "sqlite_tcl.h"
#else
# include "tcl.h"
#endif
#include "tclsqlite.h"
#include <string.h>
#include <assert.h>
+18 -1
View File
@@ -851,11 +851,26 @@ class JsonBlockCommand extends TableResultCommand {
//! --new command
class NewDbCommand extends OpenDbCommand {
public NewDbCommand(){ super(true); }
public void process(SQLTester t, TestScript ts, String[] argv) throws Exception{
if(argv.length>1){
Util.unlink(argv[1]);
}
super.process(t, ts, argv);
}
}
//! Placeholder dummy/no-op commands
//! Placeholder dummy/no-op/unimplemented commands
class NoopCommand extends Command {
private boolean verbose = false;
public NoopCommand(boolean verbose){
this.verbose = verbose;
}
public NoopCommand(){}
public void process(SQLTester t, TestScript ts, String[] argv) throws Exception{
if( this.verbose ){
t.outln("Skipping unhandled command: "+argv[0]);
}
}
}
@@ -1021,6 +1036,7 @@ class CommandDispatcher {
case "db": rv = new DbCommand(); break;
case "glob": rv = new GlobCommand(); break;
case "json": rv = new JsonCommand(); break;
case "jsonglob": rv = new NoopCommand(true); break;
case "json-block": rv = new JsonBlockCommand(); break;
case "new": rv = new NewDbCommand(); break;
case "notglob": rv = new NotGlobCommand(); break;
@@ -1030,6 +1046,7 @@ class CommandDispatcher {
case "print": rv = new PrintCommand(); break;
case "result": rv = new ResultCommand(); break;
case "run": rv = new RunCommand(); break;
case "stmt-cache": rv = new NoopCommand(); break;
case "tableresult": rv = new TableResultCommand(); break;
case "testcase": rv = new TestCaseCommand(); break;
case "verbosity": rv = new VerbosityCommand(); break;
@@ -4,7 +4,7 @@
The purpose of the Test Script Interpreter is to read and interpret
script files that contain SQL commands and desired results. The
interpreter will check results and report an discrepencies found.
interpreter will check results and report any discrepencies found.
The test script files are ASCII text files. The filename always ends with
".test". Each script is evaluated independently; context does not carry
@@ -87,6 +87,7 @@ Each command looks like an SQL comment. The command begins at the left
margin (no leading space) and starts with exactly 2 minus signs ("-").
The command name consists of lowercase letters and maybe a "-" or two.
Some commands have arguments.
The arguments are separated from the command name by one or more spaces.
Commands have access to the input buffer and might reset the input buffer.
@@ -159,9 +160,9 @@ the result buffer. This distinction does not matter for the --result
command itself, but it is important for related commands like --glob
and --notglob. Sometimes test cases will contains a bunch of SQL
followed by multiple --glob and/or --notglob statements. All of the
globs should be evaluted agains the result buffer correct, but the SQL
should only be run once. This is accomplished by resetting the input
buffer but not the result buffer.
globs should be evaluated agains the result buffer, but the SQL should
only be run once. This is accomplished by resetting the input buffer
but not the result buffer.
### The --glob command
@@ -187,7 +188,7 @@ The TEST-GLOB pattern is slightly different for a standard GLOB:
### The --notglob command
The --notglob command works just like --glob except that it reports an
error if the GLOB does match, rather than if the GLOB does not matches.
error if the GLOB does match, rather than if the GLOB does not match.
### The --oom command
+10 -3
View File
@@ -40,7 +40,7 @@
** modification-time of the target file is set to this value before
** returning.
**
** If three or more arguments are passed to this function and an
** If five or more arguments are passed to this function and an
** error is encountered, an exception is raised.
**
** READFILE(FILE):
@@ -110,6 +110,13 @@ SQLITE_EXTENSION_INIT1
#include <time.h>
#include <errno.h>
/* When used as part of the CLI, the sqlite3_stdio.h module will have
** been included before this one. In that case use the sqlite3_stdio.h
** #defines. If not, create our own for fopen().
*/
#ifndef _SQLITE3_STDIO_H_
# define sqlite3_fopen fopen
#endif
/*
** Structure of the fsdir() table-valued function
@@ -142,7 +149,7 @@ static void readFileContents(sqlite3_context *ctx, const char *zName){
sqlite3 *db;
int mxBlob;
in = fopen(zName, "rb");
in = sqlite3_fopen(zName, "rb");
if( in==0 ){
/* File does not exist or is unreadable. Leave the result set to NULL. */
return;
@@ -397,7 +404,7 @@ static int writeFile(
sqlite3_int64 nWrite = 0;
const char *z;
int rc = 0;
FILE *out = fopen(zFile, "wb");
FILE *out = sqlite3_fopen(zFile, "wb");
if( out==0 ) return 1;
z = (const char*)sqlite3_value_blob(pData);
if( z ){
+335 -52
View File
@@ -11,7 +11,7 @@
******************************************************************************
**
** This file contains code to implement the percentile(Y,P) SQL function
** as described below:
** and similar as described below:
**
** (1) The percentile(Y,P) function is an aggregate function taking
** exactly two arguments.
@@ -57,29 +57,108 @@
** (12) The percentile(Y,P) is implemented as a single C99 source-code
** file that compiles into a shared-library or DLL that can be loaded
** into SQLite using the sqlite3_load_extension() interface.
**
** (13) A separate median(Y) function is the equivalent percentile(Y,50).
**
** (14) A separate percentile_cont(Y,P) function is equivalent to
** percentile(Y,P/100.0). In other words, the fraction value in
** the second argument is in the range of 0 to 1 instead of 0 to 100.
**
** (15) A separate percentile_disc(Y,P) function is like
** percentile_cont(Y,P) except that instead of returning the weighted
** average of the nearest two input values, it returns the next lower
** value. So the percentile_disc(Y,P) will always return a value
** that was one of the inputs.
**
** (16) All of median(), percentile(Y,P), percentile_cont(Y,P) and
** percentile_disc(Y,P) can be used as window functions.
**
** Differences from standard SQL:
**
** * The percentile_cont(X,P) function is equivalent to the following in
** standard SQL:
**
** (percentile_cont(P) WITHIN GROUP (ORDER BY X))
**
** The SQLite syntax is much more compact. The standard SQL syntax
** is also supported if SQLite is compiled with the
** -DSQLITE_ENABLE_ORDERED_SET_AGGREGATES option.
**
** * No median(X) function exists in the SQL standard. App developers
** are expected to write "percentile_cont(0.5)WITHIN GROUP(ORDER BY X)".
**
** * No percentile(Y,P) function exists in the SQL standard. Instead of
** percential(Y,P), developers must write this:
** "percentile_cont(P/100.0) WITHIN GROUP (ORDER BY Y)". Note that
** the fraction parameter to percentile() goes from 0 to 100 whereas
** the fraction parameter in SQL standard percentile_cont() goes from
** 0 to 1.
**
** Implementation notes as of 2024-08-31:
**
** * The regular aggregate-function versions of these routines work
** by accumulating all values in an array of doubles, then sorting
** that array using quicksort before computing the answer. Thus
** the runtime is O(NlogN) where N is the number of rows of input.
**
** * For the window-function versions of these routines, the array of
** inputs is sorted as soon as the first value is computed. Thereafter,
** the array is kept in sorted order using an insert-sort. This
** results in O(N*K) performance where K is the size of the window.
** One can imagine alternative implementations that give O(N*logN*logK)
** performance, but they require more complex logic and data structures.
** The developers have elected to keep the asymptotically slower
** algorithm for now, for simplicity, under the theory that window
** functions are seldom used and when they are, the window size K is
** often small. The developers might revisit that decision later,
** should the need arise.
*/
#include "sqlite3ext.h"
SQLITE_EXTENSION_INIT1
#if defined(SQLITE3_H)
/* no-op */
#elif defined(SQLITE_STATIC_PERCENTILE)
# include "sqlite3.h"
#else
# include "sqlite3ext.h"
SQLITE_EXTENSION_INIT1
#endif
#include <assert.h>
#include <string.h>
#include <stdlib.h>
/* The following object is the session context for a single percentile()
** function. We have to remember all input Y values until the very end.
/* The following object is the group context for a single percentile()
** aggregate. Remember all input Y values until the very end.
** Those values are accumulated in the Percentile.a[] array.
*/
typedef struct Percentile Percentile;
struct Percentile {
unsigned nAlloc; /* Number of slots allocated for a[] */
unsigned nUsed; /* Number of slots actually used in a[] */
double rPct; /* 1.0 more than the value for P */
char bSorted; /* True if a[] is already in sorted order */
char bKeepSorted; /* True if advantageous to keep a[] sorted */
char bPctValid; /* True if rPct is valid */
double rPct; /* Fraction. 0.0 to 1.0 */
double *a; /* Array of Y values */
};
/* Details of each function in the percentile family */
typedef struct PercentileFunc PercentileFunc;
struct PercentileFunc {
const char *zName; /* Function name */
char nArg; /* Number of arguments */
char mxFrac; /* Maximum value of the "fraction" input */
char bDiscrete; /* True for percentile_disc() */
};
static const PercentileFunc aPercentFunc[] = {
{ "median", 1, 1, 0 },
{ "percentile", 2, 100, 0 },
{ "percentile_cont", 2, 1, 0 },
{ "percentile_disc", 2, 1, 1 },
};
/*
** Return TRUE if the input floating-point number is an infinity.
*/
static int isInfinity(double r){
static int percentIsInfinity(double r){
sqlite3_uint64 u;
assert( sizeof(u)==sizeof(r) );
memcpy(&u, &r, sizeof(u));
@@ -87,13 +166,64 @@ static int isInfinity(double r){
}
/*
** Return TRUE if two doubles differ by 0.001 or less
** Return TRUE if two doubles differ by 0.001 or less.
*/
static int sameValue(double a, double b){
static int percentSameValue(double a, double b){
a -= b;
return a>=-0.001 && a<=0.001;
}
/*
** Search p (which must have p->bSorted) looking for an entry with
** value y. Return the index of that entry.
**
** If bExact is true, return -1 if the entry is not found.
**
** If bExact is false, return the index at which a new entry with
** value y should be insert in order to keep the values in sorted
** order. The smallest return value in this case will be 0, and
** the largest return value will be p->nUsed.
*/
static int percentBinarySearch(Percentile *p, double y, int bExact){
int iFirst = 0; /* First element of search range */
int iLast = p->nUsed - 1; /* Last element of search range */
while( iLast>=iFirst ){
int iMid = (iFirst+iLast)/2;
double x = p->a[iMid];
if( x<y ){
iFirst = iMid + 1;
}else if( x>y ){
iLast = iMid - 1;
}else{
return iMid;
}
}
if( bExact ) return -1;
return iFirst;
}
/*
** Generate an error for a percentile function.
**
** The error format string must have exactly one occurrance of "%%s()"
** (with two '%' characters). That substring will be replaced by the name
** of the function.
*/
static void percentError(sqlite3_context *pCtx, const char *zFormat, ...){
PercentileFunc *pFunc = (PercentileFunc*)sqlite3_user_data(pCtx);
char *zMsg1;
char *zMsg2;
va_list ap;
va_start(ap, zFormat);
zMsg1 = sqlite3_vmprintf(zFormat, ap);
va_end(ap);
zMsg2 = zMsg1 ? sqlite3_mprintf(zMsg1, pFunc->zName) : 0;
sqlite3_result_error(pCtx, zMsg2, -1);
sqlite3_free(zMsg1);
sqlite3_free(zMsg2);
}
/*
** The "step" function for percentile(Y,P) is called once for each
** input row.
@@ -103,16 +233,24 @@ static void percentStep(sqlite3_context *pCtx, int argc, sqlite3_value **argv){
double rPct;
int eType;
double y;
assert( argc==2 );
assert( argc==2 || argc==1 );
/* Requirement 3: P must be a number between 0 and 100 */
eType = sqlite3_value_numeric_type(argv[1]);
rPct = sqlite3_value_double(argv[1]);
if( (eType!=SQLITE_INTEGER && eType!=SQLITE_FLOAT)
|| rPct<0.0 || rPct>100.0 ){
sqlite3_result_error(pCtx, "2nd argument to percentile() is not "
"a number between 0.0 and 100.0", -1);
return;
if( argc==1 ){
/* Requirement 13: median(Y) is the same as percentile(Y,50). */
rPct = 0.5;
}else{
/* Requirement 3: P must be a number between 0 and 100 */
PercentileFunc *pFunc = (PercentileFunc*)sqlite3_user_data(pCtx);
eType = sqlite3_value_numeric_type(argv[1]);
rPct = sqlite3_value_double(argv[1])/(double)pFunc->mxFrac;
if( (eType!=SQLITE_INTEGER && eType!=SQLITE_FLOAT)
|| rPct<0.0 || rPct>1.0
){
percentError(pCtx, "the fraction argument to %%s()"
" is not between 0.0 and %.1f",
(double)pFunc->mxFrac);
return;
}
}
/* Allocate the session context. */
@@ -121,11 +259,12 @@ static void percentStep(sqlite3_context *pCtx, int argc, sqlite3_value **argv){
/* Remember the P value. Throw an error if the P value is different
** from any prior row, per Requirement (2). */
if( p->rPct==0.0 ){
p->rPct = rPct+1.0;
}else if( !sameValue(p->rPct,rPct+1.0) ){
sqlite3_result_error(pCtx, "2nd argument to percentile() is not the "
"same for all input rows", -1);
if( !p->bPctValid ){
p->rPct = rPct;
p->bPctValid = 1;
}else if( !percentSameValue(p->rPct,rPct) ){
percentError(pCtx, "the fraction argument to %%s()"
" is not the same for all input rows");
return;
}
@@ -136,15 +275,14 @@ static void percentStep(sqlite3_context *pCtx, int argc, sqlite3_value **argv){
/* If not NULL, then Y must be numeric. Otherwise throw an error.
** Requirement 4 */
if( eType!=SQLITE_INTEGER && eType!=SQLITE_FLOAT ){
sqlite3_result_error(pCtx, "1st argument to percentile() is not "
"numeric", -1);
percentError(pCtx, "input to %%s() is not numeric");
return;
}
/* Throw an error if the Y value is infinity or NaN */
y = sqlite3_value_double(argv[0]);
if( isInfinity(y) ){
sqlite3_result_error(pCtx, "Inf input to percentile()", -1);
if( percentIsInfinity(y) ){
percentError(pCtx, "Inf input to %%s()");
return;
}
@@ -161,26 +299,143 @@ static void percentStep(sqlite3_context *pCtx, int argc, sqlite3_value **argv){
p->nAlloc = n;
p->a = a;
}
p->a[p->nUsed++] = y;
if( p->nUsed==0 ){
p->a[p->nUsed++] = y;
p->bSorted = 1;
}else if( !p->bSorted || y>=p->a[p->nUsed-1] ){
p->a[p->nUsed++] = y;
}else if( p->bKeepSorted ){
int i;
i = percentBinarySearch(p, y, 0);
if( i<(int)p->nUsed ){
memmove(&p->a[i+1], &p->a[i], (p->nUsed-i)*sizeof(p->a[0]));
}
p->a[i] = y;
p->nUsed++;
}else{
p->a[p->nUsed++] = y;
p->bSorted = 0;
}
}
/*
** Compare to doubles for sorting using qsort()
** Interchange two doubles.
*/
static int SQLITE_CDECL doubleCmp(const void *pA, const void *pB){
double a = *(double*)pA;
double b = *(double*)pB;
if( a==b ) return 0;
if( a<b ) return -1;
return +1;
}
#define SWAP_DOUBLE(X,Y) {double ttt=(X);(X)=(Y);(Y)=ttt;}
/*
** Called to compute the final output of percentile() and to clean
** up all allocated memory.
** Sort an array of doubles.
**
** Algorithm: quicksort
**
** This is implemented separately rather than using the qsort() routine
** from the standard library because:
**
** (1) To avoid a dependency on qsort()
** (2) To avoid the function call to the comparison routine for each
** comparison.
*/
static void percentFinal(sqlite3_context *pCtx){
static void percentSort(double *a, unsigned int n){
int iLt; /* Entries before a[iLt] are less than rPivot */
int iGt; /* Entries at or after a[iGt] are greater than rPivot */
int i; /* Loop counter */
double rPivot; /* The pivot value */
assert( n>=2 );
if( a[0]>a[n-1] ){
SWAP_DOUBLE(a[0],a[n-1])
}
if( n==2 ) return;
iGt = n-1;
i = n/2;
if( a[0]>a[i] ){
SWAP_DOUBLE(a[0],a[i])
}else if( a[i]>a[iGt] ){
SWAP_DOUBLE(a[i],a[iGt])
}
if( n==3 ) return;
rPivot = a[i];
iLt = i = 1;
do{
if( a[i]<rPivot ){
if( i>iLt ) SWAP_DOUBLE(a[i],a[iLt])
iLt++;
i++;
}else if( a[i]>rPivot ){
do{
iGt--;
}while( iGt>i && a[iGt]>rPivot );
SWAP_DOUBLE(a[i],a[iGt])
}else{
i++;
}
}while( i<iGt );
if( iLt>=2 ) percentSort(a, iLt);
if( n-iGt>=2 ) percentSort(a+iGt, n-iGt);
/* Uncomment for testing */
#if 0
for(i=0; i<n-1; i++){
assert( a[i]<=a[i+1] );
}
#endif
}
/*
** The "inverse" function for percentile(Y,P) is called to remove a
** row that was previously inserted by "step".
*/
static void percentInverse(sqlite3_context *pCtx,int argc,sqlite3_value **argv){
Percentile *p;
int eType;
double y;
int i;
assert( argc==2 || argc==1 );
/* Allocate the session context. */
p = (Percentile*)sqlite3_aggregate_context(pCtx, sizeof(*p));
assert( p!=0 );
/* Ignore rows for which Y is NULL */
eType = sqlite3_value_type(argv[0]);
if( eType==SQLITE_NULL ) return;
/* If not NULL, then Y must be numeric. Otherwise throw an error.
** Requirement 4 */
if( eType!=SQLITE_INTEGER && eType!=SQLITE_FLOAT ){
return;
}
/* Ignore the Y value if it is infinity or NaN */
y = sqlite3_value_double(argv[0]);
if( percentIsInfinity(y) ){
return;
}
if( p->bSorted==0 ){
assert( p->nUsed>1 );
percentSort(p->a, p->nUsed);
p->bSorted = 1;
}
p->bKeepSorted = 1;
/* Find and remove the row */
i = percentBinarySearch(p, y, 1);
if( i>=0 ){
p->nUsed--;
if( i<(int)p->nUsed ){
memmove(&p->a[i], &p->a[i+1], (p->nUsed - i)*sizeof(p->a[0]));
}
}
}
/*
** Compute the final output of percentile(). Clean up all allocated
** memory if and only if bIsFinal is true.
*/
static void percentCompute(sqlite3_context *pCtx, int bIsFinal){
Percentile *p;
PercentileFunc *pFunc = (PercentileFunc*)sqlite3_user_data(pCtx);
unsigned i1, i2;
double v1, v2;
double ix, vx;
@@ -188,21 +443,38 @@ static void percentFinal(sqlite3_context *pCtx){
if( p==0 ) return;
if( p->a==0 ) return;
if( p->nUsed ){
qsort(p->a, p->nUsed, sizeof(double), doubleCmp);
ix = (p->rPct-1.0)*(p->nUsed-1)*0.01;
if( p->bSorted==0 ){
assert( p->nUsed>1 );
percentSort(p->a, p->nUsed);
p->bSorted = 1;
}
ix = p->rPct*(p->nUsed-1);
i1 = (unsigned)ix;
i2 = ix==(double)i1 || i1==p->nUsed-1 ? i1 : i1+1;
v1 = p->a[i1];
v2 = p->a[i2];
vx = v1 + (v2-v1)*(ix-i1);
if( pFunc->bDiscrete ){
vx = p->a[i1];
}else{
i2 = ix==(double)i1 || i1==p->nUsed-1 ? i1 : i1+1;
v1 = p->a[i1];
v2 = p->a[i2];
vx = v1 + (v2-v1)*(ix-i1);
}
sqlite3_result_double(pCtx, vx);
}
sqlite3_free(p->a);
memset(p, 0, sizeof(*p));
if( bIsFinal ){
sqlite3_free(p->a);
memset(p, 0, sizeof(*p));
}else{
p->bKeepSorted = 1;
}
}
static void percentFinal(sqlite3_context *pCtx){
percentCompute(pCtx, 1);
}
static void percentValue(sqlite3_context *pCtx){
percentCompute(pCtx, 0);
}
#ifdef _WIN32
#if defined(_WIN32) && !defined(SQLITE3_H) && !defined(SQLITE_STATIC_PERCENTILE)
__declspec(dllexport)
#endif
int sqlite3_percentile_init(
@@ -211,10 +483,21 @@ int sqlite3_percentile_init(
const sqlite3_api_routines *pApi
){
int rc = SQLITE_OK;
unsigned int i;
#if defined(SQLITE3_H) || defined(SQLITE_STATIC_PERCENTILE)
(void)pApi; /* Unused parameter */
#else
SQLITE_EXTENSION_INIT2(pApi);
#endif
(void)pzErrMsg; /* Unused parameter */
rc = sqlite3_create_function(db, "percentile", 2,
SQLITE_UTF8|SQLITE_INNOCUOUS, 0,
0, percentStep, percentFinal);
for(i=0; i<sizeof(aPercentFunc)/sizeof(aPercentFunc[0]); i++){
rc = sqlite3_create_window_function(db,
aPercentFunc[i].zName,
aPercentFunc[i].nArg,
SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_SELFORDER1,
(void*)&aPercentFunc[i],
percentStep, percentFinal, percentValue, percentInverse, 0);
if( rc ) break;
}
return rc;
}
+223 -31
View File
@@ -90,6 +90,26 @@
** and a very large cost if either start or stop are unavailable. This
** encourages the query planner to order joins such that the bounds of the
** series are well-defined.
**
** Update on 2024-08-22:
** xBestIndex now also looks for equality and inequality constraints against
** the value column and uses those constraints as additional bounds against
** the sequence range. Thus, a query like this:
**
** SELECT value FROM generate_series($SA,$EA)
** WHERE value BETWEEN $SB AND $EB;
**
** Is logically the same as:
**
** SELECT value FROM generate_series(max($SA,$SB),min($EA,$EB));
**
** Constraints on the value column can server as substitutes for constraints
** on the hidden start and stop columns. So, the following two queries
** are equivalent:
**
** SELECT value FROM generate_series($S,$E);
** SELECT value FROM generate_series WHERE value BETWEEN $S and $E;
**
*/
#include "sqlite3ext.h"
SQLITE_EXTENSION_INIT1
@@ -131,8 +151,10 @@ static sqlite3_int64 genSeqMember(
typedef unsigned char u8;
typedef struct SequenceSpec {
sqlite3_int64 iBase; /* Starting value ("start") */
sqlite3_int64 iTerm; /* Given terminal value ("stop") */
sqlite3_int64 iOBase; /* Original starting value ("start") */
sqlite3_int64 iOTerm; /* Original terminal value ("stop") */
sqlite3_int64 iBase; /* Starting value to actually use */
sqlite3_int64 iTerm; /* Terminal value to actually use */
sqlite3_int64 iStep; /* Increment ("step") */
sqlite3_uint64 uSeqIndexMax; /* maximum sequence index (aka "n") */
sqlite3_uint64 uSeqIndexNow; /* Current index during generation */
@@ -325,9 +347,9 @@ static int seriesColumn(
series_cursor *pCur = (series_cursor*)cur;
sqlite3_int64 x = 0;
switch( i ){
case SERIES_COLUMN_START: x = pCur->ss.iBase; break;
case SERIES_COLUMN_STOP: x = pCur->ss.iTerm; break;
case SERIES_COLUMN_STEP: x = pCur->ss.iStep; break;
case SERIES_COLUMN_START: x = pCur->ss.iOBase; break;
case SERIES_COLUMN_STOP: x = pCur->ss.iOTerm; break;
case SERIES_COLUMN_STEP: x = pCur->ss.iStep; break;
default: x = pCur->ss.iValueNow; break;
}
sqlite3_result_int64(ctx, x);
@@ -335,7 +357,9 @@ static int seriesColumn(
}
#ifndef LARGEST_UINT64
#define LARGEST_INT64 (0xffffffff|(((sqlite3_int64)0x7fffffff)<<32))
#define LARGEST_UINT64 (0xffffffff|(((sqlite3_uint64)0xffffffff)<<32))
#define SMALLEST_INT64 (((sqlite3_int64)-1) - LARGEST_INT64)
#endif
/*
@@ -376,13 +400,18 @@ static int seriesEof(sqlite3_vtab_cursor *cur){
** parameter. (idxStr is not used in this implementation.) idxNum
** is a bitmask showing which constraints are available:
**
** 0x01: start=VALUE
** 0x02: stop=VALUE
** 0x04: step=VALUE
** 0x08: descending order
** 0x10: ascending order
** 0x20: LIMIT VALUE
** 0x40: OFFSET VALUE
** 0x0001: start=VALUE
** 0x0002: stop=VALUE
** 0x0004: step=VALUE
** 0x0008: descending order
** 0x0010: ascending order
** 0x0020: LIMIT VALUE
** 0x0040: OFFSET VALUE
** 0x0080: value=VALUE
** 0x0100: value>=VALUE
** 0x0200: value>VALUE
** 0x1000: value<=VALUE
** 0x2000: value<VALUE
**
** This routine should initialize the cursor and position it so that it
** is pointing at the first row, or pointing off the end of the table
@@ -395,6 +424,12 @@ static int seriesFilter(
){
series_cursor *pCur = (series_cursor *)pVtabCursor;
int i = 0;
int returnNoRows = 0;
sqlite3_int64 iMin = SMALLEST_INT64;
sqlite3_int64 iMax = LARGEST_INT64;
sqlite3_int64 iLimit = 0;
sqlite3_int64 iOffset = 0;
(void)idxStrUnused;
if( idxNum & 0x01 ){
pCur->ss.iBase = sqlite3_value_int64(argv[i++]);
@@ -416,16 +451,98 @@ static int seriesFilter(
}else{
pCur->ss.iStep = 1;
}
/* If there are constraints on the value column but there are
** no constraints on the start, stop, and step columns, then
** initialize the default range to be the entire range of 64-bit signed
** integers. This range will contracted by the value column constraints
** further below.
*/
if( (idxNum & 0x05)==0 && (idxNum & 0x0380)!=0 ){
pCur->ss.iBase = SMALLEST_INT64;
}
if( (idxNum & 0x06)==0 && (idxNum & 0x3080)!=0 ){
pCur->ss.iTerm = LARGEST_INT64;
}
pCur->ss.iOBase = pCur->ss.iBase;
pCur->ss.iOTerm = pCur->ss.iTerm;
/* Extract the LIMIT and OFFSET values, but do not apply them yet.
** The range must first be constrained by the limits on value.
*/
if( idxNum & 0x20 ){
sqlite3_int64 iLimit = sqlite3_value_int64(argv[i++]);
sqlite3_int64 iTerm;
iLimit = sqlite3_value_int64(argv[i++]);
if( idxNum & 0x40 ){
sqlite3_int64 iOffset = sqlite3_value_int64(argv[i++]);
if( iOffset>0 ){
pCur->ss.iBase += pCur->ss.iStep*iOffset;
iOffset = sqlite3_value_int64(argv[i++]);
}
}
if( idxNum & 0x3380 ){
/* Extract the maximum range of output values determined by
** constraints on the "value" column.
*/
if( idxNum & 0x0080 ){
iMin = iMax = sqlite3_value_int64(argv[i++]);
}else{
if( idxNum & 0x0300 ){
iMin = sqlite3_value_int64(argv[i++]);
if( idxNum & 0x0200 ){
if( iMin==LARGEST_INT64 ){
returnNoRows = 1;
}else{
iMin++;
}
}
}
if( idxNum & 0x3000 ){
iMax = sqlite3_value_int64(argv[i++]);
if( idxNum & 0x2000 ){
if( iMax==SMALLEST_INT64 ){
returnNoRows = 1;
}else{
iMax--;
}
}
}
if( iMin>iMax ){
returnNoRows = 1;
}
}
/* Try to reduce the range of values to be generated based on
** constraints on the "value" column.
*/
if( pCur->ss.iStep>0 ){
sqlite3_int64 szStep = pCur->ss.iStep;
if( pCur->ss.iBase<iMin ){
sqlite3_uint64 d = iMin - pCur->ss.iBase;
pCur->ss.iBase += ((d+szStep-1)/szStep)*szStep;
}
if( pCur->ss.iTerm>iMax ){
sqlite3_uint64 d = pCur->ss.iTerm - iMax;
pCur->ss.iTerm -= ((d+szStep-1)/szStep)*szStep;
}
}else{
sqlite3_int64 szStep = -pCur->ss.iStep;
assert( szStep>0 );
if( pCur->ss.iBase>iMax ){
sqlite3_uint64 d = pCur->ss.iBase - iMax;
pCur->ss.iBase -= ((d+szStep-1)/szStep)*szStep;
}
if( pCur->ss.iTerm<iMin ){
sqlite3_uint64 d = iMin - pCur->ss.iTerm;
pCur->ss.iTerm += ((d+szStep-1)/szStep)*szStep;
}
}
}
/* Apply LIMIT and OFFSET constraints, if any */
if( idxNum & 0x20 ){
if( iOffset>0 ){
pCur->ss.iBase += pCur->ss.iStep*iOffset;
}
if( iLimit>=0 ){
sqlite3_int64 iTerm;
iTerm = pCur->ss.iBase + (iLimit - 1)*pCur->ss.iStep;
if( pCur->ss.iStep<0 ){
if( iTerm>pCur->ss.iTerm ) pCur->ss.iTerm = iTerm;
@@ -434,16 +551,21 @@ static int seriesFilter(
}
}
}
for(i=0; i<argc; i++){
if( sqlite3_value_type(argv[i])==SQLITE_NULL ){
/* If any of the constraints have a NULL value, then return no rows.
** See ticket https://www.sqlite.org/src/info/fac496b61722daf2 */
pCur->ss.iBase = 1;
pCur->ss.iTerm = 0;
pCur->ss.iStep = 1;
returnNoRows = 1;
break;
}
}
if( returnNoRows ){
pCur->ss.iBase = 1;
pCur->ss.iTerm = 0;
pCur->ss.iStep = 1;
}
if( idxNum & 0x08 ){
pCur->ss.isReversing = pCur->ss.iStep > 0;
}else{
@@ -464,13 +586,35 @@ static int seriesFilter(
**
** The query plan is represented by bits in idxNum:
**
** 0x01 start = $value -- constraint exists
** 0x02 stop = $value -- constraint exists
** 0x04 step = $value -- constraint exists
** 0x08 output is in descending order
** 0x10 output is in ascending order
** 0x20 LIMIT $value -- constraint exists
** 0x40 OFFSET $value -- constraint exists
** 0x0001 start = $num
** 0x0002 stop = $num
** 0x0004 step = $num
** 0x0008 output is in descending order
** 0x0010 output is in ascending order
** 0x0020 LIMIT $num
** 0x0040 OFFSET $num
** 0x0080 value = $num
** 0x0100 value >= $num
** 0x0200 value > $num
** 0x1000 value <= $num
** 0x2000 value < $num
**
** Only one of 0x0100 or 0x0200 will be returned. Similarly, only
** one of 0x1000 or 0x2000 will be returned. If the 0x0080 is set, then
** none of the 0xff00 bits will be set.
**
** The order of parameters passed to xFilter is as follows:
**
** * The argument to start= if bit 0x0001 is in the idxNum mask
** * The argument to stop= if bit 0x0002 is in the idxNum mask
** * The argument to step= if bit 0x0004 is in the idxNum mask
** * The argument to LIMIT if bit 0x0020 is in the idxNum mask
** * The argument to OFFSET if bit 0x0040 is in the idxNum mask
** * The argument to value=, or value>= or value> if any of
** bits 0x0380 are in the idxNum mask
** * The argument to value<= or value< if either of bits 0x3000
** are in the mask
**
*/
static int seriesBestIndex(
sqlite3_vtab *pVTab,
@@ -483,7 +627,9 @@ static int seriesBestIndex(
#endif
int unusableMask = 0; /* Mask of unusable constraints */
int nArg = 0; /* Number of arguments that seriesFilter() expects */
int aIdx[5]; /* Constraints on start, stop, step, LIMIT, OFFSET */
int aIdx[7]; /* Constraints on start, stop, step, LIMIT, OFFSET,
** and value. aIdx[5] covers value=, value>=, and
** value>, aIdx[6] covers value<= and value< */
const struct sqlite3_index_constraint *pConstraint;
/* This implementation assumes that the start, stop, and step columns
@@ -491,7 +637,7 @@ static int seriesBestIndex(
assert( SERIES_COLUMN_STOP == SERIES_COLUMN_START+1 );
assert( SERIES_COLUMN_STEP == SERIES_COLUMN_START+2 );
aIdx[0] = aIdx[1] = aIdx[2] = aIdx[3] = aIdx[4] = -1;
aIdx[0] = aIdx[1] = aIdx[2] = aIdx[3] = aIdx[4] = aIdx[5] = aIdx[6] = -1;
pConstraint = pIdxInfo->aConstraint;
for(i=0; i<pIdxInfo->nConstraint; i++, pConstraint++){
int iCol; /* 0 for start, 1 for stop, 2 for step */
@@ -512,7 +658,50 @@ static int seriesBestIndex(
}
continue;
}
if( pConstraint->iColumn<SERIES_COLUMN_START ) continue;
if( pConstraint->iColumn==SERIES_COLUMN_VALUE ){
switch( op ){
case SQLITE_INDEX_CONSTRAINT_EQ:
case SQLITE_INDEX_CONSTRAINT_IS: {
idxNum |= 0x0080;
idxNum &= ~0x3300;
aIdx[5] = i;
aIdx[6] = -1;
bStartSeen = 1;
break;
}
case SQLITE_INDEX_CONSTRAINT_GE: {
if( idxNum & 0x0080 ) break;
idxNum |= 0x0100;
idxNum &= ~0x0200;
aIdx[5] = i;
bStartSeen = 1;
break;
}
case SQLITE_INDEX_CONSTRAINT_GT: {
if( idxNum & 0x0080 ) break;
idxNum |= 0x0200;
idxNum &= ~0x0100;
aIdx[5] = i;
bStartSeen = 1;
break;
}
case SQLITE_INDEX_CONSTRAINT_LE: {
if( idxNum & 0x0080 ) break;
idxNum |= 0x1000;
idxNum &= ~0x2000;
aIdx[6] = i;
break;
}
case SQLITE_INDEX_CONSTRAINT_LT: {
if( idxNum & 0x0080 ) break;
idxNum |= 0x2000;
idxNum &= ~0x1000;
aIdx[6] = i;
break;
}
}
continue;
}
iCol = pConstraint->iColumn - SERIES_COLUMN_START;
assert( iCol>=0 && iCol<=2 );
iMask = 1 << iCol;
@@ -534,7 +723,7 @@ static int seriesBestIndex(
idxNum &= ~0x60;
aIdx[4] = 0;
}
for(i=0; i<5; i++){
for(i=0; i<7; i++){
if( (j = aIdx[i])>=0 ){
pIdxInfo->aConstraintUsage[j].argvIndex = ++nArg;
pIdxInfo->aConstraintUsage[j].omit =
@@ -582,6 +771,9 @@ static int seriesBestIndex(
pIdxInfo->estimatedRows = 2147483647;
}
pIdxInfo->idxNum = idxNum;
#ifdef SQLITE_INDEX_SCAN_HEX
pIdxInfo->idxFlags = SQLITE_INDEX_SCAN_HEX;
#endif
return SQLITE_OK;
}
+25 -9
View File
@@ -196,7 +196,8 @@ static void hash_step_vformat(
** zOut[]. zOut[] must be at least 41 bytes long. */
static void hash_finish(
SHA1Context *p, /* The SHA1 context to finish and render */
char *zOut /* Store hexadecimal hash here */
char *zOut, /* Store hex or binary hash here */
int bAsBinary /* 1 for binary hash, 0 for hex hash */
){
unsigned int i;
unsigned char finalcount[8];
@@ -215,11 +216,15 @@ static void hash_finish(
for (i = 0; i < 20; i++){
digest[i] = (unsigned char)((p->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
}
for(i=0; i<20; i++){
zOut[i*2] = zEncode[(digest[i]>>4)&0xf];
zOut[i*2+1] = zEncode[digest[i] & 0xf];
if( bAsBinary ){
memcpy(zOut, digest, 20);
}else{
for(i=0; i<20; i++){
zOut[i*2] = zEncode[(digest[i]>>4)&0xf];
zOut[i*2+1] = zEncode[digest[i] & 0xf];
}
zOut[i*2]= 0;
}
zOut[i*2]= 0;
}
/* End of the hashing logic
*****************************************************************************/
@@ -251,8 +256,13 @@ static void sha1Func(
}else{
hash_step(&cx, sqlite3_value_text(argv[0]), nByte);
}
hash_finish(&cx, zOut);
sqlite3_result_text(context, zOut, 40, SQLITE_TRANSIENT);
if( sqlite3_user_data(context)!=0 ){
hash_finish(&cx, zOut, 1);
sqlite3_result_blob(context, zOut, 20, SQLITE_TRANSIENT);
}else{
hash_finish(&cx, zOut, 0);
sqlite3_result_blob(context, zOut, 40, SQLITE_TRANSIENT);
}
}
/*
@@ -365,7 +375,7 @@ static void sha1QueryFunc(
}
sqlite3_finalize(pStmt);
}
hash_finish(&cx, zOut);
hash_finish(&cx, zOut, 0);
sqlite3_result_text(context, zOut, 40, SQLITE_TRANSIENT);
}
@@ -379,11 +389,17 @@ int sqlite3_sha_init(
const sqlite3_api_routines *pApi
){
int rc = SQLITE_OK;
static int one = 1;
SQLITE_EXTENSION_INIT2(pApi);
(void)pzErrMsg; /* Unused parameter */
rc = sqlite3_create_function(db, "sha1", 1,
SQLITE_UTF8 | SQLITE_INNOCUOUS | SQLITE_DETERMINISTIC,
0, sha1Func, 0, 0);
0, sha1Func, 0, 0);
if( rc==SQLITE_OK ){
rc = sqlite3_create_function(db, "sha1b", 1,
SQLITE_UTF8 | SQLITE_INNOCUOUS | SQLITE_DETERMINISTIC,
(void*)&one, sha1Func, 0, 0);
}
if( rc==SQLITE_OK ){
rc = sqlite3_create_function(db, "sha1_query", 1,
SQLITE_UTF8|SQLITE_DIRECTONLY, 0,
+179 -50
View File
@@ -15,10 +15,20 @@
** Two SQL functions are implemented:
**
** sha3(X,SIZE)
** sha3_query(Y,SIZE)
** sha3_agg(Y,SIZE)
** sha3_query(Z,SIZE)
**
** The sha3(X) function computes the SHA3 hash of the input X, or NULL if
** X is NULL.
** X is NULL. If inputs X is text, the UTF-8 rendering of that text is
** used to compute the hash. If X is a BLOB, then the binary data of the
** blob is used to compute the hash. If X is an integer or real number,
** then that number if converted into UTF-8 text and the hash is computed
** over the text.
**
** The sha3_agg(Y) function computes the SHA3 hash of all Y inputs. Since
** order is important for the hash, it is recommended that the Y expression
** by followed by an ORDER BY clause to guarantee that the inputs occur
** in the desired order.
**
** The sha3_query(Y) function evaluates all queries in the SQL statements of Y
** and returns a hash of their results.
@@ -26,6 +36,68 @@
** The SIZE argument is optional. If omitted, the SHA3-256 hash algorithm
** is used. If SIZE is included it must be one of the integers 224, 256,
** 384, or 512, to determine SHA3 hash variant that is computed.
**
** Because the sha3_agg() and sha3_query() functions compute a hash over
** multiple values, the values are encode to use include type information.
**
** In sha3_agg(), the sequence of bytes that gets hashed for each input
** Y depends on the datatype of Y:
**
** typeof(Y)='null' A single "N" is hashed. (One byte)
**
** typeof(Y)='integer' The data hash is the character "I" followed
** by an 8-byte big-endian binary of the
** 64-bit signed integer. (Nine bytes total.)
**
** typeof(Y)='real' The character "F" followed by an 8-byte
** big-ending binary of the double. (Nine
** bytes total.)
**
** typeof(Y)='text' The hash is over prefix "Tnnn:" followed
** by the UTF8 encoding of the text. The "nnn"
** in the prefix is the minimum-length decimal
** representation of the octet_length of the text.
** Notice the ":" at the end of the prefix, which
** is needed to separate the prefix from the
** content in cases where the content starts
** with a digit.
**
** typeof(Y)='blob' The hash is taken over prefix "Bnnn:" followed
** by the binary content of the blob. The "nnn"
** in the prefix is the mimimum-length decimal
** representation of the byte-length of the blob.
**
** According to the rules above, all of the following SELECT statements
** should return TRUE:
**
** SELECT sha3(1) = sha3('1');
**
** SELECT sha3('hello') = sha3(x'68656c6c6f');
**
** WITH a(x) AS (VALUES('xyzzy'))
** SELECT sha3_agg(x) = sha3('T5:xyzzy') FROM a;
**
** WITH a(x) AS (VALUES(x'010203'))
** SELECT sha3_agg(x) = sha3(x'42333a010203') FROM a;
**
** WITH a(x) AS (VALUES(0x123456))
** SELECT sha3_agg(x) = sha3(x'490000000000123456') FROM a;
**
** WITH a(x) AS (VALUES(100.015625))
** SELECT sha3_agg(x) = sha3(x'464059010000000000') FROM a;
**
** WITH a(x) AS (VALUES(NULL))
** SELECT sha3_agg(x) = sha3('N') FROM a;
**
**
** In sha3_query(), individual column values are encoded as with
** sha3_agg(), but with the addition that a single "R" character is
** inserted at the start of each row.
**
** Note that sha3_agg() hashes rows for which Y is NULL. Add a FILTER
** clause if NULL rows should be excluded:
**
** SELECT sha3_agg(x ORDER BY rowid) FILTER(WHERE x NOT NULL) FROM t1;
*/
#include "sqlite3ext.h"
SQLITE_EXTENSION_INIT1
@@ -75,6 +147,7 @@ struct SHA3Context {
unsigned nRate; /* Bytes of input accepted per Keccak iteration */
unsigned nLoaded; /* Input bytes loaded into u.x[] so far this cycle */
unsigned ixMask; /* Insert next input into u.x[nLoaded^ixMask]. */
unsigned iSize; /* 224, 256, 358, or 512 */
};
/*
@@ -404,6 +477,7 @@ static void KeccakF1600Step(SHA3Context *p){
*/
static void SHA3Init(SHA3Context *p, int iSize){
memset(p, 0, sizeof(*p));
p->iSize = iSize;
if( iSize>=128 && iSize<=512 ){
p->nRate = (1600 - ((iSize + 31)&~31)*2)/8;
}else{
@@ -547,6 +621,60 @@ static void sha3_step_vformat(
SHA3Update(p, (unsigned char*)zBuf, n);
}
/*
** Update a SHA3Context using a single sqlite3_value.
*/
static void sha3UpdateFromValue(SHA3Context *p, sqlite3_value *pVal){
switch( sqlite3_value_type(pVal) ){
case SQLITE_NULL: {
SHA3Update(p, (const unsigned char*)"N",1);
break;
}
case SQLITE_INTEGER: {
sqlite3_uint64 u;
int j;
unsigned char x[9];
sqlite3_int64 v = sqlite3_value_int64(pVal);
memcpy(&u, &v, 8);
for(j=8; j>=1; j--){
x[j] = u & 0xff;
u >>= 8;
}
x[0] = 'I';
SHA3Update(p, x, 9);
break;
}
case SQLITE_FLOAT: {
sqlite3_uint64 u;
int j;
unsigned char x[9];
double r = sqlite3_value_double(pVal);
memcpy(&u, &r, 8);
for(j=8; j>=1; j--){
x[j] = u & 0xff;
u >>= 8;
}
x[0] = 'F';
SHA3Update(p,x,9);
break;
}
case SQLITE_TEXT: {
int n2 = sqlite3_value_bytes(pVal);
const unsigned char *z2 = sqlite3_value_text(pVal);
sha3_step_vformat(p,"T%d:",n2);
SHA3Update(p, z2, n2);
break;
}
case SQLITE_BLOB: {
int n2 = sqlite3_value_bytes(pVal);
const unsigned char *z2 = sqlite3_value_blob(pVal);
sha3_step_vformat(p,"B%d:",n2);
SHA3Update(p, z2, n2);
break;
}
}
}
/*
** Implementation of the sha3_query(SQL,SIZE) function.
**
@@ -636,54 +764,7 @@ static void sha3QueryFunc(
while( SQLITE_ROW==sqlite3_step(pStmt) ){
SHA3Update(&cx,(const unsigned char*)"R",1);
for(i=0; i<nCol; i++){
switch( sqlite3_column_type(pStmt,i) ){
case SQLITE_NULL: {
SHA3Update(&cx, (const unsigned char*)"N",1);
break;
}
case SQLITE_INTEGER: {
sqlite3_uint64 u;
int j;
unsigned char x[9];
sqlite3_int64 v = sqlite3_column_int64(pStmt,i);
memcpy(&u, &v, 8);
for(j=8; j>=1; j--){
x[j] = u & 0xff;
u >>= 8;
}
x[0] = 'I';
SHA3Update(&cx, x, 9);
break;
}
case SQLITE_FLOAT: {
sqlite3_uint64 u;
int j;
unsigned char x[9];
double r = sqlite3_column_double(pStmt,i);
memcpy(&u, &r, 8);
for(j=8; j>=1; j--){
x[j] = u & 0xff;
u >>= 8;
}
x[0] = 'F';
SHA3Update(&cx,x,9);
break;
}
case SQLITE_TEXT: {
int n2 = sqlite3_column_bytes(pStmt, i);
const unsigned char *z2 = sqlite3_column_text(pStmt, i);
sha3_step_vformat(&cx,"T%d:",n2);
SHA3Update(&cx, z2, n2);
break;
}
case SQLITE_BLOB: {
int n2 = sqlite3_column_bytes(pStmt, i);
const unsigned char *z2 = sqlite3_column_blob(pStmt, i);
sha3_step_vformat(&cx,"B%d:",n2);
SHA3Update(&cx, z2, n2);
break;
}
}
sha3UpdateFromValue(&cx, sqlite3_column_value(pStmt,i));
}
}
sqlite3_finalize(pStmt);
@@ -691,6 +772,44 @@ static void sha3QueryFunc(
sqlite3_result_blob(context, SHA3Final(&cx), iSize/8, SQLITE_TRANSIENT);
}
/*
** xStep function for sha3_agg().
*/
static void sha3AggStep(
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
SHA3Context *p;
p = (SHA3Context*)sqlite3_aggregate_context(context, sizeof(*p));
if( p==0 ) return;
if( p->nRate==0 ){
int sz = 256;
if( argc==2 ){
sz = sqlite3_value_int(argv[1]);
if( sz!=224 && sz!=384 && sz!=512 ){
sz = 256;
}
}
SHA3Init(p, sz);
}
sha3UpdateFromValue(p, argv[0]);
}
/*
** xFinal function for sha3_agg().
*/
static void sha3AggFinal(sqlite3_context *context){
SHA3Context *p;
p = (SHA3Context*)sqlite3_aggregate_context(context, sizeof(*p));
if( p==0 ) return;
if( p->iSize ){
sqlite3_result_blob(context, SHA3Final(p), p->iSize/8, SQLITE_TRANSIENT);
}
}
#ifdef _WIN32
__declspec(dllexport)
@@ -711,6 +830,16 @@ int sqlite3_shathree_init(
SQLITE_UTF8 | SQLITE_INNOCUOUS | SQLITE_DETERMINISTIC,
0, sha3Func, 0, 0);
}
if( rc==SQLITE_OK ){
rc = sqlite3_create_function(db, "sha3_agg", 1,
SQLITE_UTF8 | SQLITE_INNOCUOUS | SQLITE_DETERMINISTIC,
0, 0, sha3AggStep, sha3AggFinal);
}
if( rc==SQLITE_OK ){
rc = sqlite3_create_function(db, "sha3_agg", 2,
SQLITE_UTF8 | SQLITE_INNOCUOUS | SQLITE_DETERMINISTIC,
0, 0, sha3AggStep, sha3AggFinal);
}
if( rc==SQLITE_OK ){
rc = sqlite3_create_function(db, "sha3_query", 1,
SQLITE_UTF8 | SQLITE_DIRECTONLY,
+211
View File
@@ -0,0 +1,211 @@
/*
** 2024-09-24
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
**
** Implementation of standard I/O interfaces for UTF-8 that are missing
** on Windows.
*/
#ifdef _WIN32 /* This file is a no-op on all platforms except Windows */
#ifndef _SQLITE3_STDIO_H_
#include "sqlite3_stdio.h"
#endif
#undef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <assert.h>
#include "sqlite3.h"
#include <ctype.h>
#include <stdarg.h>
#include <io.h>
#include <fcntl.h>
/*
** If the SQLITE_U8TEXT_ONLY option is defined, then only use
** _O_U8TEXT, _O_WTEXT, and similar together with the UTF-16
** interfaces to the Windows CRT. The use of ANSI-only routines
** like fputs() and ANSI modes like _O_TEXT and _O_BINARY is
** avoided.
**
** The downside of using SQLITE_U8TEXT_ONLY is that it becomes
** impossible to output a bare newline character (0x0a) - that is,
** a newline that is not preceded by a carriage return (0x0d).
** And without that capability, sometimes the output will be slightly
** incorrect, as extra 0x0d characters will have been inserted where
** they do not belong.
**
** The SQLITE_U8TEXT_STDIO compile-time option is a compromise.
** It always enables _O_WTEXT or similar for stdin, stdout, stderr,
** but allows other streams to be _O_TEXT and/or O_BINARY. The
** SQLITE_U8TEXT_STDIO option has the same downside as SQLITE_U8TEXT_ONLY
** in that stray 0x0d characters might appear where they ought not, but
** at least with this option those characters only appear on standard
** I/O streams, and not on new streams that might be created by the
** application using sqlite3_fopen() or sqlite3_popen().
*/
#if defined(SQLITE_U8TEXT_ONLY)
# define UseWtextForOutput(fd) 1
# define UseWtextForInput(fd) 1
# define IsConsole(fd) _isatty(_fileno(fd))
#elif defined(SQLITE_U8TEXT_STDIO)
# define UseWtextForOutput(fd) ((fd)==stdout || (fd)==stderr)
# define UseWtextForInput(fd) ((fd)==stdin)
# define IsConsole(fd) _isatty(_fileno(fd))
#else
# define UseWtextForOutput(fd) _isatty(_fileno(fd))
# define UseWtextForInput(fd) _isatty(_fileno(fd))
# define IsConsole(fd) 1
#endif
/*
** Work-alike for the fopen() routine from the standard C library.
*/
FILE *sqlite3_fopen(const char *zFilename, const char *zMode){
FILE *fp = 0;
wchar_t *b1, *b2;
int sz1, sz2;
sz1 = (int)strlen(zFilename);
sz2 = (int)strlen(zMode);
b1 = malloc( (sz1+1)*sizeof(b1[0]) );
b2 = malloc( (sz2+1)*sizeof(b1[0]) );
if( b1 && b2 ){
sz1 = MultiByteToWideChar(CP_UTF8, 0, zFilename, sz1, b1, sz1);
b1[sz1] = 0;
sz2 = MultiByteToWideChar(CP_UTF8, 0, zMode, sz2, b2, sz2);
b2[sz2] = 0;
fp = _wfopen(b1, b2);
}
free(b1);
free(b2);
return fp;
}
/*
** Work-alike for the popen() routine from the standard C library.
*/
FILE *sqlite3_popen(const char *zCommand, const char *zMode){
FILE *fp = 0;
wchar_t *b1, *b2;
int sz1, sz2;
sz1 = (int)strlen(zCommand);
sz2 = (int)strlen(zMode);
b1 = malloc( (sz1+1)*sizeof(b1[0]) );
b2 = malloc( (sz2+1)*sizeof(b1[0]) );
if( b1 && b2 ){
sz1 = MultiByteToWideChar(CP_UTF8, 0, zCommand, sz1, b1, sz1);
b1[sz1] = 0;
sz2 = MultiByteToWideChar(CP_UTF8, 0, zMode, sz2, b2, sz2);
b2[sz2] = 0;
fp = _wpopen(b1, b2);
}
free(b1);
free(b2);
return fp;
}
/*
** Work-alike for fgets() from the standard C library.
*/
char *sqlite3_fgets(char *buf, int sz, FILE *in){
if( UseWtextForInput(in) ){
/* When reading from the command-prompt in Windows, it is necessary
** to use _O_WTEXT input mode to read UTF-16 characters, then translate
** that into UTF-8. Otherwise, non-ASCII characters all get translated
** into '?'.
*/
wchar_t *b1 = malloc( sz*sizeof(wchar_t) );
if( b1==0 ) return 0;
_setmode(_fileno(in), IsConsole(in) ? _O_WTEXT : _O_U8TEXT);
if( fgetws(b1, sz/4, in)==0 ){
sqlite3_free(b1);
return 0;
}
WideCharToMultiByte(CP_UTF8, 0, b1, -1, buf, sz, 0, 0);
sqlite3_free(b1);
return buf;
}else{
/* Reading from a file or other input source, just read bytes without
** any translation. */
return fgets(buf, sz, in);
}
}
/*
** Work-alike for fputs() from the standard C library.
*/
int sqlite3_fputs(const char *z, FILE *out){
if( UseWtextForOutput(out) ){
/* When writing to the command-prompt in Windows, it is necessary
** to use _O_WTEXT input mode and write UTF-16 characters.
*/
int sz = (int)strlen(z);
wchar_t *b1 = malloc( (sz+1)*sizeof(wchar_t) );
if( b1==0 ) return 0;
sz = MultiByteToWideChar(CP_UTF8, 0, z, sz, b1, sz);
b1[sz] = 0;
_setmode(_fileno(out), _O_U8TEXT);
fputws(b1, out);
sqlite3_free(b1);
return 0;
}else{
/* Writing to a file or other destination, just write bytes without
** any translation. */
return fputs(z, out);
}
}
/*
** Work-alike for fprintf() from the standard C library.
*/
int sqlite3_fprintf(FILE *out, const char *zFormat, ...){
int rc;
if( UseWtextForOutput(out) ){
/* When writing to the command-prompt in Windows, it is necessary
** to use _O_WTEXT input mode and write UTF-16 characters.
*/
char *z;
va_list ap;
va_start(ap, zFormat);
z = sqlite3_vmprintf(zFormat, ap);
va_end(ap);
sqlite3_fputs(z, out);
rc = (int)strlen(z);
sqlite3_free(z);
}else{
/* Writing to a file or other destination, just write bytes without
** any translation. */
va_list ap;
va_start(ap, zFormat);
rc = vfprintf(out, zFormat, ap);
va_end(ap);
}
return rc;
}
/*
** Set the mode for an output stream. mode argument is typically _O_BINARY or
** _O_TEXT.
*/
void sqlite3_fsetmode(FILE *fp, int mode){
if( !UseWtextForOutput(fp) ){
fflush(fp);
_setmode(_fileno(fp), mode);
}
}
#endif /* defined(_WIN32) */
+55
View File
@@ -0,0 +1,55 @@
/*
** 2024-09-24
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
**
** This header file contains definitions of interfaces that provide
** cross-platform I/O for UTF-8 content.
**
** On most platforms, the interfaces definitions in this file are
** just #defines. For example sqlite3_fopen() is a macro that resolves
** to the standard fopen() in the C-library.
**
** But Windows does not have a standard C-library, at least not one that
** can handle UTF-8. So for windows build, the interfaces resolve to new
** C-language routines contained in the separate sqlite3_stdio.c source file.
**
** So on all non-Windows platforms, simply #include this header file and
** use the interfaces defined herein. Then to run your application on Windows,
** also link in the accompanying sqlite3_stdio.c source file when compiling
** to get compatible interfaces.
*/
#ifndef _SQLITE3_STDIO_H_
#define _SQLITE3_STDIO_H_ 1
#ifdef _WIN32
/**** Definitions For Windows ****/
#include <stdio.h>
#include <windows.h>
FILE *sqlite3_fopen(const char *zFilename, const char *zMode);
FILE *sqlite3_popen(const char *zCommand, const char *type);
char *sqlite3_fgets(char *s, int size, FILE *stream);
int sqlite3_fputs(const char *s, FILE *stream);
int sqlite3_fprintf(FILE *stream, const char *format, ...);
void sqlite3_fsetmode(FILE *stream, int mode);
#else
/**** Definitions For All Other Platforms ****/
#include <stdio.h>
#define sqlite3_fopen fopen
#define sqlite3_popen popen
#define sqlite3_fgets fgets
#define sqlite3_fputs fputs
#define sqlite3_fprintf fprintf
#define sqlite3_fsetmode(F,X) /*no-op*/
#endif
#endif /* _SQLITE3_STDIO_H_ */
+151 -56
View File
@@ -182,7 +182,7 @@ static const char *vfstraceNextSystemCall(sqlite3_vfs*, const char *zName);
** xyzzy.txt -> xyzzy.txt
*/
static const char *fileTail(const char *z){
int i;
size_t i;
if( z==0 ) return 0;
i = strlen(z)-1;
while( i>0 && z[i-1]!='/' ){ i--; }
@@ -207,36 +207,34 @@ static void vfstrace_printf(
}
/*
** Convert value rc into a string and print it using zFormat. zFormat
** should have exactly one %s
** Try to convert an error code into a symbolic name for that error code.
*/
static void vfstrace_print_errcode(
vfstrace_info *pInfo,
const char *zFormat,
int rc
){
char zBuf[50];
char *zVal;
static const char *vfstrace_errcode_name(int rc ){
const char *zVal = 0;
switch( rc ){
case SQLITE_OK: zVal = "SQLITE_OK"; break;
case SQLITE_ERROR: zVal = "SQLITE_ERROR"; break;
case SQLITE_PERM: zVal = "SQLITE_PERM"; break;
case SQLITE_ABORT: zVal = "SQLITE_ABORT"; break;
case SQLITE_BUSY: zVal = "SQLITE_BUSY"; break;
case SQLITE_NOMEM: zVal = "SQLITE_NOMEM"; break;
case SQLITE_READONLY: zVal = "SQLITE_READONLY"; break;
case SQLITE_INTERRUPT: zVal = "SQLITE_INTERRUPT"; break;
case SQLITE_IOERR: zVal = "SQLITE_IOERR"; break;
case SQLITE_CORRUPT: zVal = "SQLITE_CORRUPT"; break;
case SQLITE_FULL: zVal = "SQLITE_FULL"; break;
case SQLITE_CANTOPEN: zVal = "SQLITE_CANTOPEN"; break;
case SQLITE_PROTOCOL: zVal = "SQLITE_PROTOCOL"; break;
case SQLITE_EMPTY: zVal = "SQLITE_EMPTY"; break;
case SQLITE_SCHEMA: zVal = "SQLITE_SCHEMA"; break;
case SQLITE_CONSTRAINT: zVal = "SQLITE_CONSTRAINT"; break;
case SQLITE_MISMATCH: zVal = "SQLITE_MISMATCH"; break;
case SQLITE_MISUSE: zVal = "SQLITE_MISUSE"; break;
case SQLITE_NOLFS: zVal = "SQLITE_NOLFS"; break;
case SQLITE_OK: zVal = "SQLITE_OK"; break;
case SQLITE_INTERNAL: zVal = "SQLITE_INTERNAL"; break;
case SQLITE_ERROR: zVal = "SQLITE_ERROR"; break;
case SQLITE_PERM: zVal = "SQLITE_PERM"; break;
case SQLITE_ABORT: zVal = "SQLITE_ABORT"; break;
case SQLITE_BUSY: zVal = "SQLITE_BUSY"; break;
case SQLITE_LOCKED: zVal = "SQLITE_LOCKED"; break;
case SQLITE_NOMEM: zVal = "SQLITE_NOMEM"; break;
case SQLITE_READONLY: zVal = "SQLITE_READONLY"; break;
case SQLITE_INTERRUPT: zVal = "SQLITE_INTERRUPT"; break;
case SQLITE_IOERR: zVal = "SQLITE_IOERR"; break;
case SQLITE_CORRUPT: zVal = "SQLITE_CORRUPT"; break;
case SQLITE_NOTFOUND: zVal = "SQLITE_NOTFOUND"; break;
case SQLITE_FULL: zVal = "SQLITE_FULL"; break;
case SQLITE_CANTOPEN: zVal = "SQLITE_CANTOPEN"; break;
case SQLITE_PROTOCOL: zVal = "SQLITE_PROTOCOL"; break;
case SQLITE_EMPTY: zVal = "SQLITE_EMPTY"; break;
case SQLITE_SCHEMA: zVal = "SQLITE_SCHEMA"; break;
case SQLITE_TOOBIG: zVal = "SQLITE_TOOBIG"; break;
case SQLITE_CONSTRAINT: zVal = "SQLITE_CONSTRAINT"; break;
case SQLITE_MISMATCH: zVal = "SQLITE_MISMATCH"; break;
case SQLITE_MISUSE: zVal = "SQLITE_MISUSE"; break;
case SQLITE_NOLFS: zVal = "SQLITE_NOLFS"; break;
case SQLITE_IOERR_READ: zVal = "SQLITE_IOERR_READ"; break;
case SQLITE_IOERR_SHORT_READ: zVal = "SQLITE_IOERR_SHORT_READ"; break;
case SQLITE_IOERR_WRITE: zVal = "SQLITE_IOERR_WRITE"; break;
@@ -266,11 +264,30 @@ static void vfstrace_print_errcode(
case SQLITE_LOCKED_SHAREDCACHE: zVal = "SQLITE_LOCKED_SHAREDCACHE"; break;
case SQLITE_BUSY_RECOVERY: zVal = "SQLITE_BUSY_RECOVERY"; break;
case SQLITE_CANTOPEN_NOTEMPDIR: zVal = "SQLITE_CANTOPEN_NOTEMPDIR"; break;
default: {
sqlite3_snprintf(sizeof(zBuf), zBuf, "%d", rc);
zVal = zBuf;
break;
}
return zVal;
}
/*
** Convert value rc into a string and print it using zFormat. zFormat
** should have exactly one %s
*/
static void vfstrace_print_errcode(
vfstrace_info *pInfo,
const char *zFormat,
int rc
){
const char *zVal;
char zBuf[50];
zVal = vfstrace_errcode_name(rc);
if( zVal==0 ){
zVal = vfstrace_errcode_name(rc&0xff);
if( zVal ){
sqlite3_snprintf(sizeof(zBuf), zBuf, "%s | 0x%x", zVal, rc&0xffff00);
}else{
sqlite3_snprintf(sizeof(zBuf), zBuf, "%d (0x%x)", rc, rc);
}
zVal = zBuf;
}
vfstrace_printf(pInfo, zFormat, zVal);
}
@@ -399,7 +416,7 @@ static const char *lockName(int eLock){
const char *azLockNames[] = {
"NONE", "SHARED", "RESERVED", "PENDING", "EXCLUSIVE"
};
if( eLock<0 || eLock>=sizeof(azLockNames)/sizeof(azLockNames[0]) ){
if( eLock<0 || eLock>=(int)(sizeof(azLockNames)/sizeof(azLockNames[0])) ){
return "???";
}else{
return azLockNames[eLock];
@@ -457,12 +474,14 @@ static int vfstraceFileControl(sqlite3_file *pFile, int op, void *pArg){
vfstrace_info *pInfo = p->pInfo;
int rc;
char zBuf[100];
char zBuf2[100];
char *zOp;
char *zRVal = 0;
switch( op ){
case SQLITE_FCNTL_LOCKSTATE: zOp = "LOCKSTATE"; break;
case SQLITE_GET_LOCKPROXYFILE: zOp = "GET_LOCKPROXYFILE"; break;
case SQLITE_SET_LOCKPROXYFILE: zOp = "SET_LOCKPROXYFILE"; break;
case SQLITE_LAST_ERRNO: zOp = "LAST_ERRNO"; break;
case SQLITE_FCNTL_LOCKSTATE: zOp = "LOCKSTATE"; break;
case SQLITE_GET_LOCKPROXYFILE: zOp = "GET_LOCKPROXYFILE"; break;
case SQLITE_SET_LOCKPROXYFILE: zOp = "SET_LOCKPROXYFILE"; break;
case SQLITE_LAST_ERRNO: zOp = "LAST_ERRNO"; break;
case SQLITE_FCNTL_SIZE_HINT: {
sqlite3_snprintf(sizeof(zBuf), zBuf, "SIZE_HINT,%lld",
*(sqlite3_int64*)pArg);
@@ -474,20 +493,62 @@ static int vfstraceFileControl(sqlite3_file *pFile, int op, void *pArg){
zOp = zBuf;
break;
}
case SQLITE_FCNTL_FILE_POINTER: zOp = "FILE_POINTER"; break;
case SQLITE_FCNTL_SYNC_OMITTED: zOp = "SYNC_OMITTED"; break;
case SQLITE_FCNTL_WIN32_AV_RETRY: zOp = "WIN32_AV_RETRY"; break;
case SQLITE_FCNTL_PERSIST_WAL: zOp = "PERSIST_WAL"; break;
case SQLITE_FCNTL_OVERWRITE: zOp = "OVERWRITE"; break;
case SQLITE_FCNTL_VFSNAME: zOp = "VFSNAME"; break;
case SQLITE_FCNTL_TEMPFILENAME: zOp = "TEMPFILENAME"; break;
case 0xca093fa0: zOp = "DB_UNCHANGED"; break;
case SQLITE_FCNTL_FILE_POINTER: zOp = "FILE_POINTER"; break;
case SQLITE_FCNTL_WIN32_AV_RETRY: zOp = "WIN32_AV_RETRY"; break;
case SQLITE_FCNTL_PERSIST_WAL: {
sqlite3_snprintf(sizeof(zBuf), zBuf, "PERSIST_WAL,%d", *(int*)pArg);
zOp = zBuf;
break;
}
case SQLITE_FCNTL_OVERWRITE: zOp = "OVERWRITE"; break;
case SQLITE_FCNTL_VFSNAME: zOp = "VFSNAME"; break;
case SQLITE_FCNTL_POWERSAFE_OVERWRITE: zOp = "POWERSAFE_OVERWRITE"; break;
case SQLITE_FCNTL_PRAGMA: {
const char *const* a = (const char*const*)pArg;
sqlite3_snprintf(sizeof(zBuf), zBuf, "PRAGMA,[%s,%s]",a[1],a[2]);
zOp = zBuf;
break;
}
case SQLITE_FCNTL_BUSYHANDLER: zOp = "BUSYHANDLER"; break;
case SQLITE_FCNTL_TEMPFILENAME: zOp = "TEMPFILENAME"; break;
case SQLITE_FCNTL_MMAP_SIZE: {
sqlite3_int64 iMMap = *(sqlite3_int64*)pArg;
sqlite3_snprintf(sizeof(zBuf), zBuf, "MMAP_SIZE,%lld",iMMap);
zOp = zBuf;
break;
}
case SQLITE_FCNTL_TRACE: zOp = "TRACE"; break;
case SQLITE_FCNTL_HAS_MOVED: zOp = "HAS_MOVED"; break;
case SQLITE_FCNTL_SYNC: zOp = "SYNC"; break;
case SQLITE_FCNTL_COMMIT_PHASETWO: zOp = "COMMIT_PHASETWO"; break;
case SQLITE_FCNTL_WIN32_SET_HANDLE: zOp = "WIN32_SET_HANDLE"; break;
case SQLITE_FCNTL_WAL_BLOCK: zOp = "WAL_BLOCK"; break;
case SQLITE_FCNTL_ZIPVFS: zOp = "ZIPVFS"; break;
case SQLITE_FCNTL_RBU: zOp = "RBU"; break;
case SQLITE_FCNTL_VFS_POINTER: zOp = "VFS_POINTER"; break;
case SQLITE_FCNTL_JOURNAL_POINTER: zOp = "JOURNAL_POINTER"; break;
case SQLITE_FCNTL_WIN32_GET_HANDLE: zOp = "WIN32_GET_HANDLE"; break;
case SQLITE_FCNTL_PDB: zOp = "PDB"; break;
case SQLITE_FCNTL_BEGIN_ATOMIC_WRITE: zOp = "BEGIN_ATOMIC_WRITE"; break;
case SQLITE_FCNTL_COMMIT_ATOMIC_WRITE: zOp = "COMMIT_ATOMIC_WRITE"; break;
case SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE: {
zOp = "ROLLBACK_ATOMIC_WRITE";
break;
}
case SQLITE_FCNTL_LOCK_TIMEOUT: {
sqlite3_snprintf(sizeof(zBuf), zBuf, "LOCK_TIMEOUT,%d", *(int*)pArg);
zOp = zBuf;
break;
}
case SQLITE_FCNTL_DATA_VERSION: zOp = "DATA_VERSION"; break;
case SQLITE_FCNTL_SIZE_LIMIT: zOp = "SIZE_LIMIT"; break;
case SQLITE_FCNTL_CKPT_DONE: zOp = "CKPT_DONE"; break;
case SQLITE_FCNTL_RESERVE_BYTES: zOp = "RESERVED_BYTES"; break;
case SQLITE_FCNTL_CKPT_START: zOp = "CKPT_START"; break;
case SQLITE_FCNTL_EXTERNAL_READER: zOp = "EXTERNAL_READER"; break;
case SQLITE_FCNTL_CKSM_FILE: zOp = "CKSM_FILE"; break;
case SQLITE_FCNTL_RESET_CACHE: zOp = "RESET_CACHE"; break;
case 0xca093fa0: zOp = "DB_UNCHANGED"; break;
default: {
sqlite3_snprintf(sizeof zBuf, zBuf, "%d", op);
zOp = zBuf;
@@ -497,15 +558,37 @@ static int vfstraceFileControl(sqlite3_file *pFile, int op, void *pArg){
vfstrace_printf(pInfo, "%s.xFileControl(%s,%s)",
pInfo->zVfsName, p->zFName, zOp);
rc = p->pReal->pMethods->xFileControl(p->pReal, op, pArg);
vfstrace_print_errcode(pInfo, " -> %s\n", rc);
if( op==SQLITE_FCNTL_VFSNAME && rc==SQLITE_OK ){
*(char**)pArg = sqlite3_mprintf("vfstrace.%s/%z",
if( rc==SQLITE_OK ){
switch( op ){
case SQLITE_FCNTL_VFSNAME: {
*(char**)pArg = sqlite3_mprintf("vfstrace.%s/%z",
pInfo->zVfsName, *(char**)pArg);
zRVal = *(char**)pArg;
break;
}
case SQLITE_FCNTL_MMAP_SIZE: {
sqlite3_snprintf(sizeof(zBuf2), zBuf2, "%lld", *(sqlite3_int64*)pArg);
zRVal = zBuf2;
break;
}
case SQLITE_FCNTL_HAS_MOVED:
case SQLITE_FCNTL_PERSIST_WAL: {
sqlite3_snprintf(sizeof(zBuf2), zBuf2, "%d", *(int*)pArg);
zRVal = zBuf2;
break;
}
case SQLITE_FCNTL_PRAGMA:
case SQLITE_FCNTL_TEMPFILENAME: {
zRVal = *(char**)pArg;
break;
}
}
}
if( (op==SQLITE_FCNTL_PRAGMA || op==SQLITE_FCNTL_TEMPFILENAME)
&& rc==SQLITE_OK && *(char**)pArg ){
vfstrace_printf(pInfo, "%s.xFileControl(%s,%s) returns %s",
pInfo->zVfsName, p->zFName, zOp, *(char**)pArg);
if( zRVal ){
vfstrace_print_errcode(pInfo, " -> %s", rc);
vfstrace_printf(pInfo, ", %s\n", zRVal);
}else{
vfstrace_print_errcode(pInfo, " -> %s\n", rc);
}
return rc;
}
@@ -840,14 +923,14 @@ int vfstrace_register(
sqlite3_vfs *pNew;
sqlite3_vfs *pRoot;
vfstrace_info *pInfo;
int nName;
int nByte;
size_t nName;
size_t nByte;
pRoot = sqlite3_vfs_find(zOldVfsName);
if( pRoot==0 ) return SQLITE_NOTFOUND;
nName = strlen(zTraceName);
nByte = sizeof(*pNew) + sizeof(*pInfo) + nName + 1;
pNew = sqlite3_malloc( nByte );
pNew = sqlite3_malloc64( nByte );
if( pNew==0 ) return SQLITE_NOMEM;
memset(pNew, 0, nByte);
pInfo = (vfstrace_info*)&pNew[1];
@@ -890,3 +973,15 @@ int vfstrace_register(
pInfo->zVfsName, pRoot->zName);
return sqlite3_vfs_register(pNew, makeDefault);
}
/*
** Look for the named VFS. If it is a TRACEVFS, then unregister it
** and delete it.
*/
void vfstrace_unregister(const char *zTraceName){
sqlite3_vfs *pVfs = sqlite3_vfs_find(zTraceName);
if( pVfs==0 ) return;
if( pVfs->xOpen!=vfstraceOpen ) return;
sqlite3_vfs_unregister(pVfs);
sqlite3_free(pVfs);
}
+10 -2
View File
@@ -35,6 +35,14 @@ SQLITE_EXTENSION_INIT1
#include <zlib.h>
/* When used as part of the CLI, the sqlite3_stdio.h module will have
** been included before this one. In that case use the sqlite3_stdio.h
** #defines. If not, create our own for fopen().
*/
#ifndef _SQLITE3_STDIO_H_
# define sqlite3_fopen fopen
#endif
#ifndef SQLITE_OMIT_VIRTUALTABLE
#ifndef SQLITE_AMALGAMATION
@@ -1291,7 +1299,7 @@ static int zipfileFilter(
}
if( 0==pTab->pWriteFd && 0==bInMemory ){
pCsr->pFile = zFile ? fopen(zFile, "rb") : 0;
pCsr->pFile = zFile ? sqlite3_fopen(zFile, "rb") : 0;
if( pCsr->pFile==0 ){
zipfileCursorErr(pCsr, "cannot open file: %s", zFile);
rc = SQLITE_ERROR;
@@ -1481,7 +1489,7 @@ static int zipfileBegin(sqlite3_vtab *pVtab){
** structure into memory. During the transaction any new file data is
** appended to the archive file, but the central directory is accumulated
** in main-memory until the transaction is committed. */
pTab->pWriteFd = fopen(pTab->zFile, "ab+");
pTab->pWriteFd = sqlite3_fopen(pTab->zFile, "ab+");
if( pTab->pWriteFd==0 ){
pTab->base.zErrMsg = sqlite3_mprintf(
"zipfile: failed to open file %s for writing", pTab->zFile
+35 -6
View File
@@ -336,6 +336,27 @@ struct RbuFrame {
u32 iWalFrame;
};
#ifndef UNUSED_PARAMETER
/*
** The following macros are used to suppress compiler warnings and to
** make it clear to human readers when a function parameter is deliberately
** left unused within the body of a function. This usually happens when
** a function is called via a function pointer. For example the
** implementation of an SQL aggregate step callback may not use the
** parameter indicating the number of arguments passed to the aggregate,
** if it knows that this is enforced elsewhere.
**
** When a function parameter is not used at all within the body of a function,
** it is generally named "NotUsed" or "NotUsed2" to make things even clearer.
** However, these macros may also be used to suppress warnings related to
** parameters that may or may not be used depending on compilation options.
** For example those parameters only used in assert() statements. In these
** cases the parameters are named as per the usual conventions.
*/
#define UNUSED_PARAMETER(x) (void)(x)
#define UNUSED_PARAMETER2(x,y) UNUSED_PARAMETER(x),UNUSED_PARAMETER(y)
#endif
/*
** RBU handle.
**
@@ -387,7 +408,7 @@ struct sqlite3rbu {
int rc; /* Value returned by last rbu_step() call */
char *zErrmsg; /* Error message if rc!=SQLITE_OK */
int nStep; /* Rows processed for current object */
int nProgress; /* Rows processed for all objects */
sqlite3_int64 nProgress; /* Rows processed for all objects */
RbuObjIter objiter; /* Iterator for skipping through tbl/idx */
const char *zVfsName; /* Name of automatically created rbu vfs */
rbu_file *pTargetFd; /* File handle open on target db */
@@ -504,7 +525,7 @@ static unsigned int rbuDeltaGetInt(const char **pz, int *pLen){
v = (v<<6) + c;
}
z--;
*pLen -= z - zStart;
*pLen -= (int)(z - zStart);
*pz = (char*)z;
return v;
}
@@ -689,6 +710,7 @@ static void rbuFossilDeltaFunc(
char *aOut;
assert( argc==2 );
UNUSED_PARAMETER(argc);
nOrig = sqlite3_value_bytes(argv[0]);
aOrig = (const char*)sqlite3_value_blob(argv[0]);
@@ -2268,13 +2290,13 @@ static char *rbuObjIterGetIndexWhere(sqlite3rbu *p, RbuObjIter *pIter){
else if( c==')' ){
nParen--;
if( nParen==0 ){
int nSpan = &zSql[i] - pIter->aIdxCol[iIdxCol].zSpan;
int nSpan = (int)(&zSql[i] - pIter->aIdxCol[iIdxCol].zSpan);
pIter->aIdxCol[iIdxCol++].nSpan = nSpan;
i++;
break;
}
}else if( c==',' && nParen==1 ){
int nSpan = &zSql[i] - pIter->aIdxCol[iIdxCol].zSpan;
int nSpan = (int)(&zSql[i] - pIter->aIdxCol[iIdxCol].zSpan);
pIter->aIdxCol[iIdxCol++].nSpan = nSpan;
pIter->aIdxCol[iIdxCol].zSpan = &zSql[i+1];
}else if( c=='"' || c=='\'' || c=='`' ){
@@ -2964,6 +2986,8 @@ static void rbuFileSuffix3(const char *zBase, char *z){
for(i=sz-1; i>0 && z[i]!='/' && z[i]!='.'; i--){}
if( z[i]=='.' && sz>i+4 ) memmove(&z[i+1], &z[sz-3], 4);
}
#else
UNUSED_PARAMETER2(zBase,z);
#endif
}
@@ -3548,7 +3572,7 @@ static void rbuSaveState(sqlite3rbu *p, int eStage){
"(%d, %Q), "
"(%d, %Q), "
"(%d, %d), "
"(%d, %d), "
"(%d, %lld), "
"(%d, %lld), "
"(%d, %lld), "
"(%d, %lld), "
@@ -3906,6 +3930,7 @@ static void rbuIndexCntFunc(
sqlite3 *db = (rbuIsVacuum(p) ? p->dbRbu : p->dbMain);
assert( nVal==1 );
UNUSED_PARAMETER(nVal);
rc = prepareFreeAndCollectError(db, &pStmt, &zErrmsg,
sqlite3_mprintf("SELECT count(*) FROM sqlite_schema "
@@ -4181,7 +4206,7 @@ sqlite3rbu *sqlite3rbu_vacuum(
){
if( zTarget==0 ){ return rbuMisuseError(); }
if( zState ){
int n = strlen(zState);
size_t n = strlen(zState);
if( n>=7 && 0==memcmp("-vactmp", &zState[n-7], 7) ){
return rbuMisuseError();
}
@@ -4398,6 +4423,7 @@ int sqlite3rbu_savestate(sqlite3rbu *p){
*/
static int xDefaultRename(void *pArg, const char *zOld, const char *zNew){
int rc = SQLITE_OK;
UNUSED_PARAMETER(pArg);
#if defined(_WIN32_WCE)
{
LPWSTR zWideOld;
@@ -5302,6 +5328,9 @@ static int rbuVfsCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
** No-op.
*/
static int rbuVfsGetLastError(sqlite3_vfs *pVfs, int a, char *b){
UNUSED_PARAMETER(pVfs);
UNUSED_PARAMETER(a);
UNUSED_PARAMETER(b);
return 0;
}
+2 -13
View File
@@ -17,14 +17,7 @@
#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_RBU)
#include "sqlite3rbu.h"
#if defined(INCLUDE_SQLITE_TCL_H)
# include "sqlite_tcl.h"
#else
# include "tcl.h"
# ifndef SQLITE_TCLAPI
# define SQLITE_TCLAPI
# endif
#endif
#include "tclsqlite.h"
#include <assert.h>
#include <string.h>
@@ -432,11 +425,7 @@ int SqliteRbu_Init(Tcl_Interp *interp){
}
#else
#if defined(INCLUDE_SQLITE_TCL_H)
# include "sqlite_tcl.h"
#else
# include "tcl.h"
#endif
#include "tclsqlite.h"
int SqliteRbu_Init(Tcl_Interp *interp){ return TCL_OK; }
#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_RBU) */
#endif /* defined(SQLITE_TEST) */
+1
View File
@@ -679,6 +679,7 @@ static int dbdataNext(sqlite3_vtab_cursor *pCursor){
** near the end of a corrupt record. */
rc = dbdataBufferSize(&pCsr->rec, nPayload+DBDATA_PADDING_BYTES);
if( rc!=SQLITE_OK ) return rc;
assert( pCsr->rec.aBuf!=0 );
assert( nPayload!=0 );
/* Load the nLocal bytes of payload */
+2 -3
View File
@@ -34,11 +34,11 @@ if {[permutation]!="inmemory_journal"} {
do_test 1.1 {
set sz [expr [file size test.db] - 1024]
set fd [open test.db]
fconfigure $fd -encoding binary -translation binary
fconfigure $fd -translation binary
set data [read $fd $sz]
set fd2 [open test.db2 w]
fconfigure $fd2 -encoding binary -translation binary
fconfigure $fd2 -translation binary
puts -nonewline $fd2 $data
close $fd2
set {} {}
@@ -61,4 +61,3 @@ if {[permutation]!="inmemory_journal"} {
}
finish_test
+3 -6
View File
@@ -39,14 +39,14 @@ foreach {pgsz bOverflow} {
set fd [open test.db]
fconfigure $fd -encoding binary -translation binary
fconfigure $fd -translation binary
seek $fd $pgsz
set pg1 [read $fd $pgsz]
set pg2 [read $fd $pgsz]
close $fd
set fd2 [open test.db2 w]
fconfigure $fd2 -encoding binary -translation binary
fconfigure $fd2 -translation binary
seek $fd2 $pgsz
puts -nonewline $fd2 $pg1
close $fd2
@@ -71,7 +71,7 @@ foreach {pgsz bOverflow} {
forcedelete test.db2
set fd2 [open test.db2 w]
fconfigure $fd2 -encoding binary -translation binary
fconfigure $fd2 -translation binary
seek $fd2 $pgsz
puts -nonewline $fd2 $pg2
close $fd2
@@ -95,6 +95,3 @@ foreach {pgsz bOverflow} {
finish_test
+1 -1
View File
@@ -363,8 +363,8 @@ static int recoverError(
va_start(ap, zFmt);
if( zFmt ){
z = sqlite3_vmprintf(zFmt, ap);
va_end(ap);
}
va_end(ap);
sqlite3_free(p->zErrMsg);
p->zErrMsg = z;
p->errCode = errCode;
+1 -3
View File
@@ -14,8 +14,7 @@
#include "sqlite3recover.h"
#include "sqliteInt.h"
#include <tcl.h>
#include "tclsqlite.h"
#include <assert.h>
#ifndef SQLITE_OMIT_VIRTUALTABLE
@@ -308,4 +307,3 @@ int TestRecover_Init(Tcl_Interp *interp){
#endif
return TCL_OK;
}
+3 -7
View File
@@ -14,11 +14,7 @@
*/
#include "sqlite3.h"
#if defined(INCLUDE_SQLITE_TCL_H)
# include "sqlite_tcl.h"
#else
# include "tcl.h"
#endif
#include "tclsqlite.h"
/* Solely for the UNUSED_PARAMETER() macro. */
#include "sqliteInt.h"
@@ -90,7 +86,7 @@ static int invokeTclGeomCb(
if( rc!=TCL_OK ){
rc = SQLITE_ERROR;
}else{
int nObj = 0;
Tcl_Size nObj = 0;
Tcl_Obj **aObj = 0;
pRes = Tcl_GetObjResult(interp);
@@ -279,7 +275,7 @@ static int box_query(sqlite3_rtree_query_info *pInfo){
if( rc==SQLITE_OK ){
double rScore = 0.0;
int nObj = 0;
Tcl_Size nObj = 0;
int eP = 0;
Tcl_Obj **aObj = 0;
Tcl_Obj *pRes = Tcl_GetObjResult(interp);
+1 -2
View File
@@ -27,7 +27,7 @@ if {$CF==""} {
proc writefile {zFile data} {
set fd [open $zFile w]
fconfigure $fd -translation binary -encoding binary
fconfigure $fd -translation binary
puts -nonewline $fd $data
close $fd
}
@@ -81,4 +81,3 @@ do_test 1.2 {
finish_test
+5 -2
View File
@@ -11,7 +11,10 @@
# This file implements regression tests for the session module.
#
package require Tcl 8.6
if {$tcl_version<8.6} {
puts "This module requires Tcl 8.6 or later"
return
}
if {![info exists testdir]} {
set testdir [file join [file dirname [info script]] .. .. test]
@@ -136,7 +139,7 @@ foreach {tn blob} {
do_test 2.$tn {
set changeset [binary decode hex $blob]
#set fd [open x.change w+]
#fconfigure $fd -encoding binary -translation binary
#fconfigure $fd -translation binary
#puts -nonewline $fd $changeset
#close $fd
list [catch { sqlite3changeset_apply db $changeset xConflict } msg] $msg
+1
View File
@@ -202,6 +202,7 @@ foreach {tn sql1 at sql2} {
sqlite3changegroup grp
grp schema db main
breakpoint
grp add $C1
grp add $C2
set T1 [grp output]
+1 -1
View File
@@ -47,7 +47,7 @@ proc database_cksum {db1} {
proc readfile {filename} {
set fd [open $filename]
fconfigure $fd -translation binary -encoding binary
fconfigure $fd -translation binary
set data [read $fd]
close $fd
set data
+1
View File
@@ -367,6 +367,7 @@ do_execsql_test 7.prep1 {
}
faultsim_save_and_close
unset -nocomplain res
set res [list]
for {set ::i 0} {$::i < 480} {incr ::i 4} {
lappend res "INSERT t1 0 X. {} {i $::i i $::i}"
+24
View File
@@ -56,4 +56,28 @@ do_faultsim_test 1 -faults oom* -prep {
faultsim_test_result {0 {}} {1 SQLITE_NOMEM}
}
#-------------------------------------------------------------------------
reset_db
do_execsql_test 2.0 {
CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
INSERT INTO t1 VALUES(1, 'one');
INSERT INTO t1 VALUES(2, 'two');
ALTER TABLE t1 ADD COLUMN c DEFAULT 'abcdefghijklmnopqrstuvwxyz';
}
faultsim_save_and_close
do_faultsim_test 2 -faults oom-t* -prep {
faultsim_restore_and_reopen
db eval {SELECT * FROM sqlite_schema}
} -body {
sqlite3session S db main
S attach *
execsql {
DELETE FROM t1 WHERE a = 1;
}
} -test {
faultsim_test_result {0 {}} {1 SQLITE_NOMEM}
catch { S delete }
}
finish_test
+1
View File
@@ -82,6 +82,7 @@ do_execsql_test 1.5 {
UPDATE p1 SET c=12345 WHERE a = 45;
}
breakpoint
sqlite3changeset_apply_v2 -noaction db $C conflict
do_execsql_test 1.6 {
SELECT * FROM c1
+32 -17
View File
@@ -74,6 +74,10 @@ struct SessionBuffer {
** input data. Input data may be supplied either as a single large buffer
** (e.g. sqlite3changeset_start()) or using a stream function (e.g.
** sqlite3changeset_start_strm()).
**
** bNoDiscard:
** If true, then the only time data is discarded is as a result of explicit
** sessionDiscardData() calls. Not within every sessionInputBuffer() call.
*/
struct SessionInput {
int bNoDiscard; /* If true, do not discard in InputBuffer() */
@@ -1757,16 +1761,19 @@ static void sessionPreupdateOneChange(
for(i=0; i<(pTab->nCol-pTab->bRowid); i++){
sqlite3_value *p = 0;
if( op!=SQLITE_INSERT ){
TESTONLY(int trc = ) pSession->hook.xOld(pSession->hook.pCtx, i, &p);
assert( trc==SQLITE_OK );
/* This may fail if the column has a non-NULL default and was added
** using ALTER TABLE ADD COLUMN after this record was created. */
rc = pSession->hook.xOld(pSession->hook.pCtx, i, &p);
}else if( pTab->abPK[i] ){
TESTONLY(int trc = ) pSession->hook.xNew(pSession->hook.pCtx, i, &p);
assert( trc==SQLITE_OK );
}
/* This may fail if SQLite value p contains a utf-16 string that must
** be converted to utf-8 and an OOM error occurs while doing so. */
rc = sessionSerializeValue(0, p, &nByte);
if( rc==SQLITE_OK ){
/* This may fail if SQLite value p contains a utf-16 string that must
** be converted to utf-8 and an OOM error occurs while doing so. */
rc = sessionSerializeValue(0, p, &nByte);
}
if( rc!=SQLITE_OK ) goto error_out;
}
if( pTab->bRowid ){
@@ -5124,15 +5131,21 @@ static int sessionChangesetApply(
int nTab = 0; /* Result of sqlite3Strlen30(zTab) */
SessionApplyCtx sApply; /* changeset_apply() context object */
int bPatchset;
u64 savedFlag = db->flags & SQLITE_FkNoAction;
assert( xConflict!=0 );
sqlite3_mutex_enter(sqlite3_db_mutex(db));
if( flags & SQLITE_CHANGESETAPPLY_FKNOACTION ){
db->flags |= ((u64)SQLITE_FkNoAction);
db->aDb[0].pSchema->schema_cookie -= 32;
}
pIter->in.bNoDiscard = 1;
memset(&sApply, 0, sizeof(sApply));
sApply.bRebase = (ppRebase && pnRebase);
sApply.bInvertConstraints = !!(flags & SQLITE_CHANGESETAPPLY_INVERT);
sApply.bIgnoreNoop = !!(flags & SQLITE_CHANGESETAPPLY_IGNORENOOP);
sqlite3_mutex_enter(sqlite3_db_mutex(db));
if( (flags & SQLITE_CHANGESETAPPLY_NOSAVEPOINT)==0 ){
rc = sqlite3_exec(db, "SAVEPOINT changeset_apply", 0, 0, 0);
}
@@ -5294,6 +5307,12 @@ static int sessionChangesetApply(
sqlite3_free((char*)sApply.azCol); /* cast works around VC++ bug */
sqlite3_free((char*)sApply.constraints.aBuf);
sqlite3_free((char*)sApply.rebase.aBuf);
if( (flags & SQLITE_CHANGESETAPPLY_FKNOACTION) && savedFlag==0 ){
assert( db->flags & SQLITE_FkNoAction );
db->flags &= ~((u64)SQLITE_FkNoAction);
db->aDb[0].pSchema->schema_cookie -= 32;
}
sqlite3_mutex_leave(sqlite3_db_mutex(db));
return rc;
}
@@ -5322,12 +5341,6 @@ int sqlite3changeset_apply_v2(
sqlite3_changeset_iter *pIter; /* Iterator to skip through changeset */
int bInv = !!(flags & SQLITE_CHANGESETAPPLY_INVERT);
int rc = sessionChangesetStart(&pIter, 0, 0, nChangeset, pChangeset, bInv, 1);
u64 savedFlag = db->flags & SQLITE_FkNoAction;
if( flags & SQLITE_CHANGESETAPPLY_FKNOACTION ){
db->flags |= ((u64)SQLITE_FkNoAction);
db->aDb[0].pSchema->schema_cookie -= 32;
}
if( rc==SQLITE_OK ){
rc = sessionChangesetApply(
@@ -5335,11 +5348,6 @@ int sqlite3changeset_apply_v2(
);
}
if( (flags & SQLITE_CHANGESETAPPLY_FKNOACTION) && savedFlag==0 ){
assert( db->flags & SQLITE_FkNoAction );
db->flags &= ~((u64)SQLITE_FkNoAction);
db->aDb[0].pSchema->schema_cookie -= 32;
}
return rc;
}
@@ -5660,6 +5668,9 @@ static int sessionChangesetExtendRecord(
sessionAppendBlob(pOut, aRec, nRec, &rc);
if( rc==SQLITE_OK && pTab->pDfltStmt==0 ){
rc = sessionPrepareDfltStmt(pGrp->db, pTab, &pTab->pDfltStmt);
if( rc==SQLITE_OK && SQLITE_ROW!=sqlite3_step(pTab->pDfltStmt) ){
rc = sqlite3_errcode(pGrp->db);
}
}
for(ii=nCol; rc==SQLITE_OK && ii<pTab->nCol; ii++){
int eType = sqlite3_column_type(pTab->pDfltStmt, ii);
@@ -5676,6 +5687,7 @@ static int sessionChangesetExtendRecord(
}
if( SQLITE_OK==sessionBufferGrow(pOut, 8, &rc) ){
sessionPutI64(&pOut->aBuf[pOut->nBuf], iVal);
pOut->nBuf += 8;
}
break;
}
@@ -5815,6 +5827,8 @@ static int sessionOneChangeToHash(
u8 *aRec = &pIter->in.aData[pIter->in.iCurrent + 2];
int nRec = (pIter->in.iNext - pIter->in.iCurrent) - 2;
assert( nRec>0 );
/* Ensure that only changesets, or only patchsets, but not a mixture
** of both, are being combined. It is an error to try to combine a
** changeset and a patchset. */
@@ -5892,6 +5906,7 @@ static int sessionChangesetToHash(
int nRec;
int rc = SQLITE_OK;
pIter->in.bNoDiscard = 1;
while( SQLITE_ROW==(sessionChangesetNext(pIter, &aRec, &nRec, 0)) ){
rc = sessionOneChangeToHash(pGrp, pIter, bRebase);
if( rc!=SQLITE_OK ) break;
+41 -40
View File
@@ -5,14 +5,7 @@
#include "sqlite3session.h"
#include <assert.h>
#include <string.h>
#if defined(INCLUDE_SQLITE_TCL_H)
# include "sqlite_tcl.h"
#else
# include "tcl.h"
# ifndef SQLITE_TCLAPI
# define SQLITE_TCLAPI
# endif
#endif
#include "tclsqlite.h"
#ifndef SQLITE_AMALGAMATION
typedef unsigned char u8;
@@ -390,10 +383,10 @@ static int SQLITE_TCLAPI test_session_cmd(
{ "rowid", SQLITE_SESSION_OBJCONFIG_ROWID },
{ 0, 0 }
};
size_t sz = sizeof(aOpt[0]);
int sz = (int)sizeof(aOpt[0]);
int iArg;
int iOpt;
Tcl_Size iOpt;
if( Tcl_GetIndexFromObjStruct(interp,objv[2],aOpt,sz,"option",0,&iOpt) ){
return TCL_ERROR;
}
@@ -517,11 +510,11 @@ struct TestConflictHandler {
};
static int test_obj_eq_string(Tcl_Obj *p, const char *z){
int n;
int nObj;
Tcl_Size n;
Tcl_Size nObj;
char *zObj;
n = (int)strlen(z);
n = (Tcl_Size)strlen(z);
zObj = Tcl_GetStringFromObj(p, &nObj);
return (nObj==n && (n==0 || 0==memcmp(zObj, z, n)));
@@ -796,7 +789,7 @@ static int SQLITE_TCLAPI testSqlite3changesetApply(
Tcl_CmdInfo info; /* Database Tcl command (objv[1]) info */
int rc; /* Return code from changeset_invert() */
void *pChangeset; /* Buffer containing changeset */
int nChangeset; /* Size of buffer aChangeset in bytes */
Tcl_Size nChangeset; /* Size of buffer aChangeset in bytes */
TestConflictHandler ctx;
TestStreamInput sStr;
void *pRebase = 0;
@@ -810,7 +803,7 @@ static int SQLITE_TCLAPI testSqlite3changesetApply(
if( bV2 ){
while( objc>1 ){
const char *z1 = Tcl_GetString(objv[1]);
int n = strlen(z1);
int n = (int)strlen(z1);
if( n>3 && n<=12 && 0==sqlite3_strnicmp("-nosavepoint", z1, n) ){
flags |= SQLITE_CHANGESETAPPLY_NOSAVEPOINT;
}
@@ -853,18 +846,18 @@ static int SQLITE_TCLAPI testSqlite3changesetApply(
if( sStr.nStream==0 ){
if( bV2==0 ){
rc = sqlite3changeset_apply(db, nChangeset, pChangeset,
rc = sqlite3changeset_apply(db, (int)nChangeset, pChangeset,
(objc==5)?test_filter_handler:0, test_conflict_handler, (void *)&ctx
);
}else{
rc = sqlite3changeset_apply_v2(db, nChangeset, pChangeset,
rc = sqlite3changeset_apply_v2(db, (int)nChangeset, pChangeset,
(objc==5)?test_filter_handler:0, test_conflict_handler, (void *)&ctx,
&pRebase, &nRebase, flags
);
}
}else{
sStr.aData = (unsigned char*)pChangeset;
sStr.nData = nChangeset;
sStr.nData = (int)nChangeset;
if( bV2==0 ){
rc = sqlite3changeset_apply_strm(db, testStreamInput, (void*)&sStr,
(objc==5) ? test_filter_handler : 0,
@@ -927,7 +920,7 @@ static int SQLITE_TCLAPI test_sqlite3changeset_apply_replace_all(
Tcl_CmdInfo info; /* Database Tcl command (objv[1]) info */
int rc; /* Return code from changeset_invert() */
void *pChangeset; /* Buffer containing changeset */
int nChangeset; /* Size of buffer aChangeset in bytes */
Tcl_Size nChangeset; /* Size of buffer aChangeset in bytes */
if( objc!=3 ){
Tcl_WrongNumArgs(interp, 1, objv, "DB CHANGESET");
@@ -940,7 +933,8 @@ static int SQLITE_TCLAPI test_sqlite3changeset_apply_replace_all(
db = *(sqlite3 **)info.objClientData;
pChangeset = (void *)Tcl_GetByteArrayFromObj(objv[2], &nChangeset);
rc = sqlite3changeset_apply(db, nChangeset, pChangeset, 0, replace_handler,0);
rc = sqlite3changeset_apply(db, (int)nChangeset, pChangeset,
0, replace_handler,0);
if( rc!=SQLITE_OK ){
return test_session_error(interp, rc, 0);
}
@@ -959,6 +953,7 @@ static int SQLITE_TCLAPI test_sqlite3changeset_invert(
Tcl_Obj *CONST objv[]
){
int rc; /* Return code from changeset_invert() */
Tcl_Size nn;
TestStreamInput sIn; /* Input stream */
TestSessionsBlob sOut; /* Output blob */
@@ -970,7 +965,8 @@ static int SQLITE_TCLAPI test_sqlite3changeset_invert(
memset(&sIn, 0, sizeof(sIn));
memset(&sOut, 0, sizeof(sOut));
sIn.nStream = test_tcl_integer(interp, SESSION_STREAM_TCL_VAR);
sIn.aData = Tcl_GetByteArrayFromObj(objv[1], &sIn.nData);
sIn.aData = Tcl_GetByteArrayFromObj(objv[1], &nn);
sIn.nData = (int)nn;
if( sIn.nStream ){
rc = sqlite3changeset_invert_strm(
@@ -999,6 +995,7 @@ static int SQLITE_TCLAPI test_sqlite3changeset_concat(
Tcl_Obj *CONST objv[]
){
int rc; /* Return code from changeset_invert() */
Tcl_Size nn;
TestStreamInput sLeft; /* Input stream */
TestStreamInput sRight; /* Input stream */
@@ -1011,8 +1008,10 @@ static int SQLITE_TCLAPI test_sqlite3changeset_concat(
memset(&sLeft, 0, sizeof(sLeft));
memset(&sRight, 0, sizeof(sRight));
sLeft.aData = Tcl_GetByteArrayFromObj(objv[1], &sLeft.nData);
sRight.aData = Tcl_GetByteArrayFromObj(objv[2], &sRight.nData);
sLeft.aData = Tcl_GetByteArrayFromObj(objv[1], &nn);
sLeft.nData = (int)nn;
sRight.aData = Tcl_GetByteArrayFromObj(objv[2], &nn);
sRight.nData = (int)nn;
sLeft.nStream = test_tcl_integer(interp, SESSION_STREAM_TCL_VAR);
sRight.nStream = sLeft.nStream;
@@ -1106,7 +1105,7 @@ static int SQLITE_TCLAPI test_sqlite3session_foreach(
Tcl_Obj *CONST objv[]
){
void *pChangeset;
int nChangeset;
Tcl_Size nChangeset;
sqlite3_changeset_iter *pIter;
int rc;
Tcl_Obj *pVarname;
@@ -1120,7 +1119,7 @@ static int SQLITE_TCLAPI test_sqlite3session_foreach(
while( objc>1 ){
char *zOpt = Tcl_GetString(objv[1]);
int nOpt = strlen(zOpt);
int nOpt = (int)strlen(zOpt);
if( zOpt[0]!='-' ) break;
if( nOpt<=7 && 0==sqlite3_strnicmp(zOpt, "-invert", nOpt) ){
isInvert = 1;
@@ -1148,19 +1147,19 @@ static int SQLITE_TCLAPI test_sqlite3session_foreach(
if( isInvert ){
int f = SQLITE_CHANGESETSTART_INVERT;
if( sStr.nStream==0 ){
rc = sqlite3changeset_start_v2(&pIter, nChangeset, pChangeset, f);
rc = sqlite3changeset_start_v2(&pIter, (int)nChangeset, pChangeset, f);
}else{
void *pCtx = (void*)&sStr;
sStr.aData = (unsigned char*)pChangeset;
sStr.nData = nChangeset;
sStr.nData = (int)nChangeset;
rc = sqlite3changeset_start_v2_strm(&pIter, testStreamInput, pCtx, f);
}
}else{
if( sStr.nStream==0 ){
rc = sqlite3changeset_start(&pIter, nChangeset, pChangeset);
rc = sqlite3changeset_start(&pIter, (int)nChangeset, pChangeset);
}else{
sStr.aData = (unsigned char*)pChangeset;
sStr.nData = nChangeset;
sStr.nData = (int)nChangeset;
rc = sqlite3changeset_start_strm(&pIter, testStreamInput, (void*)&sStr);
}
}
@@ -1237,9 +1236,9 @@ static int SQLITE_TCLAPI test_rebaser_cmd(
assert( rc==SQLITE_OK );
switch( iSub ){
case 0: { /* configure */
int nRebase = 0;
Tcl_Size nRebase = 0;
unsigned char *pRebase = Tcl_GetByteArrayFromObj(objv[2], &nRebase);
rc = sqlite3rebaser_configure(p, nRebase, pRebase);
rc = sqlite3rebaser_configure(p, (int)nRebase, pRebase);
break;
}
@@ -1250,10 +1249,12 @@ static int SQLITE_TCLAPI test_rebaser_cmd(
default: { /* rebase */
TestStreamInput sStr; /* Input stream */
TestSessionsBlob sOut; /* Output blob */
Tcl_Size nn;
memset(&sStr, 0, sizeof(sStr));
memset(&sOut, 0, sizeof(sOut));
sStr.aData = Tcl_GetByteArrayFromObj(objv[2], &sStr.nData);
sStr.aData = Tcl_GetByteArrayFromObj(objv[2], &nn);
sStr.nData = nn;
sStr.nStream = test_tcl_integer(interp, SESSION_STREAM_TCL_VAR);
if( sStr.nStream ){
@@ -1392,7 +1393,7 @@ static int SQLITE_TCLAPI test_changeset(
Tcl_Obj *CONST objv[]
){
void *pChangeset = 0; /* Buffer containing changeset */
int nChangeset = 0; /* Size of buffer aChangeset in bytes */
Tcl_Size nChangeset = 0; /* Size of buffer aChangeset in bytes */
int rc = SQLITE_OK;
char *z = 0;
@@ -1403,7 +1404,7 @@ static int SQLITE_TCLAPI test_changeset(
pChangeset = (void *)Tcl_GetByteArrayFromObj(objv[1], &nChangeset);
Tcl_ResetResult(interp);
rc = sqlite3_test_changeset(nChangeset, pChangeset, &z);
rc = sqlite3_test_changeset((int)nChangeset, pChangeset, &z);
if( rc!=SQLITE_OK ){
char *zErr = sqlite3_mprintf("(%d) - \"%s\"", rc, z);
Tcl_SetObjResult(interp, Tcl_NewStringObj(zErr, -1));
@@ -1528,9 +1529,9 @@ static int SQLITE_TCLAPI test_changegroup_cmd(
};
case 1: { /* add */
int nByte = 0;
Tcl_Size nByte = 0;
const u8 *aByte = Tcl_GetByteArrayFromObj(objv[2], &nByte);
rc = sqlite3changegroup_add(p->pGrp, nByte, (void*)aByte);
rc = sqlite3changegroup_add(p->pGrp, (int)nByte, (void*)aByte);
if( rc!=SQLITE_OK ) rc = test_session_error(interp, rc, 0);
break;
};
@@ -1678,7 +1679,7 @@ static int SQLITE_TCLAPI test_sqlite3changeset_start(
){
int isInvert = 0;
void *pChangeset = 0; /* Buffer containing changeset */
int nChangeset = 0; /* Size of buffer aChangeset in bytes */
Tcl_Size nChangeset = 0; /* Size of buffer aChangeset in bytes */
TestChangeIter *pNew = 0;
sqlite3_changeset_iter *pIter = 0;
int flags = 0;
@@ -1688,9 +1689,9 @@ static int SQLITE_TCLAPI test_sqlite3changeset_start(
char zCmd[64];
if( objc==3 ){
int n = 0;
Tcl_Size n = 0;
const char *z = Tcl_GetStringFromObj(objv[1], &n);
isInvert = (n>=2 && sqlite3_strnicmp(z, "-invert", n)==0);
isInvert = (n>=2 && sqlite3_strnicmp(z, "-invert", (int)n)==0);
}
if( objc!=2 && (objc!=3 || !isInvert) ){
@@ -1700,7 +1701,7 @@ static int SQLITE_TCLAPI test_sqlite3changeset_start(
flags = isInvert ? SQLITE_CHANGESETSTART_INVERT : 0;
pChangeset = (void *)Tcl_GetByteArrayFromObj(objv[objc-1], &nChangeset);
rc = sqlite3changeset_start_v2(&pIter, nChangeset, pChangeset, flags);
rc = sqlite3changeset_start_v2(&pIter, (int)nChangeset, pChangeset, flags);
if( rc!=SQLITE_OK ){
char *zErr = sqlite3_mprintf(
"error in sqlite3changeset_start_v2() - %d", rc
+26 -5
View File
@@ -233,6 +233,14 @@ SQLITE_OPT = \
# can be used to find errant uses of sqlite3_js_vfs_create_file()
# in client code.
########################################################################
# minimal=1 disables all "extraneous" stuff from sqlite3-wasm.c, the
# goal being to create a WASM file with only the core APIs.
minimal ?= 0
ifeq (1,$(minimal))
SQLITE_OPT += -DSQLITE_WASM_MINIMAL
endif
########################################################################@
# It's important that sqlite3.h be built to completion before any
# other parts of the build run, thus we use .NOTPARALLEL to disable
@@ -413,11 +421,22 @@ emcc_opt_full := $(emcc_opt) -g3
########################################################################
# EXPORTED_FUNCTIONS.* = files for use with Emscripten's
# -sEXPORTED_FUNCTION flag.
EXPORTED_FUNCTIONS.api.main := $(abspath $(dir.api)/EXPORTED_FUNCTIONS.sqlite3-api)
EXPORTED_FUNCTIONS.api.in := $(EXPORTED_FUNCTIONS.api.main)
EXPORTED_FUNCTIONS.api.core := $(abspath $(dir.api)/EXPORTED_FUNCTIONS.sqlite3-core)
EXPORTED_FUNCTIONS.api.in := $(EXPORTED_FUNCTIONS.api.core)
ifeq (1,$(SQLITE_C_IS_SEE))
EXPORTED_FUNCTIONS.api.in += $(abspath $(dir.api)/EXPORTED_FUNCTIONS.sqlite3-see)
endif
ifeq (0,$(minimal))
EXPORTED_FUNCTIONS.api.in += \
$(abspath $(dir.api)/EXPORTED_FUNCTIONS.sqlite3-auth) \
$(abspath $(dir.api)/EXPORTED_FUNCTIONS.sqlite3-preupdate) \
$(abspath $(dir.api)/EXPORTED_FUNCTIONS.sqlite3-session) \
$(abspath $(dir.api)/EXPORTED_FUNCTIONS.sqlite3-vtab)
else
$(info ========================================)
$(info This is a minimal-mode build)
$(info ========================================)
endif
EXPORTED_FUNCTIONS.api := $(dir.tmp)/EXPORTED_FUNCTIONS.api
$(EXPORTED_FUNCTIONS.api): $(EXPORTED_FUNCTIONS.api.in) $(sqlite3.c) $(MAKEFILE)
cat $(EXPORTED_FUNCTIONS.api.in) > $@
@@ -1059,9 +1078,9 @@ speedtest1.exit-runtime1 := -sEXIT_RUNTIME=1
# -sEXIT_RUNTIME=1 but we need EXIT_RUNTIME=0 for the worker-based app
# which runs speedtest1 multiple times.
$(EXPORTED_FUNCTIONS.speedtest1): $(EXPORTED_FUNCTIONS.api.main)
$(EXPORTED_FUNCTIONS.speedtest1): $(EXPORTED_FUNCTIONS.api.core)
@echo "Making $@ ..."
@{ echo _wasm_main; cat $(EXPORTED_FUNCTIONS.api.main); } > $@
@{ echo _wasm_main; cat $(EXPORTED_FUNCTIONS.api.core); } > $@
speedtest1.js := $(dir.dout)/speedtest1.js
speedtest1.wasm := $(dir.dout)/speedtest1.wasm
emcc.flags.speedtest1-vanilla := $(cflags.common) -DSQLITE_SPEEDTEST1_WASM
@@ -1077,6 +1096,7 @@ $(speedtest1.js): $(MAKEFILE) $(speedtest1.cfiles) \
$(emcc.speedtest1.common) \
$(emcc.flags.speedtest1-vanilla) $(pre-post-speedtest1-vanilla.flags) \
$(SQLITE_OPT) \
-USQLITE_WASM_MINIMAL \
-USQLITE_C -DSQLITE_C=$(sqlite3.canonical.c) \
$(speedtest1.exit-runtime0) \
-o $@ $(speedtest1.cfiles) -lm
@@ -1184,7 +1204,7 @@ endif
# Push files to public wasm-testing.sqlite.org server
wasm-testing.include = *.js *.mjs *.html \
./tests \
$(dir.dout) $(dir.common) $(dir.fiddle) $(dir.jacc)
$(dir.dout) $(dir.common) $(dir.fiddle) $(dir.fiddle-debug) $(dir.jacc)
wasm-testing.exclude = sql/speedtest1.sql
wasm-testing.dir = /jail/sites/wasm-testing
wasm-testing.dest ?= wasm-testing:$(wasm-testing.dir)
@@ -1233,3 +1253,4 @@ endif
# Run local web server for the test/demo pages.
httpd:
althttpd -max-age 1 -enable-sab 1 -page index.html
@@ -0,0 +1 @@
_sqlite3_set_authorizer
@@ -10,6 +10,7 @@ _sqlite3_bind_int64
_sqlite3_bind_null
_sqlite3_bind_parameter_count
_sqlite3_bind_parameter_index
_sqlite3_bind_parameter_name
_sqlite3_bind_pointer
_sqlite3_bind_text
_sqlite3_busy_handler
@@ -23,7 +24,7 @@ _sqlite3_collation_needed
_sqlite3_column_blob
_sqlite3_column_bytes
_sqlite3_column_count
_sqlite3_column_count
_sqlite3_column_decltype
_sqlite3_column_double
_sqlite3_column_int
_sqlite3_column_int64
@@ -40,15 +41,13 @@ _sqlite3_create_collation
_sqlite3_create_collation_v2
_sqlite3_create_function
_sqlite3_create_function_v2
_sqlite3_create_module
_sqlite3_create_module_v2
_sqlite3_create_window_function
_sqlite3_data_count
_sqlite3_db_filename
_sqlite3_db_handle
_sqlite3_db_name
_sqlite3_db_readonly
_sqlite3_db_status
_sqlite3_declare_vtab
_sqlite3_deserialize
_sqlite3_drop_modules
_sqlite3_errcode
@@ -65,6 +64,8 @@ _sqlite3_free
_sqlite3_get_auxdata
_sqlite3_get_autocommit
_sqlite3_initialize
_sqlite3_interrupt
_sqlite3_is_interrupted
_sqlite3_keyword_count
_sqlite3_keyword_name
_sqlite3_keyword_check
@@ -80,12 +81,6 @@ _sqlite3_open_v2
_sqlite3_overload_function
_sqlite3_prepare_v2
_sqlite3_prepare_v3
_sqlite3_preupdate_blobwrite
_sqlite3_preupdate_count
_sqlite3_preupdate_depth
_sqlite3_preupdate_hook
_sqlite3_preupdate_new
_sqlite3_preupdate_old
_sqlite3_progress_handler
_sqlite3_randomness
_sqlite3_realloc
@@ -108,7 +103,6 @@ _sqlite3_result_zeroblob
_sqlite3_result_zeroblob64
_sqlite3_rollback_hook
_sqlite3_serialize
_sqlite3_set_authorizer
_sqlite3_set_auxdata
_sqlite3_set_last_insert_rowid
_sqlite3_shutdown
@@ -117,6 +111,8 @@ _sqlite3_sql
_sqlite3_status
_sqlite3_status64
_sqlite3_step
_sqlite3_stmt_busy
_sqlite3_stmt_explain
_sqlite3_stmt_isexplain
_sqlite3_stmt_readonly
_sqlite3_stmt_status
@@ -160,45 +156,3 @@ _sqlite3_vtab_in_next
_sqlite3_vtab_nochange
_sqlite3_vtab_on_conflict
_sqlite3_vtab_rhs_value
_sqlite3changegroup_add
_sqlite3changegroup_add_strm
_sqlite3changegroup_delete
_sqlite3changegroup_new
_sqlite3changegroup_output
_sqlite3changegroup_output_strm
_sqlite3changeset_apply
_sqlite3changeset_apply_strm
_sqlite3changeset_apply_v2
_sqlite3changeset_apply_v2_strm
_sqlite3changeset_concat
_sqlite3changeset_concat_strm
_sqlite3changeset_conflict
_sqlite3changeset_finalize
_sqlite3changeset_fk_conflicts
_sqlite3changeset_invert
_sqlite3changeset_invert_strm
_sqlite3changeset_new
_sqlite3changeset_next
_sqlite3changeset_old
_sqlite3changeset_op
_sqlite3changeset_pk
_sqlite3changeset_start
_sqlite3changeset_start_strm
_sqlite3changeset_start_v2
_sqlite3changeset_start_v2_strm
_sqlite3session_attach
_sqlite3session_changeset
_sqlite3session_changeset_size
_sqlite3session_changeset_strm
_sqlite3session_config
_sqlite3session_create
_sqlite3session_delete
_sqlite3session_diff
_sqlite3session_enable
_sqlite3session_indirect
_sqlite3session_isempty
_sqlite3session_memory_used
_sqlite3session_object_config
_sqlite3session_patchset
_sqlite3session_patchset_strm
_sqlite3session_table_filter
@@ -0,0 +1,6 @@
_sqlite3_preupdate_blobwrite
_sqlite3_preupdate_count
_sqlite3_preupdate_depth
_sqlite3_preupdate_hook
_sqlite3_preupdate_new
_sqlite3_preupdate_old
@@ -0,0 +1,42 @@
_sqlite3changegroup_add
_sqlite3changegroup_add_strm
_sqlite3changegroup_delete
_sqlite3changegroup_new
_sqlite3changegroup_output
_sqlite3changegroup_output_strm
_sqlite3changeset_apply
_sqlite3changeset_apply_strm
_sqlite3changeset_apply_v2
_sqlite3changeset_apply_v2_strm
_sqlite3changeset_concat
_sqlite3changeset_concat_strm
_sqlite3changeset_conflict
_sqlite3changeset_finalize
_sqlite3changeset_fk_conflicts
_sqlite3changeset_invert
_sqlite3changeset_invert_strm
_sqlite3changeset_new
_sqlite3changeset_next
_sqlite3changeset_old
_sqlite3changeset_op
_sqlite3changeset_pk
_sqlite3changeset_start
_sqlite3changeset_start_strm
_sqlite3changeset_start_v2
_sqlite3changeset_start_v2_strm
_sqlite3session_attach
_sqlite3session_changeset
_sqlite3session_changeset_size
_sqlite3session_changeset_strm
_sqlite3session_config
_sqlite3session_create
_sqlite3session_delete
_sqlite3session_diff
_sqlite3session_enable
_sqlite3session_indirect
_sqlite3session_isempty
_sqlite3session_memory_used
_sqlite3session_object_config
_sqlite3session_patchset
_sqlite3session_patchset_strm
_sqlite3session_table_filter
@@ -0,0 +1,11 @@
_sqlite3_create_module
_sqlite3_create_module_v2
_sqlite3_declare_vtab
_sqlite3_vtab_collation
_sqlite3_vtab_distinct
_sqlite3_vtab_in
_sqlite3_vtab_in_first
_sqlite3_vtab_in_next
_sqlite3_vtab_nochange
_sqlite3_vtab_on_conflict
_sqlite3_vtab_rhs_value

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