Compare commits

...

68 Commits

Author SHA1 Message Date
drh 84c1079220 Add a missing open_db() call in the new ".dbstat" command of the CLI.
FossilOrigin-Name: a138e44a243466f8679e9652421f8c893a4a1bc0addc86736588d9aee51cf090
2026-04-15 11:58:54 +00:00
drh c8d866294b Add the .dbstat command to the CLI.
FossilOrigin-Name: fdba76df2b3a5b4d56ba79f80fd8b16d5faebca1fb07a266262be2ea635e6f94
2026-04-15 11:41:50 +00:00
drh 9efde40a5d Compute the average fanout for b-trees of depth 2 or more.
FossilOrigin-Name: 2f8598bb09f32100f22dd1d9465f3fa0f7f8d81f5d67c34de9919708345f090b
2026-04-15 10:49:14 +00:00
drh 09f37099a7 Code simplifications. Return NULL is the specified SCHEMA does not exist.
FossilOrigin-Name: 953969c88149ea2f589942b98a0a96d907956319e5aa09e2d5a3ae76d3e7d70a
2026-04-14 23:19:02 +00:00
drh 526acc1834 Merge trunk enhancements and fixes into the analyze-sql-func branch.
FossilOrigin-Name: bb4a9beac87796b4186efce416bf03f840041bc588be6702c5a444d643df684e
2026-04-14 20:17:03 +00:00
drh d962afef2d Various minor tweaks and refinements to the analyze() function.
FossilOrigin-Name: 48d94e72eaec443011dd1f7a7264e5222c05bb515c84deaf20ed4195b74d45ff
2026-04-14 20:07:29 +00:00
drh 395ac6c1bc Implementation of the analyze() SQL function is now mostly complete.
FossilOrigin-Name: 1ca0386ab2df0d88ed52941469d459114f483ecf6b7e4691bcc32e909636cb7d
2026-04-14 19:36:33 +00:00
drh e9d0bc6b68 Much, but not all, of the report generation is added. An incremental check-in.
FossilOrigin-Name: 289fefc3edfeecb06dc11897d3ff24763fd9e25db44e369eeec29b9ed3de5ccc
2026-04-14 19:02:40 +00:00
dan ab6a63ec67 In RBU vacuum commands, do as SQLite does and ignore any trailing SQL statements in the sql column of the sqlite_schema table.
FossilOrigin-Name: cf7dad1b105ab35cd7180efec735b7cbeaf42b8d53dfec5582b63cd121c3425c
2026-04-14 18:08:30 +00:00
drh 57ed7f322f Check-in [495e4851d4296b49] breaks the build for Windows. Fixed here.
FossilOrigin-Name: 5b004348c3ec15a02dd657b3619502b6f8ba1c6f46918108b3de9534622076a0
2026-04-14 18:06:41 +00:00
drh 34c2c8dc47 Further fixes and clarifications. Now ready to start generating the
actual report.

FossilOrigin-Name: 037a0e586c4aa81a53aea164080e739f9d5b87197d04fdd68feb0ab5eb01020b
2026-04-14 13:18:04 +00:00
drh 3f9df1f5fb Further improvements to error messages and robustness.
FossilOrigin-Name: 45917c1124310fd77daca47865959d3261154f7b0c6771d3689e6d345a3fd153
2026-04-14 12:46:12 +00:00
drh 2eeac123c8 Improved error messages and robustness.
FossilOrigin-Name: c09ed9eb914bde96cdc5157e29b6384ce488262a2dadc7321c44941a1d08a187
2026-04-14 12:23:11 +00:00
drh 64a123a216 Initial prototype implementation of a new run-time loadable SQL function
to do approximately the same work as sqlite3_analyze.

FossilOrigin-Name: 03934b5a6c88a97117a4743a68ee36d30bcbdcebcf11342d30ac42daf9f10874
2026-04-14 11:25:22 +00:00
stephan a10e79d91a Minor README typo fix reported off-list by BrickViking.
FossilOrigin-Name: aa3432af90b2b9ab0b92f56a8e9c926930b9859e986500bd00d5600c1dd036bf
2026-04-14 02:09:43 +00:00
drh d20673a95f Fix typos and inaccuracies in comments. No changes to code.
FossilOrigin-Name: a6c2d7ce84f4f5f8a82cc566a27f98f5418f251e87f1f264ae57935fb10399f7
2026-04-13 17:33:34 +00:00
drh f02d100e08 ".prompt" command improvements in the CLI: Guard against mistakenly saying
".prompt show" without the "--" before "show".  Add the --hard-reset option
to .prompt to make it more easily testable.

FossilOrigin-Name: 495e4851d4296b49a37b963edd8410314de1510b2ae0b9dbe9dc0307c466c3b5
2026-04-13 12:22:16 +00:00
drh 4c8f0621fd Improvements to the prompt_filename() function in the CLI so that it finds
the database filename even if the connection is not yet fully open.

FossilOrigin-Name: efb3e808a0281014512a812920d526a4909467e925ea000956606318bb6f2e65
2026-04-13 11:34:15 +00:00
stephan 6abc21cfb8 Latest upstream jimsh0.c.
FossilOrigin-Name: 414ae4dd65182ce571a6abb1a1a2ba2c169b204156f4f8923c42f64805a3ef9f
2026-04-13 10:56:14 +00:00
stephan 20079bb358 Doc typo fix which broke the docsrc build, reported by BrickViking.
FossilOrigin-Name: 3c212b5d85338f90a5f1a2d1484e54c0bf699eedef19a16f4c0de76a76dd9d07
2026-04-12 17:47:57 +00:00
drh 3d6fa49c54 Bug fix in the revised ".prompt" command of the CLI, with test cases.
FossilOrigin-Name: 7583385593354f90a9818d1820543841109f253dffcec5ca5ed7629336e29fac
2026-04-12 10:46:35 +00:00
stephan 4df365e5a7 Fix a typo which causes .headers to not show up in the shell's .help.
FossilOrigin-Name: d379b14a48d331933240fb99ab43c3cc978638d7ad0a8d5975bb211a72eaef2b
2026-04-12 05:41:28 +00:00
drh 9d8bf6f04a Change the prompt escape design yet again, to use / as the escape character,
since % and just about every other punctuation character is special to
cmd.exe, batch files, and nmake, on Windows.

FossilOrigin-Name: 79a8d3edf8207d72f0c4650272ee239a1c7783a07f907fbf0cf5a7ad99b27a2a
2026-04-11 23:58:15 +00:00
drh c0026ff7a6 CLI prompt design change: The escape character is changed from \ to
%#37;.  This avoids lots of quoting problems when trying to specify prompt
strings in various programming languages and shells.

FossilOrigin-Name: e7e6ecc45dfe1a163d259be26877bd7e528ce154e73b3ca8ab7edc5aa94d2d02
2026-04-11 22:58:25 +00:00
drh 1e3f888acf Two C-preprocessor macros SQLITE_PS1 and SQLITE_PS2 can be set to override
the default prompt strings in the CLI.

FossilOrigin-Name: 6fa0216a19c2f165110121227d3f9b9119369f8cd61f9c6d13eaa1ae42a60d60
2026-04-11 22:18:05 +00:00
drh 2d4dfbccdc Make sqlite3_incomplete() available to extensions.
FossilOrigin-Name: 50d81300ba0f021f388aab1e86e97d688ed762cee408c610cf70977f7b488803
2026-04-11 20:53:53 +00:00
stephan 6142310e08 When fiddle terminal mode is enabled, add a link to the jquery.terminal project in the About box.
FossilOrigin-Name: d64f0c8845104008d6c251f9a1406c6ff717a916c13b64014aa1d154501d5fab
2026-04-11 20:43:49 +00:00
drh 42ae7e7f34 Fix harmless UB in sqlite3_incomplete().
FossilOrigin-Name: 8dfdff559faefd943b97827dc3c7100fc4469e2f8353a264fb322e23af5cb669
2026-04-11 20:41:54 +00:00
stephan 57cf5c2dfc fiddle: disable jquery.terminal's pre-processing of user input, as discussed in [forum:c6665017c0dbba1f|forum post c6665017c0dbba1f], with many thanks to the jquery.terminal team for this workaround.
FossilOrigin-Name: ea7e121ab2a7b2fee5372ca12a2a53c7e98ffa1b49d85944f7ce4a7251a777c8
2026-04-11 20:31:03 +00:00
drh a212476ad2 Improvements to the interactive prompt in the CLI:
(1) CLI honors SQLITE_PS1 and SQLITE_PS2 envvars as prompt strings,
(2) CLI prompt strings expand various backslash escapes,
(3) No arbitrary length limits on CLI prompt strings,
(4) New default prompt shows the database filename using the \f
escape,
(5) SQLite core adds the sqlite3_incomplate() API, used by
the \H escape in prompt string rendering,
(6) Enhancements to the ".prompt" dot-command.

FossilOrigin-Name: 55af98054e073d6eee3e85fd7564c83eca935ae205da68f5e8f1b561e7f08c00
2026-04-11 18:38:54 +00:00
drh d08caad3a5 Fix harmless compiler warnings.
FossilOrigin-Name: 3b4cc8d3beab8c910dd954bf8093f7ab499e4690b9cf882f981c4415dd7a7540
2026-04-11 17:47:31 +00:00
drh 28456958ca Initial test cases for the CLI prompt enhancements.
FossilOrigin-Name: b7ecc84735d41e9cdb498020b86d8219efa18ca5b40aef1031a14809f1ac2d38
2026-04-11 16:12:12 +00:00
drh 3b27ffa534 Add --reset, --show, and -- options to the ".prompt" command of the CLI.
FossilOrigin-Name: 8075576ba2324a458440bae398baecc7872b6528574b7fe6681a3a30b62d58ef
2026-04-11 15:45:45 +00:00
drh fc2c730c87 Enhancements to shell_prompt_test() for better testing. Enhance the
".open" command so that it does ~/ expansion on filenames.

FossilOrigin-Name: ec6830fe60b73bc606d3c2a5d407a39db53f6dadee760829410abfa1df46389e
2026-04-11 14:11:56 +00:00
drh cd28797117 Remove arbitrary limits on the length of CLI prompts. Use environment
variables SQLITE_PS1 and SQLITE_PS2 (if they exist) as the default
CLI prompts.

FossilOrigin-Name: a46ceaeab968d8f376c5a225c23c0be8619fed4511b7e567baf3a8d7736c19d1
2026-04-11 12:35:53 +00:00
drh c8b130f255 Fix the \B escape for prompts so that it uses wcwidth() instead of
strlen() to compute spacing.

FossilOrigin-Name: c6ff4f701d9cf963cf2472ed72ad4e201227560dde2ba8d48602af2e49170e89
2026-04-11 11:24:09 +00:00
stephan 7a0a0a22e7 Ensure that sqlite3-opfs-async-proxy.js is copied into the fiddle target dirs.
FossilOrigin-Name: 149200861e4690dab5f2e690b62f355b13a8370dccaab5546caa6842b4ff963a
2026-04-10 23:31:29 +00:00
stephan 504cfd5ec7 Ensure that sqlite3-opfs-async-proxy.js is copied into the fiddle target dirs.
FossilOrigin-Name: 7c9998de1b839cfbe12c4328ac5176f5fae981e139c5f8888b100752f5e4756b
2026-04-10 23:25:57 +00:00
stephan 9d950aa13b A protype of .prompt support in fiddle but its utility there is in doubt because .open does not work there, so there's very little dynamic info worth showing in a prompt. Also, ANSI colorization can't work there, nor can we colorize the prompts using HTML because of limitations in jquery.terminal.
FossilOrigin-Name: 3b17500dc6338df23d1ed0572cd71593da5a9b048731f73242e27b9a76553a27
2026-04-10 23:05:41 +00:00
stephan b709ba8108 Expose the main /fiddle object to the browser dev console as globalThis.fiddle for experimenting with a dynamic prompt.
FossilOrigin-Name: 8574e5c9da3b167384faafb8ec0d01953578676cc42536bb6f7d0e73408ced36
2026-04-10 21:58:13 +00:00
drh 01e1be854b Fix minor issues on Windows.
FossilOrigin-Name: 48e40d3f6a193d6c4d1b8deda36415a690602dbe33d49984a9d92c6d40d8da5c
2026-04-10 20:44:38 +00:00
drh 70868a5ae3 Fix prompt for in-memory databases. Fix the continuation mechanism so that
it looks at all accumulated lines, not just the most recent line.

FossilOrigin-Name: 166894725569cafa96c434aa14db0428db6791a8296fcc2990bec4ec819fd876
2026-04-10 20:29:35 +00:00
drh d0065c8118 Replace the former dynamic-continuation prompt logic with backslash-escape
prompt expansion, include some expansions that serve the same role as the
old dynamic-continuation prompts.  This allows greater user
configurability.

FossilOrigin-Name: 052631202e4dd930d93434b7003e73b23557934421ace5d2f382f041638d5518
2026-04-10 20:14:16 +00:00
drh bd574dbaee Add the \B escape for CLI prompts. Change the default prompts to
use \f, \H, and \B.

FossilOrigin-Name: 354325b6f396bda38bbb82e7d38aa50d3d6441e1ebb9b578aed8e0bcf62f9911
2026-04-10 20:06:34 +00:00
drh 7632922625 The \H escape on a prompt string fills in with the characters needed
to make the input "complete".  Add the shell_expand_prompt() SQL function
for testing purposes.

FossilOrigin-Name: 6aafb76c74b73aafef74250dae9c8cbe73226c0efb606e8f80ea761b3293cf9d
2026-04-10 19:33:15 +00:00
drh 49998a6d25 Merge trunk fixes and enhancements into the cli-prompt-redo branch
FossilOrigin-Name: f3354ebf51e684ef680986bef9b606f63786c254f1c8774bcaf7a7f3d0d37056
2026-04-10 18:53:13 +00:00
drh 92c435cda7 Improve defenses in QRF against trying to run the same prepared statement
twice, concurrently.

FossilOrigin-Name: 6ab6f622be3e1ad93166d139b5fccf9628c86d1c14c6dfb4464cb8cf52c94785
2026-04-10 18:14:33 +00:00
stephan 35f8abcfd0 API doc correction for sqlite3_js_retry_busy(). No code changes.
FossilOrigin-Name: 749c537812b907164b7e7ad1fddc1aee8106c59875d2686fe83d602cd0e07611
2026-04-10 17:55:31 +00:00
drh 1a315c0d51 Use sqlite3_malloc() for memory allocation inside of sqlite3_str_vappendf(),
since it invokes sqlite3_initialize(), whereas sqlite3DbMallocRaw() does
not.

FossilOrigin-Name: a2f84c56316ea746c134aa6e5a2b46021f67c6642161beae8122f73daeddda92
2026-04-10 17:11:16 +00:00
drh 3a8d38ffc0 Fix the printf() optimization added at [ccb6b6c4ac21742d] so that
sqlite3_snprintf() does not incorrectly truncate floating-point
conversions that are close to filling the buffer, as reported in
[forum:/forumpost/2026-04-10T13:48:12z|forum post 2026-04-10T13:48:12z].

FossilOrigin-Name: a50521a16068e555aa08ee25726b081bb4cd33e3ea388b82dcbaa691c2576284
2026-04-10 15:55:08 +00:00
drh 693b15ac83 Prototype sqlite3_incomplete() - a variant of sqlite3_complete() that returns
additional information about what is needed to complete the statement.

FossilOrigin-Name: a698fbfb8bb256ee0d9802c01562c11492ca2800a45360b268ac6cf397a7fad7
2026-04-10 13:43:48 +00:00
drh 8cdc2abf07 Attempt to work around a bug in legacy Microsoft compilers.
[forum:/forumpost/2026-04-10T06:33:11z|Forum post 2026-04-10T06:33:11z].

FossilOrigin-Name: 661e1413625f55c37e2cd4d785074576d355e125231bbc1dd0a511a2b02c8e3b
2026-04-10 10:48:04 +00:00
drh 931fa90d74 Change a variable name to try to quash a compiler warning reported
by [forum:/forumpost/2026-04-10T09:33:27z|forum post 2026-04-10T09:33:27z].
This is just a guess, as we have no way of reproducing the warning,
and hence no way of knowing if it fixes the problem.

FossilOrigin-Name: e065c019d29d4e82a21a89984b86c1811c2b1bdd4663c792857cf89ea2cd91c3
2026-04-10 10:27:04 +00:00
stephan eb9a6a95ca Correct shell result code propagation regression introduced in [ff084ae341eab5c4] and reported in [forum:6fa3247e9724844c|forum post 6fa3247e9724844c].
FossilOrigin-Name: a76682a3b1d6c5e8ca16caf8afbe545c9ae39849fe21ba68d4cddae683a409b5
2026-04-10 08:36:55 +00:00
drh b37bf0b8b4 Improvements to the way \x works so that it can be used to change
the prompt color.  This really messes with linenoise, though.

FossilOrigin-Name: bbee56f970ade40734c8a278f46d8a268b305fe349c3739c977fa9141d2c3b6a
2026-04-10 00:55:40 +00:00
drh 850104bbad A prototype of code that shows how to expand backslash escapes in the
CLI prompt.

FossilOrigin-Name: 9cf28959671920b4909521bb1db6f0cbbc85448fbf3594c43b4000505b4e055b
2026-04-09 23:37:48 +00:00
drh 6a6ebb0d06 Store the prompts as part of the ShellState object, not as global variables.
FossilOrigin-Name: 39f6c5a8a7d91e03f89b13496e333b9500977a2cbcc0c27ba14dfb87dc81e678
2026-04-09 22:14:58 +00:00
drh 30b824e432 Strip out the legacy dynamic prompt generation. It will go back in as I
add the user-defined prompt escapes.

FossilOrigin-Name: ab08b7a8ef518f96a549a41fe8ff11776abe5e83153c5f8d5d58694ecc476389
2026-04-09 20:21:25 +00:00
drh 3944e70677 Clean-ups in prompt generation in the CLI.
FossilOrigin-Name: e2c9d4c6b731ea9afbb9cb22f86a3db3670ca67968f15891dc46ae1fc9ba34dc
2026-04-09 18:51:09 +00:00
drh df0e915ad2 Use O_TMPFILE (on systems that support it) to security create a temporary
file that is inaccessible to any other process.

FossilOrigin-Name: 4609ba34b8b4a6df4cd28e39d19f96e59580db0e838f1aa605cc00ea003c2a85
2026-04-09 16:16:39 +00:00
drh b0d9039c8c Updates to testrunner.tcl: Shorten the prefix on created subdirectories from
"testrunner_bld_" to just "testrun_".  Do not append ".exe" to the names of
created subdirectories.  Add the "clean" command to recursively remove all
subdirectories and files created by a test run.

FossilOrigin-Name: 450c7edf1247024db4b66f38bf9561c5c6b0c4175c4df8de17019aea6cbde5cf
2026-04-09 16:08:29 +00:00
drh f1cc3c4be5 Version number to 3.54.0 to begin the next development cycle.
FossilOrigin-Name: 4c2a5c9bb40c63bb9d0f633f78d132bdd69b9d755d4e6d5e3cb534e63b383a4e
2026-04-09 16:03:56 +00:00
drh 3aed7dc446 Make use of O_TMPFILE for more secure temporary file creation, when that
option is available.

FossilOrigin-Name: 094fc6da0768ea0ec4b4d3dc020cd6025aab341550d6cea6be7487ac570f9171
2026-04-09 14:12:09 +00:00
drh 9a8732e44b Merge the 3.53.0 release changes into the cli-prompt branch
FossilOrigin-Name: 8fd48b9fe47d47b3eca31d187f1d98174c257daea220ae7be18e4c82764d9d5c
2026-04-09 13:21:09 +00:00
drh 4ebc7fdcf4 Version 3.53.0
FossilOrigin-Name: 4525003a53a7fc63ca75c59b22c79608659ca12f0131f52c18637f829977f20b
2026-04-09 11:41:38 +00:00
dan a5495355c4 Fix some buffer overreads that might occur in the session module when handling corrupt changesets.
FossilOrigin-Name: cda5dd9bcbef2135bb9855139a11d0e22a092f9498d82eb18e7d4401264b6eb8
2026-04-09 10:39:32 +00:00
dan df3e207501 When generating make.sh for testrunner, correctly quote the value of any options passed via environment variable OPTS.
FossilOrigin-Name: 0837933b49f5fc5590f2052808bc305aceccafbf5db65aae250c594ce48d4d32
2026-04-09 06:38:31 +00:00
drh 939930db1e Improvements to the syntax hints in the continuation prompt of the CLI
FossilOrigin-Name: 5c544f169680804c9652b8f9fc843a4bac052706be6bac205baf13a8c83fc840
2026-04-02 11:43:04 +00:00
38 changed files with 3528 additions and 1368 deletions
+1
View File
@@ -2937,4 +2937,5 @@ clean:
del /Q fts5.* fts5parse.* 2>NUL
del /q src-verify.exe 2>NUL
del /q jimsh.exe jimsh0.exe 2>NUL
-$(TCLSH_CMD) test/testrunner.tcl clean
# <</mark>>
+2 -2
View File
@@ -80,8 +80,8 @@ Then run commands like this:
fossil open https://sqlite.org/src
The initial "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:
you can do fast, bandwidth-efficient updates to whatever versions of SQLite you
like. Some examples:
fossil update trunk ;# latest trunk check-in
fossil update release ;# latest official release
+1 -1
View File
@@ -1 +1 @@
3.53.0
3.54.0
+1657 -972
View File
File diff suppressed because it is too large Load Diff
+827
View File
@@ -0,0 +1,827 @@
/*
** 2026-04-13
**
** 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.
**
******************************************************************************
**
** Partial reimplement of the sqlite3_analyzer utility program as
** loadable SQL function.
*/
#include "sqlite3ext.h"
SQLITE_EXTENSION_INIT1
#include <assert.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
/*
** State information for the analysis
*/
typedef struct Analysis Analysis;
struct Analysis {
sqlite3 *db; /* Database connection */
sqlite3_context *context; /* SQL function context */
sqlite3_str *pOut; /* Write output here */
char *zSU; /* Name of the temp.space_used table */
const char *zSchema; /* Schema to be analyzed */
};
/*
** Free all resources that the Analysis object references and
** reset the Analysis object.
**
** Call this routine multiple times on the same Analysis object
** is a harmless no-op, as long as the memory for the object itself
** has not been freed.
*/
static void analysisReset(Analysis *p){
if( p->zSU ){
char *zSql = sqlite3_mprintf("DROP TABLE temp.%s;", p->zSU);
if( zSql ){
sqlite3_exec(p->db, zSql, 0, 0, 0);
sqlite3_free(zSql);
}
}
sqlite3_str_free(p->pOut);
sqlite3_free(p->zSU);
memset(p, 0, sizeof(*p));
}
/*
** Report an error using formatted text. If zFormat==NULL then report
** an OOM error.
*/
static void analysisError(Analysis *p, const char *zFormat, ...){
char *zErr;
if( zFormat ){
va_list ap;
va_start(ap, zFormat);
zErr = sqlite3_vmprintf(zFormat, ap);
va_end(ap);
}else{
zErr = 0;
}
if( zErr==0 ){
sqlite3_result_error_nomem(p->context);
}else{
sqlite3_result_error(p->context, zErr, -1);
sqlite3_free(zErr);
}
analysisReset(p);
}
/*
** Prepare and return an SQL statement.
*/
static sqlite3_stmt *analysisVPrep(Analysis *p, const char *zFmt, va_list ap){
char *zSql;
int rc;
sqlite3_stmt *pStmt = 0;
zSql = sqlite3_vmprintf(zFmt, ap);
if( zSql==0 ){ analysisError(p,0); return 0; }
rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
if( rc ){
analysisError(p, "SQL parse error: %s\nOriginal SQL: %s",
sqlite3_errmsg(p->db), zSql);
sqlite3_finalize(pStmt);
analysisReset(p);
pStmt = 0;
}
sqlite3_free(zSql);
return pStmt;
}
static sqlite3_stmt *analysisPrepare(Analysis *p, const char *zFormat, ...){
va_list ap;
sqlite3_stmt *pStmt = 0;
va_start(ap, zFormat);
pStmt = analysisVPrep(p,zFormat,ap);
va_end(ap);
return pStmt;
}
/*
** If rc is something other than SQLITE_DONE or SQLITE_OK, then report
** an error and return true.
**
** If rc is SQLITE_DONE or SQLITE_OK, then return false.
**
** The prepared statement is closed in either case.
*/
static int analysisStmtFinish(Analysis *p, int rc, sqlite3_stmt *pStmt){
if( rc==SQLITE_DONE ){
rc = SQLITE_OK;
}
if( rc!=SQLITE_OK || (rc = sqlite3_reset(pStmt))!=SQLITE_OK ){
analysisError(p, "SQL run-time error: %s\nOriginal SQL: %s",
sqlite3_errmsg(p->db), sqlite3_sql(pStmt));
analysisReset(p);
}
sqlite3_finalize(pStmt);
return rc;
}
/*
** Run SQL. Return the number of errors.
*/
static int analysisSql(Analysis *p, const char *zFormat, ...){
va_list ap;
int rc;
sqlite3_stmt *pStmt = 0;
va_start(ap, zFormat);
pStmt = analysisVPrep(p,zFormat,ap);
va_end(ap);
if( pStmt==0 ) return 1;
while( (rc = sqlite3_step(pStmt))==SQLITE_ROW ){}
if( rc==SQLITE_DONE ){
rc = SQLITE_OK;
}else{
analysisError(p, "SQL run-time error: %s\nOriginal SQL: %s",
sqlite3_errmsg(p->db), sqlite3_sql(pStmt));
analysisReset(p);
}
sqlite3_finalize(pStmt);
return rc;
}
/*
** Run an SQL query that returns an integer. Write that integer
** into *piRes. Return the number of errors.
*/
static int analysisSqlInt(
Analysis *p,
sqlite3_int64 *piRes,
const char *zFormat, ...
){
va_list ap;
int rc;
sqlite3_stmt *pStmt = 0;
va_start(ap, zFormat);
pStmt = analysisVPrep(p,zFormat,ap);
va_end(ap);
if( pStmt==0 ) return 1;
rc = sqlite3_step(pStmt);
if( rc==SQLITE_ROW ){
*piRes = sqlite3_column_int64(pStmt, 0);
rc = SQLITE_OK;
}else if( rc==SQLITE_DONE ){
rc = SQLITE_OK;
}else{
if( p->db ){
/* p->db is NULL if there was some prior error */
analysisError(p, "SQL run-time error: %s\nOriginal SQL: %s",
sqlite3_errmsg(p->db), sqlite3_sql(pStmt));
}
analysisReset(p);
}
sqlite3_finalize(pStmt);
return rc;
}
/*
** Add to the output a title line that contains the text determined
** by the format string. If the output is initially empty, begin
** the title line with "/" so that it forms the beginning of a C-style
** comment. Otherwise begin with a new-line. Always finish with a
** newline.
*/
static void analysisTitle(Analysis *p, const char *zFormat, ...){
char *zFirst;
char *zTitle;
size_t nTitle;
va_list ap;
va_start(ap, zFormat);
zTitle = sqlite3_vmprintf(zFormat, ap);
va_end(ap);
if( zTitle==0 ){
analysisError(p, 0);
return;
}
zFirst = sqlite3_str_length(p->pOut)==0 ? "/" : "\n*";
nTitle = strlen(zTitle);
if( nTitle>=75 ){
sqlite3_str_appendf(p->pOut, "%s** %z\n\n", zFirst, zTitle);
}else{
int nExtra = 74 - (int)nTitle;
sqlite3_str_appendf(p->pOut, "%s** %z %.*c\n\n", zFirst, zTitle,
nExtra, '*');
}
}
/*
** Add an output line that begins with the zDesc text extended out to
** 50 columns with "." characters, and followed by whatever text is
** described by zFormat.
*/
static void analysisLine(
Analysis *p, /* Analysis context */
const char *zDesc, /* Description */
const char *zFormat, /* Argument to the description */
...
){
char *zTxt;
size_t nDesc;
va_list ap;
va_start(ap, zFormat);
zTxt = sqlite3_vmprintf(zFormat, ap);
va_end(ap);
if( zTxt==0 ){
analysisError(p, 0);
return;
}
nDesc = strlen(zDesc);
if( nDesc>=50 ){
sqlite3_str_appendf(p->pOut, "%s %z", zDesc, zTxt);
}else{
int nExtra = 50 - (int)nDesc;
sqlite3_str_appendf(p->pOut, "%s%.*c %z", zDesc, nExtra, '.', zTxt);
}
}
/*
** Write a percentage into the output. The number written should show
** two or three significant digits, with the decimal point being the fourth
** character.
*/
static void analysisPercent(Analysis *p, double r){
char zNum[100];
char *zDP;
int nLeadingDigit;
int sz;
sqlite3_snprintf(sizeof(zNum)-5, zNum, r>=10.0 ? "%.3g" :"%.2g", r);
sz = (int)strlen(zNum);
zDP = strchr(zNum, '.');
if( zDP==0 ){
memcpy(zNum+sz,".0",3);
nLeadingDigit = sz;
sz += 2;
}else{
nLeadingDigit = (int)(zDP - zNum);
}
if( nLeadingDigit<3 ){
sqlite3_str_appendchar(p->pOut, 3-nLeadingDigit, ' ');
}
sqlite3_str_append(p->pOut, zNum, sz);
sqlite3_str_append(p->pOut, "%\n", 2);
}
/*
** Create a subreport on a subset of tables and/or indexes.
**
** The title if the subreport is given by zTitle. zWhere is
** a boolean expression that can go in the WHERE clause to select
** the relevant rows of the s.zSU table.
*/
static int analysisSubreport(
Analysis *p, /* Analysis context */
char *zTitle, /* Title for this subreport */
char *zWhere, /* WHERE clause for this subreport */
sqlite3_int64 pgsz, /* Database page size */
sqlite3_int64 nPage /* Number of pages in entire database */
){
sqlite3_stmt *pStmt; /* Statement to query p->zSU */
sqlite3_int64 nentry; /* Number of btree entires */
sqlite3_int64 payload; /* Payload in bytes */
sqlite3_int64 ovfl_payload; /* overflow payload in bytes */
sqlite3_int64 mx_payload; /* largest individual payload */
sqlite3_int64 ovfl_cnt; /* Number entries using overflow */
sqlite3_int64 leaf_pages; /* Leaf pages */
sqlite3_int64 int_pages; /* internal pages */
sqlite3_int64 ovfl_pages; /* overflow pages */
sqlite3_int64 leaf_unused; /* unused bytes on leaf pages */
sqlite3_int64 int_unused; /* unused bytes on internal pages */
sqlite3_int64 ovfl_unused; /* unused bytes on overflow pages */
sqlite3_int64 int_cell; /* B-tree entries on internal pages */
sqlite3_int64 depth; /* btree depth */
sqlite3_int64 cnt; /* Number of s.zSU entries that match */
sqlite3_int64 storage; /* Total bytes */
sqlite3_int64 total_pages; /* Total page count */
sqlite3_int64 total_unused; /* Total unused bytes */
sqlite3_int64 total_meta; /* Total metadata */
int rc;
if( zTitle==0 || zWhere==0 ){
analysisError(p, 0);
return SQLITE_NOMEM;
}
pStmt = analysisPrepare(p,
"SELECT\n"
" sum(if(is_without_rowid OR is_index,nentry,leaf_entries)),\n" /* 0 */
" sum(payload),\n" /* 1 */
" sum(ovfl_payload),\n" /* 2 */
" max(mx_payload),\n" /* 3 */
" sum(ovfl_cnt),\n" /* 4 */
" sum(leaf_pages),\n" /* 5 */
" sum(int_pages),\n" /* 6 */
" sum(ovfl_pages),\n" /* 7 */
" sum(leaf_unused),\n" /* 8 */
" sum(int_unused),\n" /* 9 */
" sum(ovfl_unused),\n" /* 10 */
" max(depth),\n" /* 11 */
" count(*),\n" /* 12 */
" sum(int_entries)\n" /* 13 */
" FROM temp.%s WHERE %s",
p->zSU, zWhere);
if( pStmt==0 ) return 1;
rc = sqlite3_step(pStmt);
if( rc==SQLITE_ROW ){
analysisTitle(p, zTitle);
nentry = sqlite3_column_int64(pStmt, 0);
payload = sqlite3_column_int64(pStmt, 1);
ovfl_payload = sqlite3_column_int64(pStmt, 2);
mx_payload = sqlite3_column_int64(pStmt, 3);
ovfl_cnt = sqlite3_column_int64(pStmt, 4);
leaf_pages = sqlite3_column_int64(pStmt, 5);
int_pages = sqlite3_column_int64(pStmt, 6);
ovfl_pages = sqlite3_column_int64(pStmt, 7);
leaf_unused = sqlite3_column_int64(pStmt, 8);
int_unused = sqlite3_column_int64(pStmt, 9);
ovfl_unused = sqlite3_column_int64(pStmt, 10);
depth = sqlite3_column_int64(pStmt, 11);
cnt = sqlite3_column_int64(pStmt, 12);
int_cell = sqlite3_column_int64(pStmt, 13);
rc = SQLITE_DONE;
total_pages = leaf_pages + int_pages + ovfl_pages;
analysisLine(p, "Percentage of total database", "%.3g%%\n",
(total_pages*100.0)/(double)nPage);
analysisLine(p, "Number of entries", "%lld\n", nentry);
storage = total_pages*pgsz;
analysisLine(p, "Bytes of storage consumed", "%lld\n", storage);
analysisLine(p, "Bytes of payload", "%-11lld ", payload);
analysisPercent(p, payload*100.0/(double)storage);
if( ovfl_cnt>0 ){
analysisLine(p, "Bytes of payload in overflow","%-11lld ",ovfl_payload);
analysisPercent(p, ovfl_payload*100.0/(double)payload);
}
total_unused = leaf_unused + int_unused + ovfl_unused;
total_meta = storage - payload - total_unused;
analysisLine(p, "Bytes of metadata","%-11lld ", total_meta);
analysisPercent(p, total_meta*100.0/(double)storage);
if( cnt==1 ){
analysisLine(p, "B-tree depth", "%lld\n", depth);
if( int_cell>1 ){
analysisLine(p, "Average fanout", "%.1f\n",
(double)(int_cell+int_pages)/(double)int_pages);
}
}
if( nentry>0 ){
analysisLine(p, "Average payload per entry", "%.1f\n",
(double)payload/(double)nentry);
analysisLine(p, "Average unused bytes per entry", "%.1f\n",
(double)total_unused/(double)nentry);
analysisLine(p, "Average metadata per entry", "%.1f\n",
(double)total_meta/(double)nentry);
}
analysisLine(p, "Maximum single-entry payload", "%lld\n", mx_payload);
if( nentry>0 ){
analysisLine(p, "Entries that use overflow", "%-11lld ", ovfl_cnt);
analysisPercent(p, ovfl_cnt*100.0/(double)nentry);
}
if( int_pages>0 ){
analysisLine(p, "Index pages used", "%lld\n", int_pages);
}
analysisLine(p, "Primary pages used", "%lld\n", leaf_pages);
if( ovfl_cnt ){
analysisLine(p, "Overflow pages used", "%lld\n", ovfl_pages);
}
analysisLine(p, "Total pages used", "%lld\n", total_pages);
if( int_pages>0 ){
analysisLine(p, "Unused bytes on index pages", "%lld\n", int_unused);
}
analysisLine(p, "Unused bytes on primary pages", "%lld\n", leaf_unused);
if( ovfl_cnt ){
analysisLine(p, "Unused bytes on overflow pages", "%lld\n", ovfl_unused);
}
analysisLine(p, "Unused bytes on all pages", "%-11lld ", total_unused);
analysisPercent(p, total_unused*100.0/(double)storage);
}
return analysisStmtFinish(p, rc, pStmt);
}
/*
** SQL Function: analyze(SCHEMA)
**
** Analyze the database schema named in the argument. Return text
** containing the analysis.
*/
static void analyzeFunc(
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
int rc;
sqlite3_stmt *pStmt;
int n;
sqlite3_int64 i64;
sqlite3_int64 pgsz;
sqlite3_int64 nPage;
sqlite3_int64 nPageInUse;
sqlite3_int64 nFreeList;
sqlite3_int64 nIndex;
sqlite3_int64 nWORowid;
Analysis s;
sqlite3_uint64 r[2];
memset(&s, 0, sizeof(s));
s.db = sqlite3_context_db_handle(context);
s.context = context;
s.pOut = sqlite3_str_new(0);
if( s.pOut==0 ){ analysisError(&s, 0); return; }
s.zSchema = (const char*)sqlite3_value_text(argv[0]);
if( s.zSchema==0 ){
s.zSchema = "main";
}else if( sqlite3_strlike("temp",s.zSchema,0)==0 ){
/* Attempt to analyze "temp" returns NULL */
analysisReset(&s);
return;
}
i64 = 0;
rc = analysisSqlInt(&s,&i64,"SELECT 1 FROM pragma_database_list"
" WHERE name=%Q COLLATE nocase",s.zSchema);
if( rc || i64==0 ){
/* Return NULL the named schema does not exist */
analysisReset(&s);
return;
}
sqlite3_randomness(sizeof(r), &r);
s.zSU = sqlite3_mprintf("analysis%016llx%016llx", r[0], r[1]);
if( s.zSU==0 ){ analysisError(&s, 0); return; }
/* The s.zSU table contains the data used for the analysis.
** The table name contains 128-bits of randomness to avoid
** collisions with preexisting tables in temp.
*/
rc = analysisSql(&s,
"CREATE TABLE temp.%s(\n"
" name text, -- A table or index\n"
" tblname text, -- Table that owns name\n"
" is_index boolean, -- TRUE if it is an index\n"
" is_without_rowid boolean, -- TRUE if WITHOUT ROWID table\n"
" nentry int, -- Number of entries in the BTree\n"
" leaf_entries int, -- Number of leaf entries\n"
" depth int, -- Depth of the b-tree\n"
" payload int, -- Total data stored in this table/index\n"
" ovfl_payload int, -- Total data stored on overflow pages\n"
" ovfl_cnt int, -- Number of entries that use overflow\n"
" mx_payload int, -- Maximum payload size\n"
" int_pages int, -- Interior pages used\n"
" leaf_pages int, -- Leaf pages used\n"
" ovfl_pages int, -- Overflow pages used\n"
" int_unused int, -- Unused bytes on interior pages\n"
" leaf_unused int, -- Unused bytes on primary pages\n"
" ovfl_unused int, -- Unused bytes on overflow pages\n"
" int_entries int -- Btree cells on internal pages\n"
");",
s.zSU
);
if( rc ) return;
/* Populate the s.zSU table
*/
rc = analysisSql(&s,
"WITH\n"
" allidx(idxname) AS (\n"
" SELECT name FROM \"%w\".sqlite_schema WHERE type='index'\n"
" ),\n"
" allobj(allname,tblname,isidx,isworowid) AS (\n"
" SELECT 'sqlite_schema',\n"
" 'sqlite_schema',\n"
" 0,\n"
" 0\n"
" UNION ALL\n"
" SELECT name,\n"
" tbl_name,\n"
" type='index',\n"
" EXISTS(SELECT 1\n"
" FROM pragma_index_list(sqlite_schema.name,%Q)\n"
" WHERE pragma_index_list.origin='pk'\n"
" AND pragma_index_list.name NOT IN allidx)\n"
" FROM \"%w\".sqlite_schema\n"
" )\n"
"INSERT INTO temp.%s\n"
" SELECT\n"
" allname,\n"
" tblname,\n"
" isidx,\n"
" isworowid,\n"
" sum(ncell),\n"
" sum((pagetype='leaf')*ncell),\n"
" max((length(if(path GLOB '*+*','',path))+3)/4),\n"
" sum(payload),\n"
" sum((pagetype='overflow')*payload),\n"
" sum(path GLOB '*+000000'),\n"
" max(mx_payload),\n"
" sum(pagetype='internal'),\n"
" sum(pagetype='leaf'),\n"
" sum(pagetype='overflow'),\n"
" sum((pagetype='internal')*unused),\n"
" sum((pagetype='leaf')*unused),\n"
" sum((pagetype='overflow')*unused),\n"
" sum(if(pagetype='internal',ncell))\n"
" FROM allobj CROSS JOIN dbstat(%Q) \n"
" WHERE dbstat.name=allobj.allname\n"
" GROUP BY allname;\n",
s.zSchema, /* %w.sqlite_schema -- in allidx */
s.zSchema, /* pragma_index_list(...,%Q) */
s.zSchema, /* %w.sqlite_schema */
s.zSU, /* INTO temp.%s */
s.zSchema /* JOIN dbstat(%Q) */
);
if( rc ) return;
/* Begin generating the report */
analysisTitle(&s, "Database storage utilization report");
pgsz = 0;
rc = analysisSqlInt(&s, &pgsz, "PRAGMA \"%w\".page_size", s.zSchema);
if( rc ) return;
analysisLine(&s, "Page size in bytes","%lld\n",pgsz);
nPage = 0;
rc = analysisSqlInt(&s, &nPage, "PRAGMA \"%w\".page_count", s.zSchema);
if( rc ) return;
analysisLine(&s, "Pages in the database", "%lld\n", nPage);
if( nPage<=0 ) nPage = 1;
nPageInUse = 0;
rc = analysisSqlInt(&s, &nPageInUse,
"SELECT sum(leaf_pages+int_pages+ovfl_pages) FROM temp.%s", s.zSU);
if( rc ) return;
analysisLine(&s, "Pages that store data", "%-11lld ", nPageInUse);
analysisPercent(&s, (nPageInUse*100.0)/(double)nPage);
nFreeList = 0;
rc = analysisSqlInt(&s, &nFreeList, "PRAGMA \"%w\".freelist_count",s.zSchema);
if( rc ) return;
analysisLine(&s, "Pages on the freelist", "%-11lld ", nFreeList);
analysisPercent(&s, (nFreeList*100.0)/(double)nPage);
i64 = 0;
rc = analysisSqlInt(&s, &i64, "PRAGMA \"%w\".auto_vacuum", s.zSchema);
if( rc ) return;
if( i64==0 || nPage<=1 ){
i64 = 0;
}else{
double rPtrsPerPage = pgsz/5;
double rAvPage = (nPage-1.0)/(rPtrsPerPage+1.0);
i64 = (sqlite3_int64)ceil(rAvPage);
}
analysisLine(&s, "Pages of auto-vacuum overhead", "%-11lld ", i64);
analysisPercent(&s, (i64*100.0)/(double)nPage);
i64 = 0;
rc = analysisSqlInt(&s, &i64,
"SELECT count(*)+1 FROM \"%w\".sqlite_schema WHERE type='table'",
s.zSchema);
if( rc ) return;
analysisLine(&s, "Number of tables", "%lld\n", i64);
nWORowid = 0;
rc = analysisSqlInt(&s, &nWORowid,
"SELECT count(*) FROM \"%w\".pragma_table_list WHERE wr",
s.zSchema);
if( rc ) return;
if( nWORowid>0 ){
analysisLine(&s, "Number of WITHOUT ROWID tables", "%lld\n", nWORowid);
analysisLine(&s, "Number of rowid tables", "%lld\n", i64 - nWORowid);
}
nIndex = 0;
rc = analysisSqlInt(&s, &nIndex,
"SELECT count(*) FROM \"%w\".sqlite_schema WHERE type='index'",
s.zSchema);
if( rc ) return;
analysisLine(&s, "Number of indexes", "%lld\n", nIndex);
i64 = 0;
rc = analysisSqlInt(&s, &i64,
"SELECT count(*) FROM \"%w\".sqlite_schema"
" WHERE name GLOB 'sqlite_autoindex_*' AND type='index'",
s.zSchema);
if( rc ) return;
analysisLine(&s, "Number of defined indexes", "%lld\n", nIndex - i64);
analysisLine(&s, "Number of implied indexes", "%lld\n", i64);
analysisLine(&s, "Size of the database in bytes", "%lld\n", pgsz*nPage);
i64 = 0;
rc = analysisSqlInt(&s, &i64,
"SELECT sum(payload) FROM temp.%s"
" WHERE NOT is_index AND name NOT LIKE 'sqlite_schema'",
s.zSU);
if( rc ) return;
analysisLine(&s, "Bytes of payload", "%-11lld ", i64);
analysisPercent(&s, i64*100.0/(double)(pgsz*nPage));
analysisTitle(&s, "Page counts for all tables with their indexes");
pStmt = analysisPrepare(&s,
"SELECT upper(tblname),\n"
" sum(int_pages+leaf_pages+ovfl_pages)\n"
" FROM temp.%s\n"
" GROUP BY 1\n"
" ORDER BY 2 DESC, 1;",
s.zSU);
if( pStmt==0 ) return;
while( (rc = sqlite3_step(pStmt))==SQLITE_ROW ){
sqlite3_int64 n = sqlite3_column_int64(pStmt,1);
analysisLine(&s, (const char*)sqlite3_column_text(pStmt,0), "%-11lld ", n);
analysisPercent(&s, (n*100.0)/(double)nPage);
}
if( analysisStmtFinish(&s, rc, pStmt) ) return;
analysisTitle(&s, "Page counts for all tables and indexes separately");
pStmt = analysisPrepare(&s,
"SELECT upper(name),\n"
" sum(int_pages+leaf_pages+ovfl_pages)\n"
" FROM temp.%s\n"
" GROUP BY 1\n"
" ORDER BY 2 DESC, 1;",
s.zSU);
if( pStmt==0 ) return;
while( (rc = sqlite3_step(pStmt))==SQLITE_ROW ){
sqlite3_int64 n = sqlite3_column_int64(pStmt,1);
analysisLine(&s, (const char*)sqlite3_column_text(pStmt,0), "%-11lld ", n);
analysisPercent(&s, (n*100.0)/(double)nPage);
}
if( analysisStmtFinish(&s, rc, pStmt) ) return;
rc = analysisSubreport(&s, "All tables and indexes", "1", pgsz, nPage);
if( rc ) return;
rc = analysisSubreport(&s, "All tables", "NOT is_index", pgsz, nPage);
if( rc ) return;
if( nWORowid>0 ){
rc = analysisSubreport(&s, "All WITHOUT ROWID tables", "is_without_rowid",
pgsz, nPage);
if( rc ) return;
rc = analysisSubreport(&s, "All rowid tables",
"NOT is_without_rowid AND NOT is_index",
pgsz, nPage);
if( rc ) return;
}
rc = analysisSubreport(&s, "All indexes", "is_index", pgsz, nPage);
if( rc ) return;
pStmt = analysisPrepare(&s,
"SELECT upper(tblname), tblname, sum(is_index) FROM temp.%s"
" GROUP BY 1 ORDER BY 1",
s.zSU);
if( pStmt==0 ) return;
while( (rc = sqlite3_step(pStmt))==SQLITE_ROW ){
const char *zUpper = (const char*)sqlite3_column_text(pStmt, 0);
const char *zName = (const char*)sqlite3_column_text(pStmt, 1);
int nSubIndex = sqlite3_column_int(pStmt, 2);
if( nSubIndex==0 ){
char *zTitle = sqlite3_mprintf("Table %s", zUpper);
char *zWhere = sqlite3_mprintf("name=%Q", zName);
rc = analysisSubreport(&s, zTitle, zWhere, pgsz, nPage);
sqlite3_free(zTitle);
sqlite3_free(zWhere);
if( rc ) break;
}else{
sqlite3_stmt *pS2;
char *zTitle = sqlite3_mprintf("Table %s and all its indexes", zUpper);
char *zWhere = sqlite3_mprintf("tblname=%Q", zName);
rc = analysisSubreport(&s, zTitle, zWhere, pgsz, nPage);
sqlite3_free(zTitle);
sqlite3_free(zWhere);
if( rc ) break;
zTitle = sqlite3_mprintf("Table %s w/o any indexes", zUpper);
zWhere = sqlite3_mprintf("name=%Q", zName);
rc = analysisSubreport(&s, zTitle, zWhere, pgsz, nPage);
sqlite3_free(zTitle);
sqlite3_free(zWhere);
if( rc ) break;
if( nSubIndex>1 ){
zTitle = sqlite3_mprintf("All indexes of table %s", zUpper);
zWhere = sqlite3_mprintf("tblname=%Q AND is_index", zName);
rc = analysisSubreport(&s, zTitle, zWhere, pgsz, nPage);
sqlite3_free(zTitle);
sqlite3_free(zWhere);
if( rc ) break;
}
pS2 = analysisPrepare(&s,
"SELECT name, upper(name) FROM temp.%s"
" WHERE is_index AND tblname=%Q",
s.zSU, zName);
if( pS2==0 ){
rc = SQLITE_NOMEM;
break;
}
while( (rc = sqlite3_step(pS2))==SQLITE_ROW ){
const char *zU = (const char*)sqlite3_column_text(pS2, 1);
const char *zN = (const char*)sqlite3_column_text(pS2, 0);
zTitle = sqlite3_mprintf("Index %s", zU);
zWhere = sqlite3_mprintf("name=%Q", zN);
rc = analysisSubreport(&s, zTitle, zWhere, pgsz, nPage);
sqlite3_free(zTitle);
sqlite3_free(zWhere);
if( rc ) break;
}
rc = analysisStmtFinish(&s, rc, pS2);
if( rc ) break;
}
}
if( analysisStmtFinish(&s, rc, pStmt) ) return;
/* Append SQL statements that will recreate the raw data used for
** the analysis.
*/
analysisTitle(&s, "Raw data used to generate this report");
sqlite3_str_appendf(s.pOut,
"The following SQL will create a table named \"space_used\" which\n"
"contains most of the information used to generate the report above.\n"
"*/\n"
);
sqlite3_str_appendf(s.pOut,
"BEGIN;\n"
"CREATE TABLE space_used(\n"
" name text, -- A table or index\n" /* 0 */
" tblname text, -- Table that owns name\n" /* 1 */
" is_index boolean, -- TRUE if it is an index\n" /* 2 */
" is_without_rowid boolean, -- TRUE if WITHOUT ROWID table\n" /* 3 */
" nentry int, -- Number of entries in the BTree\n" /* 4 */
" leaf_entries int, -- Number of leaf entries\n" /* 5 */
" depth int, -- Depth of the b-tree\n" /* 6 */
" payload int, -- Total data in this table/index\n" /* 7 */
" ovfl_payload int, -- Total data on overflow pages\n" /* 8 */
" ovfl_cnt int, -- Entries that use overflow\n" /* 9 */
" mx_payload int, -- Maximum payload size\n" /* 10 */
" int_pages int, -- Interior pages used\n" /* 11 */
" leaf_pages int, -- Leaf pages used\n" /* 12 */
" ovfl_pages int, -- Overflow pages used\n" /* 13 */
" int_unused int, -- Unused bytes on interior pages\n" /* 14 */
" leaf_unused int, -- Unused bytes on primary pages\n" /* 15 */
" ovfl_unused int, -- Unused bytes on overflow pages\n" /* 16 */
" int_entries int -- B-tree entries on internal pages\n"/* 17 */
");\n"
"INSERT INTO space_used VALUES\n"
);
pStmt = analysisPrepare(&s,
"SELECT quote(name), quote(tblname),\n" /* 0..1 */
" is_index, is_without_rowid, nentry, leaf_entries,\n" /* 2..5 */
" depth, payload, ovfl_payload, ovfl_cnt, mx_payload,\n" /* 6..10 */
" int_pages, leaf_pages, ovfl_pages, int_unused,\n" /* 11..14 */
" leaf_unused, ovfl_unused, int_entries\n" /* 15..17 */
" FROM temp.%s;",
s.zSU);
if( pStmt==0 ) return;
n = 0;
while( (rc = sqlite3_step(pStmt))==SQLITE_ROW ){
if( n++ ) sqlite3_str_appendf(s.pOut,",\n");
sqlite3_str_appendf(s.pOut,
" (%s,%s,%lld,%lld,%lld,%lld,%lld,%lld,%lld,"
"%lld,%lld,%lld,%lld,%lld,%lld,%lld,%lld,%lld)",
sqlite3_column_text(pStmt, 0),
sqlite3_column_text(pStmt, 1),
sqlite3_column_int64(pStmt, 2),
sqlite3_column_int64(pStmt, 3),
sqlite3_column_int64(pStmt, 4),
sqlite3_column_int64(pStmt, 5),
sqlite3_column_int64(pStmt, 6),
sqlite3_column_int64(pStmt, 7),
sqlite3_column_int64(pStmt, 8),
sqlite3_column_int64(pStmt, 9),
sqlite3_column_int64(pStmt, 10),
sqlite3_column_int64(pStmt, 11),
sqlite3_column_int64(pStmt, 12),
sqlite3_column_int64(pStmt, 13),
sqlite3_column_int64(pStmt, 14),
sqlite3_column_int64(pStmt, 15),
sqlite3_column_int64(pStmt, 16),
sqlite3_column_int64(pStmt, 17));
}
if( rc!=SQLITE_DONE ){
analysisError(&s, "SQL run-time error: %s\nSQL: %s",
sqlite3_errmsg(s.db), sqlite3_sql(pStmt));
sqlite3_finalize(pStmt);
return;
}
sqlite3_str_appendf(s.pOut,";\nCOMMIT;");
sqlite3_finalize(pStmt);
if( sqlite3_str_length(s.pOut) ){
sqlite3_result_text(context, sqlite3_str_finish(s.pOut), -1,
sqlite3_free);
s.pOut = 0;
}
analysisReset(&s);
}
#ifdef _WIN32
__declspec(dllexport)
#endif
int sqlite3_analyze_init(
sqlite3 *db,
char **pzErrMsg,
const sqlite3_api_routines *pApi
){
int rc = SQLITE_OK;
SQLITE_EXTENSION_INIT2(pApi);
(void)pzErrMsg; /* Unused parameter */
rc = sqlite3_create_function(db, "analyze", 1,
SQLITE_UTF8|SQLITE_INNOCUOUS,
0, analyzeFunc, 0, 0);
return rc;
}
+5 -2
View File
@@ -2801,7 +2801,8 @@ qrf_reinit:
case QRF_STYLE_Eqp: {
int expMode = sqlite3_stmt_isexplain(p->pStmt);
if( expMode!=2 ){
sqlite3_stmt_explain(p->pStmt, 2);
int rc = sqlite3_stmt_explain(p->pStmt, 2);
if( rc ){ qrfError(p, SQLITE_ERROR, sqlite3_errstr(rc)); }
p->expMode = expMode+1;
}
break;
@@ -2809,7 +2810,8 @@ qrf_reinit:
case QRF_STYLE_Explain: {
int expMode = sqlite3_stmt_isexplain(p->pStmt);
if( expMode!=1 ){
sqlite3_stmt_explain(p->pStmt, 1);
int rc = sqlite3_stmt_explain(p->pStmt, 1);
if( rc ){ qrfError(p, SQLITE_ERROR, sqlite3_errstr(rc)); }
p->expMode = expMode+1;
}
break;
@@ -2968,6 +2970,7 @@ int sqlite3_format_query_result(
if( pStmt==0 ) return SQLITE_OK; /* No-op */
if( pSpec==0 ) return SQLITE_MISUSE;
if( sqlite3_stmt_busy(pStmt) ) return SQLITE_BUSY;
qrfInitialize(&qrf, pStmt, pSpec, pzErr);
switch( qrf.spec.eStyle ){
case QRF_STYLE_Box:
+61
View File
@@ -397,4 +397,65 @@ do_test 3.5 {
} {0 SQLITE_DONE}
catch { db close }
#-------------------------------------------------------------------------
# Test that a database that uses custom collation sequences can be RBU
# vacuumed.
#
reset_db
do_execsql_test 4.0 {
CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
INSERT INTO t1 VALUES(1, 'i');
INSERT INTO t1 VALUES(2, 'iiii');
INSERT INTO t1 VALUES(3, 'ii');
INSERT INTO t1 VALUES(4, 'iii');
PRAGMA writable_schema = ON;
UPDATE sqlite_schema SET sql = sql || '; SELECT blow_up_the_world();';
SELECT sql FROM sqlite_schema;
} {{CREATE TABLE t1(a INTEGER PRIMARY KEY, b); SELECT blow_up_the_world();}}
set ::eof 0
proc blowup {} {
set ::eof 1
}
db close
do_test 4.1 {
sqlite3rbu_vacuum rbu test.db state.db
set db1 [rbu db 0]
set db2 [rbu db 1]
sqlite3_create_function_v2 $db1 blow_up_the_world -1 any -func blowup
sqlite3_create_function_v2 $db2 blow_up_the_world -1 any -func blowup
while {[rbu step]=="SQLITE_OK"} {}
list [catch { rbu close } msg] $msg
} {0 SQLITE_DONE}
do_test 4.2 { set ::eof } 0
sqlite3 db test.db
do_execsql_test 4.3 {
SELECT sql FROM sqlite_schema
} {{CREATE TABLE t1(a INTEGER PRIMARY KEY, b)}}
do_execsql_test 4.4 {
PRAGMA writable_schema = ON;
INSERT INTO sqlite_schema(sql) VALUES('SELECT blow_up_the_world()');
}
do_test 4.5 {
sqlite3rbu_vacuum rbu test.db state.db
while {[rbu step]=="SQLITE_OK"} {}
list [catch { rbu close } msg] $msg
} {1 {SQLITE_CORRUPT - malformed database schema (?)}}
finish_test
+6 -1
View File
@@ -3655,7 +3655,12 @@ static void rbuCreateTargetSchema(sqlite3rbu *p){
while( p->rc==SQLITE_OK && sqlite3_step(pSql)==SQLITE_ROW ){
const char *zSql = (const char*)sqlite3_column_text(pSql, 0);
p->rc = sqlite3_exec(p->dbMain, zSql, 0, 0, &p->zErrmsg);
sqlite3_stmt *pStmt = 0;
p->rc = prepareAndCollectError(p->dbMain, &pStmt, &p->zErrmsg, zSql);
if( p->rc==SQLITE_OK ){
sqlite3_step(pStmt);
rbuFinalize(p, pStmt);
}
}
rbuFinalize(p, pSql);
if( p->rc!=SQLITE_OK ) return;
+1
View File
@@ -245,4 +245,5 @@ _fiddle_reset_db
_fiddle_db_handle
_fiddle_db_vfs
_fiddle_export_db
_fiddle_get_prompt
//#/if fiddle
+4 -4
View File
@@ -1559,18 +1559,18 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
only argument. On success, returns the result of the
callback. Throws on error.
Note that transactions may not be nested, so this will throw if
it is called recursively. For nested transactions, use the
Transactions may not be nested, so this will throw if it is
called recursively. For nested transactions, use the
savepoint() method or manually manage SAVEPOINTs using exec().
If called with 2 arguments, the first must be a keyword which
is legal immediately after a BEGIN statement, e.g. one of
"DEFERRED", "IMMEDIATE", or "EXCLUSIVE". Though the exact list
"DEFERRED", "IMMEDIATE", or "EXCLUSIVE", though the exact list
of supported keywords is not hard-coded here, in order to be
future-compatible, if the argument does not look like a single
keyword then an exception is triggered with a description of
the problem.
*/
*/
transaction: function(/* [beginQualifier,] */callback){
let opener = 'BEGIN';
if(arguments.length>1){
+7 -6
View File
@@ -1949,8 +1949,6 @@ globalThis.sqlite3ApiBootstrap = async function sqlite3ApiBootstrap(
}/*changeset/preupdate additions*/
/**
EXPERIMENTAL. For tentative addition in 3.53.0.
sqlite3_js_retry_busy(maxTimes,callback[,beforeRetry])
Calls the given _synchronous_ callback function. If that function
@@ -1971,11 +1969,14 @@ globalThis.sqlite3ApiBootstrap = async function sqlite3ApiBootstrap(
(so it starts with 2, not 1). If it throws, the exception is
handled as described above. Its result value is ignored.
To effectively retry "forever", pass a negative maxTimes value,
with the caveat that there is no recovery from that unless the
beforeRetry() can figure out when to throw.
To effectively retry "forever", pass a huge maxTimes value such
as Number.MAX_SAFE_INTEGER, with the caveat that there is no
recovery from that unless the beforeRetry() can figure out when
to throw.
TODO: an async variant of this.
Added in 3.53.0.
TODO?: an async variant of this.
*/
capi.sqlite3_js_retry_busy = function(maxTimes, callback, beforeRetry){
for(let n = 1; n <= maxTimes; ++n){
+4 -2
View File
@@ -172,7 +172,7 @@
if(capi.sqlite3_vfs_find("opfs")){
stdout("\nOPFS is available. To open a persistent db, use:\n\n",
" .open file:name?vfs=opfs\n\nbut note that some",
"features (e.g. upload) do not yet work with OPFS.");
"features (e.g. upload) do not work with OPFS.");
}
stdout('\nEnter ".help" for usage hints.');
return true;
@@ -186,6 +186,7 @@
if(!f._){
if(!this.runMain()) return;
f._ = sqlite3.wasm.xWrap('fiddle_exec', undefined, ['string']);
f.getPrompt = sqlite3.wasm.xWrap('fiddle_get_prompt', 'string:dealloc', []);
}
if(fiddleModule.isDead){
stderr("shell module has exit()ed. Cannot run SQL.");
@@ -207,7 +208,8 @@
wMsg('working','end');
wMsg('wasm-info', {
pointerSize: sqlite3.wasm.ptr.size,
heapSize: sqlite3.wasm.heap8().byteLength
heapSize: sqlite3.wasm.heap8().byteLength,
prompt: f.getPrompt()
});
}
},
+10 -2
View File
@@ -349,9 +349,10 @@
SF.e.wasmInfo.innerText = 'WASM: '+(
4===v.pointerSize ? 32 : 64
)+'-bit'
//+' heap size: '+Number(v.heapSize)
+' heap: '+Number(v.heapSize)
// Heap size is not changing even when loading a huge db?
;
SF.jqTerm?.set_prompt?.(v.prompt);
});
/* querySelectorAll() proxy */
@@ -865,8 +866,14 @@
const jqeTerm = window.jQuery(SF.e.terminal).empty();
SF.jqTerm = jqeTerm.terminal(SF.dbExec.bind(SF),{
prompt: 'sqlite> ',
greetings: false /* note that the docs incorrectly call this 'greeting' */
greetings: false /* the docs incorrectly call this 'greeting' */
});
/* Disable all special handling of the input:
https://sqlite.org/forum/forumpost/c6665017c0dbba1f
https://github.com/jcubic/jquery.terminal/issues/1044 */
const no_formatting = (str)=>window.jQuery.terminal.escape_formatting(str);
no_formatting.__meta__ = true;
window.jQuery.terminal.new_formatter(no_formatting);
EAll('.unhide-if-terminal-available').forEach(e=>{
e.classList.remove('hidden');
});
@@ -890,5 +897,6 @@
SF.dbExec(urlParams.get('sql') || null);
delete SF.ForceResizeKludge.$disabled;
SF.ForceResizeKludge();
globalThis.fiddle = SF;
}/*onSFLoaded()*/;
})();
+3 -2
View File
@@ -322,8 +322,9 @@
<h1>Usage Summary</h1>
<ul>
<li class='hidden unhide-if-terminal-available'>In "terminal
mode" it accepts input just like the CLI shell does.</li>
<li class='hidden unhide-if-terminal-available'>In
<a href="https://github.com/jcubic/jquery.terminal">"terminal
mode"</a> it accepts input just like the CLI shell does.</li>
<li>In split-view mode:
<ul>
<li>Input can be executed with either the Run
+5 -1
View File
@@ -1021,11 +1021,15 @@ static void mk_fiddle(void){
pf("\t@$(call b.call.wasm-strip,%s)\n", zBuildName);
pf("\t@$(call b.strip-js-emcc-bindings,$(logtag.%s))\n",
zBuildName);
pf("\t@$(call b.cp,%s,$(dir.dout)/sqlite3-opfs-async-proxy.js,"
"$(dir $@)"
")\n", zBuildName);
if( isDebug ){
pf("\t@$(call b.cp,%s,"
"$(dir.fiddle)/index.html "
"$(dir.fiddle)/fiddle.js "
"$(dir.fiddle)/fiddle-worker.js,"
"$(dir.fiddle)/fiddle-worker.js "
"$(dir.fiddle)/sqlite3-opfs-async-proxy.js,"
"$(dir $@)"
")\n",
zBuildName);
+1 -1
View File
@@ -2505,7 +2505,7 @@ tidy:
# Removes build products and test logs. Retains ./configure outputs.
#
clean: tidy
rm -rf omittest* testrunner* testdir*
rm -rf omittest* testrunner* testrun_* testdir*
#
# Clean up everything. No exceptions. From an out-of-tree build which
+41 -42
View File
@@ -1,14 +1,14 @@
C Fix\ssome\sbuffer\soverreads\sthat\smight\soccur\sin\sthe\ssession\smodule\swhen\shandling\scorrupt\schangesets.
D 2026-04-09T05:33:19.706
C Add\sa\smissing\sopen_db()\scall\sin\sthe\snew\s".dbstat"\scommand\sof\sthe\sCLI.
D 2026-04-15T11:58:54.973
F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md 6bc480fc673fb4acbc4094e77edb326267dd460162d7723c7f30bee2d3d9e97d
F Makefile.in 5fda086f33b144da08119255da1d2557f983d0764a13707f05acf0159fd89ba5
F Makefile.linux-generic bd3e3cacd369821a6241d4ea1967395c962dfe3057e38cb0a435cee0e8b789d0
F Makefile.msc 92391304cf70f4c178b127aa83b88637abd28d1b83ede451616144037ea1d3dd
F README.md f49fbd826941842e348242f3ab62f240c985ceafdf8fbe576abf4eb75317468c
F VERSION 31435e19ded2aae3c1c67dacf06a995a37fd1b253baec5899b78d64cd29db4f7
F Makefile.msc 06b757f8648f1d9dd9683dbd72350cf0cf20d6fe09168cac455569b81dd97ddc
F README.md e4f1a030f813c2fafc898c66d4f10bff2c75eb1a8f504eb9ad9a5ef80e3ff814
F VERSION 99cf3be5f13d091183e4314b7fc2e0c0e69accfbe64608b45a313338bbdd7b62
F art/icon-243x273.gif 9750b734f82fdb3dc43127753d5e6fbf3b62c9f4e136c2fbf573b2f57ea87af5
F art/icon-80x90.gif 65509ce3e5f86a9cd64fe7fca2d23954199f31fe44c1e09e208c80fb83d87031
F art/sqlite370.eps aa97a671332b432a54e1d74ff5e8775be34200c2
@@ -44,7 +44,7 @@ F autosetup/cc-lib.tcl 493c5935b5dd3bf9bd4eca89b07c8b1b1a9356d61783035144e21795f
F autosetup/cc-shared.tcl 163eda58c14cd662fd8a504bd2ad8a716ef4db7015dc1de0095d5de8dd601a4b
F autosetup/cc.tcl c0fcc50ca91deff8741e449ddad05bcd08268bc31177e613a6343bbd1fd3e45f
F autosetup/find_tclconfig.tcl e64886ffe3b982d4df42cd28ed91fe0b5940c2c5785e126c1821baf61bc86a7e
F autosetup/jimsh0.c 916bbdf8023fbda9937afae57d81a853d8c2ea00f2320aa27becbc33574f963d
F autosetup/jimsh0.c 740dc8cbfaedaff1f27b54b32e0015b22fa6c1a439492b9795968d61e56bab75
F autosetup/pkg-config.tcl 4e635bf39022ff65e0d5434339dd41503ea48fc53822c9c5bde88b02d3d952ba
F autosetup/proj.tcl ce301197f364f7ce2acabbbd84b43d19e917ec73653157ca134a06f32d322712
F autosetup/sqlite-config.tcl 8fecce2838b7e7d990d161d08998034f3e3b0b2ddf4d7a99dbfafba9c902e302
@@ -358,6 +358,7 @@ F ext/jni/src/tests/000-001-ignored.test e17e874c6ab3c437f1293d88093cf06286083b6
F ext/jni/src/tests/900-001-fts.test bf0ce17a8d082773450e91f2388f5bbb2dfa316d0b676c313c637a91198090f0
F ext/misc/README.md 6243cdc4d7eb791c41ef0716f3980b8b5f6aa8c61ff76a3958cbf0031c6ebfa7
F ext/misc/amatch.c 8d237cc014b3736922c26a76a451050d244aa4980c47c531f368f817b1e77b49
F ext/misc/analyze.c c329e7fdd23caebbe5362b25a416a7fda7e1524ddba03be12f1d2e4a903caa02
F ext/misc/anycollseq.c 5ffdfde9829eeac52219136ad6aa7cd9a4edb3b15f4f2532de52f4a22525eddb
F ext/misc/appendvfs.c 9642c7a194a2a25dca7ad3e36af24a0a46d7702168c4ad7e59c9f9b0e16a3824
F ext/misc/base64.c 1445761667c16356e827fc6418294c869468be934429aaa8315035e76dd58acf
@@ -421,7 +422,7 @@ F ext/misc/zipfile.c 5a583b5e72b4d777dc9f845529e6bd185d58024b633aafc93588679c787
F ext/misc/zorder.c bddff2e1b9661a90c95c2a9a9c7ecd8908afab5763256294dd12d609d4664eee
F ext/qrf/README.md 9e644615d7d7b77ef7e9db798765679e50c5ed12eda48bce21c9ef9eb4715e9d
F ext/qrf/dev-notes.md e68a6d91ce4c7eb296ef2daadc2bb79c95c317ad15b9fafe40850c67b29c2430
F ext/qrf/qrf.c 9bef1f01e0c33a8693a9a7c1b666b8dee1aa60b8bc880d562eb4dfff551a6009
F ext/qrf/qrf.c 64203184d9fc6ee75439fb6da70fd51dc7aaf3243600e52aa87d18ea1e4d6e73
F ext/qrf/qrf.h fbb223ff5789b324b3e9c22e787e4c1f53e217cff7cc5a243164d4b2e8410f4b
F ext/rbu/rbu.c 801450b24eaf14440d8fd20385aacc751d5c9d6123398df41b1b5aa804bf4ce8
F ext/rbu/rbu1.test 25870dd7db7eb5597e2b4d6e29e7a7e095abf332660f67d89959552ce8f8f255
@@ -463,11 +464,11 @@ F ext/rbu/rburesume.test 1403752d152b55efb7fc25749c0fccc790061371ec9ffe428cc04f8
F ext/rbu/rbusave.test 588b618dad9d65c4b13d03a79931de82213503fedc26bdf5789c996ecf427fba
F ext/rbu/rbusplit.test a6dedd23cf37bcf2e8646d9d7139846e96d60d92f9bc6d6ba6ca8c24c0bd1f72
F ext/rbu/rbutemplimit.test 4980df2d4b74f4dd982add8f78809106154ef5a3c4bdce747422ab0b0481e029
F ext/rbu/rbuvacuum.test 542561741ff2b262e3694bc6012b44694ee62c545845319a06f323783b15311e
F ext/rbu/rbuvacuum.test e3585cfda220038e8186c583e9bd2aaa9eccd0a5c2e40ed861de3c987c93f68c
F ext/rbu/rbuvacuum2.test 1a9bd41f127be2826de2a65204df9118525a8af8d16e61e6bc63ba3ac0010a23
F ext/rbu/rbuvacuum3.test 3ce42695fdf21aaa3499e857d7d4253bc499ad759bcd6c9362042c13cd37d8de
F ext/rbu/rbuvacuum4.test ffccd22f67e2d0b380d2889685742159dfe0d19a3880ca3d2d1d69eefaebb205
F ext/rbu/sqlite3rbu.c e99400d29d029936075e27495b269a2dcdceae3cf8c86b1d0869b4af487be3ab
F ext/rbu/sqlite3rbu.c 28246b647831409e84dfb8286fbeda55f1de89e934571509a23a67ada572d0c0
F ext/rbu/sqlite3rbu.h e3a5bf21e09ca93ce4e8740e00d6a853e90a697968ec0ea98f40826938bdb68e
F ext/rbu/test_rbu.c 8b6e64e486c28c41ef29f6f4ea6be7b3091958987812784904f5e903f6b56418
F ext/recover/dbdata.c 10d3c56968a9af6853722a47280805ad1564714d79ea45ac6f7da14bb57fd137
@@ -582,7 +583,7 @@ F ext/wasm/SQLTester/SQLTester.mjs 6b3c52ed36a5573ca4883176f326332a8d4c0cecf5efd
F ext/wasm/SQLTester/SQLTester.run.mjs 57f2adb33f43f2784abbf8026c1bfd049d8013af1998e7dcb8b50c89ffc332e0
F ext/wasm/SQLTester/index.html 64f3435084c7d6139b08d1f2a713828a73f68de2ae6a3112cbb5980d991ba06f
F ext/wasm/SQLTester/touint8array.c 2d5ece04ec1393a6a60c4bf96385bda5e1a10ad49f3038b96460fc5e5aa7e536
F ext/wasm/api/EXPORTED_FUNCTIONS.c-pp de2ce128aebeff9ef4161cff7a0ff0089be866121bcb8941ad44a38a65f1d436
F ext/wasm/api/EXPORTED_FUNCTIONS.c-pp 189935d0106bca86661efc991ab13e1d5d6e1f55ec34dc7b5055a99321397edd
F ext/wasm/api/README.md a905d5c6bfc3e2df875bd391d6d6b7b48d41b43bdee02ad115b47244781a7e81
F ext/wasm/api/extern-post-js.c-pp.js 80accc53cc6ea1e61c721595f42ba95baa7c7ea636807d9507e69403301f8c54
F ext/wasm/api/extern-pre-js.js cc61c09c7a24a07dbecb4c352453c3985170cec12b4e7e7e7a4d11d43c5c8f41
@@ -592,8 +593,8 @@ F ext/wasm/api/post-js-footer.js a50c1a2c4d008aede7b2aa1f18891a7ee71437c2f415b8a
F ext/wasm/api/post-js-header.js f35d2dcf1ab7f22a93d565f8e0b622a2934fc4e743edf3b708e4dd8140eeff55
F ext/wasm/api/pre-js.c-pp.js d6bf82f83f60caa2904bddb95a29cb738b310f672d2796cdc5fe54463ab0d6cd
F ext/wasm/api/sqlite3-api-glue.c-pp.js 31a721ada7225838a61310a9f3f797fa5275353f8e9b0ae769d85b437be061f5
F ext/wasm/api/sqlite3-api-oo1.c-pp.js 5f203f5bb5d48a9e43ec51e791dc411c24dca825842bfb6a2d979d871bf8cfaf
F ext/wasm/api/sqlite3-api-prologue.js 4336f02ac24ba58e68e355adb9da2804a1eef15a4aee961fa813c7d812a56b54
F ext/wasm/api/sqlite3-api-oo1.c-pp.js 35e4727010f15fd72ead0dd1eb4e3c2c9bb1cc60e51544cbdff1f7c14f209de2
F ext/wasm/api/sqlite3-api-prologue.js 29ca376ff5d5f189714cf10b2b93b136e91b06ec8616579b53b2af9dfb4796bf
F ext/wasm/api/sqlite3-api-worker1.c-pp.js 1fa34e9b0e3b90a8898e4f700d7125e44c81877f182627bb8564b97989bc6e78
F ext/wasm/api/sqlite3-license-version-header.js 98d90255a12d02214db634e041c8e7f2f133d9361a8ebf000ba9c9af4c6761cc
F ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js 25e31482b04293a33d7599f1459eb552b3eb36ca10c02c816122d3308bf80cb2
@@ -621,16 +622,16 @@ F ext/wasm/demo-worker1-promiser.c-pp.js d210aa1e8a74ea6244fe2290de5710bb55b3a9e
F ext/wasm/demo-worker1.html 2c178c1890a2beb5a5fecb1453e796d067a4b8d3d2a04d65ca2eb1ab2c68ef5d
F ext/wasm/demo-worker1.js fdfa90aa9d6b402bfed802cf1595fe4da6cc834ac38c8ff854bf1ee01f5ff9bb
F ext/wasm/example_extra_init.c 2347cd69d19d839ef4e5e77b7855103a7fe3ef2af86f2e8c95839afd8b05862f
F ext/wasm/fiddle/fiddle-worker.js 6c72acac2d381480bc9f5eb538e3f2faf2c1f72dd4fcbd05d3b409818a9a8fd5
F ext/wasm/fiddle/fiddle.js 84fd75967e0af8b69d3dd849818342227d0f81d13db92e0dcbc63649b31a4893
F ext/wasm/fiddle/index.c-pp.html 02f063ef30b8124f311029855c4439e77bc6505d1bf65a163d88c064a63ee9d9
F ext/wasm/fiddle/fiddle-worker.js e45bfe9ce4cf0d0270ca0ed254af8deecc7d46c399db4a56fd1d0846d5e258ec
F ext/wasm/fiddle/fiddle.js 2a0984cc4a35e6889c0d84ee9bf853317d5545ddb3966dfb995bbe589f923c4c
F ext/wasm/fiddle/index.c-pp.html 5fd1f462864710d1b00d27fc4bc6190cb846cc865d7cc93b99644423f2c4cc84
F ext/wasm/index-dist.html db23748044e286773f2768eec287669501703b5d5f72755e8db73607dc54d290
F ext/wasm/index.html 5bf6cf1b0a3c8b9f5f54d77f2219d7ae87a15162055ce308109c49b1dcab4239
F ext/wasm/jaccwabyt/jaccwabyt.js 4e2b797dc170851c9c530c3567679f4aa509eec0fab73b466d945b00b356574b
F ext/wasm/jaccwabyt/jaccwabyt.md 6aa90fa1a973d0ad10d077088bea163b241d8470c75eafdef87620a1de1dea41
F ext/wasm/libcmpp.c 0e2cec7de7c9cbe7941e6a4dc0c123cec736578a3eeae7828ac18706acd3cea6
F ext/wasm/mkdist.sh f8883b077a2ca47cf92e6f0ce305fbf72ca648c3501810125056c4b09c2d5554 x
F ext/wasm/mkwasmbuilds.c d4479af2774a43104b819d9286961b7c09793ca39440e20191e693ceff21f911
F ext/wasm/mkwasmbuilds.c 60706fb66db7f1e24d876e3cb2493484cfb27e7b103c7741c384505dd678769c
F ext/wasm/module-symbols.html e54f42112e0aac2a31f850ab33e7f2630a2ea4f63496f484a12469a2501e07e2
F ext/wasm/scratchpad-wasmfs.html a3d7388f3c4b263676b58b526846e9d02dfcb4014ff29d3a5040935286af5b96
F ext/wasm/scratchpad-wasmfs.mjs 66034b9256b218de59248aad796760a1584c1dd842231505895eff00dbd57c63
@@ -656,7 +657,7 @@ F ext/wasm/tests/opfs/sahpool/index.html be736567fd92d3ecb9754c145755037cbbd2bca
F ext/wasm/tests/opfs/sahpool/sahpool-pausing.js f264925cfc82155de38cecb3d204c36e0f6991460fff0cb7c15079454679a4e2
F ext/wasm/tests/opfs/sahpool/sahpool-worker.js bd25a43fc2ab2d1bafd8f2854ad3943ef673f7c3be03e95ecf1612ff6e8e2a61
F magic.txt 5ade0bc977aa135e79e3faaea894d5671b26107cc91e70783aa7dc83f22f3ba0
F main.mk bf77c630aeef4ed4b9270e1fd52c35147b529412c00b74ed6eb8aca3466763f6
F main.mk 48f6b3557cefd79e5cfae1f15e32d6a0dffd7b689c582a9a7b3920a4ee18affd
F make.bat a136fd0b1c93e89854a86d5f4edcf0386d211e5d5ec2434480f6eea436c7420c
F mptest/config01.test 3c6adcbc50b991866855f1977ff172eb6d901271
F mptest/config02.test 4415dfe36c48785f751e16e32c20b077c28ae504
@@ -674,18 +675,18 @@ F src/auth.c ebec42df26b34a62b6750d30d9c2c03554a1c522020182476f7729a439fef04f
F src/backup.c 5c97e8023aab1ce14a42387eb3ae00ba5a0644569e3476f38661fa6f824c3523
F src/bitvec.c e242d4496774dfc88fa278177dd23b607dce369ccafb3f61b41638eea2c9b399
F src/btmutex.c 30dada73a819a1ef5b7583786370dce1842e12e1ad941e4d05ac29695528daea
F src/btree.c fb350c445316c1cc0529703c0b76450770a1de0ab0440641a56b19f05d6fefbe
F src/btree.c 216ffbe197e330118a2999adc7d3f09b0e2eeb163df8746ba9a2b27fed3d4335
F src/btree.h e823c46d87f63d904d735a24b76146d19f51f04445ea561f71cc3382fd1307f0
F src/btreeInt.h 9c0f9ea5c9b5f4dcaea18111d43efe95f2ac276cd86d770dce10fd99ccc93886
F src/build.c 8581de0af3b6c448f5d64e2d18a91ac1e7057b3bcb8b8827e1240f80d87486a4
F src/callback.c 3605bbf02bd7ed46c79cd48346db4a32fc51d67624400539c0532f4eead804ad
F src/carray.c 3efe3982d5fb323334c29328a4e189ccaef6b95612a6084ad5fa124fd5db1179
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
F src/complete.c f216b970ce99c5a657556cf1f17e7ddd494515d3beb63df426bf59ff43bd3d9a
F src/date.c 61e92f1f7e2e88e1cd91e91dc69eb2b2854e7877254470f9fabd776bfac922b8
F src/dbpage.c c9ea81c11727f27e02874611e92773e68e2a90a875ef2404b084564c235fd91f
F src/dbstat.c 73362c0df0f40ad5523a6f5501224959d0976757b511299bf892313e79d14f5c
F src/delete.c 1f2268d6fe3c78fc1bf794ba65d7026498b78e2342ffaf85825dedae546e6fde
F src/expr.c 51e9c77ff5d9a21439e611fe6571a3cd50387e526e13c5614fd407e5b8571930
F src/expr.c 68400681c5f6e41231d2c85abf6bb432aeeb2e36c4abdf90eb7b78551a5ce0f3
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
F src/fkey.c 931f74cec1dc8038a0217ef340c91ce147dd1bbed08dc40c47ee0ec6edfffb08
F src/func.c 706ac012bf87d8ad7416a56a1d2b1f19e5dea03506a4606a01aa9d3bacf392c7
@@ -697,8 +698,8 @@ F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
F src/insert.c dfd311b0ac2d4f6359e62013db67799757f4d2cc56cca5c10f4888acfbbfa3fd
F src/json.c 5027b856cd9b621dc9ba66b211e21a440ccdc63cefdefb44c51e7d3ac550d1a4
F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa
F src/loadext.c 56a542244fbefc739a2ef57fac007c16b2aefdb4377f584e9547db2ce3e071f9
F src/main.c 387bb9d0216d6d35b221481ba8e661d94ad043060cd89581b6422c269ce680a0
F src/loadext.c 78d5b06f18996ffa1203129b28fea043f63a87a4117539678f1d761c30b4ff65
F src/main.c 6180079f53ccdd784df2eddc3751f49ea7153c5959bee792b19ad9f4bdbcf437
F src/malloc.c 422f7e0498e1c9ef967f06283b6f2c0b16db6b905d8e06f6dbc8baaa3e4e6c5a
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
F src/mem1.c 3bb59158c38e05f6270e761a9f435bf19827a264c13d1631c58b84bdc96d73b2
@@ -719,10 +720,10 @@ F src/os.h 1ff5ae51d339d0e30d8a9d814f4b8f8e448169304d83a7ed9db66a65732f3e63
F src/os_common.h 6c0eb8dd40ef3e12fe585a13e709710267a258e2c8dd1c40b1948a1d14582e06
F src/os_kv.c e7d96727db5b67e39d590a68cc61c86daf4c093c36c011a09ebfb521182ec28d
F src/os_setup.h 8efc64eda6a6c2f221387eefc2e7e45fd5a3d5c8337a7a83519ba4fbd2957ae2
F src/os_unix.c fa5e09b4df35ad845440cad67b86908cfe1fd4c28c51915f82e23633d1992bf4
F src/os_unix.c a07dce662f6c4e18098f6faa9f7ec7cf311f56ee9151bed2aad4dcd55852c9e2
F src/os_win.c 0d553b6e8b92c8eb85e7f1b4a8036fe8638c8b32c9ad8d9d72a861c10f81b4c5
F src/os_win.h 5e168adf482484327195d10f9c3bce3520f598e04e07ffe62c9c5a8067c1037b
F src/pager.c fe34fd22ec251436985d7b6ebdd05bf238a17901c2cb23d3d28974dd2361a912
F src/pager.c fbec9063ea139dfa5d94ce540671752b89f8e8dc38f8a1f614bab1aa04a2dd40
F src/pager.h 6137149346e6c8a3ddc1eeb40aee46381e9bc8b0fcc6dda8a1efde993c2275b8
F src/parse.y 3b784d6083380a950e3b1b32ce5ddd303e8c7c209d8ab788df2c62aaf9ee8eb3
F src/pcache.c 588cc3c5ccaaadde689ed35ce5c5c891a1f7b1f4d1f56f6cf0143b74d8ee6484
@@ -730,15 +731,15 @@ F src/pcache.h 092b758d2c5e4dabb30eae46d8dfad77c0f70b16bf3ff1943f7a232b0fe0d4ba
F src/pcache1.c 131ca0daf4e66b4608d2945ae76d6ed90de3f60539afbd5ef9ec65667a5f2fcd
F src/pragma.c 789ef67117b74b5be0a2db6681f7f0c55e6913791b9da309aefd280de2c8a74d
F src/prepare.c f6a6e28a281bd1d1da12f47d370a81af46159b40f73bf7fa0b276b664f9c8b7d
F src/printf.c 41fb76fcb5ed7e16aaddc659d3b23891abebea45549fe125fc2e6ec380cc7175
F src/printf.c d442fda86ad11da7923dbb354d3761229b5b51dbe06c5c208fa75e3411c79434
F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c
F src/resolve.c 928ff887f2a7c64275182060d94d06fdddbe32226c569781cf7e7edc6f58d7fd
F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97
F src/select.c ffe199f025a0dd74670d2a77232bdea364a4d7b36f32c64a6572d39ba6a11576
F src/shell.c.in a3288615aba1b375f7dca9801874c806e8d0d047dfe4e9253a944f4b47c7459e
F src/sqlite.h.in e2915e4a86d5e0783afb5cb72411df38d987c7f3c5aa2d5441b8e74d30b649d8
F src/shell.c.in 4279e364fd909db808ab8fc46ed06f25e96aaa28726bf6342a9b74bde58bc813
F src/sqlite.h.in 39d2e09114d2bdb7afd998f4a469c8f8cd065f8093835a7d0422f260fc78fb4f
F src/sqlite3.rc 015537e6ac1eec6c7050e17b616c2ffe6f70fca241835a84a4f0d5937383c479
F src/sqlite3ext.h 1b7a0ee438bb5c2896d0609c537e917d8057b3340f6ad004d2de44f03e3d3cca
F src/sqlite3ext.h 9788c301f95370fa30e808861f1d2e6f022a816ddbe2a4f67486784c1b31db2e
F src/sqliteInt.h bc1cbc0c23dba35b324ae85a7dbb5fb182321bbd30857fb21f3d0cba049001a5
F src/sqliteLimit.h c70656b67ab5b96741a8f1c812bdd80c81f2b1c1e443d0cc3ea8c33bb1f1a092
F src/status.c 7565d63a79aa2f326339a24a0461a60096d0bd2bce711fefb50b5c89335f3592
@@ -799,13 +800,13 @@ F src/trigger.c 4bf3bfb3851d165e4404a9f9e69357345f3f7103378c07e07139fdd8aeb7bd20
F src/update.c 3e5e7ff66fa19ebe4d1b113d480639a24cc1175adbefabbd1a948a07f28e37cf
F src/upsert.c 215328c3f91623c520ec8672c44323553f12caeb4f01b1090ebdca99fdf7b4f1
F src/utf.c 7267c3fb9e2467020507601af3354c2446c61f444387e094c779dccd5ca62165
F src/util.c 4f0abc15f63829e12cdfeeb490faf25ac65894b0bcc20d660e3f3757b8e2360b
F src/util.c 377af5da226519a0f374dc3c6d408c9d303a92943e3ae5986432c7d52e6679a2
F src/vacuum.c d3d35d8ae893d419ade5fa196d761a83bddcbb62137a1a157ae751ef38b26e82
F src/vdbe.c 6c57525d7db0232d52687d30da1093db0c152f14206c2ef1adf0c19a09d863e3
F src/vdbe.h 70e862ac8a11b590f8c1eaac17a0078429d42bc4ea3f757a9af0f451dd966a71
F src/vdbeInt.h c31ba4dc8d280c2b1dc89c6fcee68f2555e3813ab34279552c20b964c0e338b1
F src/vdbeapi.c 6cdcbe5c7afa754c998e73d2d5d2805556268362914b952811bdfb9c78a37cf1
F src/vdbeaux.c 81687c55682b9f4d942186695f4f7fa4743c564a985e0889def52eded9076d61
F src/vdbeaux.c 8749b5f4f6d65e048ba78143d2dfc6898f65010ecef213891094e8166d1557da
F src/vdbeblob.c b3f0640db9642fbdc88bd6ebcc83d6009514cafc98f062f675f2c8d505d82692
F src/vdbemem.c efacb8f229422d2a4db0ed38e49b7f3897862a98d82b261aa3b43d7a2d98c6da
F src/vdbesort.c b69220f4ea9ffea5fdef34d968c60305444eea909252a81933b54c296d9cca70
@@ -816,7 +817,7 @@ F src/vxworks.h 9d18819c5235b49c2340a8a4d48195ec5d5afb637b152406de95a9436beeaeab
F src/wal.c 7340d4f9bb827bd349127cac6b2cf0cb7f76b9fda645f7b9b0bf7a6e0b1e2e7c
F src/wal.h ba252daaa94f889f4b2c17c027e823d9be47ce39da1d3799886bbd51f0490452
F src/walker.c d5006d6b005e4ea7302ad390957a8d41ed83faa177e412f89bc5600a7462a014
F src/where.c bffca5e4ef20d0bfbdc24f1dc13fd3f955284225a8ad25a4454635f6be39aad0
F src/where.c a00d35adeb2550249ba02f24e50eecfb99cba34c8d7d5299b295a591219a2e73
F src/whereInt.h 8d94cb116c9e06205c3d5ac87af065fc044f8cf08bfdccd94b6ea1c1308e65da
F src/wherecode.c 676cb6cb02878643e817d9917a2d3522b83a3736b2cedd3dc8a01d7bb92af6c2
F src/whereexpr.c e9f7185fba366d9365aa7a97329609e4cf00b3dd0400d069fbaa5187350c17c6
@@ -1619,7 +1620,8 @@ F test/sharedA.test 64bdd21216dda2c6a3bd3475348ccdc108160f34682c97f2f51c19fc0e21
F test/sharedB.test 1a84863d7a2204e0d42f2e1606577c5e92e4473fa37ea0f5bdf829e4bf8ee707
F test/shared_err.test 32634e404a3317eeb94abc7a099c556a346fdb8fb3858dbe222a4cbb8926a939
F test/sharedlock.test 5ede3c37439067c43b0198f580fd374ebf15d304
F test/shell1.test eda2e527435f139224dda67db6bbd2466597408d4fe5883d647d67fa32d88f7c
F test/shell-prompt.sql 5c18599f2b7566172007005206471aefb7e0be593e8f52d37b9ab03a12aa84a6
F test/shell1.test c84eff209f93ad17ccdf7e1634969fc8231684254edeb21d9b13d67c3179cdb5
F test/shell2.test dc541d2681503e55466a24d35a4cbf8ca5b90b8fcdef37fc4db07373a67d31d3
F test/shell3.test 91efdd545097a61a1f72cf79c9ad5b49da080f3f10282eaf4c3c272cd1012db2
F test/shell4.test e25580a792b7b54560c3a76b6968bd8189261f38979fe28e6bc6312c5db280db
@@ -1629,7 +1631,7 @@ F test/shell7.test 43fd8e511c533bab5232e95c7b4be93b243451709e89582600d4b6e67693d
F test/shell8.test 38c9e4d7e85d2a3ecfacaa9f6cda4f7a81bf4fffb5f3f37f9cd76827c6883192
F test/shell9.test c0e8871061a92151450b3332279a893b516fa73a6c46d4f51a0998407cbf8c89
F test/shellA.test 05cdaafa1f79913654487ce3aefa038d4106245d58f52e02faf506140a76d480
F test/shellB.test 31df04230f6062069bb7c5d0e5c5439ca44448fa9da1a55aa461a4b872fe6bd9
F test/shellB.test 82622da7783c32ce931138bec3d5016e802d70361b9f9364b5d49c1dfc2f5af9
F test/shmlock.test 9f1f729a7fe2c46c88b156af819ac9b72c0714ac6f7246638a73c5752b5fd13c
F test/shortread1.test bb591ef20f0fd9ed26d0d12e80eee6d7ac8897a3
F test/show_speedtest1_rtree.tcl 32e6c5f073d7426148a6936a0408f4b5b169aba5
@@ -1714,8 +1716,8 @@ F test/temptrigfault.tes fc5918e64f3867156fefe7cfca9d8e1f495134a5229b2b511b0dc11
F test/temptrigger.test a00f258ed8d21a0e8fd4f322f15e8cfb5cef2e43655670e07a753e3fb4769d61
F test/tester.tcl 2d943f60200e0a36bcd3f1f0baf181a751cd3604ef6b6bd4c8dc39b4e8a53116
F test/testloadext.c 862b848783eaed9985fbce46c65cd214664376b549fae252b364d5d1ef350a27
F test/testrunner.tcl 6b232f0d4825dec8b967754503080fc9609fad077f582d02f86bd2d95bec4110 x
F test/testrunner_data.tcl 078e251983c8fc573567125147655f68132210f226c92922daf21fb913779717
F test/testrunner.tcl 3b6cbceb4d7f0226d51a7fde247cc5592565953568c18155c8c3a454d93bee71 x
F test/testrunner_data.tcl 48c8a230fcada37f4809f95c2ba49e44bc3d520b6165c09173249c6e65b01cc1
F test/testrunner_estwork.tcl 81e2ae10238f50540f42fbf2d94913052a99bfb494b69e546506323f195dcff9
F test/thread001.test a0985c117eab62c0c65526e9fa5d1360dd1cac5b03bde223902763274ce21899
F test/thread002.test c24c83408e35ba5a952a3638b7ac03ccdf1ce4409289c54a050ac4c5f1de7502
@@ -2197,11 +2199,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee
F tool/warnings.sh a554d13f6e5cf3760f041b87939e3d616ec6961859c3245e8ef701d1eafc2ca2
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c
P be891a137af15897691250324e4d3d9c96f0c5fb414bca27d0c3bfdd3012a8a2
R 3c37bf09a4d96a6794a05c0475c7df24
T *branch * session-fixes
T *sym-session-fixes *
T -sym-trunk *
U dan
Z f9a6a87e3d60b28afdcae7eb8d4d14d0
P fdba76df2b3a5b4d56ba79f80fd8b16d5faebca1fb07a266262be2ea635e6f94
R 11ac4a0e6010f18fd1adc28138c24819
U drh
Z 0f53747329f642cf306c269a12fd15f3
# Remove this line to create a well-formed Fossil manifest.
+2 -2
View File
@@ -1,2 +1,2 @@
branch session-fixes
tag session-fixes
branch analyze-sql-func
tag analyze-sql-func
+1 -1
View File
@@ -1 +1 @@
8fcf92e15d87487703afc1129f3a89a8d4d72cb30d30a1a9151a5596473069bd
a138e44a243466f8679e9652421f8c893a4a1bc0addc86736588d9aee51cf090
+3 -3
View File
@@ -5939,12 +5939,12 @@ moveto_table_finish:
** zero if the cell is less than or equal pIdxKey. Return positive
** if unknown.
**
** Return value negative: Cell at pCur[idx] less than pIdxKey
** Return value negative: Cell at pPage[idx] less than pIdxKey
**
** Return value is zero: Cell at pCur[idx] equals pIdxKey
** Return value is zero: Cell at pPage[idx] equals pIdxKey
**
** Return value positive: Nothing is known about the relationship
** of the cell at pCur[idx] and pIdxKey.
** of the cell at pPage[idx] and pIdxKey.
**
** This routine is part of an optimization. It is always safe to return
** a positive value as that will cause the optimization to be skipped.
+91 -10
View File
@@ -49,12 +49,51 @@ extern const char sqlite3IsEbcdicIdChar[];
#endif
/*
** Return TRUE if the given SQL string ends in a semicolon.
** Return zero if the given SQL string is complete - if all comments,
** string and blob literals, and quoted identifiers have been closed and
** if the entire string ends with ";" and possible with ";END;" if the
** string is a CREATE TRIGGER statement. A non-zero return indicates
** that the string is incomplete. Bits of the return value indicate
** what is missing and is needed to close out the statement.
**
** Special handling is require for CREATE TRIGGER statements.
** Whenever the CREATE TRIGGER keywords are seen, the statement
** must end with ";END;".
**
** Let the return code be a value R. R is split up into various
** subfields, at byte boundaries:
**
** R = 0xwwwwwwww00xxyyzz
**
** In other words, zz is the least significant byte, yy is the next
** most significant byte, xx is the third byte, wwwwwwww is a 32-bit
** value from the middle.
**
** zz == SQLITE_OK Input is complete
** zz == SQLITE_ERROR Input is incomplete
** zz == SQLITE_MISUSE Input is a NULL pointer
** zz != 0 New values for zz may be added in the future
**
** yy == 0x01 Need a semicolon at the end
** yy == 0x02 Need "END" and a semicolon
** yy == 0x03 Need semicolon, "END", and semicolon
** yy != 0 New values for yy may be added in the future
**
** xx == '\'' Incomplete string or blob literal
** xx == '"' Incomplete quoted identifier
** xx == '`' Incompelte MySQL-style quoted identifier
** xx == ']' Incomplete SQLServer-style quoted identifer
** xx == '-' Incomplete SQL-style comment
** xx == '/' Incomplete C-style comment
** xx != 0 New values of xx may be added in the future
**
** wwwwwwww Interpret as a signed integer, the number
** of unmatched "(". Negative means there are
** more ")" and "(".
**
** ((R>>24)&0xff)!=0 New uses for the 4th byte may be added
** in the future
**
** This implementation uses a state machine with 8 states:
**
** (0) INVALID We have not yet seen a non-whitespace character.
@@ -101,9 +140,11 @@ extern const char sqlite3IsEbcdicIdChar[];
** to recognize the end of a trigger can be omitted. All we have to do
** is look for a semicolon that is not part of an string or comment.
*/
int sqlite3_complete(const char *zSql){
sqlite3_int64 sqlite3_incomplete(const char *zSql){
u8 state = 0; /* Current state, using numbers defined in header comment */
u8 token; /* Value of the next token */
u8 pending = 0; /* unmatched structure character */
int nParen = 0; /* Nested parentheses */
#ifndef SQLITE_OMIT_TRIGGER
/* A complex statement machine used to detect the end of a CREATE TRIGGER
@@ -133,11 +174,21 @@ int sqlite3_complete(const char *zSql){
/* 2 NORMAL: */ { 1, 2, 2, },
};
#endif /* SQLITE_OMIT_TRIGGER */
/* Mapping state number to yy value for the return */
static const u8 statemap[8] = {
/* 0 INVALID */ 1,
/* 1 START */ 0,
/* 2 NORMAL */ 1,
/* 3 EXPLAIN */ 1,
/* 4 CREATE */ 1,
/* 5 TRIGGER */ 3,
/* 6 SEMI */ 2,
/* 7 END */ 1,
};
#ifdef SQLITE_ENABLE_API_ARMOR
if( zSql==0 ){
(void)SQLITE_MISUSE_BKPT;
return 0;
return SQLITE_MISUSE_BKPT;
}
#endif
@@ -162,7 +213,10 @@ int sqlite3_complete(const char *zSql){
}
zSql += 2;
while( zSql[0] && (zSql[0]!='*' || zSql[1]!='/') ){ zSql++; }
if( zSql[0]==0 ) return 0;
if( zSql[0]==0 ){
pending = '/';
goto incomplete_finish;
}
zSql++;
token = tkWS;
break;
@@ -173,14 +227,20 @@ int sqlite3_complete(const char *zSql){
break;
}
while( *zSql && *zSql!='\n' ){ zSql++; }
if( *zSql==0 ) return state==1;
if( *zSql==0 ){
if( state!=1 ) pending = '-';
goto incomplete_finish;
}
token = tkWS;
break;
}
case '[': { /* Microsoft-style identifiers in [...] */
zSql++;
while( *zSql && *zSql!=']' ){ zSql++; }
if( *zSql==0 ) return 0;
if( *zSql==0 ){
pending = ']';
goto incomplete_finish;
}
token = tkOTHER;
break;
}
@@ -190,7 +250,20 @@ int sqlite3_complete(const char *zSql){
int c = *zSql;
zSql++;
while( *zSql && *zSql!=c ){ zSql++; }
if( *zSql==0 ) return 0;
if( *zSql==0 ){
pending = c;
goto incomplete_finish;
}
token = tkOTHER;
break;
}
case '(': {
nParen++;
token = tkOTHER;
break;
}
case ')': {
nParen--;
token = tkOTHER;
break;
}
@@ -257,7 +330,15 @@ int sqlite3_complete(const char *zSql){
state = trans[state][token];
zSql++;
}
return state==1;
incomplete_finish:
if( state==1 ) nParen = 0;
return (i64)((((u64)nParen)<<32) |
((u64)pending<<16) |
((u64)statemap[state]<<8) |
(state!=1));
}
int sqlite3_complete(const char *zSql){
return sqlite3_incomplete(zSql)==0;
}
#ifndef SQLITE_OMIT_UTF16
@@ -279,7 +360,7 @@ int sqlite3_complete16(const void *zSql){
sqlite3ValueSetStr(pVal, -1, zSql, SQLITE_UTF16NATIVE, SQLITE_STATIC);
zSql8 = sqlite3ValueText(pVal, SQLITE_UTF8);
if( zSql8 ){
rc = sqlite3_complete(zSql8);
rc = sqlite3_incomplete(zSql8)==0;
}else{
rc = SQLITE_NOMEM_BKPT;
}
+1 -1
View File
@@ -2650,7 +2650,7 @@ int sqlite3ExprIsConstant(Parse *pParse, Expr *p){
** Walk an expression tree. Return non-zero if
**
** (1) the expression is constant, and
** (2) the expression does originate in the ON or USING clause
** (2) the expression does not originate in the ON or USING clause
** of a LEFT JOIN, and
** (3) the expression does not contain any EP_FixedCol TK_COLUMN
** operands created by the constant propagation optimization.
+3 -2
View File
@@ -528,11 +528,12 @@ static const sqlite3_api_routines sqlite3Apis = {
sqlite3_str_free,
#ifdef SQLITE_ENABLE_CARRAY
sqlite3_carray_bind,
sqlite3_carray_bind_v2
sqlite3_carray_bind_v2,
#else
0,
0
0,
#endif
sqlite3_incomplete
};
/* True if x is the directory separator character
+2 -1
View File
@@ -1136,7 +1136,8 @@ void sqlite3_set_last_insert_rowid(sqlite3 *db, sqlite3_int64 iRowid){
}
/*
** Return the number of changes in the most recent call to sqlite3_exec().
** Return the number of changes in the most recently executed DML
** statement.
*/
sqlite3_int64 sqlite3_changes64(sqlite3 *db){
#ifdef SQLITE_ENABLE_API_ARMOR
+16 -1
View File
@@ -6646,7 +6646,22 @@ static int unixOpen(
}else if( !zName ){
/* If zName is NULL, the upper layer is requesting a temp file. */
assert(isDelete && !isNewJrnl);
assert( isDelete );
assert( !isNewJrnl );
assert( isExclusive );
assert( isReadWrite );
#if defined(__linux__) && defined(O_TMPFILE)
/* On systems that support O_TMPFILE, use that flag to create a more
** secure temporary file that cannot be accessed by other processes
*/
zName = unixTempFileDir();
if( zName
&& (fd = robust_open(zName, O_RDWR|O_CREAT|O_EXCL|O_TMPFILE, 0600))>=0
){
rc = fillInUnixFile(pVfs, fd, pFile, zPath, ctrlFlags);
goto open_finished;
}
#endif
rc = unixGetTempname(pVfs->mxPathname, zTmpname);
if( rc!=SQLITE_OK ){
return rc;
+4 -4
View File
@@ -1993,7 +1993,7 @@ static int pagerFlushOnCommit(Pager *pPager, int bCommit){
** database transaction.
**
** This routine is never called in PAGER_ERROR state. If it is called
** in PAGER_NONE or PAGER_SHARED state and the lock held is less
** in PAGER_OPEN or PAGER_READER state and the lock held is less
** exclusive than a RESERVED lock, it is a no-op.
**
** Otherwise, any active savepoints are released.
@@ -3754,7 +3754,7 @@ void sqlite3PagerSetBusyHandler(
**
** then the pager object page size is set to *pPageSize.
**
** If the page size is changed, then this function uses sqlite3PagerMalloc()
** If the page size is changed, then this function uses sqlite3PageMalloc()
** to obtain a new Pager.pTmpSpace buffer. If this allocation attempt
** fails, SQLITE_NOMEM is returned and the page size remains unchanged.
** In all other cases, SQLITE_OK is returned.
@@ -5101,8 +5101,8 @@ sqlite3_file *sqlite3_database_file_object(const char *zName){
/*
** This function is called after transitioning from PAGER_UNLOCK to
** PAGER_SHARED state. It tests if there is a hot journal present in
** This function is called while transitioning from PAGER_OPEN to a
** higher state. It tests if there is a hot journal present in
** the file-system for the given pager. A hot journal is one that
** needs to be played back. According to this function, a hot-journal
** file exists if the following criteria are met:
+37 -13
View File
@@ -165,7 +165,7 @@ static char *printfTempBuf(sqlite3_str *pAccum, sqlite3_int64 n){
sqlite3StrAccumSetError(pAccum, SQLITE_TOOBIG);
return 0;
}
z = sqlite3DbMallocRaw(pAccum->db, n);
z = sqlite3_malloc(n);
if( z==0 ){
sqlite3StrAccumSetError(pAccum, SQLITE_NOMEM);
}
@@ -623,11 +623,27 @@ void sqlite3_str_vappendf(
szBufNeeded = MAX(e2,0)+(i64)precision+(i64)width+10;
if( cThousand && e2>0 ) szBufNeeded += (e2+2)/3;
if( sqlite3StrAccumEnlargeIfNeeded(pAccum, szBufNeeded) ){
width = length = 0;
break;
if( szBufNeeded + pAccum->nChar >= pAccum->nAlloc ){
if( pAccum->mxAlloc==0 && pAccum->accError==0 ){
/* Unable to allocate space in pAccum, perhaps because it
** is coming from sqlite3_snprintf() or similar. We'll have
** to render into temporary space and the memcpy() it over. */
bufpt = sqlite3_malloc(szBufNeeded);
if( bufpt==0 ){
sqlite3StrAccumSetError(pAccum, SQLITE_NOMEM);
return;
}
zExtra = bufpt;
}else if( sqlite3StrAccumEnlarge(pAccum, szBufNeeded)<szBufNeeded ){
width = length = 0;
break;
}else{
bufpt = pAccum->zText + pAccum->nChar;
}
}else{
bufpt = pAccum->zText + pAccum->nChar;
}
bufpt = zOut = pAccum->zText + pAccum->nChar;
zOut = bufpt;
flag_dp = (precision>0 ?1:0) | flag_alternateform | flag_altform2;
/* The sign in front of the number */
@@ -728,14 +744,22 @@ void sqlite3_str_vappendf(
}
length = width;
}
pAccum->nChar += length;
zOut[length] = 0;
/* Floating point conversions render directly into the output
** buffer. Hence, don't just break out of the switch(). Bypass the
** output buffer writing that occurs after the switch() by continuing
** to the next character in the format string. */
continue;
if( zExtra==0 ){
/* The result is being rendered directory into pAccum. This
** is the command and fast case */
pAccum->nChar += length;
zOut[length] = 0;
continue;
}else{
/* We were unable to render directly into pAccum because we
** couldn't allocate sufficient memory. We need to memcpy()
** the rendering (or some prefix thereof) into the output
** buffer. */
bufpt[0] = 0;
bufpt = zExtra;
break;
}
}
case etSIZE:
if( !bArgList ){
@@ -782,7 +806,7 @@ void sqlite3_str_vappendf(
if( sqlite3StrAccumEnlargeIfNeeded(pAccum, nCopyBytes) ){
break;
}
sqlite3_str_append(pAccum,
sqlite3_str_append(pAccum,
&pAccum->zText[pAccum->nChar-nCopyBytes], nCopyBytes);
precision -= nPrior;
nPrior *= 2;
+509 -269
View File
File diff suppressed because it is too large Load Diff
+20 -8
View File
@@ -2960,8 +2960,9 @@ int sqlite3_is_interrupted(sqlite3*);
** These routines are useful during command-line input to determine if the
** currently entered text seems to form a complete SQL statement or
** if additional input is needed before sending the text into
** SQLite for parsing. ^These routines return 1 if the input string
** appears to be a complete SQL statement. ^A statement is judged to be
** SQLite for parsing. ^The sqlite3_complete(X) and sqlite3_complete16(X)
** routines return 1 if the input string X appears to be a complete SQL
** statement. ^A statement is judged to be
** complete if it ends with a semicolon token and is not a prefix of a
** well-formed CREATE TRIGGER statement. ^Semicolons that are embedded within
** string literals or quoted identifier names or comments are not
@@ -2969,11 +2970,21 @@ int sqlite3_is_interrupted(sqlite3*);
** embedded) and thus do not count as a statement terminator. ^Whitespace
** and comments that follow the final semicolon are ignored.
**
** ^These routines return 0 if the statement is incomplete. ^If a
** memory allocation fails, then SQLITE_NOMEM is returned.
** ^The sqlite3_complete(X) and sqlite3_complete16(X) routines return 0
** if the statement is incomplete. ^If a memory allocation fails, then
** SQLITE_NOMEM is returned.
**
** ^These routines do not parse the SQL statements and thus
** will not detect syntactically incorrect SQL.
** The [sqlite3_incomplete(X)] routine is similar to [sqlite3_complete(X)]
** except that sqlite3_incomplete(X) returns 0 if the input X is complete
** and non-zero if X is incomplete. The non-zero return from
** sqlite3_incomplete(X) contains additional information about what is
** needed to complete the input X. The sqlite3_incomplete(X) interface
** is only available for UTF-8 text.
**
** ^None of these routines do a full parse the SQL statements and thus
** will not detect syntactically incorrect SQL. They only determine if
** input text has properly terminated comments, string literals, and
** quoted identifiers, and if the statement ends with a semicolon.
**
** ^(If SQLite has not been initialized using [sqlite3_initialize()] prior
** to invoking sqlite3_complete16() then sqlite3_initialize() is invoked
@@ -2981,14 +2992,15 @@ int sqlite3_is_interrupted(sqlite3*);
** then the return value from sqlite3_complete16() will be non-zero
** regardless of whether or not the input SQL is complete.)^
**
** The input to [sqlite3_complete()] must be a zero-terminated
** UTF-8 string.
** The X input to [sqlite3_complete(X)] and [sqlite3_incomplete(X)]
** must be a zero-terminated UTF-8 string.
**
** The input to [sqlite3_complete16()] must be a zero-terminated
** UTF-16 string in native byte order.
*/
int sqlite3_complete(const char *sql);
int sqlite3_complete16(const void *sql);
sqlite3_int64 sqlite3_incomplete(const char *sql);
/*
** CAPI3REF: Register A Callback To Handle SQLITE_BUSY Errors
+4
View File
@@ -376,6 +376,8 @@ struct sqlite3_api_routines {
void (*str_free)(sqlite3_str*);
int (*carray_bind)(sqlite3_stmt*,int,void*,int,int,void(*)(void*));
int (*carray_bind_v2)(sqlite3_stmt*,int,void*,int,int,void(*)(void*),void*);
/* Version 3.54.0 and later */
sqlite3_int64 (*incomplete)(const char*);
};
/*
@@ -719,6 +721,8 @@ typedef int (*sqlite3_loadext_entry)(
#define sqlite3_str_free sqlite3_api->str_free
#define sqlite3_carray_bind sqlite3_api->carray_bind
#define sqlite3_carray_bind_v2 sqlite3_api->carray_bind_v2
/* Version 3.54.0 and later */
#define sqlite3_incomplete sqlite3_api->incomplete
#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
+7
View File
@@ -19,8 +19,15 @@
#include <stdarg.h>
#ifndef SQLITE_OMIT_FLOATING_POINT
#include <math.h>
/* Work around a bug in older Microsoft compilers
** Forum post 2026-04-10T06:33:11z */
#if !defined(INFINITY) && defined(_MSC_VER)
# define INFINITY HUGE_VAL
#endif
#endif /* SQLITE_OMIT_FLOATING_POINT */
/*
** Calls to sqlite3FaultSim() are used to simulate a failure during testing,
** or to bypass normal error detection during testing in order to let
+7 -8
View File
@@ -1900,7 +1900,6 @@ static void displayP4Expr(StrAccum *p, Expr *pExpr){
#if VDBE_DISPLAY_P4
/*
** Compute a string that describes the P4 parameter for an opcode.
** Use zTemp for any required temporary buffer space.
*/
char *sqlite3VdbeDisplayP4(sqlite3 *db, Op *pOp){
char *zP4 = 0;
@@ -5450,12 +5449,12 @@ static int vdbeIsMatchingIndexKey(
){
u8 *aRec = 0;
u32 nRec = 0;
Mem mem;
Mem m;
int rc = SQLITE_OK;
memset(&mem, 0, sizeof(mem));
mem.enc = p->pKeyInfo->enc;
mem.db = p->pKeyInfo->db;
memset(&m, 0, sizeof(m));
m.enc = p->pKeyInfo->enc;
m.db = p->pKeyInfo->db;
nRec = sqlite3BtreePayloadSize(pCur);
if( nRec>0x7fffffff ){
return SQLITE_CORRUPT_BKPT;
@@ -5497,9 +5496,9 @@ static int vdbeIsMatchingIndexKey(
if( (idxRec+nSerial)>nRec ){
rc = SQLITE_CORRUPT_BKPT;
}else{
sqlite3VdbeSerialGet(&aRec[idxRec], iSerial, &mem);
if( vdbeSkipField(mask, ii, &p->aMem[ii], &mem, bInt)==0 ){
res = sqlite3MemCompare(&mem, &p->aMem[ii], p->pKeyInfo->aColl[ii]);
sqlite3VdbeSerialGet(&aRec[idxRec], iSerial, &m);
if( vdbeSkipField(mask, ii, &p->aMem[ii], &m, bInt)==0 ){
res = sqlite3MemCompare(&m, &p->aMem[ii], p->pKeyInfo->aColl[ii]);
if( res!=0 ) break;
}
}
+1 -1
View File
@@ -163,7 +163,7 @@ int sqlite3WhereBreakLabel(WhereInfo *pWInfo){
** If the ONEPASS optimization is used (if this routine returns true)
** then also write the indices of open cursors used by ONEPASS
** into aiCur[0] and aiCur[1]. iaCur[0] gets the cursor of the data
** table and iaCur[1] gets the cursor used by an auxiliary index.
** table and aiCur[1] gets the cursor used by an auxiliary index.
** Either value may be -1, indicating that cursor is not used.
** Any cursors returned will have been opened for writing.
**
+140
View File
@@ -0,0 +1,140 @@
#!sqlite3
#
# 2026-04-11
#
# The author disclaims copyright to this source code. In place of
# a legal notice, here is a blessing:
#
# May you do good and not evil.
# May you find forgiveness for yourself and forgive others.
# May you share freely, never taking more than you give.
#
#***********************************************************************
#
# Tests for the .prompt command and prompt rendering.
#
# ./sqlite3 test/shell-prompt.sql
#
.testcase setup
.open -new test.db
.mode list -quote off -escape ascii
.prompt --hard-reset
.check ''
.testcase 100
.prompt
.check ''
.testcase 110
.prompt --show
.check <<END
Main prompt: 'SQLite /f> '
Continuation: '/B.../H> '
END
.testcase 111
.prompt 'abc> ' '123> ' -show
.check <<END
Main prompt: 'abc> '
Continuation: '123> '
END
.testcase 112
.prompt -- --first --second
.prompt --show
.check <<END
Main prompt: '--first'
Continuation: '--second'
END
.testcase 113
.prompt --reset --show
.check <<END
Main prompt: 'SQLite /f> '
Continuation: '/B.../H> '
END
.testcase 120 --error-prefix ERROR:
.prompt show
.check <<END
ERROR: .prompt show
ERROR: ^--- use quotes around the prompt string
END
.testcase 121
.prompt 'show'
.check ''
.testcase 122
.prompt --show
.check <<END
Main prompt: 'show'
Continuation: '/B.../H> '
END
.testcase 130
.prompt --reset
.help prompt
.check <<END
.prompt MAIN CONTINUE Replace the standard prompts
--hard-reset Unset SQLITE_PS1/2 and then --reset
--reset Revert to default prompts
--show Show the current prompt strings
-- No more options. Subsequent args are prompts
END
.testcase 140 --error-prefix ERROR:
.prompt --xyz
.check <<END
ERROR: .prompt --xyz
ERROR: ^--- unknown option
END
.testcase 1000
SELECT shell_prompt_test(NULL);
.check 'SQLite test.db> ';
.testcase 1001
SELECT shell_prompt_test(NULL,'SELECT');
.check ' ...;> ';
.testcase 1002
SELECT shell_prompt_test(NULL,'SELECT ((("');
.check ' ...")));> ';
.testcase 1003
SELECT shell_prompt_test(NULL,'SELECT ((()[');
.check ' ...]));> ';
.testcase 1004
SELECT shell_prompt_test(NULL,'SELECT ''');
.check " ...';> ";
.testcase 1005
SELECT shell_prompt_test(NULL,'CREATE TRIGGER t1 BEGIN');
.check " ...;END;> ";
.testcase 1006
SELECT shell_prompt_test(NULL,'CREATE TRIGGER t1 BEGIN SELECT ((([');
.check " ...])));END;> ";
.testcase 1007
SELECT shell_prompt_test(NULL,'CREATE TRIGGER t1 BEGIN SELECT ((/*a(((''bc');
.check " ...*/));END;> ";
.testcase 1008
SELECT shell_prompt_test(NULL,'CREATE TRIGGER t1 BEGIN SELECT 1;');
.check " ...END;> ";
.testcase 2000
.prompt 'SQLite/x-txn$/:>/; '
SELECT shell_prompt_test(NULL);
.check 'SQLite> ';
.testcase 2001
BEGIN;
SELECT shell_prompt_test(NULL);
.check 'SQLite-txn$ ';
.testcase 2002
ROLLBACK;
SELECT shell_prompt_test(NULL);
.check 'SQLite> ';
.testcase 2003
.prompt -- '--show '
SELECT shell_prompt_test(NULL);
.check '--show ';
.testcase 2004
.prompt --reset
SELECT shell_prompt_test(NULL);
.check 'SQLite test.db> ';
.testcase
+2 -1
View File
@@ -548,7 +548,8 @@ do_test shell1-3.17.3 {
do_test shell1-3.17.4 {
# too many arguments
catchcmd "test.db" ".prompt FOO BAR BAD"
} {0 {}}
} {1 {line 1: .prompt FOO BAR BAD
line 1: ^--- extra argument}}
# .quit Exit this program
do_test shell1-3.18.1 {
+3
View File
@@ -49,5 +49,8 @@ ifcapable vtab {
do_clitest intck01.sql
}
do_clitest fptest01.sql
unset -nocomplain ::env(SQLITE_PS1)
unset -nocomplain ::env(SQLITE_PS2)
do_clitest shell-prompt.sql
finish_test
+38 -4
View File
@@ -97,15 +97,16 @@ proc usage {} {
Usage:
$a0 ?SWITCHES? ?PERMUTATION? ?PATTERNS?
$a0 PERMUTATION FILE
$a0 clean
$a0 errors ?-v|--verbose? ?-s|--summary? ?PATTERN?
$a0 estwork
$a0 halt
$a0 help
$a0 joblist ?PATTERN?
$a0 njob ?NJOB?
$a0 retest
$a0 script ?-msvc? CONFIG
$a0 status ?-d SECS? ?--cls?
$a0 halt
$a0 estwork
where SWITCHES are:
--buildonly Build test exes but do not run tests
@@ -161,6 +162,12 @@ of the tests. Use the "-d N" option to have the status display clear the
screen and repeat every N seconds. The "njob" command may be used to query
or modify the number of sub-processes the test script uses to run tests.
The "halt" command modifies the database so that all tasks are marked
as complete. Testing will halt when all tests currently running complete.
The "clean" command removes files and directories created by a prior
invocation of testrunner.tcl.
The "script" command outputs the script used to build a configuration.
Add the "-msvc" option for a Windows-compatible script. For a list of
available configurations enter "$a0 script help".
@@ -460,6 +467,32 @@ if {([llength $argv]==2 || [llength $argv]==1)
}
#--------------------------------------------------------------------------
#--------------------------------------------------------------------------
# Check if this is the "clean" command:
#
if {([llength $argv]==2 || [llength $argv]==1)
&& [string compare -nocase clean [lindex $argv 0]]==0
} {
set pattern {_(fuzzcheck|sessionfuzz|sqlite3|testfixture)}
foreach f [glob testrun_*] {
if {[file isdir $f] && [regexp $pattern $f]} {
file delete -force $f
}
}
foreach f [glob testdir*] {
if {[file isdir $f] && [regexp {^testdir[0-9]+$} $f]} {
file delete -force $f
}
}
foreach f [glob testrunner.db*] {
file delete -force $f
}
file delete -force testrunner.log
exit
}
#--------------------------------------------------------------------------
#--------------------------------------------------------------------------
# Check if this is the "halt" command:
#
@@ -1177,7 +1210,7 @@ proc job_matches_any_pattern {patternlist jobcmd} {
#
# e.g
#
# {1 /home/user/sqlite/test/testrunner_bld_xyz All-Debug}
# {1 /home/user/sqlite/test/testrun_xyz All-Debug}
#
proc add_tcl_jobs {build config patternlist {shelldepid ""}} {
global TRG
@@ -1243,7 +1276,8 @@ proc add_build_job {buildname target {postcmd ""} {depid ""}} {
global TRG
set dirname "[string tolower [string map {- _} $buildname]]_$target"
set dirname "testrunner_bld_$dirname"
regsub {\.exe$} $dirname {} dirname
set dirname "testrun_$dirname"
set cmd "$TRG(makecmd) $target"
if {$postcmd!=""} {
+1 -1
View File
@@ -481,7 +481,7 @@ proc make_sh_script {srcdir opts cflags makeOpts configOpts} {
set myopts ""
if {[info exists ::env(OPTS)]} {
append myopts "# From environment variable:\n"
append myopts "OPTS=$::env(OPTS)\n\n"
append myopts "OPTS=\"$::env(OPTS)\"\n\n"
}
foreach o [lsort $opts] {
append myopts "OPTS=\"\$OPTS $o\"\n"