Compare commits

..

34 Commits

Author SHA1 Message Date
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
dan 535b1f2875 Fix some buffer overreads that might occur in the session module when handling corrupt changesets.
FossilOrigin-Name: 8fcf92e15d87487703afc1129f3a89a8d4d72cb30d30a1a9151a5596473069bd
2026-04-09 05:33:19 +00:00
drh a7200804eb Fix a buffer overflow bug in a recent check-in, reported by unsolicted
email from OpenAI/Codex.

FossilOrigin-Name: be891a137af15897691250324e4d3d9c96f0c5fb414bca27d0c3bfdd3012a8a2
2026-04-08 17:00:33 +00:00
stephan 0d979c217f Fix a few doc typos and inconsistencies. No code changes.
FossilOrigin-Name: 025abd4cf409fb9938e116289f23dc5bcd6d14feb46066221e691b146ee9b354
2026-04-07 15:54:35 +00:00
drh e9af8caac0 Fix incorrect datatype on the auto_ext_leak_tester() function in the CLI.
FossilOrigin-Name: 4a36454904e1c5e7d25406713ab0125f11df66eabe0d378edcb837ef8dedc981
2026-04-07 12:51:52 +00:00
drh 606c64a543 Fix redundant typedef in qrf.c when that file is amalgamated into
tclsqlite3.c.

FossilOrigin-Name: b8f0c71b48953cb6d5a8b3d33d004a31b63c59d59d455f285bf8fa91c3b07129
2026-04-07 11:31:41 +00:00
stephan eefe3aa9ad Replace a doc reference to a renamed file, as reported by [forum:5d9d70c618|forum post 5d9d70c618]. No code changes.
FossilOrigin-Name: c8121593fa455cd43b3878f8b65ebac47c07dab4b8ce081aa34b14fc9440afbc
2026-04-07 09:15:21 +00:00
stephan fcef193a82 Add a dummy auto-extension to the shell in SQLITE_DEBUG builds to validate that [9d56df17b4ab49] does the right thing.
FossilOrigin-Name: 164af3703b8fb5d88612edcceeaae0ae5a230c34c7a0f2ac9b650f5a742b2787
2026-04-06 22:00:20 +00:00
stephan 8e7ffc09f5 Add a call to sqlite3_reset_auto_extension() near the end of shell.c.in:main() to squelch a leak message when SQLITE_EXTRA_INIT adds auto-extensions, as reported in [forum:310cb231b07c80d1|forum post 310cb231b07c80d1].
FossilOrigin-Name: c4dd7e8b36deced3ee9cc6b5f87d8b3cc9a752cad8d62c9b711c7b58db11834b
2026-04-06 20:24:02 +00:00
drh 9ad63c0f4e Appease static analyzers by masking the index to the
WalHashLoc.aPgno array to make it easy to prove that there
is never OOB read or write.

FossilOrigin-Name: 9d56df17b4ab4940f7bc24488a9df118f6172fcfbf3e5cb95bdcbd2db2a07911
2026-04-04 14:43:37 +00:00
stephan d4b74b9fac Add some comments to the OPFS async proxy about potential future experimentation. No code changes.
FossilOrigin-Name: 9c14ee74305a5db3be95dbd9ae8d1db0abf39b323001be4e2f02b7226e6ca0d3
2026-04-04 08:07:25 +00:00
drh 7ff8b558e8 Enhance testrunner.tcl so that a PATTERN argument that begins with "~" is
an "anti-pattern".  Only run tests that match one or more patterns if there
are any patterns *and* do not match any anti-pattern.

FossilOrigin-Name: c313d91bb67b56be2db46194c3baa5a72b469595de3b2abe249612838dc175e4
2026-04-03 19:48:01 +00:00
stephan bb6d2a5f07 configure script: replace two 'file normalize' calls with file-normalize (a tcl/jimsh compatibility issue) to fix --with-linenoise. Problem reported in [forum:ce688d13793bd78f|forum post ce688d13793bd78f].
FossilOrigin-Name: 2be1c5a3e47f1276b9f0a4771f2d5fb0bc1ccb907c855caa04d757b4145533f5
2026-04-03 13:54:48 +00:00
drh 217c590688 Fix Tcl9 compatibility issues in test_session.c.
FossilOrigin-Name: 1387b5819085146cafb0e8740410faaa48bfb5aefc78ff763aaa8e85744d48b3
2026-04-03 11:48:00 +00:00
drh fc19b2ca8a Minor patch to test/json/json-speed-check.sh. That script is not maintained,
but this fix at least gets it working for now.

FossilOrigin-Name: 9d92e371ca375776d251fe446f17a437823cc96e48a5c45f42cb0768d0a47f65
2026-04-02 16:21:47 +00:00
dan 62f3150204 Fix a potential 4-byte overread in the sessions module when processing a corrupt changeset.
FossilOrigin-Name: c1c7e024c34da8eb0258ce552f3f81921280ccf0f1fea59374f381c0c7b43b74
2026-04-01 17:43:22 +00:00
drh 34e139d3a3 Always use sqlite3_malloc64() in extensions, where possible.
FossilOrigin-Name: 6194f3b5314ef98b5d73060450de8e3497272494b47e6f96992453418894ded1
2026-04-01 16:56:48 +00:00
dan 6e6598c8ff Fix a problem in the sessions module allowing a NULL pointer to be passed to memcpy().
FossilOrigin-Name: 91ead3c62dd7b1db3fdfd318e3c35a42fb33e8fa2e347b682eecbff2f4e8677b
2026-04-01 16:11:47 +00:00
drh e230de2cbf Minor improvements to the documentation on how to compile for Unix.
No changes to code.

FossilOrigin-Name: 7bc1d0c4572f126cfe68fa51fe992d2bd46b1e57c04721991bd5fad36dd795c5
2026-04-01 11:54:20 +00:00
stephan eb8edc0bac Doc cleanups in opfs-wl. No code changes.
FossilOrigin-Name: 009b576dcd5fccaaa52459dbfaa1b2a6fcf6d372e4b8d63553dfa88aab9a759c
2026-04-01 11:39:13 +00:00
drh d6226a9c27 Add appropriate headers to ext/session/sqlite3session.h so that the
documentation generator will pick up the API documentation for the
new one-at-a-time changegroup APIs.

FossilOrigin-Name: da514f10b7804fd0affaf0fd4b8089012288ba99c165ef4ab78ab28edd331211
2026-03-31 18:49:23 +00:00
dan d9f047bd15 Add an API to the sessions module to add changes one at a time to an sqlite3_changegroup object.
FossilOrigin-Name: cf1122ea6409bcbd341b67ae45147abb8d5cd491ae95491c801d0621181da40b
2026-03-31 10:59:13 +00:00
dan 5e4fb95edf Update this branch with changes from trunk.
FossilOrigin-Name: 716e62e3d1d6ff96f6e4906175818439103e9534e89bec4a86776265a04954b9
2026-03-31 10:52:00 +00:00
drh 60b829e0db Turn an incorrect assert() into a testcase(). Fix over-length code lines
in the sqlite.h.in source file.  Fix the documentation on OOM conditions
in the sqlite3_value_text() family of APIs.

FossilOrigin-Name: 934582706109d2ebda26952c7c95f7a5095fa47ec837570a66c991866f7d08cf
2026-03-31 10:32:23 +00:00
stephan f92d107242 Move some build docs around for clarity. Move the TARGET_DEBUG flags from the end of T.cc to the beginning so that -Ox flags can be passed to make for specific binaries without having to reconfigure.
FossilOrigin-Name: 240294653ceb202b847699e9691140db4fe623a03d86fa3cf7495f8831576331
2026-03-30 15:44:20 +00:00
drh b060cecb2e Remove an unused variable in sqlite3Reindex(). Minor enhancements to the
header comment on sqlite3AtoF().

FossilOrigin-Name: fbba900728d444f6a0b428197ebb41fe039b235e18caa2243c9f8f04fce42595
2026-03-30 10:00:48 +00:00
drh 9660a4dec0 Enhance the printf() formatter to write floating point conversions directly
into the output buffer, rather than staging into an intermediate buffer.

FossilOrigin-Name: ccb6b6c4ac21742dbfc435cf3a2a0dc887075b3e0877aea7ed8eace08b7b5571
2026-03-29 23:37:16 +00:00
dan c1975b6a6f Improve some of the documentation comments for the new code on this branch.
FossilOrigin-Name: f352485db45a1280f91ec76f661b6dd50bb1d564b74bdff474c92e928860a47d
2026-01-14 17:02:22 +00:00
dan de88171c4c Merge latest trunk changes into this branch.
FossilOrigin-Name: fae9f376b74ae688dbdb5c0838a38427258d3d14c29c5346a3549e56db79961a
2026-01-14 16:01:28 +00:00
dan 613cf76c2f Add tests for edge cases in the new code on this branch.
FossilOrigin-Name: cd115f0f4437bf254058e40d70ba4e82e87227d2752695aa18f8431c3abc5c0b
2026-01-14 15:27:26 +00:00
dan c289cf57a7 Allow the APIs on this branch to be used to create patchsets as well as changesets.
FossilOrigin-Name: 8699fe5b24c8aeb5e552aa7f4995f2b50dd33d1febd23ec1c07c8fc72497da72
2026-01-13 19:59:47 +00:00
dan 817c509365 Add an API to the sessions module to add changes one at a time to an sqlite3_changegroup object.
FossilOrigin-Name: 27150a8c22dc5331efa9e97637eae3741682bc14ae993f0b7672ccc63c37f1f9
2026-01-12 16:39:27 +00:00
56 changed files with 1769 additions and 332 deletions
+11 -3
View File
@@ -131,9 +131,15 @@ libsqlite3.DLL.install-rules = @SQLITE_DLL_INSTALL_RULES@
CFLAGS.fuzzcheck-asan.fsanitize = @CFLAGS_ASAN_FSANITIZE@
#
# Intended to either be empty or be set to -g -DSQLITE_DEBUG=1.
# TARGET_DEBUG is intended to either be empty or be set to -g
# -DSQLITE_DEBUG=1, plus any other flags relevant for debug-only
# builds. These get added near the front of $(T.cc) so that they can
# be overridden by CFLAGS passed directly to make. Historically (prior
# to 2026-03-30) these were at/near the end of the flags but that made
# it impossible to pass custom -O* flags to specific binaries without
# reconfiguring.
#
T.cc.TARGET_DEBUG = @TARGET_DEBUG@
T.cc += @TARGET_DEBUG@
#
# $(JIMSH) and $(CFLAGS.jimsh) are documented in main.mk. $(JIMSH)
@@ -164,7 +170,9 @@ OPT_FEATURE_FLAGS = @OPT_FEATURE_FLAGS@ $(OPTIONS)
PACKAGE_VERSION = @PACKAGE_VERSION@
#
# Filename extensions for binaries and libraries
# Filename extensions for binaries and libraries. B.* are for the
# being-built-on platform and T.* are for the build's target platform.
# i.e. B.* is for build-time tooling and T.* is for deliverables.
#
B.exe = @BUILD_EXEEXT@
T.exe = @TARGET_EXEEXT@
+2
View File
@@ -97,6 +97,8 @@ the build products. It is recommended, but not required, that the
build directory be separate from the source directory. Cd into the
build directory and then from the build directory run the configure
script found at the root of the source tree. Then run "make".
See the [compile-for-unix.md](doc/compile-for-unix.md) document for
more detail.
For example:
+5 -6
View File
@@ -743,12 +743,11 @@ proc sqlite-setup-default-cflags {} {
# compiling binaries for the target system (CC a.k.a. $(T.cc)).
# Normally they're the same, but they will differ when
# cross-compiling.
#
# When cross-compiling we default to not using the -g flag, based on a
# /chat discussion prompted by
# https://sqlite.org/forum/forumpost/9a67df63eda9925c
set defaultCFlags {-O2}
if {!$::sqliteConfig(is-cross-compiling)} {
# When cross-compiling we default to not using the -g flag, based
# on a /chat discussion prompted by
# https://sqlite.org/forum/forumpost/9a67df63eda9925c
lappend defaultCFlags -g
}
define CFLAGS [proj-get-env CFLAGS $defaultCFlags]
@@ -1149,7 +1148,7 @@ proc sqlite-check-line-editing {} {
&& ![proj-opt-was-provided editline]
} {
set dirlist ../linenoise
catch {lappend dirlist [file normalize $::autosetup(srcdir)/../linenoise]}
catch {lappend dirlist [file-normalize $::autosetup(srcdir)/../linenoise]}
catch {lappend dirlist $::env(HOME)/linenoise}
foreach d $dirlist {
if {[file exists $d/linenoise.c] && [file exists $d/linenoise.h]} {
@@ -1195,7 +1194,7 @@ proc sqlite-check-line-editing {} {
define-append CFLAGS_JIMSH -DUSE_LINENOISE [get-define CFLAGS_READLINE]
user-notice "Adding linenoise support to jimsh."
} else {
msg-result "Using linenoise at [file normalize $dirLn]"
msg-result "Using linenoise at [file-normalize $dirLn]"
}
return "linenoise ($flavor)"
} elseif {[opt-bool editline]} {
+28 -9
View File
@@ -37,18 +37,35 @@ guidance on building for Windows.
4. Download the SQLite source tree and unpack it. CD into the
toplevel directory of the source tree.
5. Run: `./configure --enable-all --with-tclsh=$HOME/local/bin/tclsh9.0`
5. *(Optional):* Download Antirez's "linenoise" command-line editing
library to provide command-line editing in the CLI. You can find
a suitable copy of the linenoise sources at
<https://sqlite.org/linenoise.tar.gz> or at various other locations
on the internet. If you put the linenoise source tree in
a directory named $HOME/linenoise or a directory "linenoise" which
is a sibling of the SQLite source tree, then the SQLite ./configure
script will automatically find and use that source code to provide
command-line editing in the CLI. If you would rather use the readline
or editline libraries or a precompiled linenoise library, there are
./configure options to accommodate that choice. The SQLite developers
typically use $HOME/linenoise since linenoise is small, has no
external dependencies, "just works", and the ./configure script
will pick it up and use it automatically. But you do what works
best for you.
<p>
You are not required to have any command-line editing support in
order to use SQLite. But command-line editing does make the
interactive experience more enjoyable.
6. Run: `./configure --enable-all --with-tclsh=$HOME/local/bin/tclsh9.0`
You do not need to use --with-tclsh if the tclsh you want to use is the
first one on your PATH or if you are building without TCL.
The SQLite developers typically add the
&ensp; `--with-linenoise=$HOME/linenoise` &ensp; option
to provide command-line editing. "$HOME/linenoise" is a directory
that contains [linenoise](https://github.com/antirez/linenoise) source
code files, `linenoise.c` and `linenoise.h`.
Lots of other options to ./configure are available.
Run `./configure --help` for further guidance.
6. Run the "`Makefile`" makefile with an appropriate target.
7. Run the "`Makefile`" makefile with an appropriate target.
Examples:
<ul>
<li> `make sqlite3.c`
@@ -73,5 +90,7 @@ guidance on building for Windows.
of SQLite.
7. For a debugging build of the CLI, where the ".treetrace" and ".wheretrace"
commands work, add the the --with-debug argument to configure.
8. For a debugging build of the CLI, use `./configure --dev`. A debugging
build contains lots of extra debugging code, so it is slow and a lot
bigger. You probably do not want to deploy a debugging build. But if
you are working on the code, a debugging build works much better.
+2 -2
View File
@@ -847,7 +847,7 @@ static int amatchConnect(
(void)pAux;
*ppVtab = 0;
pNew = sqlite3_malloc( sizeof(*pNew) );
pNew = sqlite3_malloc64( sizeof(*pNew) );
if( pNew==0 ) return SQLITE_NOMEM;
rc = SQLITE_NOMEM;
memset(pNew, 0, sizeof(*pNew));
@@ -928,7 +928,7 @@ amatchConnectError:
static int amatchOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
amatch_vtab *p = (amatch_vtab*)pVTab;
amatch_cursor *pCur;
pCur = sqlite3_malloc( sizeof(*pCur) );
pCur = sqlite3_malloc64( sizeof(*pCur) );
if( pCur==0 ) return SQLITE_NOMEM;
memset(pCur, 0, sizeof(*pCur));
pCur->pVtab = p;
+2 -2
View File
@@ -232,7 +232,7 @@ static void base64(sqlite3_context *context, int na, sqlite3_value *av[]){
sqlite3_result_text(context,"",-1,SQLITE_STATIC);
break;
}
cBuf = sqlite3_malloc(nc);
cBuf = sqlite3_malloc64(nc);
if( !cBuf ) goto memFail;
nc = (int)(toBase64(bBuf, nb, cBuf) - cBuf);
sqlite3_result_text(context, cBuf, nc, sqlite3_free);
@@ -254,7 +254,7 @@ static void base64(sqlite3_context *context, int na, sqlite3_value *av[]){
sqlite3_result_zeroblob(context, 0);
break;
}
bBuf = sqlite3_malloc(nb);
bBuf = sqlite3_malloc64(nb);
if( !bBuf ) goto memFail;
nb = (int)(fromBase64(cBuf, nc, bBuf) - bBuf);
sqlite3_result_blob(context, bBuf, nb, sqlite3_free);
+2 -2
View File
@@ -309,7 +309,7 @@ static void base85(sqlite3_context *context, int na, sqlite3_value *av[]){
sqlite3_result_text(context,"",-1,SQLITE_STATIC);
break;
}
cBuf = sqlite3_malloc(nc);
cBuf = sqlite3_malloc64(nc);
if( !cBuf ) goto memFail;
nc = (int)(toBase85(bBuf, nb, cBuf, "\n") - cBuf);
sqlite3_result_text(context, cBuf, nc, sqlite3_free);
@@ -331,7 +331,7 @@ static void base85(sqlite3_context *context, int na, sqlite3_value *av[]){
sqlite3_result_zeroblob(context, 0);
break;
}
bBuf = sqlite3_malloc(nb);
bBuf = sqlite3_malloc64(nb);
if( !bBuf ) goto memFail;
nb = (int)(fromBase85(cBuf, nc, bBuf) - bBuf);
sqlite3_result_blob(context, bBuf, nb, sqlite3_free);
+3 -3
View File
@@ -516,7 +516,7 @@ static int closureConnect(
(void)pAux;
*ppVtab = 0;
pNew = sqlite3_malloc( sizeof(*pNew) );
pNew = sqlite3_malloc64( sizeof(*pNew) );
if( pNew==0 ) return SQLITE_NOMEM;
rc = SQLITE_NOMEM;
memset(pNew, 0, sizeof(*pNew));
@@ -579,7 +579,7 @@ closureConnectError:
static int closureOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
closure_vtab *p = (closure_vtab*)pVTab;
closure_cursor *pCur;
pCur = sqlite3_malloc( sizeof(*pCur) );
pCur = sqlite3_malloc64( sizeof(*pCur) );
if( pCur==0 ) return SQLITE_NOMEM;
memset(pCur, 0, sizeof(*pCur));
pCur->pVtab = p;
@@ -638,7 +638,7 @@ static int closureInsertNode(
sqlite3_int64 id, /* The node ID */
int iGeneration /* The generation number for this node */
){
closure_avl *pNew = sqlite3_malloc( sizeof(*pNew) );
closure_avl *pNew = sqlite3_malloc64( sizeof(*pNew) );
if( pNew==0 ) return SQLITE_NOMEM;
memset(pNew, 0, sizeof(*pNew));
pNew->id = id;
+2 -2
View File
@@ -132,7 +132,7 @@ static int completionConnect(
" phase INT HIDDEN" /* Used for debugging only */
")");
if( rc==SQLITE_OK ){
pNew = sqlite3_malloc( sizeof(*pNew) );
pNew = sqlite3_malloc64( sizeof(*pNew) );
*ppVtab = (sqlite3_vtab*)pNew;
if( pNew==0 ) return SQLITE_NOMEM;
memset(pNew, 0, sizeof(*pNew));
@@ -154,7 +154,7 @@ static int completionDisconnect(sqlite3_vtab *pVtab){
*/
static int completionOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
completion_cursor *pCur;
pCur = sqlite3_malloc( sizeof(*pCur) );
pCur = sqlite3_malloc64( sizeof(*pCur) );
if( pCur==0 ) return SQLITE_NOMEM;
memset(pCur, 0, sizeof(*pCur));
pCur->db = ((completion_vtab*)p)->db;
+2 -2
View File
@@ -129,7 +129,7 @@ static int csv_reader_open(
const char *zData /* ... or use this data */
){
if( zFilename ){
p->zIn = sqlite3_malloc( CSV_INBUFSZ );
p->zIn = sqlite3_malloc64( CSV_INBUFSZ );
if( p->zIn==0 ){
csv_errmsg(p, "out of memory");
return 1;
@@ -564,7 +564,7 @@ static int csvtabConnect(
){
goto csvtab_connect_error;
}
pNew = sqlite3_malloc( sizeof(*pNew) );
pNew = sqlite3_malloc64( sizeof(*pNew) );
*ppVtab = (sqlite3_vtab*)pNew;
if( pNew==0 ) goto csvtab_connect_oom;
memset(pNew, 0, sizeof(*pNew));
+2 -2
View File
@@ -74,7 +74,7 @@ static Decimal *decimalNewFromText(const char *zIn, int n){
int iExp = 0;
if( zIn==0 ) goto new_from_text_failed;
p = sqlite3_malloc( sizeof(*p) );
p = sqlite3_malloc64( sizeof(*p) );
if( p==0 ) goto new_from_text_failed;
p->sign = 0;
p->oom = 0;
@@ -814,7 +814,7 @@ static void decimalSumStep(
if( p==0 ) return;
if( !p->isInit ){
p->isInit = 1;
p->a = sqlite3_malloc(2);
p->a = sqlite3_malloc64(2);
if( p->a==0 ){
p->oom = 1;
}else{
+2 -2
View File
@@ -92,7 +92,7 @@ static int explainConnect(
rc = sqlite3_declare_vtab(db,
"CREATE TABLE x(addr,opcode,p1,p2,p3,p4,p5,comment,sql HIDDEN)");
if( rc==SQLITE_OK ){
pNew = sqlite3_malloc( sizeof(*pNew) );
pNew = sqlite3_malloc64( sizeof(*pNew) );
*ppVtab = (sqlite3_vtab*)pNew;
if( pNew==0 ) return SQLITE_NOMEM;
memset(pNew, 0, sizeof(*pNew));
@@ -114,7 +114,7 @@ static int explainDisconnect(sqlite3_vtab *pVtab){
*/
static int explainOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
explain_cursor *pCur;
pCur = sqlite3_malloc( sizeof(*pCur) );
pCur = sqlite3_malloc64( sizeof(*pCur) );
if( pCur==0 ) return SQLITE_NOMEM;
memset(pCur, 0, sizeof(*pCur));
pCur->db = ((explain_vtab*)p)->db;
+2 -2
View File
@@ -613,7 +613,7 @@ static int fsdirConnect(
(void)pzErr;
rc = sqlite3_declare_vtab(db, "CREATE TABLE x" FSDIR_SCHEMA);
if( rc==SQLITE_OK ){
pNew = (fsdir_tab*)sqlite3_malloc( sizeof(*pNew) );
pNew = (fsdir_tab*)sqlite3_malloc64( sizeof(*pNew) );
if( pNew==0 ) return SQLITE_NOMEM;
memset(pNew, 0, sizeof(*pNew));
sqlite3_vtab_config(db, SQLITE_VTAB_DIRECTONLY);
@@ -636,7 +636,7 @@ static int fsdirDisconnect(sqlite3_vtab *pVtab){
static int fsdirOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
fsdir_cursor *pCur;
(void)p;
pCur = sqlite3_malloc( sizeof(*pCur) );
pCur = sqlite3_malloc64( sizeof(*pCur) );
if( pCur==0 ) return SQLITE_NOMEM;
memset(pCur, 0, sizeof(*pCur));
pCur->iLvl = -1;
+1 -1
View File
@@ -843,7 +843,7 @@ static int deltaparsevtabDisconnect(sqlite3_vtab *pVtab){
*/
static int deltaparsevtabOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
deltaparsevtab_cursor *pCur;
pCur = sqlite3_malloc( sizeof(*pCur) );
pCur = sqlite3_malloc64( sizeof(*pCur) );
if( pCur==0 ) return SQLITE_NOMEM;
memset(pCur, 0, sizeof(*pCur));
*ppCursor = &pCur->base;
+2 -2
View File
@@ -556,7 +556,7 @@ static int fuzzerConnect(
static int fuzzerOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
fuzzer_vtab *p = (fuzzer_vtab*)pVTab;
fuzzer_cursor *pCur;
pCur = sqlite3_malloc( sizeof(*pCur) );
pCur = sqlite3_malloc64( sizeof(*pCur) );
if( pCur==0 ) return SQLITE_NOMEM;
memset(pCur, 0, sizeof(*pCur));
pCur->pVtab = p;
@@ -622,7 +622,7 @@ static int fuzzerRender(
n = pStem->nBasis + pRule->nTo - pRule->nFrom;
if( (*pnBuf)<n+1 ){
(*pzBuf) = sqlite3_realloc((*pzBuf), n+100);
(*pzBuf) = sqlite3_realloc64((*pzBuf), n+100);
if( (*pzBuf)==0 ) return SQLITE_NOMEM;
(*pnBuf) = n+100;
}
+2 -2
View File
@@ -85,7 +85,7 @@ static int memstatConnect(
rc = sqlite3_declare_vtab(db,"CREATE TABLE x(name,schema,value,hiwtr)");
if( rc==SQLITE_OK ){
pNew = sqlite3_malloc( sizeof(*pNew) );
pNew = sqlite3_malloc64( sizeof(*pNew) );
*ppVtab = (sqlite3_vtab*)pNew;
if( pNew==0 ) return SQLITE_NOMEM;
memset(pNew, 0, sizeof(*pNew));
@@ -107,7 +107,7 @@ static int memstatDisconnect(sqlite3_vtab *pVtab){
*/
static int memstatOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
memstat_cursor *pCur;
pCur = sqlite3_malloc( sizeof(*pCur) );
pCur = sqlite3_malloc64( sizeof(*pCur) );
if( pCur==0 ) return SQLITE_NOMEM;
memset(pCur, 0, sizeof(*pCur));
pCur->db = ((memstat_vtab*)p)->db;
+2 -2
View File
@@ -75,7 +75,7 @@ static int prefixesConnect(
"CREATE TABLE prefixes(prefix TEXT, original_string TEXT HIDDEN)"
);
if( rc==SQLITE_OK ){
pNew = sqlite3_malloc( sizeof(*pNew) );
pNew = sqlite3_malloc64( sizeof(*pNew) );
*ppVtab = (sqlite3_vtab*)pNew;
if( pNew==0 ) return SQLITE_NOMEM;
memset(pNew, 0, sizeof(*pNew));
@@ -98,7 +98,7 @@ static int prefixesDisconnect(sqlite3_vtab *pVtab){
*/
static int prefixesOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
prefixes_cursor *pCur;
pCur = sqlite3_malloc( sizeof(*pCur) );
pCur = sqlite3_malloc64( sizeof(*pCur) );
if( pCur==0 ) return SQLITE_NOMEM;
memset(pCur, 0, sizeof(*pCur));
*ppCursor = &pCur->base;
+2 -2
View File
@@ -152,7 +152,7 @@ static int qpvtabConnect(
#define QPVTAB_FLAGS 11
#define QPVTAB_NONE 12
if( rc==SQLITE_OK ){
pNew = sqlite3_malloc( sizeof(*pNew) );
pNew = sqlite3_malloc64( sizeof(*pNew) );
*ppVtab = (sqlite3_vtab*)pNew;
if( pNew==0 ) return SQLITE_NOMEM;
memset(pNew, 0, sizeof(*pNew));
@@ -174,7 +174,7 @@ static int qpvtabDisconnect(sqlite3_vtab *pVtab){
*/
static int qpvtabOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
qpvtab_cursor *pCur;
pCur = sqlite3_malloc( sizeof(*pCur) );
pCur = sqlite3_malloc64( sizeof(*pCur) );
if( pCur==0 ) return SQLITE_NOMEM;
memset(pCur, 0, sizeof(*pCur));
*ppCursor = &pCur->base;
+1 -1
View File
@@ -676,7 +676,7 @@ static const char *re_compile(
int i, j;
*ppRe = 0;
pRe = sqlite3_malloc( sizeof(*pRe) );
pRe = sqlite3_malloc64( sizeof(*pRe) );
if( pRe==0 ){
return "out of memory";
}
+1 -1
View File
@@ -92,7 +92,7 @@ static void scrubBackupErr(ScrubState *p, const char *zFormat, ...){
static u8 *scrubBackupAllocPage(ScrubState *p){
u8 *pPage;
if( p->rcErr ) return 0;
pPage = sqlite3_malloc( p->szPage );
pPage = sqlite3_malloc64( p->szPage );
if( pPage==0 ) p->rcErr = SQLITE_NOMEM;
return pPage;
}
+2 -2
View File
@@ -239,7 +239,7 @@ static int seriesConnect(
rc = sqlite3_declare_vtab(db,
"CREATE TABLE x(value,start hidden,stop hidden,step hidden)");
if( rc==SQLITE_OK ){
pNew = *ppVtab = sqlite3_malloc( sizeof(*pNew) );
pNew = *ppVtab = sqlite3_malloc64( sizeof(*pNew) );
if( pNew==0 ) return SQLITE_NOMEM;
memset(pNew, 0, sizeof(*pNew));
sqlite3_vtab_config(db, SQLITE_VTAB_INNOCUOUS);
@@ -261,7 +261,7 @@ static int seriesDisconnect(sqlite3_vtab *pVtab){
static int seriesOpen(sqlite3_vtab *pUnused, sqlite3_vtab_cursor **ppCursor){
series_cursor *pCur;
(void)pUnused;
pCur = sqlite3_malloc( sizeof(*pCur) );
pCur = sqlite3_malloc64( sizeof(*pCur) );
if( pCur==0 ) return SQLITE_NOMEM;
memset(pCur, 0, sizeof(*pCur));
*ppCursor = &pCur->base;
+2 -2
View File
@@ -46,7 +46,7 @@ static void sqlarCompressFunc(
uLongf nOut = compressBound(nData);
Bytef *pOut;
pOut = (Bytef*)sqlite3_malloc(nOut);
pOut = (Bytef*)sqlite3_malloc64(nOut);
if( pOut==0 ){
sqlite3_result_error_nomem(context);
return;
@@ -91,7 +91,7 @@ static void sqlarUncompressFunc(
}else{
uLongf szf = sz;
const Bytef *pData= sqlite3_value_blob(argv[0]);
Bytef *pOut = sqlite3_malloc(sz);
Bytef *pOut = sqlite3_malloc64(sz);
if( pOut==0 ){
sqlite3_result_error_nomem(context);
}else if( Z_OK!=uncompress(pOut, &szf, pData, nData) ){
+6 -6
View File
@@ -101,8 +101,8 @@ FILE *sqlite3_fopen(const char *zFilename, const char *zMode){
sz1 = (int)strlen(zFilename);
sz2 = (int)strlen(zMode);
b1 = sqlite3_malloc( (sz1+1)*sizeof(b1[0]) );
b2 = sqlite3_malloc( (sz2+1)*sizeof(b1[0]) );
b1 = sqlite3_malloc64( (sz1+1)*sizeof(b1[0]) );
b2 = sqlite3_malloc64( (sz2+1)*sizeof(b1[0]) );
if( b1 && b2 ){
sz1 = MultiByteToWideChar(CP_UTF8, 0, zFilename, sz1, b1, sz1);
b1[sz1] = 0;
@@ -127,8 +127,8 @@ FILE *sqlite3_popen(const char *zCommand, const char *zMode){
sz1 = (int)strlen(zCommand);
sz2 = (int)strlen(zMode);
b1 = sqlite3_malloc( (sz1+1)*sizeof(b1[0]) );
b2 = sqlite3_malloc( (sz2+1)*sizeof(b1[0]) );
b1 = sqlite3_malloc64( (sz1+1)*sizeof(b1[0]) );
b2 = sqlite3_malloc64( (sz2+1)*sizeof(b1[0]) );
if( b1 && b2 ){
sz1 = MultiByteToWideChar(CP_UTF8, 0, zCommand, sz1, b1, sz1);
b1[sz1] = 0;
@@ -151,7 +151,7 @@ char *sqlite3_fgets(char *buf, int sz, FILE *in){
** that into UTF-8. Otherwise, non-ASCII characters all get translated
** into '?'.
*/
wchar_t *b1 = sqlite3_malloc( sz*sizeof(wchar_t) );
wchar_t *b1 = sqlite3_malloc64( sz*sizeof(wchar_t) );
if( b1==0 ) return 0;
#ifdef SQLITE_USE_W32_FOR_CONSOLE_IO
DWORD nRead = 0;
@@ -226,7 +226,7 @@ int sqlite3_fputs(const char *z, FILE *out){
** to the console on Windows.
*/
int sz = (int)strlen(z);
wchar_t *b1 = sqlite3_malloc( (sz+1)*sizeof(wchar_t) );
wchar_t *b1 = sqlite3_malloc64( (sz+1)*sizeof(wchar_t) );
if( b1==0 ) return 0;
sz = MultiByteToWideChar(CP_UTF8, 0, z, sz, b1, sz);
b1[sz] = 0;
+1 -1
View File
@@ -52,7 +52,7 @@ static void stmtrandFunc(
p = (Stmtrand*)sqlite3_get_auxdata(context, STMTRAND_KEY);
if( p==0 ){
unsigned int seed;
p = sqlite3_malloc( sizeof(*p) );
p = sqlite3_malloc64( sizeof(*p) );
if( p==0 ){
sqlite3_result_error_nomem(context);
return;
+2 -2
View File
@@ -101,7 +101,7 @@ static int templatevtabConnect(
#define TEMPLATEVTAB_A 0
#define TEMPLATEVTAB_B 1
if( rc==SQLITE_OK ){
pNew = sqlite3_malloc( sizeof(*pNew) );
pNew = sqlite3_malloc64( sizeof(*pNew) );
*ppVtab = (sqlite3_vtab*)pNew;
if( pNew==0 ) return SQLITE_NOMEM;
memset(pNew, 0, sizeof(*pNew));
@@ -123,7 +123,7 @@ static int templatevtabDisconnect(sqlite3_vtab *pVtab){
*/
static int templatevtabOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
templatevtab_cursor *pCur;
pCur = sqlite3_malloc( sizeof(*pCur) );
pCur = sqlite3_malloc64( sizeof(*pCur) );
if( pCur==0 ) return SQLITE_NOMEM;
memset(pCur, 0, sizeof(*pCur));
*ppCursor = &pCur->base;
+2 -2
View File
@@ -613,7 +613,7 @@ static int vstattabConnect(
rc = sqlite3_declare_vtab(db,"CREATE TABLE x(file,stat,count)");
if( rc==SQLITE_OK ){
pNew = *ppVtab = sqlite3_malloc( sizeof(*pNew) );
pNew = *ppVtab = sqlite3_malloc64( sizeof(*pNew) );
if( pNew==0 ) return SQLITE_NOMEM;
memset(pNew, 0, sizeof(*pNew));
}
@@ -633,7 +633,7 @@ static int vstattabDisconnect(sqlite3_vtab *pVtab){
*/
static int vstattabOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
VfsStatCursor *pCur;
pCur = sqlite3_malloc( sizeof(*pCur) );
pCur = sqlite3_malloc64( sizeof(*pCur) );
if( pCur==0 ) return SQLITE_NOMEM;
memset(pCur, 0, sizeof(*pCur));
*ppCursor = &pCur->base;
+1 -1
View File
@@ -892,7 +892,7 @@ static int vfstraceOpen(
vfstrace_printf(pInfo, "%s.xOpen(%s,flags=0x%x)",
pInfo->zVfsName, p->zFName, flags);
if( p->pReal->pMethods ){
sqlite3_io_methods *pNew = sqlite3_malloc( sizeof(*pNew) );
sqlite3_io_methods *pNew = sqlite3_malloc64( sizeof(*pNew) );
const sqlite3_io_methods *pSub = p->pReal->pMethods;
memset(pNew, 0, sizeof(*pNew));
pNew->iVersion = pSub->iVersion;
+2 -2
View File
@@ -240,7 +240,7 @@ static int vtablogConnectCreate(
printf(" schema = '%s'\n", zSchema);
rc = sqlite3_declare_vtab(db, zSchema);
if( rc==SQLITE_OK ){
pNew = sqlite3_malloc( sizeof(*pNew) );
pNew = sqlite3_malloc64( sizeof(*pNew) );
*ppVtab = (sqlite3_vtab*)pNew;
if( pNew==0 ) return SQLITE_NOMEM;
memset(pNew, 0, sizeof(*pNew));
@@ -313,7 +313,7 @@ static int vtablogOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
vtablog_cursor *pCur;
printf("%s.%s.xOpen(cursor=%d)\n", pTab->zDb, pTab->zName,
++pTab->nCursor);
pCur = sqlite3_malloc( sizeof(*pCur) );
pCur = sqlite3_malloc64( sizeof(*pCur) );
if( pCur==0 ) return SQLITE_NOMEM;
memset(pCur, 0, sizeof(*pCur));
pCur->iCursor = pTab->nCursor;
+5 -5
View File
@@ -86,7 +86,7 @@ static int vtshimCreate(
}
return SQLITE_ERROR;
}
pNew = sqlite3_malloc( sizeof(*pNew) );
pNew = sqlite3_malloc64( sizeof(*pNew) );
*ppVtab = (sqlite3_vtab*)pNew;
if( pNew==0 ) return SQLITE_NOMEM;
memset(pNew, 0, sizeof(*pNew));
@@ -125,7 +125,7 @@ static int vtshimConnect(
}
return SQLITE_ERROR;
}
pNew = sqlite3_malloc( sizeof(*pNew) );
pNew = sqlite3_malloc64( sizeof(*pNew) );
*ppVtab = (sqlite3_vtab*)pNew;
if( pNew==0 ) return SQLITE_NOMEM;
memset(pNew, 0, sizeof(*pNew));
@@ -192,7 +192,7 @@ static int vtshimOpen(sqlite3_vtab *pBase, sqlite3_vtab_cursor **ppCursor){
int rc;
*ppCursor = 0;
if( pAux->bDisposed ) return SQLITE_ERROR;
pCur = sqlite3_malloc( sizeof(*pCur) );
pCur = sqlite3_malloc64( sizeof(*pCur) );
if( pCur==0 ) return SQLITE_NOMEM;
memset(pCur, 0, sizeof(*pCur));
rc = pAux->pMod->xOpen(pVtab->pChild, &pCur->pChild);
@@ -444,7 +444,7 @@ static int vtshimCopyModule(
){
sqlite3_module *p;
if( !pMod || !ppMod ) return SQLITE_ERROR;
p = sqlite3_malloc( sizeof(*p) );
p = sqlite3_malloc64( sizeof(*p) );
if( p==0 ) return SQLITE_NOMEM;
memcpy(p, pMod, sizeof(*p));
*ppMod = p;
@@ -464,7 +464,7 @@ void *sqlite3_create_disposable_module(
vtshim_aux *pAux;
sqlite3_module *pMod;
int rc;
pAux = sqlite3_malloc( sizeof(*pAux) );
pAux = sqlite3_malloc64( sizeof(*pAux) );
if( pAux==0 ){
if( xDestroy ) xDestroy(pClientData);
return 0;
+2 -2
View File
@@ -47,7 +47,7 @@ static int wholenumberConnect(
char **pzErr
){
sqlite3_vtab *pNew;
pNew = *ppVtab = sqlite3_malloc( sizeof(*pNew) );
pNew = *ppVtab = sqlite3_malloc64( sizeof(*pNew) );
if( pNew==0 ) return SQLITE_NOMEM;
sqlite3_declare_vtab(db, "CREATE TABLE x(value)");
sqlite3_vtab_config(db, SQLITE_VTAB_INNOCUOUS);
@@ -69,7 +69,7 @@ static int wholenumberDisconnect(sqlite3_vtab *pVtab){
*/
static int wholenumberOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
wholenumber_cursor *pCur;
pCur = sqlite3_malloc( sizeof(*pCur) );
pCur = sqlite3_malloc64( sizeof(*pCur) );
if( pCur==0 ) return SQLITE_NOMEM;
memset(pCur, 0, sizeof(*pCur));
*ppCursor = &pCur->base;
+3 -3
View File
@@ -456,7 +456,7 @@ static int zipfileDisconnect(sqlite3_vtab *pVtab){
static int zipfileOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCsr){
ZipfileTab *pTab = (ZipfileTab*)p;
ZipfileCsr *pCsr;
pCsr = sqlite3_malloc(sizeof(*pCsr));
pCsr = sqlite3_malloc64(sizeof(*pCsr));
*ppCsr = (sqlite3_vtab_cursor*)pCsr;
if( pCsr==0 ){
return SQLITE_NOMEM;
@@ -995,7 +995,7 @@ static void zipfileInflate(
int nIn, /* Size of buffer aIn[] in bytes */
int nOut /* Expected output size */
){
u8 *aRes = sqlite3_malloc(nOut);
u8 *aRes = sqlite3_malloc64(nOut);
if( aRes==0 ){
sqlite3_result_error_nomem(pCtx);
}else{
@@ -1392,7 +1392,7 @@ static int zipfileBestIndex(
static ZipfileEntry *zipfileNewEntry(const char *zPath){
ZipfileEntry *pNew;
pNew = sqlite3_malloc(sizeof(ZipfileEntry));
pNew = sqlite3_malloc64(sizeof(ZipfileEntry));
if( pNew ){
memset(pNew, 0, sizeof(ZipfileEntry));
pNew->cds.zFile = sqlite3_mprintf("%s", zPath);
+4 -2
View File
@@ -9,8 +9,8 @@
** May you share freely, never taking more than you give.
**
*************************************************************************
** Implementation of the Result-Format or "qrf" utility library for SQLite.
** See the qrf.md documentation for additional information.
** Implementation of the Query Result-Format or "qrf" utility library for
** SQLite. See the README.md documentation for additional information.
*/
#ifndef SQLITE_QRF_H
#include "qrf.h"
@@ -19,7 +19,9 @@
#include <assert.h>
#include <stdint.h>
#ifndef SQLITE_AMALGAMATION
typedef sqlite3_int64 i64;
#endif
/* A single line in the EQP output */
typedef struct qrfEQPGraphRow qrfEQPGraphRow;
+2 -2
View File
@@ -9,8 +9,8 @@
** May you share freely, never taking more than you give.
**
*************************************************************************
** Header file for the Result-Format or "resfmt" utility library for SQLite.
** See the resfmt.md documentation for additional information.
** Header file for the Query Result-Format or "qrf" utility library for
** SQLite. See the README.md documentation for additional information.
*/
#ifndef SQLITE_QRF_H
#define SQLITE_QRF_H
+59 -2
View File
@@ -195,13 +195,70 @@ do_test 3.3 {
#-------------------------------------------------------------------------
#
reset_db
set C [binary format c* 0x54 0x01 0x01 0x00 0x12 0x00 0x05]
set C [binary format c* {0x54 0x01 0x01 0x00 0x12 0x00 0x05}]
do_test 4.0 {
sqlite3changegroup grp
list [catch { grp add $C } msg] $msg
} {1 SQLITE_CORRUPT}
} {0 {}}
grp delete
#-------------------------------------------------------------------------
#
reset_db
set C [binary format c* {0x54 0xda 0xda 0xda 0xda 0xda}]
do_execsql_test 5.0 {
CREATE TABLE t1(a PRIMARY KEY, b, c, d);
}
do_test 5.1 {
list [catch { sqlite3changeset_apply db $C noop xFilter } msg] $msg
} {1 SQLITE_CORRUPT}
#-------------------------------------------------------------------------
#
foreach {tn type C2hex C3hex} {
1 changeset 54020100743100170001000000000000000A030374656E000306656C6576656E
54020100743100170001000000000000000A030374656E0003FFFF01656C6576656E
2 patchset 50020100743100170001000000000000000A0306656C6576656E
50020100743100170001000000000000000A03FFFF06656C6576656E
3 changeset 54020100743100170001000000000000000A030374656E000306656C6576656E
54020100743100170001000000000000000A030374656E0003FFFF
} {
reset_db
do_execsql_test 6.$tn.0 {
CREATE TABLE t1(x INTEGER PRIMARY KEY, y TEXT);
INSERT INTO t1 VALUES(1, 'one');
INSERT INTO t1 VALUES(2, 'two');
INSERT INTO t1 VALUES(3, 'three');
} {}
do_test 6.$tn.1 {
set C1 [${type}_from_sql {
INSERT INTO t1 VALUES(10, 'ten');
}]
set C2 [${type}_from_sql {
UPDATE t1 SET y='eleven' WHERE x=10;
}]
db one { SELECT quote($C2) }
} "X'$C2hex'"
do_test 6.$tn.2 {
changeset_to_list [sqlite3changeset_concat $C1 $C2]
} {{INSERT t1 0 X. {} {i 10 t eleven}}}
set C3 [db one {SELECT unhex($C3hex)}]
do_test 6.$tn.3 {
list [catch { sqlite3changeset_concat $C1 $C3 } msg] $msg
} {1 SQLITE_CORRUPT}
}
finish_test
+400
View File
@@ -0,0 +1,400 @@
# 2026 January 09
#
# The author disclaims copyright to this source code. In place of
# a legal notice, here is a blessing:
#
# May you do good and not evil.
# May you find forgiveness for yourself and forgive others.
# May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.
#
if {![info exists testdir]} {
set testdir [file join [file dirname [info script]] .. .. test]
}
source [file join [file dirname [info script]] session_common.tcl]
source $testdir/tester.tcl
ifcapable !session {finish_test; return}
set testprefix sessionchange2
do_test 1.1.1 {
sqlite3changegroup grp
list [catch { grp change_begin INSERT "nosuchtable" 0 } msg] $msg
} {1 {SQLITE_ERROR - no such table: nosuchtable}}
do_test 1.1.2 {
grp schema db main
list [catch { grp change_begin INSERT "nosuchtable" 0 } msg] $msg
} {1 {SQLITE_ERROR - no such table: nosuchtable}}
do_test 1.1.3 {
list [catch { grp change_begin_ne INSERT "nosuchtable" 0 } msg] $msg
} {1 SQLITE_ERROR}
do_execsql_test 1.2.1 {
CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
}
do_test 1.2.2 {
list [catch { grp change_begin 435 "t1" 0 } msg] $msg
} {1 SQLITE_ERROR}
#-------------------------------------------------------------------------
reset_db
do_execsql_test 2.0 {
CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
CREATE TABLE t2(a, b);
}
do_test 2.1.1 {
sqlite3changegroup grp
grp schema db main
grp change_begin INSERT "t1" 0
grp change_int64 new 0 55
grp change_int64 new 1 101
grp change_finish false
} {}
do_test 2.1.2 {
set C [grp output]
grp delete
changeset_to_list $C
} {
{INSERT t1 0 X. {} {i 55 i 101}}
}
do_test 2.2.1 {
sqlite3changegroup grp
grp schema db main
grp change_begin INSERT "t2" 0
grp change_int64 new 0 -5
grp change_int64 new 1 -10
grp change_int64 new 2 -20
grp change_finish false
} {}
do_test 2.2.2 {
set C [grp output]
grp delete
changeset_to_list $C
} {
{INSERT t2 0 X.. {} {i -5 i -10 i -20}}
}
do_test 2.2.3 {
sqlite3changegroup grp
grp schema db main
grp change_begin INSERT "t1" 0
grp change_int64 new 0 223344
grp change_null new 1
grp change_finish false
} {}
do_test 2.2.4 {
set C [grp output]
grp delete
changeset_to_list $C
} {
{INSERT t1 0 X. {} {i 223344 n {}}}
}
do_test 2.2.5 {
sqlite3changegroup grp
grp schema db main
grp change_begin DELETE "t1" 0
grp change_int64 old 0 1
grp change_int64 old 1 123
grp change_finish false
} {}
do_test 2.2.6 {
set C [grp output]
grp delete
changeset_to_list $C
} {
{DELETE t1 0 X. {i 1 i 123} {}}
}
#-------------------------------------------------------------------------
reset_db
do_execsql_test 3.0 {
CREATE TABLE t1(a PRIMARY KEY, b, c);
CREATE TABLE t2(x, y);
}
foreach {tn script error} {
1 {
grp change_begin UPDATE t1 0
} {SQLITE_ERROR - invalid change: undefined value in PK of old.* record}
2 {
grp change_begin UPDATE t1 0
grp change_int64 old 0 1234
grp change_int64 new 0 5678
} {SQLITE_ERROR - invalid change: defined value in PK of new.* record}
3 {
grp change_begin UPDATE t1 0
grp change_null old 0
} {SQLITE_ERROR - invalid change: null value in PK of old.* record}
4 {
grp change_begin UPDATE t1 0
grp change_int64 old 0 1234
grp change_int64 old 1 20
} {SQLITE_ERROR - invalid change: column 1 - old.* value is defined but new.* is undefined}
5 {
grp change_begin UPDATE t1 0
grp change_int64 old 0 1234
grp change_int64 new 1 20
} {SQLITE_ERROR - invalid change: column 1 - old.* value is undefined but new.* is defined}
6 {
grp change_begin INSERT t1 0
grp change_null new 0
grp change_int64 new 1 20
} {SQLITE_ERROR - invalid change: null value in PK}
7 {
grp change_begin INSERT t1 0
grp change_int64 new 1 20
} {SQLITE_ERROR - invalid change: column 0 is undefined}
8 {
grp change_begin INSERT t1 0
grp change_int64 new 0 20
} {SQLITE_ERROR - invalid change: column 1 is undefined}
9 {
grp change_begin DELETE t1 0
grp change_int64 old 0 20
} {SQLITE_ERROR - invalid change: column 1 is undefined}
10 {
grp change_begin DELETE t1 0
grp change_int64 old 1 20
} {SQLITE_ERROR - invalid change: column 0 is undefined}
} {
sqlite3changegroup grp
grp schema db main
eval $script
do_test 3.1.$tn {
list [catch { grp change_finish false } msg] $msg
} [list 1 $error]
grp delete
}
do_test 3.2.1 {
sqlite3changegroup grp
grp schema db main
grp change_begin DELETE t1 0
list [catch {grp change_int64 new 0 20} msg] $msg
} {1 SQLITE_ERROR}
do_test 3.2.2 {
grp change_finish true
grp change_begin INSERT t1 0
list [catch {grp change_int64 old 0 20} msg] $msg
} {1 SQLITE_ERROR}
grp delete
#-------------------------------------------------------------------------
reset_db
do_execsql_test 3.0 {
CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
CREATE TABLE t2(a, b);
}
proc do_changegroup_script_test {tn script changeset patchset} {
breakpoint
sqlite3changegroup grp
grp schema db main
eval $script
do_test $tn.1 {
changeset_to_list [grp output]
} [list {*}$changeset]
grp delete
sqlite3changegroup grp
grp config patchset 1
grp schema db main
eval $script
do_test $tn.2 {
changeset_to_list [grp output]
} [list {*}$patchset]
grp delete
}
proc do_changegroup_patchset_test {tn script patchset} {
sqlite3changegroup grp
grp config patchset 1
grp schema db main
eval $script
do_test $tn {
changeset_to_list [grp output]
} [list {*}$patchset]
grp delete
}
do_changegroup_script_test 3.1 {
grp change_begin UPDATE t1 0
grp change_int64 old 0 123
grp change_int64 old 1 456
grp change_int64 new 1 789
grp change_finish false
grp change_begin INSERT t1 0
grp change_int64 new 0 124
grp change_text new 1 hello_world
grp change_finish false
grp change_begin DELETE t1 0
grp change_int64 old 0 125
grp change_double old 1 45.67
grp change_finish false
} {
{DELETE t1 0 X. {i 125 f 45.67} {}}
{INSERT t1 0 X. {} {i 124 t hello_world}}
{UPDATE t1 0 X. {i 123 i 456} {{} {} i 789}}
} {
{DELETE t1 0 X. {i 125 {} {}} {}}
{INSERT t1 0 X. {} {i 124 t hello_world}}
{UPDATE t1 0 X. {i 123 {} {}} {{} {} i 789}}
}
do_changegroup_script_test 3.1.2 {
grp change_begin INSERT t1 0
grp change_int64 new 0 124
grp change_text new 1 hello_world
grp change_finish false
} {
{INSERT t1 0 X. {} {i 124 t hello_world}}
} {
{INSERT t1 0 X. {} {i 124 t hello_world}}
}
do_changegroup_patchset_test 3.2 {
grp change_begin UPDATE t1 0
grp change_int64 old 0 123
grp change_int64 new 1 789
grp change_finish false
grp change_begin DELETE t1 1
grp change_int64 old 0 122
grp change_finish false
} {
{DELETE t1 1 X. {i 122 {} {}} {}}
{UPDATE t1 0 X. {i 123 {} {}} {{} {} i 789}}
}
do_changegroup_patchset_test 3.3 {
grp change_begin DELETE t1 0
grp change_int64 old 0 123
grp change_finish false
} {
{DELETE t1 0 X. {i 123 {} {}} {}}
}
do_changegroup_script_test 3.4 {
grp change_begin INSERT t1 0
grp change_int64 new 0 124
grp change_text new 1 hello_world
grp change_finish false
grp change_begin DELETE t1 0
grp change_int64 old 0 124
grp change_text old 1 hello_world
grp change_finish false
grp change_begin INSERT t1 0
grp change_int64 new 0 1000
grp change_blob new 1 abcd
grp change_finish false
grp change_begin UPDATE t1 0
grp change_int64 old 0 1000
grp change_blob old 1 abcd
grp change_blob new 1 bcda
grp change_finish false
} {
{INSERT t1 0 X. {} {i 1000 b bcda}}
} {
{INSERT t1 0 X. {} {i 1000 b bcda}}
}
do_changegroup_script_test 3.5 {
grp change_begin DELETE t1 0
grp change_int64 old 0 1000
grp change_text-1 old 1 "hello world"
grp change_finish false
} {
{DELETE t1 0 X. {i 1000 t {hello world}} {}}
} {
{DELETE t1 0 X. {i 1000 {} {}} {}}
}
#-------------------------------------------------------------------------
# Calling sqlite3changegroup_change_finish() if a change has not been
# started is a no-op.
#
do_test 4.0 {
sqlite3changegroup grp
grp change_finish false
} {}
# But calling any other sqlite3changegroup_change_xxx() function if a
# change has not been started is a misuse.
#
foreach {tn cmd} {
1 { grp change_blob old 0 abcd }
2 { grp change_text new 1 helloworld }
3 { grp change_int64 old 2 12345678 }
4 { grp change_double new 3 12.345 }
5 { grp change_null old 4 }
} {
do_test 4.1.$tn {
list [catch $::cmd msg] $msg
} {1 SQLITE_MISUSE}
}
grp delete
do_execsql_test 4.2.1 {
CREATE TABLE t3(a, b PRIMARY KEY);
}
do_test 4.2 {
sqlite3changegroup grp
grp schema db main
grp change_begin INSERT t3 0
list [catch { grp change_begin INSERT t3 0 } msg] $msg
} {1 SQLITE_MISUSE}
grp delete
do_test 4.3 {
sqlite3changegroup grp
grp schema db main
grp change_begin UPDATE t3 0
} {}
foreach {tn cmd} {
1 { grp change_blob old -1 abcd }
2 { grp change_text new 2 helloworld }
} {
do_test 4.4.$tn {
list [catch $::cmd msg] $msg
} {1 SQLITE_RANGE}
}
grp delete
finish_test
+15 -1
View File
@@ -43,7 +43,7 @@ set C2 [changeset_from_sql {
INSERT INTO t1 VALUES(0, 0, 0, 0);
}]
do_faultsim_test 1 -faults oom* -prep {
do_faultsim_test 1.2 -faults oom* -prep {
sqlite3changegroup G
} -body {
G schema db main
@@ -56,6 +56,20 @@ do_faultsim_test 1 -faults oom* -prep {
faultsim_test_result {0 {}} {1 SQLITE_NOMEM}
}
do_faultsim_test 1.3 -faults oom* -prep {
sqlite3changegroup G
} -body {
G schema db main
G change_begin INSERT t1 0
G change_int64 new 0 12345
G change_int64 new 1 67890
G output
set {} {}
} -test {
catch { G delete }
faultsim_test_result {0 {}} {1 SQLITE_NOMEM}
}
#-------------------------------------------------------------------------
reset_db
do_execsql_test 2.0 {
+483 -65
View File
@@ -354,9 +354,10 @@ static int sessionVarintGet(const u8 *aBuf, int *piVal){
** Return the number of bytes read.
*/
static int sessionVarintGetSafe(const u8 *aBuf, int nBuf, int *piVal){
u8 aCopy[5];
u8 aCopy[9];
const u8 *aRead = aBuf;
if( nBuf<5 ){
memset(aCopy, 0, sizeof(aCopy));
if( nBuf<sizeof(aCopy) ){
memcpy(aCopy, aBuf, nBuf);
aRead = aCopy;
}
@@ -391,6 +392,19 @@ static void sessionPutI64(u8 *aBuf, sqlite3_int64 i){
aBuf[7] = (i>> 0) & 0xFF;
}
/*
** Write a double value to the buffer aBuf[].
*/
static void sessionPutDouble(u8 *aBuf, double r){
/* TODO: SQLite does something special to deal with mixed-endian
** floating point values (e.g. ARM7). This code probably should
** too. */
u64 i;
assert( sizeof(double)==8 && sizeof(u64)==8 );
memcpy(&i, &r, 8);
sessionPutI64(aBuf, i);
}
/*
** This function is used to serialize the contents of value pValue (see
** comment titled "RECORD FORMAT" above).
@@ -428,16 +442,13 @@ static int sessionSerializeValue(
/* TODO: SQLite does something special to deal with mixed-endian
** floating point values (e.g. ARM7). This code probably should
** too. */
u64 i;
if( eType==SQLITE_INTEGER ){
i = (u64)sqlite3_value_int64(pValue);
u64 i = (u64)sqlite3_value_int64(pValue);
sessionPutI64(&aBuf[1], i);
}else{
double r;
assert( sizeof(double)==8 && sizeof(u64)==8 );
r = sqlite3_value_double(pValue);
memcpy(&i, &r, 8);
double r = sqlite3_value_double(pValue);
sessionPutDouble(&aBuf[1], r);
}
sessionPutI64(&aBuf[1], i);
}
nByte = 9;
break;
@@ -1369,9 +1380,7 @@ static void sessionUpdateOneChange(
case SQLITE_FLOAT: {
double rVal = sqlite3_column_double(pDflt, iField);
i64 iVal = 0;
memcpy(&iVal, &rVal, sizeof(rVal));
sessionPutI64(&pNew->aRecord[pNew->nRecord], iVal);
sessionPutDouble(&pNew->aRecord[pNew->nRecord], rVal);
pNew->nRecord += 8;
break;
}
@@ -2628,15 +2637,14 @@ static void sessionAppendCol(
int eType = sqlite3_column_type(pStmt, iCol);
sessionAppendByte(p, (u8)eType, pRc);
if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
sqlite3_int64 i;
u8 aBuf[8];
if( eType==SQLITE_INTEGER ){
i = sqlite3_column_int64(pStmt, iCol);
sqlite3_int64 i = sqlite3_column_int64(pStmt, iCol);
sessionPutI64(aBuf, i);
}else{
double r = sqlite3_column_double(pStmt, iCol);
memcpy(&i, &r, 8);
sessionPutDouble(aBuf, r);
}
sessionPutI64(aBuf, i);
sessionAppendBlob(p, aBuf, 8, pRc);
}
if( eType==SQLITE_BLOB || eType==SQLITE_TEXT ){
@@ -3679,7 +3687,7 @@ static int sessionChangesetBufferRecord(
int *pnByte /* OUT: Size of record in bytes */
){
int rc = SQLITE_OK;
int nByte = 0;
i64 nByte = 0;
int i;
for(i=0; rc==SQLITE_OK && i<nCol; i++){
int eType;
@@ -3688,13 +3696,17 @@ static int sessionChangesetBufferRecord(
eType = pIn->aData[pIn->iNext + nByte++];
if( eType==SQLITE_TEXT || eType==SQLITE_BLOB ){
int n;
nByte += sessionVarintGet(&pIn->aData[pIn->iNext+nByte], &n);
int nRem = pIn->nData - (pIn->iNext + nByte);
nByte += sessionVarintGetSafe(&pIn->aData[pIn->iNext+nByte], nRem, &n);
nByte += n;
rc = sessionInputBuffer(pIn, nByte);
}else if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
nByte += 8;
}
}
if( (pIn->iNext+nByte)>pIn->nData ){
rc = SQLITE_CORRUPT_BKPT;
}
}
*pnByte = nByte;
return rc;
@@ -5677,6 +5689,21 @@ int sqlite3changeset_apply_strm(
);
}
/*
** The parts of the sqlite3_changegroup structure used by the
** sqlite3changegroup_change_xxx() APIs.
*/
typedef struct ChangeData ChangeData;
struct ChangeData {
SessionTable *pTab;
int bIndirect;
int eOp;
int nBufAlloc;
SessionBuffer *aBuf;
SessionBuffer record;
};
/*
** sqlite3_changegroup handle.
*/
@@ -5688,12 +5715,17 @@ struct sqlite3_changegroup {
sqlite3 *db; /* Configured by changegroup_schema() */
char *zDb; /* Configured by changegroup_schema() */
ChangeData cd; /* Used by changegroup_change_xxx() APIs. */
};
/*
** This function is called to merge two changes to the same row together as
** part of an sqlite3changeset_concat() operation. A new change object is
** allocated and a pointer to it stored in *ppNew.
**
** Because they have been vetted by sqlite3changegroup_add() or similar,
** both the aRec[] change and the pExist change are safe to use without
** checking for buffer overflows.
*/
static int sessionChangeMerge(
SessionTable *pTab, /* Table structure */
@@ -5834,7 +5866,7 @@ static int sessionChangeMerge(
memcpy(aCsr, aRec, nRec);
aCsr += nRec;
}else{
if( 0==sessionMergeUpdate(&aCsr, pTab, bPatchset, aExist, 0,aRec,0) ){
if( 0==sessionMergeUpdate(&aCsr, pTab, bPatchset, aExist,0,aRec,0) ){
sqlite3_free(pNew);
pNew = 0;
}
@@ -5927,15 +5959,14 @@ static int sessionChangesetExtendRecord(
switch( eType ){
case SQLITE_FLOAT:
case SQLITE_INTEGER: {
i64 iVal;
if( eType==SQLITE_INTEGER ){
iVal = sqlite3_column_int64(pTab->pDfltStmt, ii);
}else{
double rVal = sqlite3_column_int64(pTab->pDfltStmt, ii);
memcpy(&iVal, &rVal, sizeof(i64));
}
if( SQLITE_OK==sessionBufferGrow(pOut, 8, &rc) ){
sessionPutI64(&pOut->aBuf[pOut->nBuf], iVal);
if( eType==SQLITE_INTEGER ){
sqlite3_int64 iVal = sqlite3_column_int64(pTab->pDfltStmt, ii);
sessionPutI64(&pOut->aBuf[pOut->nBuf], iVal);
}else{
double rVal = sqlite3_column_double(pTab->pDfltStmt, ii);
sessionPutDouble(&pOut->aBuf[pOut->nBuf], rVal);
}
pOut->nBuf += 8;
}
break;
@@ -6006,13 +6037,19 @@ static int sessionChangesetFindTable(
int nCol = 0;
*ppTab = 0;
sqlite3changeset_pk(pIter, &abPK, &nCol);
/* Search the list for an existing table */
for(pTab = pGrp->pList; pTab; pTab=pTab->pNext){
if( 0==sqlite3_strnicmp(pTab->zName, zTab, nTab+1) ) break;
}
if( pIter ){
sqlite3changeset_pk(pIter, &abPK, &nCol);
}else if( !pTab && !pGrp->db ){
return SQLITE_OK;
}
/* If one was not found above, create a new table now */
if( !pTab ){
SessionTable **ppNew;
@@ -6024,15 +6061,17 @@ static int sessionChangesetFindTable(
memset(pTab, 0, sizeof(SessionTable));
pTab->nCol = nCol;
pTab->abPK = (u8*)&pTab[1];
memcpy(pTab->abPK, abPK, nCol);
if( nCol>0 ){
memcpy(pTab->abPK, abPK, nCol);
}
pTab->zName = (char*)&pTab->abPK[nCol];
memcpy(pTab->zName, zTab, nTab+1);
if( pGrp->db ){
pTab->nCol = 0;
rc = sessionInitTable(0, pTab, pGrp->db, pGrp->zDb);
if( rc ){
assert( pTab->azCol==0 );
if( rc || pTab->nCol==0 ){
sqlite3_free(pTab->azCol);
sqlite3_free(pTab);
return rc;
}
@@ -6047,7 +6086,7 @@ static int sessionChangesetFindTable(
}
/* Check that the table is compatible. */
if( !sessionChangesetCheckCompat(pTab, nCol, abPK) ){
if( pIter && !sessionChangesetCheckCompat(pTab, nCol, abPK) ){
rc = SQLITE_SCHEMA;
}
@@ -6056,44 +6095,27 @@ static int sessionChangesetFindTable(
}
/*
** Add the change currently indicated by iterator pIter to the hash table
** belonging to changegroup pGrp.
** Add a single change to the changegroup pGrp.
*/
static int sessionOneChangeToHash(
sqlite3_changegroup *pGrp,
sqlite3_changeset_iter *pIter,
int bRebase
sqlite3_changegroup *pGrp, /* Changegroup to update */
SessionTable *pTab, /* Table change pertains to */
int op, /* One of SQLITE_INSERT, UPDATE, DELETE */
int bIndirect, /* True to flag change as "indirect" */
int nCol, /* Number of columns in record(s) */
u8 *aRec, /* Serialized change record(s) */
int nRec, /* Size of aRec[] in bytes */
int bRebase /* True if this is a rebase blob */
){
int rc = SQLITE_OK;
int nCol = 0;
int op = 0;
int iHash = 0;
int bIndirect = 0;
SessionChange *pChange = 0;
SessionChange *pExist = 0;
SessionChange **pp = 0;
SessionTable *pTab = 0;
u8 *aRec = &pIter->in.aData[pIter->in.iCurrent + 2];
int nRec = (pIter->in.iNext - pIter->in.iCurrent) - 2;
assert( nRec>0 );
/* Ensure that only changesets, or only patchsets, but not a mixture
** of both, are being combined. It is an error to try to combine a
** changeset and a patchset. */
if( pGrp->pList==0 ){
pGrp->bPatch = pIter->bPatchset;
}else if( pIter->bPatchset!=pGrp->bPatch ){
rc = SQLITE_ERROR;
}
if( rc==SQLITE_OK ){
const char *zTab = 0;
sqlite3changeset_op(pIter, &zTab, &nCol, &op, &bIndirect);
rc = sessionChangesetFindTable(pGrp, zTab, pIter, &pTab);
}
if( rc==SQLITE_OK && nCol<pTab->nCol ){
if( nCol<pTab->nCol ){
SessionBuffer *pBuf = &pGrp->rec;
rc = sessionChangesetExtendRecord(pGrp, pTab, nCol, op, aRec, nRec, pBuf);
aRec = pBuf->aBuf;
@@ -6101,7 +6123,7 @@ static int sessionOneChangeToHash(
assert( pGrp->db );
}
if( rc==SQLITE_OK && sessionGrowHash(0, pIter->bPatchset, pTab) ){
if( rc==SQLITE_OK && sessionGrowHash(0, pGrp->bPatch, pTab) ){
rc = SQLITE_NOMEM;
}
@@ -6109,12 +6131,12 @@ static int sessionOneChangeToHash(
/* Search for existing entry. If found, remove it from the hash table.
** Code below may link it back in. */
iHash = sessionChangeHash(
pTab, (pIter->bPatchset && op==SQLITE_DELETE), aRec, pTab->nChange
pTab, (pGrp->bPatch && op==SQLITE_DELETE), aRec, pTab->nChange
);
for(pp=&pTab->apChange[iHash]; *pp; pp=&(*pp)->pNext){
int bPkOnly1 = 0;
int bPkOnly2 = 0;
if( pIter->bPatchset ){
if( pGrp->bPatch ){
bPkOnly1 = (*pp)->op==SQLITE_DELETE;
bPkOnly2 = op==SQLITE_DELETE;
}
@@ -6129,7 +6151,7 @@ static int sessionOneChangeToHash(
if( rc==SQLITE_OK ){
rc = sessionChangeMerge(pTab, bRebase,
pIter->bPatchset, pExist, op, bIndirect, aRec, nRec, &pChange
pGrp->bPatch, pExist, op, bIndirect, aRec, nRec, &pChange
);
}
if( rc==SQLITE_OK && pChange ){
@@ -6138,6 +6160,47 @@ static int sessionOneChangeToHash(
pTab->nEntry++;
}
return rc;
}
/*
** Add the change currently indicated by iterator pIter to the hash table
** belonging to changegroup pGrp.
*/
static int sessionOneChangeIterToHash(
sqlite3_changegroup *pGrp,
sqlite3_changeset_iter *pIter,
int bRebase
){
u8 *aRec = &pIter->in.aData[pIter->in.iCurrent + 2];
int nRec = (pIter->in.iNext - pIter->in.iCurrent) - 2;
const char *zTab = 0;
int nCol = 0;
int op = 0;
int bIndirect = 0;
int rc = SQLITE_OK;
SessionTable *pTab = 0;
/* Ensure that only changesets, or only patchsets, but not a mixture
** of both, are being combined. It is an error to try to combine a
** changeset and a patchset. */
if( pGrp->pList==0 ){
pGrp->bPatch = pIter->bPatchset;
}else if( pIter->bPatchset!=pGrp->bPatch ){
rc = SQLITE_ERROR;
}
if( rc==SQLITE_OK ){
sqlite3changeset_op(pIter, &zTab, &nCol, &op, &bIndirect);
rc = sessionChangesetFindTable(pGrp, zTab, pIter, &pTab);
}
if( rc==SQLITE_OK ){
rc = sessionOneChangeToHash(
pGrp, pTab, op, bIndirect, nCol, aRec, nRec, bRebase
);
}
if( rc==SQLITE_OK ) rc = pIter->rc;
return rc;
}
@@ -6157,7 +6220,7 @@ static int sessionChangesetToHash(
pIter->in.bNoDiscard = 1;
while( SQLITE_ROW==(sessionChangesetNext(pIter, &aRec, &nRec, 0)) ){
rc = sessionOneChangeToHash(pGrp, pIter, bRebase);
rc = sessionOneChangeIterToHash(pGrp, pIter, bRebase);
if( rc!=SQLITE_OK ) break;
}
@@ -6247,6 +6310,33 @@ int sqlite3changegroup_new(sqlite3_changegroup **pp){
return rc;
}
/*
** Configure a changegroup object.
*/
int sqlite3changegroup_config(
sqlite3_changegroup *pGrp,
int op,
void *pArg
){
int rc = SQLITE_OK;
switch( op ){
case SQLITE_CHANGEGROUP_CONFIG_PATCHSET: {
int arg = *(int*)pArg;
if( pGrp->pList==0 && arg>=0 ){
pGrp->bPatch = (arg>0);
}
*(int*)pArg = pGrp->bPatch;
break;
}
default:
rc = SQLITE_MISUSE;
break;
}
return rc;
}
/*
** Provide a database schema to the changegroup object.
*/
@@ -6305,7 +6395,7 @@ int sqlite3changegroup_add_change(
rc = SQLITE_ERROR;
}else{
pIter->in.bNoDiscard = 1;
rc = sessionOneChangeToHash(pGrp, pIter, 0);
rc = sessionOneChangeIterToHash(pGrp, pIter, 0);
}
return rc;
}
@@ -6357,6 +6447,12 @@ int sqlite3changegroup_output_strm(
*/
void sqlite3changegroup_delete(sqlite3_changegroup *pGrp){
if( pGrp ){
int ii;
for(ii=0; ii<pGrp->cd.nBufAlloc; ii++){
sqlite3_free(pGrp->cd.aBuf[ii].aBuf);
}
sqlite3_free(pGrp->cd.record.aBuf);
sqlite3_free(pGrp->cd.aBuf);
sqlite3_free(pGrp->zDb);
sessionDeleteTable(0, pGrp->pList);
sqlite3_free(pGrp->rec.aBuf);
@@ -6787,4 +6883,326 @@ int sqlite3session_config(int op, void *pArg){
return rc;
}
/*
** Begin adding a change to a changegroup object.
*/
int sqlite3changegroup_change_begin(
sqlite3_changegroup *pGrp,
int eOp,
const char *zTab,
int bIndirect,
char **pzErr
){
SessionTable *pTab = 0;
int rc = SQLITE_OK;
if( pGrp->cd.pTab ){
rc = SQLITE_MISUSE;
}else if( eOp!=SQLITE_INSERT && eOp!=SQLITE_UPDATE && eOp!=SQLITE_DELETE ){
rc = SQLITE_ERROR;
}else{
rc = sessionChangesetFindTable(pGrp, zTab, 0, &pTab);
}
if( rc==SQLITE_OK ){
if( pTab==0 ){
if( pzErr ){
*pzErr = sqlite3_mprintf("no such table: %s", zTab);
}
rc = SQLITE_ERROR;
}else{
int nReq = pTab->nCol * (eOp==SQLITE_UPDATE ? 2 : 1);
pGrp->cd.pTab = pTab;
pGrp->cd.eOp = eOp;
pGrp->cd.bIndirect = bIndirect;
if( pGrp->cd.nBufAlloc<nReq ){
SessionBuffer *aBuf = (SessionBuffer*)sqlite3_realloc(
pGrp->cd.aBuf, nReq * sizeof(SessionBuffer)
);
if( aBuf==0 ){
rc = SQLITE_NOMEM;
}else{
memset(&aBuf[pGrp->cd.nBufAlloc], 0,
sizeof(SessionBuffer) * (nReq - pGrp->cd.nBufAlloc)
);
pGrp->cd.aBuf = aBuf;
pGrp->cd.nBufAlloc = nReq;
}
}
#ifdef SQLITE_DEBUG
{
/* Assert that all column values are currently undefined */
int ii;
for(ii=0; ii<pGrp->cd.nBufAlloc; ii++){
assert( pGrp->cd.aBuf[ii].nBuf==0 );
}
}
#endif
}
}
return rc;
}
/*
** This function does processing common to the _change_int64(), _change_text()
** and other similar APIs.
*/
static int checkChangeParams(
sqlite3_changegroup *pGrp,
int bNew,
int iCol,
sqlite3_int64 nReq,
SessionBuffer **ppBuf
){
int rc = SQLITE_OK;
if( pGrp->cd.pTab==0 ){
rc = SQLITE_MISUSE;
}else if( iCol<0 || iCol>=pGrp->cd.pTab->nCol ){
rc = SQLITE_RANGE;
}else if(
(bNew && pGrp->cd.eOp==SQLITE_DELETE)
|| (!bNew && pGrp->cd.eOp==SQLITE_INSERT)
){
rc = SQLITE_ERROR;
}else{
SessionBuffer *pBuf = &pGrp->cd.aBuf[iCol];
if( pGrp->cd.eOp==SQLITE_UPDATE && bNew ){
pBuf += pGrp->cd.pTab->nCol;
}
pBuf->nBuf = 0;
sessionBufferGrow(pBuf, nReq, &rc);
pBuf->nBuf = nReq;
*ppBuf = pBuf;
}
return rc;
}
/*
** Configure the change currently under construction with an integer value.
*/
int sqlite3changegroup_change_int64(
sqlite3_changegroup *pGrp,
int bNew,
int iCol,
sqlite3_int64 iVal
){
int rc = SQLITE_OK;
SessionBuffer *pBuf = 0;
if( SQLITE_OK!=(rc = checkChangeParams(pGrp, bNew, iCol, 9, &pBuf)) ){
return rc;
}
pBuf->aBuf[0] = SQLITE_INTEGER;
sessionPutI64(&pBuf->aBuf[1], iVal);
return SQLITE_OK;
}
/*
** Configure the change currently under construction with a null value.
*/
int sqlite3changegroup_change_null(
sqlite3_changegroup *pGrp,
int bNew,
int iCol
){
int rc = SQLITE_OK;
SessionBuffer *pBuf = 0;
if( SQLITE_OK!=(rc = checkChangeParams(pGrp, bNew, iCol, 1, &pBuf)) ){
return rc;
}
pBuf->aBuf[0] = SQLITE_NULL;
return SQLITE_OK;
}
/*
** Configure the change currently under construction with a real value.
*/
int sqlite3changegroup_change_double(
sqlite3_changegroup *pGrp,
int bNew,
int iCol,
double fVal
){
int rc = SQLITE_OK;
SessionBuffer *pBuf = 0;
if( SQLITE_OK!=(rc = checkChangeParams(pGrp, bNew, iCol, 9, &pBuf)) ){
return rc;
}
pBuf->aBuf[0] = SQLITE_FLOAT;
sessionPutDouble(&pBuf->aBuf[1], fVal);
return SQLITE_OK;
}
/*
** Configure the change currently under construction with a text value.
*/
int sqlite3changegroup_change_text(
sqlite3_changegroup *pGrp,
int bNew,
int iCol,
const char *pVal,
int nVal
){
int nText = nVal>=0 ? nVal : strlen(pVal);
sqlite3_int64 nByte = 1 + sessionVarintLen(nText) + nText;
int rc = SQLITE_OK;
SessionBuffer *pBuf = 0;
if( SQLITE_OK!=(rc = checkChangeParams(pGrp, bNew, iCol, nByte, &pBuf)) ){
return rc;
}
pBuf->aBuf[0] = SQLITE_TEXT;
pBuf->nBuf = (1 + sessionVarintPut(&pBuf->aBuf[1], nText));
memcpy(&pBuf->aBuf[pBuf->nBuf], pVal, nText);
pBuf->nBuf += nText;
return SQLITE_OK;
}
/*
** Configure the change currently under construction with a blob value.
*/
int sqlite3changegroup_change_blob(
sqlite3_changegroup *pGrp,
int bNew,
int iCol,
const void *pVal,
int nVal
){
sqlite3_int64 nByte = 1 + sessionVarintLen(nVal) + nVal;
int rc = SQLITE_OK;
SessionBuffer *pBuf = 0;
if( SQLITE_OK!=(rc = checkChangeParams(pGrp, bNew, iCol, nByte, &pBuf)) ){
return rc;
}
pBuf->aBuf[0] = SQLITE_BLOB;
pBuf->nBuf = (1 + sessionVarintPut(&pBuf->aBuf[1], nVal));
memcpy(&pBuf->aBuf[pBuf->nBuf], pVal, nVal);
pBuf->nBuf += nVal;
return SQLITE_OK;
}
/*
** Finish any change currently being constructed by the changegroup object.
*/
int sqlite3changegroup_change_finish(
sqlite3_changegroup *pGrp,
int bDiscard,
char **pzErr
){
int rc = SQLITE_OK;
if( pGrp->cd.pTab ){
SessionBuffer *aBuf = pGrp->cd.aBuf;
int ii;
if( bDiscard==0 ){
int nBuf = pGrp->cd.pTab->nCol;
u8 eUndef = SQLITE_NULL;
if( pGrp->cd.eOp==SQLITE_UPDATE ){
for(ii=0; ii<nBuf; ii++){
if( pGrp->cd.pTab->abPK[ii] ){
if( aBuf[ii].nBuf<=1 ){
*pzErr = sqlite3_mprintf(
"invalid change: %s value in PK of old.* record",
aBuf[ii].nBuf==1 ? "null" : "undefined"
);
rc = SQLITE_ERROR;
break;
}else if( aBuf[ii + nBuf].nBuf>0 ){
*pzErr = sqlite3_mprintf(
"invalid change: defined value in PK of new.* record"
);
rc = SQLITE_ERROR;
break;
}
}else
if( pGrp->bPatch==0 && (aBuf[ii].nBuf>0)!=(aBuf[ii+nBuf].nBuf>0) ){
*pzErr = sqlite3_mprintf(
"invalid change: column %d "
"- old.* value is %sdefined but new.* is %sdefined",
ii, aBuf[ii].nBuf ? "" : "un", aBuf[ii+nBuf].nBuf ? "" : "un"
);
rc = SQLITE_ERROR;
break;
}
}
eUndef = 0x00;
if( pGrp->bPatch==0 ) nBuf = nBuf * 2;
}else{
for(ii=0; ii<nBuf; ii++){
int isPK = pGrp->cd.pTab->abPK[ii];
if( (pGrp->cd.eOp==SQLITE_INSERT || pGrp->bPatch==0 || isPK)
&& aBuf[ii].nBuf==0
){
*pzErr = sqlite3_mprintf(
"invalid change: column %d is undefined", ii
);
rc = SQLITE_ERROR;
break;
}
if( aBuf[ii].nBuf==1 && isPK ){
*pzErr = sqlite3_mprintf(
"invalid change: null value in PK"
);
rc = SQLITE_ERROR;
break;
}
}
}
pGrp->cd.record.nBuf = 0;
for(ii=0; ii<nBuf; ii++){
SessionBuffer *p = &pGrp->cd.aBuf[ii];
if( pGrp->bPatch ){
if( pGrp->cd.pTab->abPK[ii]==0 ){
if( pGrp->cd.eOp==SQLITE_UPDATE ){
p += pGrp->cd.pTab->nCol;
}else if( pGrp->cd.eOp==SQLITE_DELETE ){
continue;
}
}
}
if( 0==sessionBufferGrow(&pGrp->cd.record, p->nBuf?p->nBuf:1, &rc) ){
if( p->nBuf ){
memcpy(&pGrp->cd.record.aBuf[pGrp->cd.record.nBuf],p->aBuf,p->nBuf);
pGrp->cd.record.nBuf += p->nBuf;
}else{
pGrp->cd.record.aBuf[pGrp->cd.record.nBuf++] = eUndef;
}
}
}
if( rc==SQLITE_OK ){
rc = sessionOneChangeToHash(
pGrp, pGrp->cd.pTab,
pGrp->cd.eOp, pGrp->cd.bIndirect, pGrp->cd.pTab->nCol,
pGrp->cd.record.aBuf, pGrp->cd.record.nBuf, 0
);
}
}
/* Reset all aBuf[] entries to "undefined". */
{
int nZero = pGrp->cd.pTab->nCol;
if( pGrp->cd.eOp==SQLITE_UPDATE ) nZero += nZero;
for(ii=0; ii<nZero; ii++){
pGrp->cd.aBuf[ii].nBuf = 0;
}
}
pGrp->cd.pTab = 0;
}
return rc;
}
#endif /* SQLITE_ENABLE_SESSION && SQLITE_ENABLE_PREUPDATE_HOOK */
+226
View File
@@ -1853,6 +1853,232 @@ int sqlite3session_config(int op, void *pArg);
*/
#define SQLITE_SESSION_CONFIG_STRMSIZE 1
/*
** CAPI3REF: Configure a changegroup object
**
** Configure the changegroup object passed as the first argument.
** At present the only valid value for the second parameter is
** [SQLITE_CHANGEGROUP_CONFIG_PATCHSET].
*/
int sqlite3changegroup_config(sqlite3_changegroup*, int, void *pArg);
/*
** CAPI3REF: Options for sqlite3changegroup_config().
**
** The following values may be passed as the 2nd parameter to
** sqlite3changegroup_config().
**
** <dt>SQLITE_CHANGEGROUP_CONFIG_PATCHSET <dd>
** A changegroup object generates either a changeset or patchset. Usually,
** this is determined by whether the first call to sqlite3changegroup_add()
** is passed a changeset or a patchset. Or, if the first changes are added
** to the changegroup object using the sqlite3changegroup_change_xxx()
** APIs, then this option may be used to configure whether the changegroup
** object generates a changeset or patchset.
**
** When this option is invoked, parameter pArg must point to a value of
** type int. If the changegroup currently contains zero changes, and the
** value of the int variable is zero or greater than zero, then the
** changegroup is configured to generate a changeset or patchset,
** respectively. It is a no-op, not an error, if the changegroup is not
** configured because it has already started accumulating changes.
**
** Before returning, the int variable is set to 0 if the changegroup is
** configured to generate a changeset, or 1 if it is configured to generate
** a patchset.
*/
#define SQLITE_CHANGEGROUP_CONFIG_PATCHSET 1
/*
** CAPI3REF: Begin adding a change to a changegroup
**
** This API is used, in concert with other sqlite3changegroup_change_xxx()
** APIs, to add changes to a changegroup object one at a time. To add a
** single change, the caller must:
**
** 1. Invoke sqlite3changegroup_change_begin() to indicate the type of
** change (INSERT, UPDATE or DELETE), the affected table and whether
** or not the change should be marked as indirect.
**
** 2. Invoke sqlite3changegroup_change_int64() or one of the other four
** value functions - _null(), _double(), _text() or _blob() - one or
** more times to specify old.* and new.* values for the change being
** constructed.
**
** 3. Invoke sqlite3changegroup_change_finish() to either finish adding
** the change to the group, or to discard the change altogether.
**
** The first argument to this function must be a pointer to the existing
** changegroup object that the change will be added to. The second argument
** must be SQLITE_INSERT, SQLITE_UPDATE or SQLITE_DELETE. The third is the
** name of the table that the change affects, and the fourth is a boolean
** flag specifying whether the change should be marked as "indirect" (if
** bIndirect is non-zero) or not indirect (if bIndirect is zero).
**
** Following a successful call to this function, this function may not be
** called again on the same changegroup object until after
** sqlite3changegroup_change_finish() has been called. Doing so is an
** SQLITE_MISUSE error.
**
** The changegroup object passed as the first argument must be already
** configured with schema data for the specified table. It may be configured
** either by calling sqlite3changegroup_schema() with a database that contains
** the table, or sqlite3changegroup_add() with a changeset that contains the
** table. If the changegroup object has not been configured with a schema for
** the specified table when this function is called, SQLITE_ERROR is returned.
**
** If successful, SQLITE_OK is returned. Otherwise, if an error occurs, an
** SQLite error code is returned. In this case, if argument pzErr is non-NULL,
** then (*pzErr) may be set to point to a buffer containing a utf-8 formated,
** nul-terminated, English language error message. It is the responsibility
** of the caller to eventually free this buffer using sqlite3_free().
*/
int sqlite3changegroup_change_begin(
sqlite3_changegroup*,
int eOp,
const char *zTab,
int bIndirect,
char **pzErr
);
/*
** CAPI3REF: Add a 64-bit integer to a changegroup
**
** This function may only be called between a successful call to
** sqlite3changegroup_change_begin() and its matching
** sqlite3changegroup_change_finish() call. If it is called at any
** other time, it is an SQLITE_MISUSE error. Calling this function
** specifies a 64-bit integer value to be used in the change currently being
** added to the changegroup object passed as the first argument.
**
** The second parameter, bNew, specifies whether the value is to be part of
** the new.* (if bNew is non-zero) or old.* (if bNew is zero) record of
** the change under construction. If this does not match the type of change
** specified by the preceding call to sqlite3changegroup_change_begin() (i.e.
** an old.* value for an SQLITE_INSERT change, or a new.* value for an
** SQLITE_DELETE), then SQLITE_ERROR is returned.
**
** The third parameter specifies the column of the old.* or new.* record that
** the value will be a part of. If the specified table has an explicit primary
** key, then this is the index of the table column, numbered from 0 in the order
** specified within the CREATE TABLE statement. Or, if the table uses an
** implicit rowid key, then the column 0 is the rowid and the explicit columns
** are numbered starting from 1. If the iCol parameter is less than 0 or greater
** than the index of the last column in the table, SQLITE_RANGE is returned.
**
** The fourth parameter is the integer value to use as part of the old.* or
** new.* record.
**
** If this call is successful, SQLITE_OK is returned. Otherwise, if an
** error occurs, an SQLite error code is returned.
*/
int sqlite3changegroup_change_int64(
sqlite3_changegroup*,
int bNew,
int iCol,
sqlite3_int64 iVal
);
/*
** CAPI3REF: Add a NULL to a changegroup
**
** This function is similar to sqlite3changegroup_change_int64(). Except that
** it configures the change currently under construction with a NULL value
** instead of a 64-bit integer.
*/
int sqlite3changegroup_change_null(sqlite3_changegroup*, int, int);
/*
** CAPI3REF: Add an double to a changegroup
**
** This function is similar to sqlite3changegroup_change_int64(). Except that
** it configures the change currently being constructed with a real value
** instead of a 64-bit integer.
*/
int sqlite3changegroup_change_double(sqlite3_changegroup*, int, int, double);
/*
** CAPI3REF: Add a text value to a changegroup
**
** This function is similar to sqlite3changegroup_change_int64(). It configures
** the currently accumulated change with a text value instead of a 64-bit
** integer. Parameter pVal points to a buffer containing the text encoded using
** utf-8. Parameter nVal may either be the size of the text value in bytes, or
** else a negative value, in which case the buffer pVal points to is assumed to
** be nul-terminated.
*/
int sqlite3changegroup_change_text(
sqlite3_changegroup*, int, int, const char *pVal, int nVal
);
/*
** CAPI3REF: Add a blob to a changegroup
**
** This function is similar to sqlite3changegroup_change_int64(). It configures
** the currently accumulated change with a blob value instead of a 64-bit
** integer. Parameter pVal points to a buffer containing the blob. Parameter
** nVal is the size of the blob in bytes.
*/
int sqlite3changegroup_change_blob(
sqlite3_changegroup*, int, int, const void *pVal, int nVal
);
/*
** CAPI3REF: Finish adding one-at-at-time changes to a changegroup
**
** This function may only be called following a successful call to
** sqlite3changegroup_change_begin(). Otherwise, it is an SQLITE_MISUSE error.
**
** If parameter bDiscard is non-zero, then the current change is simply
** discarded. In this case this function is always successful and SQLITE_OK
** returned.
**
** If parameter bDiscard is zero, then an attempt is made to add the current
** change to the changegroup. Assuming the changegroup is configured to
** produce a changeset (not a patchset), this requires that:
**
** * If the change is an INSERT or DELETE, then a value must be specified
** for all columns of the new.* or old.* record, respectively.
**
** * If the change is an UPDATE record, then values must be provided for
** the PRIMARY KEY columns of the old.* record, but must not be provided
** for PRIMARY KEY columns of the new.* record.
**
** * If the change is an UPDATE record, then for each non-PRIMARY KEY
** column in the old.* record for which a value has been provided, a
** value must also be provided for the same column in the new.* record.
** Similarly, for each non-PK column in the old.* record for which
** a value is not provided, a value must not be provided for the same
** column in the new.* record.
**
** * All values specified for PRIMARY KEY columns must be non-NULL.
**
** Otherwise, it is an error.
**
** If the changegroup already contains a change for the same row (identified
** by PRIMARY KEY columns), then the current change is combined with the
** existing change in the same way as for sqlite3changegroup_add().
**
** For a patchset, all of the above rules apply except that it doesn't matter
** whether or not values are provided for the non-PK old.* record columns
** for an UPDATE or DELETE change. This means that code used to produce
** a changeset using the sqlite3changegroup_change_xxx() APIs may also
** be used to produce patchsets.
**
** If the call is successful, SQLITE_OK is returned. Otherwise, if an error
** occurs, an SQLite error code is returned. If an error is returned and
** parameter pzErr is not NULL, then (*pzErr) may be set to point to a buffer
** containing a nul-terminated, utf-8 encoded, English language error message.
** It is the responsibility of the caller to eventually free any such error
** message buffer using sqlite3_free().
*/
int sqlite3changegroup_change_finish(
sqlite3_changegroup*,
int bDiscard,
char **pzErr
);
/*
** Make sure we can call this stuff from C++.
*/
+236 -8
View File
@@ -13,6 +13,8 @@
typedef unsigned char u8;
#endif
extern const char *sqlite3ErrName(int);
typedef struct TestSession TestSession;
struct TestSession {
sqlite3_session *pSession;
@@ -397,7 +399,6 @@ static int SQLITE_TCLAPI test_session_cmd(
}
rc = sqlite3session_object_config(pSession, aOpt[iOpt].opt, &iArg);
if( rc!=SQLITE_OK ){
extern const char *sqlite3ErrName(int);
Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1));
}else{
Tcl_SetObjResult(interp, Tcl_NewIntObj(iArg));
@@ -1114,6 +1115,21 @@ static int SQLITE_TCLAPI test_sqlite3changeset_invert(
return rc;
}
/*
** Copy buffer aIn[] to a new nIn byte buffer obtained from malloc(). Use
** plain malloc() instead of any Tcl function because valgrind and asan are
** better at detecting small overflows in that case. Avoid sqlite3_malloc()
** here because that means dealing with injected OOM errors.
**
** The caller is responsible for eventually calling free() on the returned
** value.
*/
static u8 *copyToMalloc(const u8 *aIn, int nIn){
u8 *pRet = malloc(nIn);
memcpy(pRet, aIn, nIn);
return pRet;
}
/*
** sqlite3changeset_concat LEFT RIGHT
*/
@@ -1144,6 +1160,9 @@ static int SQLITE_TCLAPI test_sqlite3changeset_concat(
sLeft.nStream = test_tcl_integer(interp, SESSION_STREAM_TCL_VAR);
sRight.nStream = sLeft.nStream;
sLeft.aData = copyToMalloc(sLeft.aData, sLeft.nData);
sRight.aData = copyToMalloc(sRight.aData, sRight.nData);
if( sLeft.nStream>0 ){
rc = sqlite3changeset_concat_strm(
testStreamInput, (void*)&sLeft,
@@ -1156,6 +1175,9 @@ static int SQLITE_TCLAPI test_sqlite3changeset_concat(
);
}
free(sLeft.aData);
free(sRight.aData);
if( rc!=SQLITE_OK ){
rc = test_session_error(interp, rc, 0);
}else{
@@ -1554,6 +1576,14 @@ static void test_changegroup_del(void *clientData){
ckfree(pGrp);
}
static int testGetNewOrOld(Tcl_Interp *interp, Tcl_Obj *pObj, int *pbNew){
const char *azVal[] = { "old", "new", 0 };
int iIdx = 0;
int rc = Tcl_GetIndexFromObj(interp, pObj, azVal, "record", 0, &iIdx);
*pbNew = iIdx;
return rc;
}
/*
** Tclcmd: $changegroup schema DB DBNAME
** Tclcmd: $changegroup add CHANGESET
@@ -1571,14 +1601,25 @@ static int SQLITE_TCLAPI test_changegroup_cmd(
const char *zSub;
int nArg;
const char *zMsg;
int iSub;
} aSub[] = {
{ "schema", 2, "DB DBNAME", }, /* 0 */
{ "add", 1, "CHANGESET", }, /* 1 */
{ "output", 0, "", }, /* 2 */
{ "delete", 0, "", }, /* 3 */
{ "add_change", 1, "ITERATOR", }, /* 4 */
{ 0 }
{ "schema", 2, "DB DBNAME" }, /* 0 */
{ "add", 1, "CHANGESET" }, /* 1 */
{ "output", 0, "" }, /* 2 */
{ "delete", 0, "" }, /* 3 */
{ "add_change", 1, "ITERATOR" }, /* 4 */
{ "change_begin", 3, "TYPE TABLE INDIRECT" }, /* 5 */
{ "change_int64", 3, "[new|old] ICOL VALUE" }, /* 6 */
{ "change_null", 2, "[new|old] ICOL" }, /* 7 */
{ "change_double", 3, "[new|old] ICOL VALUE" }, /* 8 */
{ "change_text", 3, "[new|old] ICOL VALUE" }, /* 9 */
{ "change_blob", 3, "[new|old] ICOL VALUE" }, /* 10 */
{ "change_finish", 1, "BDISCARD" }, /* 11 */
{ "config", 2, "OPTION INTVAL" }, /* 12 */
{ "change_text-1", 3, "[new|old] ICOL VALUE" }, /* 13 */
{ "change_begin_ne", 3, "TYPE TABLE INDIRECT" }, /* 14 */
{ 0, 0, 0 }
};
int rc = TCL_OK;
int iSub = 0;
@@ -1647,6 +1688,193 @@ static int SQLITE_TCLAPI test_changegroup_cmd(
break;
};
case 14: /* change_beginne */
case 5: { /* change_begin */
struct ChangeType {
const char *zType;
int eType;
} aType[] = {
{ "INSERT", SQLITE_INSERT },
{ "UPDATE", SQLITE_UPDATE },
{ "DELETE", SQLITE_DELETE },
{ 0, 0 }
};
int eType = 0;
const char *zTab = 0;
int bIndirect;
int iIdx = 0;
char *zErr = 0;
char **pz = ((iSub==5) ? &zErr : 0);
if( TCL_OK!=Tcl_GetIntFromObj(0, objv[2], &eType) ){
rc = Tcl_GetIndexFromObjStruct(
interp, objv[2], aType, sizeof(aType[0]), "TYPE", 0, &iIdx
);
if( rc!=TCL_OK ) return rc;
eType = aType[iIdx].eType;
}
zTab = Tcl_GetString(objv[3]);
if( Tcl_GetBooleanFromObj(interp, objv[4], &bIndirect) ){
return TCL_ERROR;
}
rc = sqlite3changegroup_change_begin(p->pGrp, eType, zTab, bIndirect, pz);
assert( zErr==0 || rc!=SQLITE_OK );
if( rc!=SQLITE_OK ){
rc = test_session_error(interp, rc, zErr);
}
break;
}
case 6: { /* change_int64 */
int bNew = 0;
int iCol = 0;
sqlite3_int64 iVal = 0;
if( TCL_OK!=testGetNewOrOld(interp, objv[2], &bNew)
|| TCL_OK!=Tcl_GetIntFromObj(interp, objv[3], &iCol)
|| TCL_OK!=Tcl_GetWideIntFromObj(interp, objv[4], &iVal)
){
rc = TCL_ERROR;
}else{
rc = sqlite3changegroup_change_int64(p->pGrp, bNew, iCol, iVal);
if( rc!=SQLITE_OK ){
rc = test_session_error(interp, rc, 0);
}
}
break;
}
case 7: { /* change_null */
int bNew = 0;
int iCol = 0;
if( TCL_OK!=testGetNewOrOld(interp, objv[2], &bNew)
|| TCL_OK!=Tcl_GetIntFromObj(interp, objv[3], &iCol)
){
rc = TCL_ERROR;
}else{
rc = sqlite3changegroup_change_null(p->pGrp, bNew, iCol);
if( rc!=SQLITE_OK ){
rc = test_session_error(interp, rc, 0);
}
}
break;
}
case 8: { /* change_double */
int bNew = 0;
int iCol = 0;
double rVal = 0;
if( TCL_OK!=testGetNewOrOld(interp, objv[2], &bNew)
|| TCL_OK!=Tcl_GetIntFromObj(interp, objv[3], &iCol)
|| TCL_OK!=Tcl_GetDoubleFromObj(interp, objv[4], &rVal)
){
rc = TCL_ERROR;
}else{
rc = sqlite3changegroup_change_double(p->pGrp, bNew, iCol, rVal);
if( rc!=SQLITE_OK ){
rc = test_session_error(interp, rc, 0);
}
}
break;
}
case 9: { /* change_text */
int bNew = 0;
int iCol = 0;
if( TCL_OK!=testGetNewOrOld(interp, objv[2], &bNew)
|| TCL_OK!=Tcl_GetIntFromObj(interp, objv[3], &iCol)
){
rc = TCL_ERROR;
}else{
Tcl_Size nVal = 0;
const char *pVal = Tcl_GetStringFromObj(objv[4], &nVal);
rc = sqlite3changegroup_change_text(p->pGrp, bNew, iCol, pVal, nVal);
if( rc!=SQLITE_OK ){
rc = test_session_error(interp, rc, 0);
}
}
break;
}
case 10: { /* change_blob */
int bNew = 0;
int iCol = 0;
if( TCL_OK!=testGetNewOrOld(interp, objv[2], &bNew)
|| TCL_OK!=Tcl_GetIntFromObj(interp, objv[3], &iCol)
){
rc = TCL_ERROR;
}else{
Tcl_Size nVal = 0;
const u8 *pVal = Tcl_GetByteArrayFromObj(objv[4], &nVal);
rc = sqlite3changegroup_change_blob(p->pGrp, bNew, iCol, pVal, nVal);
if( rc!=SQLITE_OK ){
rc = test_session_error(interp, rc, 0);
}
}
break;
}
case 11: { /* change_finish */
int bDiscard = 0;
if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[2], &bDiscard) ){
rc = TCL_ERROR;
}else{
char *zErr = 0;
rc = sqlite3changegroup_change_finish(p->pGrp, bDiscard, &zErr);
if( rc!=SQLITE_OK ){
rc = test_session_error(interp, rc, zErr);
}
}
break;
}
case 12: { /* config */
struct OptionName {
const char *zOpt;
int op;
} aOp[] = {
{ "patchset", SQLITE_CHANGEGROUP_CONFIG_PATCHSET },
{ 0, 0 }
};
int iIdx = 0;
int iArg = 0;
rc = Tcl_GetIndexFromObjStruct(
interp, objv[2], aOp, sizeof(aOp[0]), "option", 0, &iIdx
);
if( rc==TCL_OK
&& (rc = Tcl_GetIntFromObj(interp, objv[3], &iArg))==TCL_OK
){
int op = aOp[iIdx].op;
void *pArg = (void*)&iArg;
rc = sqlite3changegroup_config(p->pGrp, op, pArg);
if( rc!=SQLITE_OK ){
rc = test_session_error(interp, rc, 0);
}else{
Tcl_SetObjResult(interp, Tcl_NewIntObj(iArg));
}
}
break;
}
case 13: { /* change_text-1 */
int bNew = 0;
int iCol = 0;
if( TCL_OK!=testGetNewOrOld(interp, objv[2], &bNew)
|| TCL_OK!=Tcl_GetIntFromObj(interp, objv[3], &iCol)
){
rc = TCL_ERROR;
}else{
const char *pVal = Tcl_GetString(objv[4]);
rc = sqlite3changegroup_change_text(p->pGrp, bNew, iCol, pVal, -1);
if( rc!=SQLITE_OK ){
rc = test_session_error(interp, rc, 0);
}
}
break;
}
default: { /* delete */
assert( iSub==3 );
Tcl_DeleteCommand(interp, Tcl_GetString(objv[0]));
+34 -14
View File
@@ -49,6 +49,36 @@
versions (approximately) 104-107 are extinct) we should change our
usage of those methods to remove the "await".
*/
//#if 0
/**
2026-04-04: this file gets included by both the "opfs" and "opfs-wl"
VFSes. It would, in hindsight, hypothetically be possible to restructure
it very slightly to support both VFSes via a single Worker instance.
Some of the changes we would need for that:
- The xLock/xUnlock "op codes" would need to differ for each impl.
i.e. we'd need state.opIds.xLock{,WL} and state.opIds.xUnlock{,WL}
to distinguish between the two, rather than doing so when this Worker
is loaded.
- We would need to centralize loading of this Worker, outside of
the VFS-specific pieces, and change the handshake in order to be
able to distinguish between clients which support
Atomics.waitAsync() and those which do not ("opfs-wl" requires
waitAsync()).
One down-side would be for clients which, for whatever reason, want
to use both "opfs" and "opfs-wl" within the same session: because
both would go through the same Worker, any operations for one VFS
would, while they're being processed on this side of the proxy,
effectively block the other VFS from doing anything, potentially
deadlocking. This use case seems unlikely enough that it can
possibly be ruled out (or even reasonably flat-out prohibited by
the library).
*/
//#/if
"use strict";
const urlParams = new URL(globalThis.location.href).searchParams;
const vfsName = urlParams.get('vfs');
@@ -678,9 +708,9 @@ const installAsyncProxy = function(){
const lockName = "sqlite3-vfs-opfs:" + fh.filenameAbs;
const oldLockType = fh.xLock;
return new Promise((resolveWaitLoop) => {
//error("xLock() initial promise entered...");
//log("xLock() initial promise entered...");
navigator.locks.request(lockName, { mode: requestedMode }, async (lock) => {
//error("xLock() Web Lock entered.", fh);
//log("xLock() Web Lock entered.", fh);
__implicitLocks.delete(fid);
let rc = 0;
try{
@@ -726,7 +756,7 @@ const installAsyncProxy = function(){
storeAndNotify('xUnlock', rc);
return rc;
}
//error("xUnlock()",fid, lockType, fh);
//log("xUnlock()",fid, lockType, fh);
let rc = 0;
if( lockType === state.sq3Codes.SQLITE_LOCK_NONE ){
/* SQLite usually unlocks all the way to NONE */
@@ -736,7 +766,7 @@ const installAsyncProxy = function(){
fh.xLock = lockType;
}else if( lockType === state.sq3Codes.SQLITE_LOCK_SHARED
&& existing.mode === 'exclusive' ){
/* downgrade Exclusive -> Shared */
/* downgrade EXCLUSIVE -> SHARED */
rc = await wlCloseHandle(fh);
if( 0===rc ){
fh.xLock = lockType;
@@ -882,16 +912,6 @@ const installAsyncProxy = function(){
operation */
) || [];
//error("waitLoop() whichOp =",opId, f.opHandlers[opId].key, args);
//#if 0
if( isWebLocker && (opId==opIds.xLock || opIds==opIds.xUnlock) ){
/* An expert suggests that this introduces a race condition,
but my eyes aren't seeing it. The hope was that this
would improve the lock speed a tick, but it does not
appear to. */
hnd(...args);
continue;
}
//#/if
await hnd(...args);
}catch(e){
error('in waitLoop():', e);
+11 -16
View File
@@ -13,24 +13,19 @@
This file is a reimplementation of the "opfs" VFS (as distinct from
"opfs-sahpool") which uses WebLocks for locking instead of a bespoke
custom Atomics.wait()/notify() protocol. This file holds the
"synchronous half" of the VFS, whereas it shares the "asynchronous
half" of the "opfs" VFS.
Atomics.wait()/notify() protocol. This file holds the "synchronous
half" of the VFS, whereas it shares the "asynchronous half" with the
"opfs" VFS.
Testing has failed to show any genuine functional difference between
these VFSes other than "opfs-wl" being able to dole out xLock()
requests in a strictly FIFO manner by virtue of WebLocks being
globally managed by the browser. This tends to lead to, but does not
guaranty, fairer distribution of locks. Differences are unlikely to
be noticed except, perhaps, under very high contention.
This file is intended to be appended to the main sqlite3 JS
deliverable somewhere after sqlite3-api-oo1.js.
TODOs (2026-03-03):
- For purposes of tester1.js we need to figure out which of these
VFSes will install the (internal-use-only) sqlite3.opfs utility code
namespace. We need that in order to clean up OPFS files during test
runs. Alternately, move those into their own
sqlite3ApiBootstrap.initializers entry which precedes both of the
VFSes, so they'll have access to it during bootstrapping. The
sqlite3.opfs namespace is removed at the end of bootstrapping unless
the library is told to run in testing mode (which is not a
documented feature).
deliverable somewhere after opfs-common-shared.c-pp.js.
*/
'use strict';
globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
+7 -21
View File
@@ -269,6 +269,11 @@ EXTRA_SRC ?=
# invocations of $(B.cc)). The configure process does not set either
# of $(OPTIONS) or $(OPTS).
#
# The difference between $(OPT_FEATURE_FLAGS) and $(OPTS) is that the
# former is historically provided by the configure script, whereas
# $(OPTS) is intended to be provided as an argument to the make
# invocation.
#
OPT_FEATURE_FLAGS ?=
#
# $(SHELL_OPT) =
@@ -328,6 +333,7 @@ all: sqlite3.h sqlite3.c
CFLAGS.core ?=
CFLAGS.env = $(CFLAGS)
T.cc += $(CFLAGS.core) $(CFLAGS.env)
T.cc += $(OPT_FEATURE_FLAGS) $(OPTS)
#
# $(LDFLAGS.configure) represents any LDFLAGS=... the client passes to
@@ -349,20 +355,6 @@ T.cc += $(CFLAGS.core) $(CFLAGS.env)
#
LDFLAGS.configure ?=
#
# The difference between $(OPT_FEATURE_FLAGS) and $(OPTS) is that the
# former is historically provided by the configure script, whereas
# $(OPTS) is intended to be provided as arguments to the make
# invocation.
#
T.cc += $(OPT_FEATURE_FLAGS)
#
# Add in any optional global compilation flags on the make command
# line i.e. make "OPTS=-DSQLITE_ENABLE_FOO=1 -DSQLITE_OMIT_FOO=1".
#
T.cc += $(OPTS)
#
# $(INSTALL) invocation for use with non-executable files.
#
@@ -386,19 +378,13 @@ T.link.gcov ?=
#
T.compile = $(T.cc) $(T.compile.gcov)
#
# Optionally set by the configure script to include -DSQLITE_DEBUG=1
# and other debug-related flags.
#
T.cc.TARGET_DEBUG ?=
#
# Extra CFLAGS for both the core sqlite3 components and extensions.
#
# Define -D_HAVE_SQLITE_CONFIG_H so that the code knows it
# can include the generated sqlite_cfg.h.
#
T.cc.sqlite.extras = -D_HAVE_SQLITE_CONFIG_H -DBUILD_sqlite $(T.cc.TARGET_DEBUG)
T.cc.sqlite.extras = -D_HAVE_SQLITE_CONFIG_H -DBUILD_sqlite
#
# $(T.cc.sqlite) is $(T.cc) plus any flags which are desired for the
+61 -57
View File
@@ -1,13 +1,13 @@
C Fix\sharmless\scompiler\swarnings\sabout\sunused\svariable\sassignments.
D 2026-03-29T22:41:12.963
C Version\s3.53.0
D 2026-04-09T11:41:38.498
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 3ce07126d7e87c7464301482e161fdae6a51d0a2aa06b200b8f0000ef4d6163b
F Makefile.in 5fda086f33b144da08119255da1d2557f983d0764a13707f05acf0159fd89ba5
F Makefile.linux-generic bd3e3cacd369821a6241d4ea1967395c962dfe3057e38cb0a435cee0e8b789d0
F Makefile.msc 92391304cf70f4c178b127aa83b88637abd28d1b83ede451616144037ea1d3dd
F README.md 3fa51fc7ababc32edd175ae8b2986c86d5ea120c1cb1e57c7f7849492d1405ec
F README.md f49fbd826941842e348242f3ab62f240c985ceafdf8fbe576abf4eb75317468c
F VERSION 31435e19ded2aae3c1c67dacf06a995a37fd1b253baec5899b78d64cd29db4f7
F art/icon-243x273.gif 9750b734f82fdb3dc43127753d5e6fbf3b62c9f4e136c2fbf573b2f57ea87af5
F art/icon-80x90.gif 65509ce3e5f86a9cd64fe7fca2d23954199f31fe44c1e09e208c80fb83d87031
@@ -47,7 +47,7 @@ F autosetup/find_tclconfig.tcl e64886ffe3b982d4df42cd28ed91fe0b5940c2c5785e126c1
F autosetup/jimsh0.c 916bbdf8023fbda9937afae57d81a853d8c2ea00f2320aa27becbc33574f963d
F autosetup/pkg-config.tcl 4e635bf39022ff65e0d5434339dd41503ea48fc53822c9c5bde88b02d3d952ba
F autosetup/proj.tcl ce301197f364f7ce2acabbbd84b43d19e917ec73653157ca134a06f32d322712
F autosetup/sqlite-config.tcl b215e97ad734f148069da3efd57ac8b2b2b893e6f08d20dd1eceff1e8b95313d
F autosetup/sqlite-config.tcl 8fecce2838b7e7d990d161d08998034f3e3b0b2ddf4d7a99dbfafba9c902e302
F autosetup/system.tcl 51d4be76cd9a9074704b584e5c9cbba616202c8468cf9ba8a4f8294a7ab1dba9
F autosetup/teaish/README.txt b40071e6f8506500a2f7f71d5fc69e0bf87b9d7678dd9da1e5b4d0acbf40b1ca
F autosetup/teaish/core.tcl e014dd95900c7f9a34e8e0f460f47e94841059827bce8b4c49668b0c7ae3f1a0
@@ -56,7 +56,7 @@ F autosetup/teaish/tester.tcl 1799514c2652db49561b3386c5242b94534d1663f2cfac861a
F configure 9a00b21dfd13757bbfb8d89b30660a89ec1f8f3a79402b8f9f9b6fc475c3303a x
F contrib/sqlitecon.tcl eb4c6578e08dd353263958da0dc620f8400b869a50d06e271ab0be85a51a08d3
F doc/F2FS.txt c1d4a0ae9711cfe0e1d8b019d154f1c29e0d3abfe820787ba1e9ed7691160fcd
F doc/compile-for-unix.md c8f05bf9ff8c588c501515eb11642540572203e53d0b5eb5bf60983acdd47643
F doc/compile-for-unix.md ebd6e461c71d43291e7e8c6487c9c2716bd997053556ec757509011e77e25581
F doc/compile-for-windows.md 36601c95fa4070eebfe757684271d17a7c4a586912ba706d0b5e7817e1df54ad
F doc/json-enhancements.md e356fc834781f1f1aa22ee300027a270b2c960122468499bf347bb123ce1ea4f
F doc/jsonb.md acd77fc3a709f51242655ad7803510c886aa8304202fa9cf2abc5f5c4e9d7ae5
@@ -357,28 +357,28 @@ F ext/jni/src/tests/000-000-sanity.test c3427a0e0ac84d7cbe4c95fdc1cd4b61f9ddcf43
F ext/jni/src/tests/000-001-ignored.test e17e874c6ab3c437f1293d88093cf06286083b65bf162317f91bbfd92f961b70
F ext/jni/src/tests/900-001-fts.test bf0ce17a8d082773450e91f2388f5bbb2dfa316d0b676c313c637a91198090f0
F ext/misc/README.md 6243cdc4d7eb791c41ef0716f3980b8b5f6aa8c61ff76a3958cbf0031c6ebfa7
F ext/misc/amatch.c 0e0124c1e03ee4cb99b25969f6b7b39c53a847b8bf12279efbcb896b0df1059a
F ext/misc/amatch.c 8d237cc014b3736922c26a76a451050d244aa4980c47c531f368f817b1e77b49
F ext/misc/anycollseq.c 5ffdfde9829eeac52219136ad6aa7cd9a4edb3b15f4f2532de52f4a22525eddb
F ext/misc/appendvfs.c 9642c7a194a2a25dca7ad3e36af24a0a46d7702168c4ad7e59c9f9b0e16a3824
F ext/misc/base64.c 313bd363214ba732198f205eead2f445e5caf6248f0384bc29a0430e1edc497f
F ext/misc/base85.c 6fff354a637554f2574dbcf32d5f18898a98d4bb0ba0d73a2af91f6e87d02b62
F ext/misc/base64.c 1445761667c16356e827fc6418294c869468be934429aaa8315035e76dd58acf
F ext/misc/base85.c c713c7c81b05558c488cbdd8c68d612d5a97f9f0b8adf1167148dd7c89ce3f96
F ext/misc/basexx.c 89ad6b76558efbceb627afd5e2ef1d84b2e96d9aaf9b7ecb20e3d00b51be6fcf
F ext/misc/blobio.c a867c4c4617f6ec223a307ebfe0eabb45e0992f74dd47722b96f3e631c0edb2a
F ext/misc/btreeinfo.c 13bc9e9f1c13cde370d0e4a6a2683e9f1926a4cead7fb72c71871b11a06d78a1
F ext/misc/cksumvfs.c 9d7d0cf1a8893ac5d48922bfe9f3f217b4a61a6265f559263a02bb2001259913
F ext/misc/closure.c 5559daf1daf742228431db929d1aa86dd535a4224cc634a81d2fd0d1e6ad7839
F ext/misc/completion.c fd94e8231bb286a2eef7225368938565162daa72a8e8d06f946cc30ce15bf600
F ext/misc/closure.c c983987a8d7846c3e52b1885ed3e20af7d4ca52a81a8f94ec6d1cd68f93acc86
F ext/misc/completion.c 3f5db28e88c3313103b2dd86d910a2944fd500c46754e473493968ce81e994a4
F ext/misc/compress.c 8191118b9b73e7796c961790db62d35d9b0fb724b045e005a5713dc9e0795565
F ext/misc/csv.c 256ee522fcf505d6eeaee0a891be9decd8df53c7d8d6a3629c52e6e803adf5f7
F ext/misc/csv.c 5e9d4dd749e762c144104c0f01db5bf4458735b19081ebe481a64e589a66687a
F ext/misc/dbdump.c 678f1b9ae2317b4473f65d03132a2482c3f4b08920799ed80feedd2941a06680
F ext/misc/decimal.c b64911bcc77ed86e40075a6a51a9efb48520720f289b9be544adf6e2587094d5
F ext/misc/decimal.c 23698283d9365ce66d54b5bb97c01e69b4aa7ac804f226f9117a0d42efd15a65
F ext/misc/eval.c 04bc9aada78c888394204b4ed996ab834b99726fb59603b0ee3ed6e049755dc1
F ext/misc/explain.c 606100185fb90d6a1eade1ed0414d53503c86820d8956a06e3b0a56291894f2b
F ext/misc/fileio.c f24c7ea70f1a53f319d31034fd0001ca4015ad4bde8577faa1ecfc58b8e5a5e3
F ext/misc/fossildelta.c 86dfa83f85f7ccd640591d8a5c6865346d0c2ee6a949d78591eceb892f1cbfec
F ext/misc/fuzzer.c 684a4996b523ea89f495b38fd8a14a2ae00695089a88031366a4df6adc2c873b
F ext/misc/explain.c 9670c8ff7b255eea7845abc5123a4958e74016c16990b10497e56380f91704b9
F ext/misc/fileio.c e72033f987894ed821bf324a426ed462743399c274f1290dcb646349b6d7548f
F ext/misc/fossildelta.c 40add35db7f355d29ae856fe09043e66802fceff6f2551baccb28d794cadbc77
F ext/misc/fuzzer.c decaca5a3479dfba69576cd41d4e17161eaf154a5438e12d316bbc5853571802
F ext/misc/ieee754.c 2901d08a586d00a1d3c0fd89e03c57ee9e2b5f013b0daab9e49c7a48a9d5946b
F ext/misc/memstat.c 43705d795090efb78c85c736b89251e743c291e23daaa8382fe7a0df2c6a283d
F ext/misc/memstat.c 03ab52d2d841eb3f55118105c1964d5225f152b23bd708844c648b48d14ccbcf
F ext/misc/memtrace.c 7c0d115d2ef716ad0ba632c91e05bd119cb16c1aedf3bec9f06196ead2d5537b
F ext/misc/mmapwarm.c a81af4aaec00f24f308e2f4c19bf1d88f3ac3ce848c36daa7a4cd38145c4080d
F ext/misc/nextchar.c 7877914c2a80c2f181dd04c3dbef550dfb54c93495dc03da2403b5dd58f34edd
@@ -386,24 +386,24 @@ F ext/misc/noop.c f1a21cc9b7a4e667e5c8458d80ba680b8bd4315a003f256006046879f679c5
F ext/misc/normalize.c fbb144a861809686ff2b5b6eee8bb2e1207f9bf13ce7376e5273c700a1eafbd5
F ext/misc/pcachetrace.c f4227ce03fb16aa8d6f321b72dd051097419d7a028a9853af048bee7645cb405
F ext/misc/percentile.c 72e05a21db20a2fa85264b99515941f00ae698824c9db82d7edfbb16cea8ec80
F ext/misc/prefixes.c 82645f79229877afab08c8b08ca1e7fa31921280906b90a61c294e4f540cd2a6
F ext/misc/qpvtab.c fc189e127f68f791af90a487f4460ec91539a716daf45a0c357e963fd47cc06c
F ext/misc/prefixes.c aa15fd268e7d1336d1a1d4bc79265860d1d2ad68bba4cbcab61f83e4989dc68c
F ext/misc/qpvtab.c 470a5fffba005c8e1994209e59c1848122351e19522de71beb68d666c4fa39a5
F ext/misc/randomjson.c ef835fc64289e76ac4873b85fe12f9463a036168d7683cf2b773e36e6262c4ed
F ext/misc/regexp.c fa2d4c479e8bfe8c228d57dd4dde8e4aecb5b0abee70713853dcaa3c52d3fd8a
F ext/misc/regexp.c 9dada9e9aa91f0cc23e35429e5d1111f110cc201b4c8dcc49aa6d2fc4b2a865d
F ext/misc/remember.c add730f0f7e7436cd15ea3fd6a90fd83c3f706ab44169f7f048438b7d6baa69c
F ext/misc/rot13.c 51ac5f51e9d5fd811db58a9c23c628ad5f333c173f1fc53c8491a3603d38556c
F ext/misc/scrub.c 2a44b0d44c69584c0580ad2553f6290a307a49df4668941d2812135bfb96a946
F ext/misc/series.c 22c6d8f00cc1b5089b1b37392e9097e9df9a5db53be86daf9a7669d95bb179f4
F ext/misc/scrub.c df54e202887e480bf9cd73168c9ac829e3b0211381b68b9809e0cb5bc1bdc2cf
F ext/misc/series.c 9454c7ef27d3729432496f31caabc892aeee1c21377d403f681126d93c09d6e9
F ext/misc/sha1.c 8bf60344c11a525384c2efd1ae77f160b06be336db679effaadf292d4b41451c
F ext/misc/shathree.c fd22d70620f86a0467acfdd3acd8435d5cb54eb1e2d9ff36ae44e389826993df
F ext/misc/showauth.c 732578f0fe4ce42d577e1c86dc89dd14a006ab52
F ext/misc/spellfix.c 693c8fd3293087fa821322967a97e59dfa24051e5d2ca7fa85790a4034db6fa4
F ext/misc/sqlar.c d7774383d07c93ab2a617cad5a25db8c4ac5150e3d9ff249f23ba248fc158974
F ext/misc/sqlite3_stdio.c e49c07050bf7bdc87866da7583beda236f2f8c462018a34b61785d99cbddedfd
F ext/misc/sqlar.c 97c100b010159c08a7a9acd8eb1ea510a5522e64741aaafcd7b6c629de682edc
F ext/misc/sqlite3_stdio.c b43a0f530c6f0fb3d41d9af8c0b40f3f71198a1db55ab8ffffbef5c8cc329d22
F ext/misc/sqlite3_stdio.h 27a4ecea47e61bc9574ccdf2806f468afe23af2f95028c9b689bfa08ab1ce99f
F ext/misc/stmt.c b090086cd6bd6281c21271d38d576eeffe662f0e6b67536352ce32bbaa438321
F ext/misc/stmtrand.c 59cffa5d8e158943ff1ce078956d8e208e8c04e67307e8f249dece2436dcb7fc
F ext/misc/templatevtab.c 10f15b165b95423ddef593bc5dcb915ec4eb5e0f1066d585e5435a368b8bc22b
F ext/misc/stmtrand.c 1c7c6a478e9c808d53a2efa9a744c86c265b6b95b4a96964e1b960c7c642ad49
F ext/misc/templatevtab.c f2771161158bb78a0bfeaed9b50a018a731c7566df6a67181df0acea1920ab9c
F ext/misc/tmstmpvfs.c 240caad4441328dc52bd2871f48811db46dff858d5598030e389176837a2f4df
F ext/misc/totype.c ba11aac3c0b52c685bd25aa4e0f80c41c624fb1cc5ab763250e09ddc762bc3a8
F ext/misc/uint.c 327afc166058acf566f33a15bf47c869d2d3564612644d9ff81a23efc8b36039
@@ -411,18 +411,18 @@ F ext/misc/unionvtab.c 716d385256d5fb4beea31b0efede640807e423e85c9784d21d22f0cce
F ext/misc/urifuncs.c f71360d14fa9e7626b563f1f781c6148109462741c5235ac63ae0f8917b9c751
F ext/misc/uuid.c 5bb2264c1b64d163efa46509544fd7500cb8769cb7c16dd52052da8d961505cf
F ext/misc/vfslog.c 3932ab932eeb2601dbc4447cb14d445aaa9fbe43b863ef5f014401c3420afd20
F ext/misc/vfsstat.c 0b23c0a69a2b63dc0ef0af44f9c1fc977300c480a1f7a9814500369d8211f56e
F ext/misc/vfstrace.c 0e4b8b17ac0675ea90f6d168d8214687e06ca3efbc0060aad4814994d82b41fb
F ext/misc/vtablog.c 402496fb38add7dd2c50f2a0ad20f83a9916ceab48dcd31e62ad621e663c83ac
F ext/misc/vtshim.c e5bce24ab8c532f4fdc600148718fe1802cb6ed57417f1c1032d8961f72b0e8f
F ext/misc/wholenumber.c 0fa0c082676b7868bf2fa918e911133f2b349bcdceabd1198bba5f65b4fc0668
F ext/misc/vfsstat.c 2b21efa93062ce814fbe28e6dff2acfafa4073a14b8d02cacfb4da1d604d05a5
F ext/misc/vfstrace.c fc8c393a8316a8c20867b7e6e92908c4f81060c9e1f24d6ad9aefdc91c01dd13
F ext/misc/vtablog.c 6c0c11c4822ab6c1a205718ea7c6d1bb561d96b27104b9c1fe84d01aa62d6c9c
F ext/misc/vtshim.c f5ab480d1e33fa46a0b138359bedc9979e32798d72348e04bbe6093f9ae95c7b
F ext/misc/wholenumber.c aa5e6d786fe8d79bc100ea0e852249c026a91ae65a5c1bcb2b869cd1a7cdd6d5
F ext/misc/windirent.h 02211ce51f3034c675f2dbf4d228194d51b3ee05734678bad5106fff6292e60c
F ext/misc/zipfile.c c8ee04e1b349270b5df401ad732f5d7c387146e69b33c02fa90322760cc6fee0
F ext/misc/zipfile.c 5a583b5e72b4d777dc9f845529e6bd185d58024b633aafc93588679c78719700
F ext/misc/zorder.c bddff2e1b9661a90c95c2a9a9c7ecd8908afab5763256294dd12d609d4664eee
F ext/qrf/README.md 9e644615d7d7b77ef7e9db798765679e50c5ed12eda48bce21c9ef9eb4715e9d
F ext/qrf/dev-notes.md e68a6d91ce4c7eb296ef2daadc2bb79c95c317ad15b9fafe40850c67b29c2430
F ext/qrf/qrf.c 7334c688296f818f99c0cf37318b279ef62982a4860762096158237981fecb06
F ext/qrf/qrf.h 751fc5b102fa7e19aa4f1e2e75012fdc477bf6af7409dff36f9de5a9f3f6cf22
F ext/qrf/qrf.c 9bef1f01e0c33a8693a9a7c1b666b8dee1aa60b8bc880d562eb4dfff551a6009
F ext/qrf/qrf.h fbb223ff5789b324b3e9c22e787e4c1f53e217cff7cc5a243164d4b2e8410f4b
F ext/rbu/rbu.c 801450b24eaf14440d8fd20385aacc751d5c9d6123398df41b1b5aa804bf4ce8
F ext/rbu/rbu1.test 25870dd7db7eb5597e2b4d6e29e7a7e095abf332660f67d89959552ce8f8f255
F ext/rbu/rbu10.test 7c22caa32c2ff26983ca8320779a31495a6555737684af7aba3daaf762ef3363
@@ -540,7 +540,7 @@ F ext/session/session8.test 326f3273abf9d5d2d7d559eee8f5994c4ea74a5d935562454605
F ext/session/session9.test 0c4a8fbe7a5031f50855f020f3408e1f07fd7859f1daa1629eadcec3422072d6
F ext/session/sessionA.test 1feeab0b8e03527f08f2f1defb442da25480138f
F ext/session/sessionB.test c4fb7f8a688787111606e123a555f18ee04f65bb9f2a4bb2aa71d55ce4e6d02c
F ext/session/sessionC.test c3fade0a460d898fa42e9077b88e45c0d24ead3150268e145c8e19aeafc24ba1
F ext/session/sessionC.test 2bd42225efdf5f5b1a20f75b672665bcd4f67e2a6d7ddf7420fe7bf523ba41f8
F ext/session/sessionD.test 470ff917dc849e2eb78142ade63aaabd729d773833cff0ff01bca0eda68a21ce
F ext/session/sessionE.test b2010949c9d7415306f64e3c2072ddabc4b8250c98478d3c0c4d064bce83111d
F ext/session/sessionF.test d37ed800881e742c208df443537bf29aa49fd56eac520d0f0c6df3e6320f3401
@@ -555,11 +555,12 @@ F ext/session/sessionat.test 00c8badb35e43a2f12a716d2734a44d614ff62361979b6b8541
F ext/session/sessionbig.test 47c381e7acfabeef17d98519a3080d69151723354d220afa2053852182ca7adf
F ext/session/sessionblob.test 87faf667870b72f08e91969abd9f52a383ab7b514506ee194d64a39d8faff00a
F ext/session/sessionchange.test 6618cb1c1338a4b6df173b6ac42d09623fb71269962abf23ebb7617fe9f45a50
F ext/session/sessionchange2.test 6b5b7e3d1cc4ede43817f7fb68e3771aac4aa6500adb21a458b3e5a9fd841f83
F ext/session/sessionconflict.test 19e4a53795c4c930bfec49e809311e09b2a9e202d9446e56d7a8b139046a0c07 x
F ext/session/sessiondiff.test e89f7aedcdd89e5ebac3a455224eb553a171e9586fc3e1e6a7b3388d2648ba8d
F ext/session/sessionfault.test c2b43d01213b389a3f518e90775fca2120812ba51e50444c4066962263e45c11
F ext/session/sessionfault2.test b0d6a7c1d7398a7e800d84657404909c7d385965ea8576dc79ed344c46fbf41c
F ext/session/sessionfault3.test ce0b5d182133935c224d72507dbf1c5be1a1febf7e85d0b0fbd6d2f724b32b96
F ext/session/sessionfault3.test 9397819ec25b0960c5bc03c78613f9cb5cacc970f83e817aec1775c2a839a787
F ext/session/sessioninvert.test 9018f6a7387ac745084b6374c5e1aa14d648b372e6e1181cfab3df632b662d26 x
F ext/session/sessionmem.test f2a735db84a3e9e19f571033b725b0b2daf847f3f28b1da55a0c1a4e74f1de09
F ext/session/sessionnoact.test 4c7ae5c7d351cb5323bca62b6b095592ad24bd90a6713c178b62ab0063d23e19
@@ -570,9 +571,9 @@ F ext/session/sessionrowid.test 85187c2f1b38861a5844868126f69f9ec62223a03449a98a
F ext/session/sessionsize.test 8fcf4685993c3dbaa46a24183940ab9f5aa9ed0d23e5fb63bfffbdb56134b795
F ext/session/sessionstat1.test 5e718d5888c0c49bbb33a7a4f816366db85f59f6a4f97544a806421b85dc2dec
F ext/session/sessionwor.test 6fd9a2256442cebde5b2284936ae9e0d54bde692d0f5fd009ecef8511f4cf3fc
F ext/session/sqlite3session.c 6ebd02be470f36d41c4bd78927f39d507b62051ba025eacaed9936c769902a07
F ext/session/sqlite3session.h 7404723606074fcb2afdc6b72c206072cdb2b7d8ba097ca1559174a80bc26f7a
F ext/session/test_session.c 190110e3bd9463717248dec1272b44fe9943e57b7646d0b4200dcf11e4dccee6
F ext/session/sqlite3session.c d5c91d5b07d2b8e860f2782ae23f7b44ce929280e00645418ee84a0fd14525b2
F ext/session/sqlite3session.h 063e7bf7be2fff874456f452a224b5b3013b25682d108933b0351c93a1279b9c
F ext/session/test_session.c 2a02a68b522e2f3d4a64b2a4733af54b0f3e500769aeccd5bcbdd440103db069
F ext/wasm/GNUmakefile 68c750f173106d9d63f12c1edf1256c6f4bad9894b155da5db64322f4912de4b
F ext/wasm/README-dist.txt f01081a850ce38a56706af6b481e3a7878e24e42b314cfcd4b129f0f8427066a
F ext/wasm/README.md 2e87804e12c98f1d194b7a06162a88441d33bb443efcfe00dc6565a780d2f259
@@ -595,11 +596,11 @@ F ext/wasm/api/sqlite3-api-oo1.c-pp.js 5f203f5bb5d48a9e43ec51e791dc411c24dca8258
F ext/wasm/api/sqlite3-api-prologue.js 4336f02ac24ba58e68e355adb9da2804a1eef15a4aee961fa813c7d812a56b54
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 3f85af55609f1452b29c476e59893cbeed417c59560795f50911318e916083b1
F ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js 25e31482b04293a33d7599f1459eb552b3eb36ca10c02c816122d3308bf80cb2
F ext/wasm/api/sqlite3-vfs-helper.c-pp.js 3f828cc66758acb40e9c5b4dcfd87fd478a14c8fb7f0630264e6c7fa0e57515d
F ext/wasm/api/sqlite3-vfs-kvvfs.c-pp.js 27fb135ba3b805b66c90a7333b56080345bf1db79335c3e48b6d01ad7aa09607
F ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js 1c742ed92c0515c8ef97d2b132feb01168252bfd847fed5d52607d8a42d23c6a
F ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js 0d95dc35dfb518f0cd7bac993289a7f0753fe39c60fd6f0a5742b3f55c6e6347
F ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js 3dbd918ef037cd8fa9c7b4dccb3c8637b228638654c429e7df6acab5981c75e2
F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js 3da8fe72dc9e76614a9c102b92e777ce03f81d788b607701c828d8fcbac44b06
F ext/wasm/api/sqlite3-vtab-helper.c-pp.js 366596d8ff73d4cefb938bbe95bc839d503c3fab6c8335ce4bf52f0d8a7dee81
F ext/wasm/api/sqlite3-wasm.c ddf9d435b2e901eaceb805ff694e9609c2f32b5cf89a4f164e734a6fa303fdd2
@@ -655,7 +656,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 0ed98e9faa3a8e2ce40ec5b55781101048c13c6970bc50d456d4c2834e74f4ea
F main.mk bf77c630aeef4ed4b9270e1fd52c35147b529412c00b74ed6eb8aca3466763f6
F make.bat a136fd0b1c93e89854a86d5f4edcf0386d211e5d5ec2434480f6eea436c7420c
F mptest/config01.test 3c6adcbc50b991866855f1977ff172eb6d901271
F mptest/config02.test 4415dfe36c48785f751e16e32c20b077c28ae504
@@ -676,7 +677,7 @@ F src/btmutex.c 30dada73a819a1ef5b7583786370dce1842e12e1ad941e4d05ac29695528daea
F src/btree.c fb350c445316c1cc0529703c0b76450770a1de0ab0440641a56b19f05d6fefbe
F src/btree.h e823c46d87f63d904d735a24b76146d19f51f04445ea561f71cc3382fd1307f0
F src/btreeInt.h 9c0f9ea5c9b5f4dcaea18111d43efe95f2ac276cd86d770dce10fd99ccc93886
F src/build.c f370ed7458c1c3258bf8d83abf4af7130b2ba3a76536022e2b4d42973c53f70e
F src/build.c 8581de0af3b6c448f5d64e2d18a91ac1e7057b3bcb8b8827e1240f80d87486a4
F src/callback.c 3605bbf02bd7ed46c79cd48346db4a32fc51d67624400539c0532f4eead804ad
F src/carray.c 3efe3982d5fb323334c29328a4e189ccaef6b95612a6084ad5fa124fd5db1179
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
@@ -729,13 +730,13 @@ F src/pcache.h 092b758d2c5e4dabb30eae46d8dfad77c0f70b16bf3ff1943f7a232b0fe0d4ba
F src/pcache1.c 131ca0daf4e66b4608d2945ae76d6ed90de3f60539afbd5ef9ec65667a5f2fcd
F src/pragma.c 789ef67117b74b5be0a2db6681f7f0c55e6913791b9da309aefd280de2c8a74d
F src/prepare.c f6a6e28a281bd1d1da12f47d370a81af46159b40f73bf7fa0b276b664f9c8b7d
F src/printf.c 9abec48ffb0fc1aac72a461e2ca456b5284a39c84cddc932c86822311e059882
F src/printf.c 41fb76fcb5ed7e16aaddc659d3b23891abebea45549fe125fc2e6ec380cc7175
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 91ee40ec3f75192362cbaa0ad85316140b8dde00a184113d73a837fb6173dbcc
F src/sqlite.h.in e7acbb01518f05c5a342149ec1eeb1afcdccf9b90a6e9770a4893ae9a3c756ae
F src/shell.c.in a3288615aba1b375f7dca9801874c806e8d0d047dfe4e9253a944f4b47c7459e
F src/sqlite.h.in e2915e4a86d5e0783afb5cb72411df38d987c7f3c5aa2d5441b8e74d30b649d8
F src/sqlite3.rc 015537e6ac1eec6c7050e17b616c2ffe6f70fca241835a84a4f0d5937383c479
F src/sqlite3ext.h 1b7a0ee438bb5c2896d0609c537e917d8057b3340f6ad004d2de44f03e3d3cca
F src/sqliteInt.h bc1cbc0c23dba35b324ae85a7dbb5fb182321bbd30857fb21f3d0cba049001a5
@@ -798,7 +799,7 @@ F src/trigger.c 4bf3bfb3851d165e4404a9f9e69357345f3f7103378c07e07139fdd8aeb7bd20
F src/update.c 3e5e7ff66fa19ebe4d1b113d480639a24cc1175adbefabbd1a948a07f28e37cf
F src/upsert.c 215328c3f91623c520ec8672c44323553f12caeb4f01b1090ebdca99fdf7b4f1
F src/utf.c 7267c3fb9e2467020507601af3354c2446c61f444387e094c779dccd5ca62165
F src/util.c f264a84eda716ae009089f1d788b55718062810792b0bfa331e7899f2add39c6
F src/util.c 4f0abc15f63829e12cdfeeb490faf25ac65894b0bcc20d660e3f3757b8e2360b
F src/vacuum.c d3d35d8ae893d419ade5fa196d761a83bddcbb62137a1a157ae751ef38b26e82
F src/vdbe.c 6c57525d7db0232d52687d30da1093db0c152f14206c2ef1adf0c19a09d863e3
F src/vdbe.h 70e862ac8a11b590f8c1eaac17a0078429d42bc4ea3f757a9af0f451dd966a71
@@ -806,13 +807,13 @@ F src/vdbeInt.h c31ba4dc8d280c2b1dc89c6fcee68f2555e3813ab34279552c20b964c0e338b1
F src/vdbeapi.c 6cdcbe5c7afa754c998e73d2d5d2805556268362914b952811bdfb9c78a37cf1
F src/vdbeaux.c 81687c55682b9f4d942186695f4f7fa4743c564a985e0889def52eded9076d61
F src/vdbeblob.c b3f0640db9642fbdc88bd6ebcc83d6009514cafc98f062f675f2c8d505d82692
F src/vdbemem.c 5af6cf1253ac2aed0612b85138a1faf43f30ad38777d554db6c85b7281fa79fb
F src/vdbemem.c efacb8f229422d2a4db0ed38e49b7f3897862a98d82b261aa3b43d7a2d98c6da
F src/vdbesort.c b69220f4ea9ffea5fdef34d968c60305444eea909252a81933b54c296d9cca70
F src/vdbetrace.c 49e689f751505839742f4a243a1a566e57d5c9eaf0d33bbaa26e2de3febf7b41
F src/vdbevtab.c fc46b9cbd759dc013f0b3724549cc0d71379183c667df3a5988f7e2f1bd485f3
F src/vtab.c 5437ce986db2f70e639ce8a3fe68dcdfe64b0f1abb14eaebecdabd5e0766cc68
F src/vxworks.h 9d18819c5235b49c2340a8a4d48195ec5d5afb637b152406de95a9436beeaeab
F src/wal.c 88d94fd15a75f6eda831fa32d1148a267ea37bf0a4b69829a73dfde06244b08f
F src/wal.c 7340d4f9bb827bd349127cac6b2cf0cb7f76b9fda645f7b9b0bf7a6e0b1e2e7c
F src/wal.h ba252daaa94f889f4b2c17c027e823d9be47ce39da1d3799886bbd51f0490452
F src/walker.c d5006d6b005e4ea7302ad390957a8d41ed83faa177e412f89bc5600a7462a014
F src/where.c bffca5e4ef20d0bfbdc24f1dc13fd3f955284225a8ad25a4454635f6be39aad0
@@ -1352,7 +1353,7 @@ F test/jrnlmode3.test 556b447a05be0e0963f4311e95ab1632b11c9eaa
F test/json/README.md de59d5ba0bd2796d797115688630a6405bbf43a2891bad445ac6b9f38b83f236
F test/json/json-generator.tcl dc0dd0f393800c98658fc4c47eaa6af29d4e17527380cd28656fb261bddc8a3f
F test/json/json-q1.txt 65f9d1cdcc4cffa9823fb73ed936aae5658700cd001fde448f68bfb91c807307
F test/json/json-speed-check.sh 7d5898808ce7542762318306ae6075a30f5e7ee115c4a409f487e123afe91d88 x
F test/json/json-speed-check.sh 45862b216f1f8bbf16d74e2ad6ea20c773ee77774b299a7e0f76a22eb98e91f1 x
F test/json/jsonb-q1.txt 1e180fe6491efab307e318b22879e3a736ac9a96539bbde7911a13ee5b33abc7
F test/json101.test cf53254f0f0c1399a01b21fc58fee0e63a12a556be91b9ee9faccdb8b82c083c
F test/json102.test ea5c9811e408e115c8fc539548deef431fda4924c23cacd79dd4b783f4449f07
@@ -1513,7 +1514,7 @@ F test/pragma5.test 7b33fc43e2e41abf17f35fb73f71b49671a380ea92a6c94b6ce530a25f8d
F test/pragma6.test c5ec577ba087954b4dfa619a3cbe97b155b60a0af487527abe89b10fc17e6512
F test/pragmafault.test 275edaf3161771d37de60e5c2b412627ac94cef11739236bec12ed1258b240f8
F test/prefixes.test b524a1c44bffec225b9aec98bd728480352aa8532ac4c15771fb85e8beef65d9
F test/printf.test 685fec5a0c5af2490ab0632775a301554361d674211d690f5bee0a97b05333de
F test/printf.test bcb093ef5cbd17e2d94d93d62045ee61ed0f465c1ca123f284774e474e73a9ea
F test/printf2.test 3f55c1871a5a65507416076f6eb97e738d5210aeda7595a74ee895f2224cce60
F test/progress.test ebab27f670bd0d4eb9d20d49cef96e68141d92fb
F test/ptrchng.test ef1aa72d6cf35a2bbd0869a649b744e9d84977fc
@@ -1713,8 +1714,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 78d67079fc39caf2af3fd9d4c30bdac78dae7ec50b9fc802835e7a5189581e07 x
F test/testrunner_data.tcl 078e251983c8fc573567125147655f68132210f226c92922daf21fb913779717
F test/testrunner.tcl 6b232f0d4825dec8b967754503080fc9609fad077f582d02f86bd2d95bec4110 x
F test/testrunner_data.tcl 48c8a230fcada37f4809f95c2ba49e44bc3d520b6165c09173249c6e65b01cc1
F test/testrunner_estwork.tcl 81e2ae10238f50540f42fbf2d94913052a99bfb494b69e546506323f195dcff9
F test/thread001.test a0985c117eab62c0c65526e9fa5d1360dd1cac5b03bde223902763274ce21899
F test/thread002.test c24c83408e35ba5a952a3638b7ac03ccdf1ce4409289c54a050ac4c5f1de7502
@@ -2196,8 +2197,11 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee
F tool/warnings.sh a554d13f6e5cf3760f041b87939e3d616ec6961859c3245e8ef701d1eafc2ca2
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c
P 9fa9cd11f8f5f7591168870c6e41121221b58a4a3094e708e3fa5bab1502f190
R 3d9d1b868f679fc05545d2cf5aa8e36a
P cda5dd9bcbef2135bb9855139a11d0e22a092f9498d82eb18e7d4401264b6eb8
R 78f8c181262c6bdd7ab10b5492ff03ea
T +sym-major-release *
T +sym-release *
T +sym-version-3.53.0 *
U drh
Z e2629b4a210900f82e89295566df240e
Z 5cc2d306947f7e965f5f798b08602c26
# Remove this line to create a well-formed Fossil manifest.
+5 -2
View File
@@ -1,2 +1,5 @@
branch direct-printf
tag direct-printf
branch trunk
tag trunk
tag release
tag major-release
tag version-3.53.0
+1 -1
View File
@@ -1 +1 @@
afe7e9fd1c476c7cdcefab0adf0191a8dc3283811f72a685fff3eb6539b72dcc
4525003a53a7fc63ca75c59b22c79608659ca12f0131f52c18637f829977f20b
+1 -2
View File
@@ -5562,7 +5562,6 @@ static int collationMatch(const char *zColl, Index *pIndex){
*/
#ifndef SQLITE_OMIT_REINDEX
void sqlite3Reindex(Parse *pParse, Token *pName1, Token *pName2){
CollSeq *pColl; /* Collating sequence to be reindexed, or NULL */
char *z = 0; /* Name of a table or index or collation */
const char *zDb = 0; /* Name of the database */
int iReDb = -1; /* The database index number */
@@ -5601,7 +5600,7 @@ void sqlite3Reindex(Parse *pParse, Token *pName1, Token *pName2){
isExprIdx = 1;
bMatch = 1;
}
if( zDb==0 && (pColl = sqlite3FindCollSeq(db, ENC(db), z, 0))!=0 ){
if( zDb==0 && sqlite3FindCollSeq(db, ENC(db), z, 0)!=0 ){
zColl = z;
bMatch = 1;
}
+1 -1
View File
@@ -621,7 +621,7 @@ void sqlite3_str_vappendf(
e2 = s.iDP - 1;
}
szBufNeeded = MAX(e2,0)+(i64)precision+(i64)width+8;
szBufNeeded = MAX(e2,0)+(i64)precision+(i64)width+10;
if( cThousand && e2>0 ) szBufNeeded += (e2+2)/3;
if( sqlite3StrAccumEnlargeIfNeeded(pAccum, szBufNeeded) ){
width = length = 0;
+20
View File
@@ -12869,6 +12869,22 @@ static int vfstraceOut(const char *z, void *pArg){
return 1;
}
#if defined(SQLITE_DEBUG) && !defined(SQLITE_SHELL_FIDDLE)
/* Ensure that sqlite3_reset_auto_extension() clears auto-extension
** memory. https://sqlite.org/forum/forumpost/310cb231b07c80d1.
** Testing this: if we (inadvertently) remove the
** sqlite3_reset_auto_extension() call from main(), most shell tests
** will fail because of a leak message in their output. */
static int auto_ext_leak_tester(
sqlite3 *db,
char **pzErrMsg,
const struct sqlite3_api_routines *pThunk
){
(void)db; (void)pzErrMsg; (void)pThunk;
return SQLITE_OK;
}
#endif
/* Alternative name to the entry point for Fiddle */
#ifdef SQLITE_SHELL_FIDDLE
# define main fiddle_main
@@ -13271,6 +13287,9 @@ int SQLITE_CDECL main(int argc, char **argv){
}
#ifndef SQLITE_SHELL_FIDDLE
sqlite3_appendvfs_init(0,0,0);
#ifdef SQLITE_DEBUG
sqlite3_auto_extension( (void (*)())auto_ext_leak_tester );
#endif
#endif
modeDefault(&data);
@@ -13648,6 +13667,7 @@ int SQLITE_CDECL main(int argc, char **argv){
if( bEnableVfstrace ){
vfstrace_unregister("trace");
}
sqlite3_reset_auto_extension();
#ifdef SQLITE_DEBUG
if( sqlite3_memory_used()>mem_main_enter ){
cli_printf(stderr,"Memory leaked: %u bytes\n",
+51 -47
View File
@@ -578,7 +578,7 @@ int sqlite3_exec(
#define SQLITE_WARNING_AUTOINDEX (SQLITE_WARNING | (1<<8))
#define SQLITE_AUTH_USER (SQLITE_AUTH | (1<<8))
#define SQLITE_OK_LOAD_PERMANENTLY (SQLITE_OK | (1<<8))
#define SQLITE_OK_SYMLINK (SQLITE_OK | (2<<8)) /* internal use only */
#define SQLITE_OK_SYMLINK (SQLITE_OK | (2<<8)) /* internal only */
/*
** CAPI3REF: Flags For File Open Operations
@@ -1717,7 +1717,8 @@ int sqlite3_os_end(void);
** are called "anytime configuration options".
** ^If sqlite3_config() is called after [sqlite3_initialize()] and before
** [sqlite3_shutdown()] with a first argument that is not an anytime
** configuration option, then the sqlite3_config() call will return SQLITE_MISUSE.
** configuration option, then the sqlite3_config() call will
** return SQLITE_MISUSE.
** Note, however, that ^sqlite3_config() can be called as part of the
** implementation of an application-defined [sqlite3_os_init()].
**
@@ -2283,9 +2284,10 @@ struct sqlite3_mem_methods {
** is less than 8. The "sz" argument should be a multiple of 8 less than
** 65536. If "sz" does not meet this constraint, it is reduced in size until
** it does.
** <li><p>The third argument ("cnt") is the number of slots. Lookaside is disabled
** if "cnt"is less than 1. The "cnt" value will be reduced, if necessary, so
** that the product of "sz" and "cnt" does not exceed 2,147,418,112. The "cnt"
** <li><p>The third argument ("cnt") is the number of slots.
** Lookaside is disabled if "cnt"is less than 1.
* The "cnt" value will be reduced, if necessary, so
** that the product of "sz" and "cnt" does not exceed 2,147,418,112. The "cnt"
** parameter is usually chosen so that the product of "sz" and "cnt" is less
** than 1,000,000.
** </ol>
@@ -2664,7 +2666,7 @@ struct sqlite3_mem_methods {
** This option takes two arguments which are an integer and a pointer
** to an integer. The first argument is a small integer, between 3 and 23, or
** zero. The FP_DIGITS setting is changed to that small integer, or left
** unaltered if the first argument is zero or out of range. The second argument
** unaltered if the first argument is zero or out of range. The second argument
** is a pointer to an integer. If the pointer is not NULL, then the value of
** the FP_DIGITS setting, after possibly being modified by the first
** arguments, is written into the integer to which the second argument points.
@@ -2676,10 +2678,12 @@ struct sqlite3_mem_methods {
**
** <p>Most of the SQLITE_DBCONFIG options take two arguments, so that the
** overall call to [sqlite3_db_config()] has a total of four parameters.
** The first argument (the third parameter to sqlite3_db_config()) is an integer.
** The second argument is a pointer to an integer. If the first argument is 1,
** then the option becomes enabled. If the first integer argument is 0, then the
** option is disabled. If the first argument is -1, then the option setting
** The first argument (the third parameter to sqlite3_db_config()) is
** an integer.
** The second argument is a pointer to an integer. If the first argument is 1,
** then the option becomes enabled. If the first integer argument is 0,
** then the option is disabled.
** If the first argument is -1, then the option setting
** is unchanged. The second argument, the pointer to an integer, may be NULL.
** If the second argument is not NULL, then a value of 0 or 1 is written into
** the integer to which the second argument points, depending on whether the
@@ -5856,8 +5860,9 @@ int sqlite3_create_window_function(
** of the strings must be aligned to a 2-byte boundary.
**
** [[SQLITE_UTF8_ZT]] <dt>SQLITE_UTF8_ZT</dt><dd>This option can only be
** used to specify the text encoding to strings input to [sqlite3_result_text64()]
** and [sqlite3_bind_text64()]. It means that the input string (call it "z")
** used to specify the text encoding to strings input to
** [sqlite3_result_text64()] and [sqlite3_bind_text64()].
** The SQLITE_UTF8_ZT encoding means that the input string (call it "z")
** is UTF-8 encoded and that it is zero-terminated. If the length parameter
** (call it "n") is non-negative, this encoding option means that the caller
** guarantees that z array contains at least n+1 bytes and that the z&#91;n&#93;
@@ -6109,26 +6114,22 @@ SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int64,int),
** the SQL function that supplied the [sqlite3_value*] parameters.
**
** As long as the input parameter is correct, these routines can only
** fail if an out-of-memory error occurs during a format conversion.
** Only the following subset of interfaces are subject to out-of-memory
** errors:
**
** <ul>
** <li> sqlite3_value_blob()
** <li> sqlite3_value_text()
** <li> sqlite3_value_text16()
** <li> sqlite3_value_text16le()
** <li> sqlite3_value_text16be()
** <li> sqlite3_value_bytes()
** <li> sqlite3_value_bytes16()
** </ul>
**
** fail if an out-of-memory error occurs while trying to do a
** UTF8&rarr;UTF16 or UTF16&rarr;UTF8 conversion.
** If an out-of-memory error occurs, then the return value from these
** routines is the same as if the column had contained an SQL NULL value.
** Valid SQL NULL returns can be distinguished from out-of-memory errors
** by invoking the [sqlite3_errcode()] immediately after the suspect
** If the input sqlite3_value was not obtained from [sqlite3_value_dup()],
** then valid SQL NULL returns can also be distinguished from
** out-of-memory errors after extracting the value
** by invoking the [sqlite3_errcode()] immediately after the suspicious
** return value is obtained and before any
** other SQLite interface is called on the same [database connection].
** If the input sqlite3_value was obtained from sqlite3_value_dup() then
** it is disconnected from the database connection and so sqlite3_errcode()
** will not work.
** In that case, the only way to distinguish an out-of-memory
** condition from a true SQL NULL is to invoke sqlite3_value_type() on the
** input to see if it is NULL prior to trying to extract the value.
*/
const void *sqlite3_value_blob(sqlite3_value*);
double sqlite3_value_double(sqlite3_value*);
@@ -6155,7 +6156,8 @@ int sqlite3_value_frombind(sqlite3_value*);
** of the value X, assuming that X has type TEXT.)^ If sqlite3_value_type(X)
** returns something other than SQLITE_TEXT, then the return value from
** sqlite3_value_encoding(X) is meaningless. ^Calls to
** [sqlite3_value_text(X)], [sqlite3_value_text16(X)], [sqlite3_value_text16be(X)],
** [sqlite3_value_text(X)], [sqlite3_value_text16(X)],
** [sqlite3_value_text16be(X)],
** [sqlite3_value_text16le(X)], [sqlite3_value_bytes(X)], or
** [sqlite3_value_bytes16(X)] might change the encoding of the value X and
** thus change the return from subsequent calls to sqlite3_value_encoding(X).
@@ -6286,17 +6288,17 @@ sqlite3 *sqlite3_context_db_handle(sqlite3_context*);
** query execution, under some circumstances the associated auxiliary data
** might be preserved. An example of where this might be useful is in a
** regular-expression matching function. The compiled version of the regular
** expression can be stored as auxiliary data associated with the pattern string.
** Then as long as the pattern string remains the same,
** expression can be stored as auxiliary data associated with the pattern
** string. Then as long as the pattern string remains the same,
** the compiled regular expression can be reused on multiple
** invocations of the same function.
**
** ^The sqlite3_get_auxdata(C,N) interface returns a pointer to the auxiliary data
** associated by the sqlite3_set_auxdata(C,N,P,X) function with the Nth argument
** value to the application-defined function. ^N is zero for the left-most
** function argument. ^If there is no auxiliary data
** associated with the function argument, the sqlite3_get_auxdata(C,N) interface
** returns a NULL pointer.
** ^The sqlite3_get_auxdata(C,N) interface returns a pointer to the auxiliary
** data associated by the sqlite3_set_auxdata(C,N,P,X) function with the
** Nth argument value to the application-defined function. ^N is zero
** for the left-most function argument. ^If there is no auxiliary data
** associated with the function argument, the sqlite3_get_auxdata(C,N)
** interface returns a NULL pointer.
**
** ^The sqlite3_set_auxdata(C,N,P,X) interface saves P as auxiliary data for the
** N-th argument of the application-defined function. ^Subsequent
@@ -7613,7 +7615,7 @@ int sqlite3_enable_load_extension(sqlite3 *db, int onoff);
** <blockquote><pre>
** &nbsp; int xEntryPoint(
** &nbsp; sqlite3 *db,
** &nbsp; const char **pzErrMsg,
** &nbsp; char **pzErrMsg,
** &nbsp; const struct sqlite3_api_routines *pThunk
** &nbsp; );
** </pre></blockquote>)^
@@ -10409,7 +10411,8 @@ const char *sqlite3_vtab_collation(sqlite3_index_info*,int);
** <tr>
** <td valign="top">sqlite3_vtab_distinct() return value
** <td valign="top">Rows are returned in aOrderBy order
** <td valign="top">Rows with the same value in all aOrderBy columns are adjacent
** <td valign="top">Rows with the same value in all aOrderBy columns are
** adjacent
** <td valign="top">Duplicates over all colUsed columns may be omitted
** <tr><td>0<td>yes<td>yes<td>no
** <tr><td>1<td>no<td>yes<td>no
@@ -10418,8 +10421,8 @@ const char *sqlite3_vtab_collation(sqlite3_index_info*,int);
** </table>
**
** ^For the purposes of comparing virtual table output values to see if the
** values are the same value for sorting purposes, two NULL values are considered
** to be the same. In other words, the comparison operator is "IS"
** values are the same value for sorting purposes, two NULL values are
** considered to be the same. In other words, the comparison operator is "IS"
** (or "IS NOT DISTINCT FROM") and not "==".
**
** If a virtual table implementation is unable to meet the requirements
@@ -11273,12 +11276,13 @@ int sqlite3_deserialize(
**
** The sqlite3_carray_bind_v2(S,I,P,N,F,X,D) interface binds an array value to
** parameter that is the first argument of the [carray() table-valued function].
** The S parameter is a pointer to the [prepared statement] that uses the carray()
** functions. I is the parameter index to be bound. I must be the index of the
** parameter that is the first argument to the carray() table-valued function.
** P is a pointer to the array to be bound, and N is the number of elements in
** the array. The F argument is one of constants [SQLITE_CARRAY_INT32],
** [SQLITE_CARRAY_INT64], [SQLITE_CARRAY_DOUBLE], [SQLITE_CARRAY_TEXT],
** The S parameter is a pointer to the [prepared statement] that uses the
** carray() functions. I is the parameter index to be bound. I must be the
** index of the parameter that is the first argument to the carray()
** table-valued function. P is a pointer to the array to be bound, and N
** is the number of elements in the array. The F argument is one of
** constants [SQLITE_CARRAY_INT32], [SQLITE_CARRAY_INT64],
** [SQLITE_CARRAY_DOUBLE], [SQLITE_CARRAY_TEXT],
** or [SQLITE_CARRAY_BLOB] to indicate the datatype of the array P.
**
** If the X argument is not a NULL pointer or one of the special
+8 -5
View File
@@ -827,12 +827,15 @@ static double sqlite3Fp10Convert2(u64 d, int p){
** Lower bits of the return value contain addition information about the
** parse:
**
** bit 0 => Set for any valid input
** bit 1 => Input contains a decimal point or eNNN clause
** This bit is zero if the input is an integer
** bit 0 => Set if any prefix of the input is valid. Clear if
** there is no prefix of the input that can be seen as
** a valid floating point number.
** bit 1 => Set if the input contains a decimal point or eNNN
** clause. Zero if the input is an integer.
** bit 2 => The input is exactly 0.0, not an underflow from
** some value near zero
** bit 3 => More than 19 significant digits in the input
** some value near zero.
** bit 3 => Set if there are more than about 19 significant
** digits in the input.
**
** If the input contains a syntax error but begins with text that might
** be a valid number of some kind, then the result is negative. The
+1 -1
View File
@@ -733,7 +733,7 @@ static SQLITE_NOINLINE int sqlite3MemRealValueRCSlowPath(
** decimal point or eNNN suffix.
*/
int sqlite3MemRealValueRC(Mem *pMem, double *pValue){
assert( pMem->db!=0 );
testcase( pMem->db==0 );
assert( pMem->flags & (MEM_Str|MEM_Blob) );
if( pMem->z==0 ){
*pValue = 0.0;
+6 -3
View File
@@ -1126,7 +1126,7 @@ static void walUnlockExclusive(Wal *pWal, int lockIdx, int n){
/*
** Compute a hash on a page number. The resulting hash value must land
** between 0 and (HASHTABLE_NSLOT-1). The walHashNext() function advances
** between 0 and (HASHTABLE_NSLOT-1). The walNextHash() function advances
** the hash to the next value in the event of a collision.
*/
static int walHash(u32 iPage){
@@ -1334,7 +1334,7 @@ static int walIndexAppend(Wal *pWal, u32 iFrame, u32 iPage){
for(iKey=walHash(iPage); sLoc.aHash[iKey]; iKey=walNextHash(iKey)){
if( (nCollide--)==0 ) return SQLITE_CORRUPT_BKPT;
}
sLoc.aPgno[idx-1] = iPage;
sLoc.aPgno[(idx-1)&(HASHTABLE_NPAGE-1)] = iPage;
AtomicStore(&sLoc.aHash[iKey], (ht_slot)idx);
#ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT
@@ -3582,7 +3582,10 @@ static int walFindFrame(
SEH_INJECT_FAULT;
while( (iH = AtomicLoad(&sLoc.aHash[iKey]))!=0 ){
u32 iFrame = iH + sLoc.iZero;
if( iFrame<=iLast && iFrame>=pWal->minFrame && sLoc.aPgno[iH-1]==pgno ){
if( iFrame<=iLast
&& iFrame>=pWal->minFrame
&& sLoc.aPgno[(iH-1)&(HASHTABLE_NPAGE-1)]==pgno
){
assert( iFrame>iRead || CORRUPT_DB );
iRead = iFrame;
}
+1 -1
View File
@@ -72,7 +72,7 @@ done
echo "NAME = $NAME" | tee summary-$NAME.txt
echo "CC_OPTS = $CC_OPTS" | tee -a summary-$NAME.txt
rm -f cachegrind.out.* jsonshell
$CC -g -Os -Wall -I. $CC_OPTS ./shell.c ./sqlite3.c -o jsonshell -ldl -lpthread
$CC -g -Os -Wall -I. $CC_OPTS ./shell.c ./sqlite3.c -o jsonshell -lm -ldl -lpthread
ls -l jsonshell | tee -a summary-$NAME.txt
home=`echo $0 | sed -e 's,/[^/]*$,,'`
DB=$TYPE''100mb.db
+5
View File
@@ -3823,6 +3823,11 @@ do_execsql_test printf-17.11 {
SELECT format('%.30f',1.0000000000000000076e-50);
} 0.000000000000000000000000000000
# Reported by OpenAI Codex Security on 2026-04-08
do_execsql_test printf-17.12 {
SELECT format('%!.0e',-1e100);
} -1.0e+100
#-------------------------------------------------------------------------
# dbsqlfuzz ad651aad4bb2100f3a724129a555d8d773366d46
#
+26 -4
View File
@@ -141,7 +141,10 @@ are run. Otherwise, each pattern is interpreted as a glob pattern. Only
those tcl tests for which the final component of the filename matches at
least one specified pattern are run. The glob wildcard '*' is prepended
to the pattern if it does not start with '^' and appended to every
pattern that does not end with '$'.
pattern that does not end with '$'. If PATTERN begins with "~", then it
is an anti-pattern that only matches tests that do not match PATTERN.
Tests or only run if they match one or more patterns and match no
anti-patterns.
If no PATTERN arguments are present, then various fuzztest, threadtest
and other tests are run as part of the "release" permutation. These are
@@ -1124,10 +1127,21 @@ proc add_job {args} {
#
# An empty patternlist matches everything
#
# Entries of patternlist that begin with "~" mean "match anything that
# does not match the following pattern". For example, a patternlist
# of {fuzzcheck ~san} will match "fuzzcheck" but not "fuzzcheck-asan".
#
proc job_matches_any_pattern {patternlist jobcmd} {
set bMatch 0
set bMiss 0
if {[llength $patternlist]==0} {return 1}
foreach p $patternlist {
if {[string index $p 0] eq "~"} {
set p [string range $p 1 end]
set not 1
} else {
set not 0
}
set p [string trim $p *]
if {[string index $p 0]=="^"} {
set p [string range $p 1 end]
@@ -1139,11 +1153,19 @@ proc job_matches_any_pattern {patternlist jobcmd} {
} else {
set p "$p*"
}
if {[string match $p $jobcmd]} {
set bMatch 1
break
if {$not} {
if {[string match $p $jobcmd]} {return 0}
} else {
if {[string match $p $jobcmd]} {
set bMatch 1
} else {
set bMiss 1
}
}
}
if {!$bMiss} {
set bMatch 1
}
return $bMatch
}
+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"