Compare commits
139 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 84c1079220 | |||
| c8d866294b | |||
| 9efde40a5d | |||
| 09f37099a7 | |||
| 526acc1834 | |||
| d962afef2d | |||
| 395ac6c1bc | |||
| e9d0bc6b68 | |||
| ab6a63ec67 | |||
| 57ed7f322f | |||
| 34c2c8dc47 | |||
| 3f9df1f5fb | |||
| 2eeac123c8 | |||
| 64a123a216 | |||
| a10e79d91a | |||
| d20673a95f | |||
| f02d100e08 | |||
| 4c8f0621fd | |||
| 6abc21cfb8 | |||
| 20079bb358 | |||
| 3d6fa49c54 | |||
| 4df365e5a7 | |||
| 9d8bf6f04a | |||
| c0026ff7a6 | |||
| 1e3f888acf | |||
| 2d4dfbccdc | |||
| 6142310e08 | |||
| 42ae7e7f34 | |||
| 57cf5c2dfc | |||
| a212476ad2 | |||
| d08caad3a5 | |||
| 28456958ca | |||
| 3b27ffa534 | |||
| fc2c730c87 | |||
| cd28797117 | |||
| c8b130f255 | |||
| 7a0a0a22e7 | |||
| 504cfd5ec7 | |||
| 9d950aa13b | |||
| b709ba8108 | |||
| 01e1be854b | |||
| 70868a5ae3 | |||
| d0065c8118 | |||
| bd574dbaee | |||
| 7632922625 | |||
| 49998a6d25 | |||
| 92c435cda7 | |||
| 35f8abcfd0 | |||
| 1a315c0d51 | |||
| 3a8d38ffc0 | |||
| 693b15ac83 | |||
| 8cdc2abf07 | |||
| 931fa90d74 | |||
| eb9a6a95ca | |||
| b37bf0b8b4 | |||
| 850104bbad | |||
| 6a6ebb0d06 | |||
| 30b824e432 | |||
| 3944e70677 | |||
| df0e915ad2 | |||
| b0d9039c8c | |||
| f1cc3c4be5 | |||
| 3aed7dc446 | |||
| 9a8732e44b | |||
| 4ebc7fdcf4 | |||
| a5495355c4 | |||
| df3e207501 | |||
| 535b1f2875 | |||
| a7200804eb | |||
| 0d979c217f | |||
| e9af8caac0 | |||
| 606c64a543 | |||
| eefe3aa9ad | |||
| fcef193a82 | |||
| 8e7ffc09f5 | |||
| 9ad63c0f4e | |||
| d4b74b9fac | |||
| 7ff8b558e8 | |||
| bb6d2a5f07 | |||
| 217c590688 | |||
| fc19b2ca8a | |||
| 939930db1e | |||
| 62f3150204 | |||
| 34e139d3a3 | |||
| 6e6598c8ff | |||
| e230de2cbf | |||
| eb8edc0bac | |||
| d6226a9c27 | |||
| d9f047bd15 | |||
| 5e4fb95edf | |||
| 60b829e0db | |||
| f92d107242 | |||
| b060cecb2e | |||
| 9660a4dec0 | |||
| 0cb576f306 | |||
| 6d27844bbe | |||
| 03f13d77a5 | |||
| 445fbc61c8 | |||
| eb0cb3f53b | |||
| 5239e69fb1 | |||
| 20d93e16d7 | |||
| c409eaaf14 | |||
| 2e01416762 | |||
| ff8a0895d6 | |||
| a2f78f665c | |||
| c4cedd7ffe | |||
| 00c6eca32c | |||
| be2242d2ee | |||
| 2dd3b4a646 | |||
| 4570aeb7bc | |||
| 1283969f26 | |||
| 772ea2f01c | |||
| d4af925e34 | |||
| 61d3bc8ddc | |||
| f9a3b78561 | |||
| f855727e45 | |||
| 3d58f022a8 | |||
| 7e9eaf3c1f | |||
| 0944b3efad | |||
| f3f194c385 | |||
| 183a73c352 | |||
| 53197b7940 | |||
| f1f1784f4b | |||
| 814f592cf0 | |||
| 9b805c6248 | |||
| 3c2ccd2903 | |||
| 7bf4d708dc | |||
| 5239e821e8 | |||
| a217a4af09 | |||
| 3e3c31ff0e | |||
| dc32016ee0 | |||
| 5700f8c471 | |||
| 80b88b2482 | |||
| 8e7f122c7d | |||
| c1975b6a6f | |||
| de88171c4c | |||
| 613cf76c2f | |||
| c289cf57a7 | |||
| 817c509365 |
+11
-3
@@ -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@
|
||||
|
||||
@@ -2627,6 +2627,12 @@ smoketest: $(TESTPROGS)
|
||||
@set PATH=$(LIBTCLPATH);$(PATH)
|
||||
.\testfixture.exe $(TOP)\test\main.test $(TESTOPTS)
|
||||
|
||||
# Measure the performance of floating-point conversions.
|
||||
#
|
||||
fp-speed-test: fp-speed-1.exe fp-speed-2.exe
|
||||
fp-speed-1 1000000
|
||||
fp-speed-2 1000000
|
||||
|
||||
shelltest:
|
||||
$(TCLSH_CMD) $(TOP)\test\testrunner.tcl release shell
|
||||
|
||||
@@ -2719,6 +2725,14 @@ speedtest1.exe: $(TOP)\test\speedtest1.c $(SQLITE3C) $(SQLITE3H)
|
||||
$(LTLINK) $(NO_WARN) $(ST_COMPILE_OPTS) -DSQLITE_OMIT_LOAD_EXTENSION \
|
||||
$(TOP)\test\speedtest1.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS)
|
||||
|
||||
fp-speed-1.exe: $(TOP)\test\fp-speed-1.c $(SQLITE3C) $(SQLITE3H)
|
||||
$(LTLINK) $(NO_WARN) $(ST_COMPILE_OPTS) -DSQLITE_OMIT_LOAD_EXTENSION \
|
||||
$(TOP)\test\fp-speed-1.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS)
|
||||
|
||||
fp-speed-2.exe: $(TOP)\test\fp-speed-2.c $(SQLITE3C) $(SQLITE3H)
|
||||
$(LTLINK) $(NO_WARN) $(ST_COMPILE_OPTS) -DSQLITE_OMIT_LOAD_EXTENSION \
|
||||
$(TOP)\test\fp-speed-2.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS)
|
||||
|
||||
kvtest.exe: $(TOP)\test\kvtest.c $(SQLITE3C) $(SQLITE3H)
|
||||
$(LTLINK) $(NO_WARN) $(KV_COMPILE_OPTS) \
|
||||
$(TOP)\test\kvtest.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS)
|
||||
@@ -2908,6 +2922,7 @@ clean:
|
||||
del /Q LogEst.exe fts3view.exe rollback-test.exe showdb.exe dbdump.exe 2>NUL
|
||||
del /Q changeset.exe 2>NUL
|
||||
del /Q showjournal.exe showstat4.exe showwal.exe speedtest1.exe 2>NUL
|
||||
del /Q fp-speed-1.exe fp-speed-2.exe 2>NUL
|
||||
del /Q mptester.exe wordcount.exe rbu.exe srcck1.exe 2>NUL
|
||||
del /Q sqlite3.c sqlite3-*.c sqlite3.h 2>NUL
|
||||
del /Q sqlite3rc.h 2>NUL
|
||||
@@ -2922,4 +2937,5 @@ clean:
|
||||
del /Q fts5.* fts5parse.* 2>NUL
|
||||
del /q src-verify.exe 2>NUL
|
||||
del /q jimsh.exe jimsh0.exe 2>NUL
|
||||
-$(TCLSH_CMD) test/testrunner.tcl clean
|
||||
# <</mark>>
|
||||
|
||||
@@ -80,8 +80,8 @@ Then run commands like this:
|
||||
fossil open https://sqlite.org/src
|
||||
|
||||
The initial "fossil open" command will take two or three minutes. Afterwards,
|
||||
you can do fast, bandwidth-efficient updates to the whatever versions
|
||||
of SQLite you like. Some examples:
|
||||
you can do fast, bandwidth-efficient updates to whatever versions of SQLite you
|
||||
like. Some examples:
|
||||
|
||||
fossil update trunk ;# latest trunk check-in
|
||||
fossil update release ;# latest official release
|
||||
@@ -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:
|
||||
|
||||
|
||||
+1657
-972
File diff suppressed because it is too large
Load Diff
@@ -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
@@ -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
|
||||
  `--with-linenoise=$HOME/linenoise`   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
@@ -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;
|
||||
|
||||
@@ -0,0 +1,827 @@
|
||||
/*
|
||||
** 2026-04-13
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
******************************************************************************
|
||||
**
|
||||
** Partial reimplement of the sqlite3_analyzer utility program as
|
||||
** loadable SQL function.
|
||||
*/
|
||||
#include "sqlite3ext.h"
|
||||
SQLITE_EXTENSION_INIT1
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <math.h>
|
||||
|
||||
/*
|
||||
** State information for the analysis
|
||||
*/
|
||||
typedef struct Analysis Analysis;
|
||||
struct Analysis {
|
||||
sqlite3 *db; /* Database connection */
|
||||
sqlite3_context *context; /* SQL function context */
|
||||
sqlite3_str *pOut; /* Write output here */
|
||||
char *zSU; /* Name of the temp.space_used table */
|
||||
const char *zSchema; /* Schema to be analyzed */
|
||||
};
|
||||
|
||||
/*
|
||||
** Free all resources that the Analysis object references and
|
||||
** reset the Analysis object.
|
||||
**
|
||||
** Call this routine multiple times on the same Analysis object
|
||||
** is a harmless no-op, as long as the memory for the object itself
|
||||
** has not been freed.
|
||||
*/
|
||||
static void analysisReset(Analysis *p){
|
||||
if( p->zSU ){
|
||||
char *zSql = sqlite3_mprintf("DROP TABLE temp.%s;", p->zSU);
|
||||
if( zSql ){
|
||||
sqlite3_exec(p->db, zSql, 0, 0, 0);
|
||||
sqlite3_free(zSql);
|
||||
}
|
||||
}
|
||||
sqlite3_str_free(p->pOut);
|
||||
sqlite3_free(p->zSU);
|
||||
memset(p, 0, sizeof(*p));
|
||||
}
|
||||
|
||||
/*
|
||||
** Report an error using formatted text. If zFormat==NULL then report
|
||||
** an OOM error.
|
||||
*/
|
||||
static void analysisError(Analysis *p, const char *zFormat, ...){
|
||||
char *zErr;
|
||||
if( zFormat ){
|
||||
va_list ap;
|
||||
va_start(ap, zFormat);
|
||||
zErr = sqlite3_vmprintf(zFormat, ap);
|
||||
va_end(ap);
|
||||
}else{
|
||||
zErr = 0;
|
||||
}
|
||||
if( zErr==0 ){
|
||||
sqlite3_result_error_nomem(p->context);
|
||||
}else{
|
||||
sqlite3_result_error(p->context, zErr, -1);
|
||||
sqlite3_free(zErr);
|
||||
}
|
||||
analysisReset(p);
|
||||
}
|
||||
|
||||
/*
|
||||
** Prepare and return an SQL statement.
|
||||
*/
|
||||
static sqlite3_stmt *analysisVPrep(Analysis *p, const char *zFmt, va_list ap){
|
||||
char *zSql;
|
||||
int rc;
|
||||
sqlite3_stmt *pStmt = 0;
|
||||
zSql = sqlite3_vmprintf(zFmt, ap);
|
||||
if( zSql==0 ){ analysisError(p,0); return 0; }
|
||||
rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
|
||||
if( rc ){
|
||||
analysisError(p, "SQL parse error: %s\nOriginal SQL: %s",
|
||||
sqlite3_errmsg(p->db), zSql);
|
||||
sqlite3_finalize(pStmt);
|
||||
analysisReset(p);
|
||||
pStmt = 0;
|
||||
}
|
||||
sqlite3_free(zSql);
|
||||
return pStmt;
|
||||
}
|
||||
static sqlite3_stmt *analysisPrepare(Analysis *p, const char *zFormat, ...){
|
||||
va_list ap;
|
||||
sqlite3_stmt *pStmt = 0;
|
||||
va_start(ap, zFormat);
|
||||
pStmt = analysisVPrep(p,zFormat,ap);
|
||||
va_end(ap);
|
||||
return pStmt;
|
||||
}
|
||||
|
||||
/*
|
||||
** If rc is something other than SQLITE_DONE or SQLITE_OK, then report
|
||||
** an error and return true.
|
||||
**
|
||||
** If rc is SQLITE_DONE or SQLITE_OK, then return false.
|
||||
**
|
||||
** The prepared statement is closed in either case.
|
||||
*/
|
||||
static int analysisStmtFinish(Analysis *p, int rc, sqlite3_stmt *pStmt){
|
||||
if( rc==SQLITE_DONE ){
|
||||
rc = SQLITE_OK;
|
||||
}
|
||||
if( rc!=SQLITE_OK || (rc = sqlite3_reset(pStmt))!=SQLITE_OK ){
|
||||
analysisError(p, "SQL run-time error: %s\nOriginal SQL: %s",
|
||||
sqlite3_errmsg(p->db), sqlite3_sql(pStmt));
|
||||
analysisReset(p);
|
||||
}
|
||||
sqlite3_finalize(pStmt);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Run SQL. Return the number of errors.
|
||||
*/
|
||||
static int analysisSql(Analysis *p, const char *zFormat, ...){
|
||||
va_list ap;
|
||||
int rc;
|
||||
sqlite3_stmt *pStmt = 0;
|
||||
va_start(ap, zFormat);
|
||||
pStmt = analysisVPrep(p,zFormat,ap);
|
||||
va_end(ap);
|
||||
if( pStmt==0 ) return 1;
|
||||
while( (rc = sqlite3_step(pStmt))==SQLITE_ROW ){}
|
||||
if( rc==SQLITE_DONE ){
|
||||
rc = SQLITE_OK;
|
||||
}else{
|
||||
analysisError(p, "SQL run-time error: %s\nOriginal SQL: %s",
|
||||
sqlite3_errmsg(p->db), sqlite3_sql(pStmt));
|
||||
analysisReset(p);
|
||||
}
|
||||
sqlite3_finalize(pStmt);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Run an SQL query that returns an integer. Write that integer
|
||||
** into *piRes. Return the number of errors.
|
||||
*/
|
||||
static int analysisSqlInt(
|
||||
Analysis *p,
|
||||
sqlite3_int64 *piRes,
|
||||
const char *zFormat, ...
|
||||
){
|
||||
va_list ap;
|
||||
int rc;
|
||||
sqlite3_stmt *pStmt = 0;
|
||||
va_start(ap, zFormat);
|
||||
pStmt = analysisVPrep(p,zFormat,ap);
|
||||
va_end(ap);
|
||||
if( pStmt==0 ) return 1;
|
||||
rc = sqlite3_step(pStmt);
|
||||
if( rc==SQLITE_ROW ){
|
||||
*piRes = sqlite3_column_int64(pStmt, 0);
|
||||
rc = SQLITE_OK;
|
||||
}else if( rc==SQLITE_DONE ){
|
||||
rc = SQLITE_OK;
|
||||
}else{
|
||||
if( p->db ){
|
||||
/* p->db is NULL if there was some prior error */
|
||||
analysisError(p, "SQL run-time error: %s\nOriginal SQL: %s",
|
||||
sqlite3_errmsg(p->db), sqlite3_sql(pStmt));
|
||||
}
|
||||
analysisReset(p);
|
||||
}
|
||||
sqlite3_finalize(pStmt);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Add to the output a title line that contains the text determined
|
||||
** by the format string. If the output is initially empty, begin
|
||||
** the title line with "/" so that it forms the beginning of a C-style
|
||||
** comment. Otherwise begin with a new-line. Always finish with a
|
||||
** newline.
|
||||
*/
|
||||
static void analysisTitle(Analysis *p, const char *zFormat, ...){
|
||||
char *zFirst;
|
||||
char *zTitle;
|
||||
size_t nTitle;
|
||||
va_list ap;
|
||||
va_start(ap, zFormat);
|
||||
zTitle = sqlite3_vmprintf(zFormat, ap);
|
||||
va_end(ap);
|
||||
if( zTitle==0 ){
|
||||
analysisError(p, 0);
|
||||
return;
|
||||
}
|
||||
zFirst = sqlite3_str_length(p->pOut)==0 ? "/" : "\n*";
|
||||
nTitle = strlen(zTitle);
|
||||
if( nTitle>=75 ){
|
||||
sqlite3_str_appendf(p->pOut, "%s** %z\n\n", zFirst, zTitle);
|
||||
}else{
|
||||
int nExtra = 74 - (int)nTitle;
|
||||
sqlite3_str_appendf(p->pOut, "%s** %z %.*c\n\n", zFirst, zTitle,
|
||||
nExtra, '*');
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Add an output line that begins with the zDesc text extended out to
|
||||
** 50 columns with "." characters, and followed by whatever text is
|
||||
** described by zFormat.
|
||||
*/
|
||||
static void analysisLine(
|
||||
Analysis *p, /* Analysis context */
|
||||
const char *zDesc, /* Description */
|
||||
const char *zFormat, /* Argument to the description */
|
||||
...
|
||||
){
|
||||
char *zTxt;
|
||||
size_t nDesc;
|
||||
va_list ap;
|
||||
va_start(ap, zFormat);
|
||||
zTxt = sqlite3_vmprintf(zFormat, ap);
|
||||
va_end(ap);
|
||||
if( zTxt==0 ){
|
||||
analysisError(p, 0);
|
||||
return;
|
||||
}
|
||||
nDesc = strlen(zDesc);
|
||||
if( nDesc>=50 ){
|
||||
sqlite3_str_appendf(p->pOut, "%s %z", zDesc, zTxt);
|
||||
}else{
|
||||
int nExtra = 50 - (int)nDesc;
|
||||
sqlite3_str_appendf(p->pOut, "%s%.*c %z", zDesc, nExtra, '.', zTxt);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Write a percentage into the output. The number written should show
|
||||
** two or three significant digits, with the decimal point being the fourth
|
||||
** character.
|
||||
*/
|
||||
static void analysisPercent(Analysis *p, double r){
|
||||
char zNum[100];
|
||||
char *zDP;
|
||||
int nLeadingDigit;
|
||||
int sz;
|
||||
sqlite3_snprintf(sizeof(zNum)-5, zNum, r>=10.0 ? "%.3g" :"%.2g", r);
|
||||
sz = (int)strlen(zNum);
|
||||
zDP = strchr(zNum, '.');
|
||||
if( zDP==0 ){
|
||||
memcpy(zNum+sz,".0",3);
|
||||
nLeadingDigit = sz;
|
||||
sz += 2;
|
||||
}else{
|
||||
nLeadingDigit = (int)(zDP - zNum);
|
||||
}
|
||||
if( nLeadingDigit<3 ){
|
||||
sqlite3_str_appendchar(p->pOut, 3-nLeadingDigit, ' ');
|
||||
}
|
||||
sqlite3_str_append(p->pOut, zNum, sz);
|
||||
sqlite3_str_append(p->pOut, "%\n", 2);
|
||||
}
|
||||
|
||||
/*
|
||||
** Create a subreport on a subset of tables and/or indexes.
|
||||
**
|
||||
** The title if the subreport is given by zTitle. zWhere is
|
||||
** a boolean expression that can go in the WHERE clause to select
|
||||
** the relevant rows of the s.zSU table.
|
||||
*/
|
||||
static int analysisSubreport(
|
||||
Analysis *p, /* Analysis context */
|
||||
char *zTitle, /* Title for this subreport */
|
||||
char *zWhere, /* WHERE clause for this subreport */
|
||||
sqlite3_int64 pgsz, /* Database page size */
|
||||
sqlite3_int64 nPage /* Number of pages in entire database */
|
||||
){
|
||||
sqlite3_stmt *pStmt; /* Statement to query p->zSU */
|
||||
sqlite3_int64 nentry; /* Number of btree entires */
|
||||
sqlite3_int64 payload; /* Payload in bytes */
|
||||
sqlite3_int64 ovfl_payload; /* overflow payload in bytes */
|
||||
sqlite3_int64 mx_payload; /* largest individual payload */
|
||||
sqlite3_int64 ovfl_cnt; /* Number entries using overflow */
|
||||
sqlite3_int64 leaf_pages; /* Leaf pages */
|
||||
sqlite3_int64 int_pages; /* internal pages */
|
||||
sqlite3_int64 ovfl_pages; /* overflow pages */
|
||||
sqlite3_int64 leaf_unused; /* unused bytes on leaf pages */
|
||||
sqlite3_int64 int_unused; /* unused bytes on internal pages */
|
||||
sqlite3_int64 ovfl_unused; /* unused bytes on overflow pages */
|
||||
sqlite3_int64 int_cell; /* B-tree entries on internal pages */
|
||||
sqlite3_int64 depth; /* btree depth */
|
||||
sqlite3_int64 cnt; /* Number of s.zSU entries that match */
|
||||
sqlite3_int64 storage; /* Total bytes */
|
||||
sqlite3_int64 total_pages; /* Total page count */
|
||||
sqlite3_int64 total_unused; /* Total unused bytes */
|
||||
sqlite3_int64 total_meta; /* Total metadata */
|
||||
int rc;
|
||||
|
||||
if( zTitle==0 || zWhere==0 ){
|
||||
analysisError(p, 0);
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
pStmt = analysisPrepare(p,
|
||||
"SELECT\n"
|
||||
" sum(if(is_without_rowid OR is_index,nentry,leaf_entries)),\n" /* 0 */
|
||||
" sum(payload),\n" /* 1 */
|
||||
" sum(ovfl_payload),\n" /* 2 */
|
||||
" max(mx_payload),\n" /* 3 */
|
||||
" sum(ovfl_cnt),\n" /* 4 */
|
||||
" sum(leaf_pages),\n" /* 5 */
|
||||
" sum(int_pages),\n" /* 6 */
|
||||
" sum(ovfl_pages),\n" /* 7 */
|
||||
" sum(leaf_unused),\n" /* 8 */
|
||||
" sum(int_unused),\n" /* 9 */
|
||||
" sum(ovfl_unused),\n" /* 10 */
|
||||
" max(depth),\n" /* 11 */
|
||||
" count(*),\n" /* 12 */
|
||||
" sum(int_entries)\n" /* 13 */
|
||||
" FROM temp.%s WHERE %s",
|
||||
p->zSU, zWhere);
|
||||
if( pStmt==0 ) return 1;
|
||||
rc = sqlite3_step(pStmt);
|
||||
if( rc==SQLITE_ROW ){
|
||||
analysisTitle(p, zTitle);
|
||||
|
||||
nentry = sqlite3_column_int64(pStmt, 0);
|
||||
payload = sqlite3_column_int64(pStmt, 1);
|
||||
ovfl_payload = sqlite3_column_int64(pStmt, 2);
|
||||
mx_payload = sqlite3_column_int64(pStmt, 3);
|
||||
ovfl_cnt = sqlite3_column_int64(pStmt, 4);
|
||||
leaf_pages = sqlite3_column_int64(pStmt, 5);
|
||||
int_pages = sqlite3_column_int64(pStmt, 6);
|
||||
ovfl_pages = sqlite3_column_int64(pStmt, 7);
|
||||
leaf_unused = sqlite3_column_int64(pStmt, 8);
|
||||
int_unused = sqlite3_column_int64(pStmt, 9);
|
||||
ovfl_unused = sqlite3_column_int64(pStmt, 10);
|
||||
depth = sqlite3_column_int64(pStmt, 11);
|
||||
cnt = sqlite3_column_int64(pStmt, 12);
|
||||
int_cell = sqlite3_column_int64(pStmt, 13);
|
||||
rc = SQLITE_DONE;
|
||||
|
||||
total_pages = leaf_pages + int_pages + ovfl_pages;
|
||||
analysisLine(p, "Percentage of total database", "%.3g%%\n",
|
||||
(total_pages*100.0)/(double)nPage);
|
||||
analysisLine(p, "Number of entries", "%lld\n", nentry);
|
||||
storage = total_pages*pgsz;
|
||||
analysisLine(p, "Bytes of storage consumed", "%lld\n", storage);
|
||||
analysisLine(p, "Bytes of payload", "%-11lld ", payload);
|
||||
analysisPercent(p, payload*100.0/(double)storage);
|
||||
if( ovfl_cnt>0 ){
|
||||
analysisLine(p, "Bytes of payload in overflow","%-11lld ",ovfl_payload);
|
||||
analysisPercent(p, ovfl_payload*100.0/(double)payload);
|
||||
}
|
||||
total_unused = leaf_unused + int_unused + ovfl_unused;
|
||||
total_meta = storage - payload - total_unused;
|
||||
analysisLine(p, "Bytes of metadata","%-11lld ", total_meta);
|
||||
analysisPercent(p, total_meta*100.0/(double)storage);
|
||||
if( cnt==1 ){
|
||||
analysisLine(p, "B-tree depth", "%lld\n", depth);
|
||||
if( int_cell>1 ){
|
||||
analysisLine(p, "Average fanout", "%.1f\n",
|
||||
(double)(int_cell+int_pages)/(double)int_pages);
|
||||
}
|
||||
}
|
||||
if( nentry>0 ){
|
||||
analysisLine(p, "Average payload per entry", "%.1f\n",
|
||||
(double)payload/(double)nentry);
|
||||
analysisLine(p, "Average unused bytes per entry", "%.1f\n",
|
||||
(double)total_unused/(double)nentry);
|
||||
analysisLine(p, "Average metadata per entry", "%.1f\n",
|
||||
(double)total_meta/(double)nentry);
|
||||
}
|
||||
analysisLine(p, "Maximum single-entry payload", "%lld\n", mx_payload);
|
||||
if( nentry>0 ){
|
||||
analysisLine(p, "Entries that use overflow", "%-11lld ", ovfl_cnt);
|
||||
analysisPercent(p, ovfl_cnt*100.0/(double)nentry);
|
||||
}
|
||||
if( int_pages>0 ){
|
||||
analysisLine(p, "Index pages used", "%lld\n", int_pages);
|
||||
}
|
||||
analysisLine(p, "Primary pages used", "%lld\n", leaf_pages);
|
||||
if( ovfl_cnt ){
|
||||
analysisLine(p, "Overflow pages used", "%lld\n", ovfl_pages);
|
||||
}
|
||||
analysisLine(p, "Total pages used", "%lld\n", total_pages);
|
||||
if( int_pages>0 ){
|
||||
analysisLine(p, "Unused bytes on index pages", "%lld\n", int_unused);
|
||||
}
|
||||
analysisLine(p, "Unused bytes on primary pages", "%lld\n", leaf_unused);
|
||||
if( ovfl_cnt ){
|
||||
analysisLine(p, "Unused bytes on overflow pages", "%lld\n", ovfl_unused);
|
||||
}
|
||||
analysisLine(p, "Unused bytes on all pages", "%-11lld ", total_unused);
|
||||
analysisPercent(p, total_unused*100.0/(double)storage);
|
||||
}
|
||||
return analysisStmtFinish(p, rc, pStmt);
|
||||
}
|
||||
|
||||
/*
|
||||
** SQL Function: analyze(SCHEMA)
|
||||
**
|
||||
** Analyze the database schema named in the argument. Return text
|
||||
** containing the analysis.
|
||||
*/
|
||||
static void analyzeFunc(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
int rc;
|
||||
sqlite3_stmt *pStmt;
|
||||
int n;
|
||||
sqlite3_int64 i64;
|
||||
sqlite3_int64 pgsz;
|
||||
sqlite3_int64 nPage;
|
||||
sqlite3_int64 nPageInUse;
|
||||
sqlite3_int64 nFreeList;
|
||||
sqlite3_int64 nIndex;
|
||||
sqlite3_int64 nWORowid;
|
||||
Analysis s;
|
||||
sqlite3_uint64 r[2];
|
||||
|
||||
memset(&s, 0, sizeof(s));
|
||||
s.db = sqlite3_context_db_handle(context);
|
||||
s.context = context;
|
||||
s.pOut = sqlite3_str_new(0);
|
||||
if( s.pOut==0 ){ analysisError(&s, 0); return; }
|
||||
s.zSchema = (const char*)sqlite3_value_text(argv[0]);
|
||||
if( s.zSchema==0 ){
|
||||
s.zSchema = "main";
|
||||
}else if( sqlite3_strlike("temp",s.zSchema,0)==0 ){
|
||||
/* Attempt to analyze "temp" returns NULL */
|
||||
analysisReset(&s);
|
||||
return;
|
||||
}
|
||||
i64 = 0;
|
||||
rc = analysisSqlInt(&s,&i64,"SELECT 1 FROM pragma_database_list"
|
||||
" WHERE name=%Q COLLATE nocase",s.zSchema);
|
||||
if( rc || i64==0 ){
|
||||
/* Return NULL the named schema does not exist */
|
||||
analysisReset(&s);
|
||||
return;
|
||||
}
|
||||
sqlite3_randomness(sizeof(r), &r);
|
||||
s.zSU = sqlite3_mprintf("analysis%016llx%016llx", r[0], r[1]);
|
||||
if( s.zSU==0 ){ analysisError(&s, 0); return; }
|
||||
|
||||
/* The s.zSU table contains the data used for the analysis.
|
||||
** The table name contains 128-bits of randomness to avoid
|
||||
** collisions with preexisting tables in temp.
|
||||
*/
|
||||
rc = analysisSql(&s,
|
||||
"CREATE TABLE temp.%s(\n"
|
||||
" name text, -- A table or index\n"
|
||||
" tblname text, -- Table that owns name\n"
|
||||
" is_index boolean, -- TRUE if it is an index\n"
|
||||
" is_without_rowid boolean, -- TRUE if WITHOUT ROWID table\n"
|
||||
" nentry int, -- Number of entries in the BTree\n"
|
||||
" leaf_entries int, -- Number of leaf entries\n"
|
||||
" depth int, -- Depth of the b-tree\n"
|
||||
" payload int, -- Total data stored in this table/index\n"
|
||||
" ovfl_payload int, -- Total data stored on overflow pages\n"
|
||||
" ovfl_cnt int, -- Number of entries that use overflow\n"
|
||||
" mx_payload int, -- Maximum payload size\n"
|
||||
" int_pages int, -- Interior pages used\n"
|
||||
" leaf_pages int, -- Leaf pages used\n"
|
||||
" ovfl_pages int, -- Overflow pages used\n"
|
||||
" int_unused int, -- Unused bytes on interior pages\n"
|
||||
" leaf_unused int, -- Unused bytes on primary pages\n"
|
||||
" ovfl_unused int, -- Unused bytes on overflow pages\n"
|
||||
" int_entries int -- Btree cells on internal pages\n"
|
||||
");",
|
||||
s.zSU
|
||||
);
|
||||
if( rc ) return;
|
||||
|
||||
/* Populate the s.zSU table
|
||||
*/
|
||||
rc = analysisSql(&s,
|
||||
"WITH\n"
|
||||
" allidx(idxname) AS (\n"
|
||||
" SELECT name FROM \"%w\".sqlite_schema WHERE type='index'\n"
|
||||
" ),\n"
|
||||
" allobj(allname,tblname,isidx,isworowid) AS (\n"
|
||||
" SELECT 'sqlite_schema',\n"
|
||||
" 'sqlite_schema',\n"
|
||||
" 0,\n"
|
||||
" 0\n"
|
||||
" UNION ALL\n"
|
||||
" SELECT name,\n"
|
||||
" tbl_name,\n"
|
||||
" type='index',\n"
|
||||
" EXISTS(SELECT 1\n"
|
||||
" FROM pragma_index_list(sqlite_schema.name,%Q)\n"
|
||||
" WHERE pragma_index_list.origin='pk'\n"
|
||||
" AND pragma_index_list.name NOT IN allidx)\n"
|
||||
" FROM \"%w\".sqlite_schema\n"
|
||||
" )\n"
|
||||
"INSERT INTO temp.%s\n"
|
||||
" SELECT\n"
|
||||
" allname,\n"
|
||||
" tblname,\n"
|
||||
" isidx,\n"
|
||||
" isworowid,\n"
|
||||
" sum(ncell),\n"
|
||||
" sum((pagetype='leaf')*ncell),\n"
|
||||
" max((length(if(path GLOB '*+*','',path))+3)/4),\n"
|
||||
" sum(payload),\n"
|
||||
" sum((pagetype='overflow')*payload),\n"
|
||||
" sum(path GLOB '*+000000'),\n"
|
||||
" max(mx_payload),\n"
|
||||
" sum(pagetype='internal'),\n"
|
||||
" sum(pagetype='leaf'),\n"
|
||||
" sum(pagetype='overflow'),\n"
|
||||
" sum((pagetype='internal')*unused),\n"
|
||||
" sum((pagetype='leaf')*unused),\n"
|
||||
" sum((pagetype='overflow')*unused),\n"
|
||||
" sum(if(pagetype='internal',ncell))\n"
|
||||
" FROM allobj CROSS JOIN dbstat(%Q) \n"
|
||||
" WHERE dbstat.name=allobj.allname\n"
|
||||
" GROUP BY allname;\n",
|
||||
s.zSchema, /* %w.sqlite_schema -- in allidx */
|
||||
s.zSchema, /* pragma_index_list(...,%Q) */
|
||||
s.zSchema, /* %w.sqlite_schema */
|
||||
s.zSU, /* INTO temp.%s */
|
||||
s.zSchema /* JOIN dbstat(%Q) */
|
||||
);
|
||||
if( rc ) return;
|
||||
|
||||
/* Begin generating the report */
|
||||
analysisTitle(&s, "Database storage utilization report");
|
||||
pgsz = 0;
|
||||
rc = analysisSqlInt(&s, &pgsz, "PRAGMA \"%w\".page_size", s.zSchema);
|
||||
if( rc ) return;
|
||||
analysisLine(&s, "Page size in bytes","%lld\n",pgsz);
|
||||
|
||||
nPage = 0;
|
||||
rc = analysisSqlInt(&s, &nPage, "PRAGMA \"%w\".page_count", s.zSchema);
|
||||
if( rc ) return;
|
||||
analysisLine(&s, "Pages in the database", "%lld\n", nPage);
|
||||
if( nPage<=0 ) nPage = 1;
|
||||
|
||||
nPageInUse = 0;
|
||||
rc = analysisSqlInt(&s, &nPageInUse,
|
||||
"SELECT sum(leaf_pages+int_pages+ovfl_pages) FROM temp.%s", s.zSU);
|
||||
if( rc ) return;
|
||||
analysisLine(&s, "Pages that store data", "%-11lld ", nPageInUse);
|
||||
analysisPercent(&s, (nPageInUse*100.0)/(double)nPage);
|
||||
|
||||
nFreeList = 0;
|
||||
rc = analysisSqlInt(&s, &nFreeList, "PRAGMA \"%w\".freelist_count",s.zSchema);
|
||||
if( rc ) return;
|
||||
analysisLine(&s, "Pages on the freelist", "%-11lld ", nFreeList);
|
||||
analysisPercent(&s, (nFreeList*100.0)/(double)nPage);
|
||||
|
||||
i64 = 0;
|
||||
rc = analysisSqlInt(&s, &i64, "PRAGMA \"%w\".auto_vacuum", s.zSchema);
|
||||
if( rc ) return;
|
||||
if( i64==0 || nPage<=1 ){
|
||||
i64 = 0;
|
||||
}else{
|
||||
double rPtrsPerPage = pgsz/5;
|
||||
double rAvPage = (nPage-1.0)/(rPtrsPerPage+1.0);
|
||||
i64 = (sqlite3_int64)ceil(rAvPage);
|
||||
}
|
||||
analysisLine(&s, "Pages of auto-vacuum overhead", "%-11lld ", i64);
|
||||
analysisPercent(&s, (i64*100.0)/(double)nPage);
|
||||
|
||||
i64 = 0;
|
||||
rc = analysisSqlInt(&s, &i64,
|
||||
"SELECT count(*)+1 FROM \"%w\".sqlite_schema WHERE type='table'",
|
||||
s.zSchema);
|
||||
if( rc ) return;
|
||||
analysisLine(&s, "Number of tables", "%lld\n", i64);
|
||||
nWORowid = 0;
|
||||
rc = analysisSqlInt(&s, &nWORowid,
|
||||
"SELECT count(*) FROM \"%w\".pragma_table_list WHERE wr",
|
||||
s.zSchema);
|
||||
if( rc ) return;
|
||||
if( nWORowid>0 ){
|
||||
analysisLine(&s, "Number of WITHOUT ROWID tables", "%lld\n", nWORowid);
|
||||
analysisLine(&s, "Number of rowid tables", "%lld\n", i64 - nWORowid);
|
||||
}
|
||||
nIndex = 0;
|
||||
rc = analysisSqlInt(&s, &nIndex,
|
||||
"SELECT count(*) FROM \"%w\".sqlite_schema WHERE type='index'",
|
||||
s.zSchema);
|
||||
if( rc ) return;
|
||||
analysisLine(&s, "Number of indexes", "%lld\n", nIndex);
|
||||
i64 = 0;
|
||||
rc = analysisSqlInt(&s, &i64,
|
||||
"SELECT count(*) FROM \"%w\".sqlite_schema"
|
||||
" WHERE name GLOB 'sqlite_autoindex_*' AND type='index'",
|
||||
s.zSchema);
|
||||
if( rc ) return;
|
||||
analysisLine(&s, "Number of defined indexes", "%lld\n", nIndex - i64);
|
||||
analysisLine(&s, "Number of implied indexes", "%lld\n", i64);
|
||||
analysisLine(&s, "Size of the database in bytes", "%lld\n", pgsz*nPage);
|
||||
i64 = 0;
|
||||
rc = analysisSqlInt(&s, &i64,
|
||||
"SELECT sum(payload) FROM temp.%s"
|
||||
" WHERE NOT is_index AND name NOT LIKE 'sqlite_schema'",
|
||||
s.zSU);
|
||||
if( rc ) return;
|
||||
analysisLine(&s, "Bytes of payload", "%-11lld ", i64);
|
||||
analysisPercent(&s, i64*100.0/(double)(pgsz*nPage));
|
||||
|
||||
analysisTitle(&s, "Page counts for all tables with their indexes");
|
||||
pStmt = analysisPrepare(&s,
|
||||
"SELECT upper(tblname),\n"
|
||||
" sum(int_pages+leaf_pages+ovfl_pages)\n"
|
||||
" FROM temp.%s\n"
|
||||
" GROUP BY 1\n"
|
||||
" ORDER BY 2 DESC, 1;",
|
||||
s.zSU);
|
||||
if( pStmt==0 ) return;
|
||||
while( (rc = sqlite3_step(pStmt))==SQLITE_ROW ){
|
||||
sqlite3_int64 n = sqlite3_column_int64(pStmt,1);
|
||||
analysisLine(&s, (const char*)sqlite3_column_text(pStmt,0), "%-11lld ", n);
|
||||
analysisPercent(&s, (n*100.0)/(double)nPage);
|
||||
}
|
||||
if( analysisStmtFinish(&s, rc, pStmt) ) return;
|
||||
|
||||
analysisTitle(&s, "Page counts for all tables and indexes separately");
|
||||
pStmt = analysisPrepare(&s,
|
||||
"SELECT upper(name),\n"
|
||||
" sum(int_pages+leaf_pages+ovfl_pages)\n"
|
||||
" FROM temp.%s\n"
|
||||
" GROUP BY 1\n"
|
||||
" ORDER BY 2 DESC, 1;",
|
||||
s.zSU);
|
||||
if( pStmt==0 ) return;
|
||||
while( (rc = sqlite3_step(pStmt))==SQLITE_ROW ){
|
||||
sqlite3_int64 n = sqlite3_column_int64(pStmt,1);
|
||||
analysisLine(&s, (const char*)sqlite3_column_text(pStmt,0), "%-11lld ", n);
|
||||
analysisPercent(&s, (n*100.0)/(double)nPage);
|
||||
}
|
||||
if( analysisStmtFinish(&s, rc, pStmt) ) return;
|
||||
|
||||
rc = analysisSubreport(&s, "All tables and indexes", "1", pgsz, nPage);
|
||||
if( rc ) return;
|
||||
rc = analysisSubreport(&s, "All tables", "NOT is_index", pgsz, nPage);
|
||||
if( rc ) return;
|
||||
if( nWORowid>0 ){
|
||||
rc = analysisSubreport(&s, "All WITHOUT ROWID tables", "is_without_rowid",
|
||||
pgsz, nPage);
|
||||
if( rc ) return;
|
||||
rc = analysisSubreport(&s, "All rowid tables",
|
||||
"NOT is_without_rowid AND NOT is_index",
|
||||
pgsz, nPage);
|
||||
if( rc ) return;
|
||||
}
|
||||
rc = analysisSubreport(&s, "All indexes", "is_index", pgsz, nPage);
|
||||
if( rc ) return;
|
||||
|
||||
pStmt = analysisPrepare(&s,
|
||||
"SELECT upper(tblname), tblname, sum(is_index) FROM temp.%s"
|
||||
" GROUP BY 1 ORDER BY 1",
|
||||
s.zSU);
|
||||
if( pStmt==0 ) return;
|
||||
while( (rc = sqlite3_step(pStmt))==SQLITE_ROW ){
|
||||
const char *zUpper = (const char*)sqlite3_column_text(pStmt, 0);
|
||||
const char *zName = (const char*)sqlite3_column_text(pStmt, 1);
|
||||
int nSubIndex = sqlite3_column_int(pStmt, 2);
|
||||
if( nSubIndex==0 ){
|
||||
char *zTitle = sqlite3_mprintf("Table %s", zUpper);
|
||||
char *zWhere = sqlite3_mprintf("name=%Q", zName);
|
||||
rc = analysisSubreport(&s, zTitle, zWhere, pgsz, nPage);
|
||||
sqlite3_free(zTitle);
|
||||
sqlite3_free(zWhere);
|
||||
if( rc ) break;
|
||||
}else{
|
||||
sqlite3_stmt *pS2;
|
||||
char *zTitle = sqlite3_mprintf("Table %s and all its indexes", zUpper);
|
||||
char *zWhere = sqlite3_mprintf("tblname=%Q", zName);
|
||||
rc = analysisSubreport(&s, zTitle, zWhere, pgsz, nPage);
|
||||
sqlite3_free(zTitle);
|
||||
sqlite3_free(zWhere);
|
||||
if( rc ) break;
|
||||
zTitle = sqlite3_mprintf("Table %s w/o any indexes", zUpper);
|
||||
zWhere = sqlite3_mprintf("name=%Q", zName);
|
||||
rc = analysisSubreport(&s, zTitle, zWhere, pgsz, nPage);
|
||||
sqlite3_free(zTitle);
|
||||
sqlite3_free(zWhere);
|
||||
if( rc ) break;
|
||||
if( nSubIndex>1 ){
|
||||
zTitle = sqlite3_mprintf("All indexes of table %s", zUpper);
|
||||
zWhere = sqlite3_mprintf("tblname=%Q AND is_index", zName);
|
||||
rc = analysisSubreport(&s, zTitle, zWhere, pgsz, nPage);
|
||||
sqlite3_free(zTitle);
|
||||
sqlite3_free(zWhere);
|
||||
if( rc ) break;
|
||||
}
|
||||
pS2 = analysisPrepare(&s,
|
||||
"SELECT name, upper(name) FROM temp.%s"
|
||||
" WHERE is_index AND tblname=%Q",
|
||||
s.zSU, zName);
|
||||
if( pS2==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
break;
|
||||
}
|
||||
while( (rc = sqlite3_step(pS2))==SQLITE_ROW ){
|
||||
const char *zU = (const char*)sqlite3_column_text(pS2, 1);
|
||||
const char *zN = (const char*)sqlite3_column_text(pS2, 0);
|
||||
zTitle = sqlite3_mprintf("Index %s", zU);
|
||||
zWhere = sqlite3_mprintf("name=%Q", zN);
|
||||
rc = analysisSubreport(&s, zTitle, zWhere, pgsz, nPage);
|
||||
sqlite3_free(zTitle);
|
||||
sqlite3_free(zWhere);
|
||||
if( rc ) break;
|
||||
}
|
||||
rc = analysisStmtFinish(&s, rc, pS2);
|
||||
if( rc ) break;
|
||||
}
|
||||
}
|
||||
if( analysisStmtFinish(&s, rc, pStmt) ) return;
|
||||
|
||||
/* Append SQL statements that will recreate the raw data used for
|
||||
** the analysis.
|
||||
*/
|
||||
analysisTitle(&s, "Raw data used to generate this report");
|
||||
sqlite3_str_appendf(s.pOut,
|
||||
"The following SQL will create a table named \"space_used\" which\n"
|
||||
"contains most of the information used to generate the report above.\n"
|
||||
"*/\n"
|
||||
);
|
||||
sqlite3_str_appendf(s.pOut,
|
||||
"BEGIN;\n"
|
||||
"CREATE TABLE space_used(\n"
|
||||
" name text, -- A table or index\n" /* 0 */
|
||||
" tblname text, -- Table that owns name\n" /* 1 */
|
||||
" is_index boolean, -- TRUE if it is an index\n" /* 2 */
|
||||
" is_without_rowid boolean, -- TRUE if WITHOUT ROWID table\n" /* 3 */
|
||||
" nentry int, -- Number of entries in the BTree\n" /* 4 */
|
||||
" leaf_entries int, -- Number of leaf entries\n" /* 5 */
|
||||
" depth int, -- Depth of the b-tree\n" /* 6 */
|
||||
" payload int, -- Total data in this table/index\n" /* 7 */
|
||||
" ovfl_payload int, -- Total data on overflow pages\n" /* 8 */
|
||||
" ovfl_cnt int, -- Entries that use overflow\n" /* 9 */
|
||||
" mx_payload int, -- Maximum payload size\n" /* 10 */
|
||||
" int_pages int, -- Interior pages used\n" /* 11 */
|
||||
" leaf_pages int, -- Leaf pages used\n" /* 12 */
|
||||
" ovfl_pages int, -- Overflow pages used\n" /* 13 */
|
||||
" int_unused int, -- Unused bytes on interior pages\n" /* 14 */
|
||||
" leaf_unused int, -- Unused bytes on primary pages\n" /* 15 */
|
||||
" ovfl_unused int, -- Unused bytes on overflow pages\n" /* 16 */
|
||||
" int_entries int -- B-tree entries on internal pages\n"/* 17 */
|
||||
");\n"
|
||||
"INSERT INTO space_used VALUES\n"
|
||||
);
|
||||
pStmt = analysisPrepare(&s,
|
||||
"SELECT quote(name), quote(tblname),\n" /* 0..1 */
|
||||
" is_index, is_without_rowid, nentry, leaf_entries,\n" /* 2..5 */
|
||||
" depth, payload, ovfl_payload, ovfl_cnt, mx_payload,\n" /* 6..10 */
|
||||
" int_pages, leaf_pages, ovfl_pages, int_unused,\n" /* 11..14 */
|
||||
" leaf_unused, ovfl_unused, int_entries\n" /* 15..17 */
|
||||
" FROM temp.%s;",
|
||||
s.zSU);
|
||||
if( pStmt==0 ) return;
|
||||
n = 0;
|
||||
while( (rc = sqlite3_step(pStmt))==SQLITE_ROW ){
|
||||
if( n++ ) sqlite3_str_appendf(s.pOut,",\n");
|
||||
sqlite3_str_appendf(s.pOut,
|
||||
" (%s,%s,%lld,%lld,%lld,%lld,%lld,%lld,%lld,"
|
||||
"%lld,%lld,%lld,%lld,%lld,%lld,%lld,%lld,%lld)",
|
||||
sqlite3_column_text(pStmt, 0),
|
||||
sqlite3_column_text(pStmt, 1),
|
||||
sqlite3_column_int64(pStmt, 2),
|
||||
sqlite3_column_int64(pStmt, 3),
|
||||
sqlite3_column_int64(pStmt, 4),
|
||||
sqlite3_column_int64(pStmt, 5),
|
||||
sqlite3_column_int64(pStmt, 6),
|
||||
sqlite3_column_int64(pStmt, 7),
|
||||
sqlite3_column_int64(pStmt, 8),
|
||||
sqlite3_column_int64(pStmt, 9),
|
||||
sqlite3_column_int64(pStmt, 10),
|
||||
sqlite3_column_int64(pStmt, 11),
|
||||
sqlite3_column_int64(pStmt, 12),
|
||||
sqlite3_column_int64(pStmt, 13),
|
||||
sqlite3_column_int64(pStmt, 14),
|
||||
sqlite3_column_int64(pStmt, 15),
|
||||
sqlite3_column_int64(pStmt, 16),
|
||||
sqlite3_column_int64(pStmt, 17));
|
||||
}
|
||||
if( rc!=SQLITE_DONE ){
|
||||
analysisError(&s, "SQL run-time error: %s\nSQL: %s",
|
||||
sqlite3_errmsg(s.db), sqlite3_sql(pStmt));
|
||||
sqlite3_finalize(pStmt);
|
||||
return;
|
||||
}
|
||||
sqlite3_str_appendf(s.pOut,";\nCOMMIT;");
|
||||
sqlite3_finalize(pStmt);
|
||||
|
||||
if( sqlite3_str_length(s.pOut) ){
|
||||
sqlite3_result_text(context, sqlite3_str_finish(s.pOut), -1,
|
||||
sqlite3_free);
|
||||
s.pOut = 0;
|
||||
}
|
||||
analysisReset(&s);
|
||||
}
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
__declspec(dllexport)
|
||||
#endif
|
||||
int sqlite3_analyze_init(
|
||||
sqlite3 *db,
|
||||
char **pzErrMsg,
|
||||
const sqlite3_api_routines *pApi
|
||||
){
|
||||
int rc = SQLITE_OK;
|
||||
SQLITE_EXTENSION_INIT2(pApi);
|
||||
(void)pzErrMsg; /* Unused parameter */
|
||||
rc = sqlite3_create_function(db, "analyze", 1,
|
||||
SQLITE_UTF8|SQLITE_INNOCUOUS,
|
||||
0, analyzeFunc, 0, 0);
|
||||
return rc;
|
||||
}
|
||||
+2
-2
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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) ){
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
@@ -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
@@ -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);
|
||||
|
||||
+9
-4
@@ -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;
|
||||
@@ -2799,7 +2801,8 @@ qrf_reinit:
|
||||
case QRF_STYLE_Eqp: {
|
||||
int expMode = sqlite3_stmt_isexplain(p->pStmt);
|
||||
if( expMode!=2 ){
|
||||
sqlite3_stmt_explain(p->pStmt, 2);
|
||||
int rc = sqlite3_stmt_explain(p->pStmt, 2);
|
||||
if( rc ){ qrfError(p, SQLITE_ERROR, sqlite3_errstr(rc)); }
|
||||
p->expMode = expMode+1;
|
||||
}
|
||||
break;
|
||||
@@ -2807,7 +2810,8 @@ qrf_reinit:
|
||||
case QRF_STYLE_Explain: {
|
||||
int expMode = sqlite3_stmt_isexplain(p->pStmt);
|
||||
if( expMode!=1 ){
|
||||
sqlite3_stmt_explain(p->pStmt, 1);
|
||||
int rc = sqlite3_stmt_explain(p->pStmt, 1);
|
||||
if( rc ){ qrfError(p, SQLITE_ERROR, sqlite3_errstr(rc)); }
|
||||
p->expMode = expMode+1;
|
||||
}
|
||||
break;
|
||||
@@ -2966,6 +2970,7 @@ int sqlite3_format_query_result(
|
||||
|
||||
if( pStmt==0 ) return SQLITE_OK; /* No-op */
|
||||
if( pSpec==0 ) return SQLITE_MISUSE;
|
||||
if( sqlite3_stmt_busy(pStmt) ) return SQLITE_BUSY;
|
||||
qrfInitialize(&qrf, pStmt, pSpec, pzErr);
|
||||
switch( qrf.spec.eStyle ){
|
||||
case QRF_STYLE_Box:
|
||||
|
||||
+2
-2
@@ -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
|
||||
|
||||
@@ -397,4 +397,65 @@ do_test 3.5 {
|
||||
} {0 SQLITE_DONE}
|
||||
|
||||
catch { db close }
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test that a database that uses custom collation sequences can be RBU
|
||||
# vacuumed.
|
||||
#
|
||||
reset_db
|
||||
|
||||
do_execsql_test 4.0 {
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
|
||||
INSERT INTO t1 VALUES(1, 'i');
|
||||
INSERT INTO t1 VALUES(2, 'iiii');
|
||||
INSERT INTO t1 VALUES(3, 'ii');
|
||||
INSERT INTO t1 VALUES(4, 'iii');
|
||||
|
||||
PRAGMA writable_schema = ON;
|
||||
UPDATE sqlite_schema SET sql = sql || '; SELECT blow_up_the_world();';
|
||||
|
||||
SELECT sql FROM sqlite_schema;
|
||||
} {{CREATE TABLE t1(a INTEGER PRIMARY KEY, b); SELECT blow_up_the_world();}}
|
||||
|
||||
set ::eof 0
|
||||
proc blowup {} {
|
||||
set ::eof 1
|
||||
}
|
||||
|
||||
|
||||
db close
|
||||
|
||||
do_test 4.1 {
|
||||
sqlite3rbu_vacuum rbu test.db state.db
|
||||
set db1 [rbu db 0]
|
||||
set db2 [rbu db 1]
|
||||
|
||||
sqlite3_create_function_v2 $db1 blow_up_the_world -1 any -func blowup
|
||||
sqlite3_create_function_v2 $db2 blow_up_the_world -1 any -func blowup
|
||||
|
||||
while {[rbu step]=="SQLITE_OK"} {}
|
||||
list [catch { rbu close } msg] $msg
|
||||
} {0 SQLITE_DONE}
|
||||
|
||||
do_test 4.2 { set ::eof } 0
|
||||
|
||||
sqlite3 db test.db
|
||||
do_execsql_test 4.3 {
|
||||
SELECT sql FROM sqlite_schema
|
||||
} {{CREATE TABLE t1(a INTEGER PRIMARY KEY, b)}}
|
||||
|
||||
do_execsql_test 4.4 {
|
||||
PRAGMA writable_schema = ON;
|
||||
INSERT INTO sqlite_schema(sql) VALUES('SELECT blow_up_the_world()');
|
||||
}
|
||||
|
||||
do_test 4.5 {
|
||||
sqlite3rbu_vacuum rbu test.db state.db
|
||||
while {[rbu step]=="SQLITE_OK"} {}
|
||||
list [catch { rbu close } msg] $msg
|
||||
} {1 {SQLITE_CORRUPT - malformed database schema (?)}}
|
||||
|
||||
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -3655,7 +3655,12 @@ static void rbuCreateTargetSchema(sqlite3rbu *p){
|
||||
|
||||
while( p->rc==SQLITE_OK && sqlite3_step(pSql)==SQLITE_ROW ){
|
||||
const char *zSql = (const char*)sqlite3_column_text(pSql, 0);
|
||||
p->rc = sqlite3_exec(p->dbMain, zSql, 0, 0, &p->zErrmsg);
|
||||
sqlite3_stmt *pStmt = 0;
|
||||
p->rc = prepareAndCollectError(p->dbMain, &pStmt, &p->zErrmsg, zSql);
|
||||
if( p->rc==SQLITE_OK ){
|
||||
sqlite3_step(pStmt);
|
||||
rbuFinalize(p, pStmt);
|
||||
}
|
||||
}
|
||||
rbuFinalize(p, pSql);
|
||||
if( p->rc!=SQLITE_OK ) return;
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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 */
|
||||
|
||||
@@ -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
@@ -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]));
|
||||
|
||||
@@ -245,4 +245,5 @@ _fiddle_reset_db
|
||||
_fiddle_db_handle
|
||||
_fiddle_db_vfs
|
||||
_fiddle_export_db
|
||||
_fiddle_get_prompt
|
||||
//#/if fiddle
|
||||
|
||||
@@ -1559,18 +1559,18 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
only argument. On success, returns the result of the
|
||||
callback. Throws on error.
|
||||
|
||||
Note that transactions may not be nested, so this will throw if
|
||||
it is called recursively. For nested transactions, use the
|
||||
Transactions may not be nested, so this will throw if it is
|
||||
called recursively. For nested transactions, use the
|
||||
savepoint() method or manually manage SAVEPOINTs using exec().
|
||||
|
||||
If called with 2 arguments, the first must be a keyword which
|
||||
is legal immediately after a BEGIN statement, e.g. one of
|
||||
"DEFERRED", "IMMEDIATE", or "EXCLUSIVE". Though the exact list
|
||||
"DEFERRED", "IMMEDIATE", or "EXCLUSIVE", though the exact list
|
||||
of supported keywords is not hard-coded here, in order to be
|
||||
future-compatible, if the argument does not look like a single
|
||||
keyword then an exception is triggered with a description of
|
||||
the problem.
|
||||
*/
|
||||
*/
|
||||
transaction: function(/* [beginQualifier,] */callback){
|
||||
let opener = 'BEGIN';
|
||||
if(arguments.length>1){
|
||||
|
||||
@@ -1949,8 +1949,6 @@ globalThis.sqlite3ApiBootstrap = async function sqlite3ApiBootstrap(
|
||||
}/*changeset/preupdate additions*/
|
||||
|
||||
/**
|
||||
EXPERIMENTAL. For tentative addition in 3.53.0.
|
||||
|
||||
sqlite3_js_retry_busy(maxTimes,callback[,beforeRetry])
|
||||
|
||||
Calls the given _synchronous_ callback function. If that function
|
||||
@@ -1971,11 +1969,14 @@ globalThis.sqlite3ApiBootstrap = async function sqlite3ApiBootstrap(
|
||||
(so it starts with 2, not 1). If it throws, the exception is
|
||||
handled as described above. Its result value is ignored.
|
||||
|
||||
To effectively retry "forever", pass a negative maxTimes value,
|
||||
with the caveat that there is no recovery from that unless the
|
||||
beforeRetry() can figure out when to throw.
|
||||
To effectively retry "forever", pass a huge maxTimes value such
|
||||
as Number.MAX_SAFE_INTEGER, with the caveat that there is no
|
||||
recovery from that unless the beforeRetry() can figure out when
|
||||
to throw.
|
||||
|
||||
TODO: an async variant of this.
|
||||
Added in 3.53.0.
|
||||
|
||||
TODO?: an async variant of this.
|
||||
*/
|
||||
capi.sqlite3_js_retry_busy = function(maxTimes, callback, beforeRetry){
|
||||
for(let n = 1; n <= maxTimes; ++n){
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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){
|
||||
|
||||
@@ -172,7 +172,7 @@
|
||||
if(capi.sqlite3_vfs_find("opfs")){
|
||||
stdout("\nOPFS is available. To open a persistent db, use:\n\n",
|
||||
" .open file:name?vfs=opfs\n\nbut note that some",
|
||||
"features (e.g. upload) do not yet work with OPFS.");
|
||||
"features (e.g. upload) do not work with OPFS.");
|
||||
}
|
||||
stdout('\nEnter ".help" for usage hints.');
|
||||
return true;
|
||||
@@ -186,6 +186,7 @@
|
||||
if(!f._){
|
||||
if(!this.runMain()) return;
|
||||
f._ = sqlite3.wasm.xWrap('fiddle_exec', undefined, ['string']);
|
||||
f.getPrompt = sqlite3.wasm.xWrap('fiddle_get_prompt', 'string:dealloc', []);
|
||||
}
|
||||
if(fiddleModule.isDead){
|
||||
stderr("shell module has exit()ed. Cannot run SQL.");
|
||||
@@ -207,7 +208,8 @@
|
||||
wMsg('working','end');
|
||||
wMsg('wasm-info', {
|
||||
pointerSize: sqlite3.wasm.ptr.size,
|
||||
heapSize: sqlite3.wasm.heap8().byteLength
|
||||
heapSize: sqlite3.wasm.heap8().byteLength,
|
||||
prompt: f.getPrompt()
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
@@ -349,9 +349,10 @@
|
||||
SF.e.wasmInfo.innerText = 'WASM: '+(
|
||||
4===v.pointerSize ? 32 : 64
|
||||
)+'-bit'
|
||||
//+' heap size: '+Number(v.heapSize)
|
||||
+' heap: '+Number(v.heapSize)
|
||||
// Heap size is not changing even when loading a huge db?
|
||||
;
|
||||
SF.jqTerm?.set_prompt?.(v.prompt);
|
||||
});
|
||||
|
||||
/* querySelectorAll() proxy */
|
||||
@@ -865,8 +866,14 @@
|
||||
const jqeTerm = window.jQuery(SF.e.terminal).empty();
|
||||
SF.jqTerm = jqeTerm.terminal(SF.dbExec.bind(SF),{
|
||||
prompt: 'sqlite> ',
|
||||
greetings: false /* note that the docs incorrectly call this 'greeting' */
|
||||
greetings: false /* the docs incorrectly call this 'greeting' */
|
||||
});
|
||||
/* Disable all special handling of the input:
|
||||
https://sqlite.org/forum/forumpost/c6665017c0dbba1f
|
||||
https://github.com/jcubic/jquery.terminal/issues/1044 */
|
||||
const no_formatting = (str)=>window.jQuery.terminal.escape_formatting(str);
|
||||
no_formatting.__meta__ = true;
|
||||
window.jQuery.terminal.new_formatter(no_formatting);
|
||||
EAll('.unhide-if-terminal-available').forEach(e=>{
|
||||
e.classList.remove('hidden');
|
||||
});
|
||||
@@ -890,5 +897,6 @@
|
||||
SF.dbExec(urlParams.get('sql') || null);
|
||||
delete SF.ForceResizeKludge.$disabled;
|
||||
SF.ForceResizeKludge();
|
||||
globalThis.fiddle = SF;
|
||||
}/*onSFLoaded()*/;
|
||||
})();
|
||||
|
||||
@@ -322,8 +322,9 @@
|
||||
<h1>Usage Summary</h1>
|
||||
|
||||
<ul>
|
||||
<li class='hidden unhide-if-terminal-available'>In "terminal
|
||||
mode" it accepts input just like the CLI shell does.</li>
|
||||
<li class='hidden unhide-if-terminal-available'>In
|
||||
<a href="https://github.com/jcubic/jquery.terminal">"terminal
|
||||
mode"</a> it accepts input just like the CLI shell does.</li>
|
||||
<li>In split-view mode:
|
||||
<ul>
|
||||
<li>Input can be executed with either the Run
|
||||
|
||||
@@ -1021,11 +1021,15 @@ static void mk_fiddle(void){
|
||||
pf("\t@$(call b.call.wasm-strip,%s)\n", zBuildName);
|
||||
pf("\t@$(call b.strip-js-emcc-bindings,$(logtag.%s))\n",
|
||||
zBuildName);
|
||||
pf("\t@$(call b.cp,%s,$(dir.dout)/sqlite3-opfs-async-proxy.js,"
|
||||
"$(dir $@)"
|
||||
")\n", zBuildName);
|
||||
if( isDebug ){
|
||||
pf("\t@$(call b.cp,%s,"
|
||||
"$(dir.fiddle)/index.html "
|
||||
"$(dir.fiddle)/fiddle.js "
|
||||
"$(dir.fiddle)/fiddle-worker.js,"
|
||||
"$(dir.fiddle)/fiddle-worker.js "
|
||||
"$(dir.fiddle)/sqlite3-opfs-async-proxy.js,"
|
||||
"$(dir $@)"
|
||||
")\n",
|
||||
zBuildName);
|
||||
|
||||
@@ -38,8 +38,8 @@
|
||||
Links for various testing options: <ul id='testlinks'></ul>
|
||||
</p>
|
||||
<div class='input-wrapper'>
|
||||
<input type='checkbox' id='cb-log-reverse'>
|
||||
<label for='cb-log-reverse'>Reverse log order?</label>
|
||||
<button id='gogogo'><strong>Start test</strong></button>
|
||||
<label><input type='checkbox' id='cb-log-reverse'>Reverse log order?</label>
|
||||
</div>
|
||||
<div id='test-output'></div>
|
||||
<script>(function(){
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
(async function(self){
|
||||
const btnGo = document.querySelector('#gogogo');
|
||||
|
||||
const logCss = (function(){
|
||||
const mapToString = (v)=>{
|
||||
@@ -92,6 +93,7 @@
|
||||
logCss('tests-pass',"All",workers.length,"workers finished in",
|
||||
calcTime(new Date()),"ms");
|
||||
}
|
||||
logCss("Reload page to run the test again.");
|
||||
};
|
||||
|
||||
workers.onmessage = function(msg){
|
||||
@@ -158,25 +160,28 @@
|
||||
a.innerText = args;
|
||||
}
|
||||
|
||||
stdout("Launching",options.workerCount,"workers. Options:",options);
|
||||
workers.uri = (
|
||||
'worker.js?'
|
||||
+ 'sqlite3.dir='+options.sqlite3Dir
|
||||
+ '&vfs='+options.vfs
|
||||
+ '&interval='+options.interval
|
||||
+ '&iterations='+options.iterations
|
||||
+ '&opfs-verbose='+options.opfsVerbose
|
||||
+ '&opfs-unlock-asap='+options.unlockAsap
|
||||
);
|
||||
for(let i = 0; i < options.workerCount; ++i){
|
||||
stdout("Launching worker...", i, );
|
||||
workers.push(new Worker(
|
||||
workers.uri+'&workerId='+(i+1)+(
|
||||
(i || options.noUnlink) ? '' : '&unlink-db'
|
||||
)
|
||||
));
|
||||
}
|
||||
// Have to delay onmessage assignment until after the loop
|
||||
// to avoid that early workers get an undue head start.
|
||||
workers.forEach((w)=>w.onmessage = workers.onmessage);
|
||||
btnGo.addEventListener('click', ()=>{
|
||||
btnGo.remove();
|
||||
stdout("Launching",options.workerCount,"workers. Options:",options);
|
||||
workers.uri = (
|
||||
'worker.js?'
|
||||
+ 'sqlite3.dir='+options.sqlite3Dir
|
||||
+ '&vfs='+options.vfs
|
||||
+ '&interval='+options.interval
|
||||
+ '&iterations='+options.iterations
|
||||
+ '&opfs-verbose='+options.opfsVerbose
|
||||
+ '&opfs-unlock-asap='+options.unlockAsap
|
||||
);
|
||||
for(let i = 0; i < options.workerCount; ++i){
|
||||
stdout("Launching worker...", i, );
|
||||
workers.push(new Worker(
|
||||
workers.uri+'&workerId='+(i+1)+(
|
||||
(i || options.noUnlink) ? '' : '&unlink-db'
|
||||
)
|
||||
));
|
||||
}
|
||||
// Have to delay onmessage assignment until after the loop
|
||||
// to avoid that early workers get an undue head start.
|
||||
workers.forEach((w)=>w.onmessage = workers.onmessage);
|
||||
});
|
||||
})(globalThis);
|
||||
|
||||
@@ -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
|
||||
@@ -1920,6 +1906,12 @@ smoketest: $(TESTPROGS) fuzzcheck$(T.exe)
|
||||
shelltest:
|
||||
$(TCLSH_CMD) $(TOP)/test/testrunner.tcl release shell
|
||||
|
||||
# Test performance of floating-point conversions.
|
||||
#
|
||||
fp-speed-test: fp-speed-1$(T.exe) fp-speed-2$(T.exe)
|
||||
./fp-speed-1 1000000
|
||||
./fp-speed-2 1000000
|
||||
|
||||
#
|
||||
# sqlite3_analyzer.c build depends on $(LINK_TOOLS_DYNAMICALLY).
|
||||
#
|
||||
@@ -2037,6 +2029,14 @@ speedtest1$(T.exe): $(TOP)/test/speedtest1.c sqlite3.c Makefile
|
||||
$(LDFLAGS.libsqlite3)
|
||||
xbin: speedtest1$(T.exe)
|
||||
|
||||
fp-speed-1$(T.exe): $(TOP)/test/fp-speed-1.c sqlite3.o Makefile
|
||||
$(T.link) $(ST_OPT) -o $@ $(TOP)/test/fp-speed-1.c sqlite3.o \
|
||||
$(LDFLAGS.libsqlite3)
|
||||
|
||||
fp-speed-2$(T.exe): $(TOP)/test/fp-speed-2.c sqlite3.o Makefile
|
||||
$(T.link) $(ST_OPT) -o $@ $(TOP)/test/fp-speed-2.c sqlite3.o \
|
||||
$(LDFLAGS.libsqlite3)
|
||||
|
||||
startup$(T.exe): $(TOP)/test/startup.c sqlite3.c
|
||||
$(T.link) -Os -g -USQLITE_THREADSAFE -DSQLITE_THREADSAFE=0 \
|
||||
-o $@ $(TOP)/test/startup.c sqlite3.c $(LDFLAGS.libsqlite3)
|
||||
@@ -2482,6 +2482,7 @@ tidy:
|
||||
rm -f tclsqlite3$(T.exe) $(TESTPROGS)
|
||||
rm -f LogEst$(T.exe) fts3view$(T.exe) rollback-test$(T.exe) showdb$(T.exe)
|
||||
rm -f showjournal$(T.exe) showstat4$(T.exe) showwal$(T.exe) speedtest1$(T.exe)
|
||||
rm -f fp-speed-1$(T.exe) fp-speed-2$(T.exe)
|
||||
rm -f wordcount$(T.exe) changeset$(T.exe) version-info$(T.exe)
|
||||
rm -f *.exp *.vsix pkgIndex.tcl
|
||||
rm -f sqlite3_analyzer$(T.exe) sqlite3_rsync$(T.exe) sqlite3_expert$(T.exe)
|
||||
@@ -2504,7 +2505,7 @@ tidy:
|
||||
# Removes build products and test logs. Retains ./configure outputs.
|
||||
#
|
||||
clean: tidy
|
||||
rm -rf omittest* testrunner* testdir*
|
||||
rm -rf omittest* testrunner* testrun_* testdir*
|
||||
|
||||
#
|
||||
# Clean up everything. No exceptions. From an out-of-tree build which
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
C Additional\sperformance\simprovements\sin\ssqlite3AtoF().\s\sAlso\supdate\sthe\nheader\scomments.
|
||||
D 2026-03-22T17:50:48.147
|
||||
C Add\sa\smissing\sopen_db()\scall\sin\sthe\snew\s".dbstat"\scommand\sof\sthe\sCLI.
|
||||
D 2026-04-15T11:58:54.973
|
||||
F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x
|
||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||
F LICENSE.md 6bc480fc673fb4acbc4094e77edb326267dd460162d7723c7f30bee2d3d9e97d
|
||||
F Makefile.in 3ce07126d7e87c7464301482e161fdae6a51d0a2aa06b200b8f0000ef4d6163b
|
||||
F Makefile.in 5fda086f33b144da08119255da1d2557f983d0764a13707f05acf0159fd89ba5
|
||||
F Makefile.linux-generic bd3e3cacd369821a6241d4ea1967395c962dfe3057e38cb0a435cee0e8b789d0
|
||||
F Makefile.msc bee487191dcc9394d0e38854aa311b79d4488e0b877cc1a1a61ba5ad8ef225a6
|
||||
F README.md 3fa51fc7ababc32edd175ae8b2986c86d5ea120c1cb1e57c7f7849492d1405ec
|
||||
F VERSION 31435e19ded2aae3c1c67dacf06a995a37fd1b253baec5899b78d64cd29db4f7
|
||||
F Makefile.msc 06b757f8648f1d9dd9683dbd72350cf0cf20d6fe09168cac455569b81dd97ddc
|
||||
F README.md e4f1a030f813c2fafc898c66d4f10bff2c75eb1a8f504eb9ad9a5ef80e3ff814
|
||||
F VERSION 99cf3be5f13d091183e4314b7fc2e0c0e69accfbe64608b45a313338bbdd7b62
|
||||
F art/icon-243x273.gif 9750b734f82fdb3dc43127753d5e6fbf3b62c9f4e136c2fbf573b2f57ea87af5
|
||||
F art/icon-80x90.gif 65509ce3e5f86a9cd64fe7fca2d23954199f31fe44c1e09e208c80fb83d87031
|
||||
F art/sqlite370.eps aa97a671332b432a54e1d74ff5e8775be34200c2
|
||||
@@ -44,10 +44,10 @@ F autosetup/cc-lib.tcl 493c5935b5dd3bf9bd4eca89b07c8b1b1a9356d61783035144e21795f
|
||||
F autosetup/cc-shared.tcl 163eda58c14cd662fd8a504bd2ad8a716ef4db7015dc1de0095d5de8dd601a4b
|
||||
F autosetup/cc.tcl c0fcc50ca91deff8741e449ddad05bcd08268bc31177e613a6343bbd1fd3e45f
|
||||
F autosetup/find_tclconfig.tcl e64886ffe3b982d4df42cd28ed91fe0b5940c2c5785e126c1821baf61bc86a7e
|
||||
F autosetup/jimsh0.c 916bbdf8023fbda9937afae57d81a853d8c2ea00f2320aa27becbc33574f963d
|
||||
F autosetup/jimsh0.c 740dc8cbfaedaff1f27b54b32e0015b22fa6c1a439492b9795968d61e56bab75
|
||||
F autosetup/pkg-config.tcl 4e635bf39022ff65e0d5434339dd41503ea48fc53822c9c5bde88b02d3d952ba
|
||||
F autosetup/proj.tcl ce301197f364f7ce2acabbbd84b43d19e917ec73653157ca134a06f32d322712
|
||||
F autosetup/sqlite-config.tcl 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,29 @@ 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/analyze.c c329e7fdd23caebbe5362b25a416a7fda7e1524ddba03be12f1d2e4a903caa02
|
||||
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 +387,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 +412,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 64203184d9fc6ee75439fb6da70fd51dc7aaf3243600e52aa87d18ea1e4d6e73
|
||||
F ext/qrf/qrf.h fbb223ff5789b324b3e9c22e787e4c1f53e217cff7cc5a243164d4b2e8410f4b
|
||||
F ext/rbu/rbu.c 801450b24eaf14440d8fd20385aacc751d5c9d6123398df41b1b5aa804bf4ce8
|
||||
F ext/rbu/rbu1.test 25870dd7db7eb5597e2b4d6e29e7a7e095abf332660f67d89959552ce8f8f255
|
||||
F ext/rbu/rbu10.test 7c22caa32c2ff26983ca8320779a31495a6555737684af7aba3daaf762ef3363
|
||||
@@ -463,11 +464,11 @@ F ext/rbu/rburesume.test 1403752d152b55efb7fc25749c0fccc790061371ec9ffe428cc04f8
|
||||
F ext/rbu/rbusave.test 588b618dad9d65c4b13d03a79931de82213503fedc26bdf5789c996ecf427fba
|
||||
F ext/rbu/rbusplit.test a6dedd23cf37bcf2e8646d9d7139846e96d60d92f9bc6d6ba6ca8c24c0bd1f72
|
||||
F ext/rbu/rbutemplimit.test 4980df2d4b74f4dd982add8f78809106154ef5a3c4bdce747422ab0b0481e029
|
||||
F ext/rbu/rbuvacuum.test 542561741ff2b262e3694bc6012b44694ee62c545845319a06f323783b15311e
|
||||
F ext/rbu/rbuvacuum.test e3585cfda220038e8186c583e9bd2aaa9eccd0a5c2e40ed861de3c987c93f68c
|
||||
F ext/rbu/rbuvacuum2.test 1a9bd41f127be2826de2a65204df9118525a8af8d16e61e6bc63ba3ac0010a23
|
||||
F ext/rbu/rbuvacuum3.test 3ce42695fdf21aaa3499e857d7d4253bc499ad759bcd6c9362042c13cd37d8de
|
||||
F ext/rbu/rbuvacuum4.test ffccd22f67e2d0b380d2889685742159dfe0d19a3880ca3d2d1d69eefaebb205
|
||||
F ext/rbu/sqlite3rbu.c e99400d29d029936075e27495b269a2dcdceae3cf8c86b1d0869b4af487be3ab
|
||||
F ext/rbu/sqlite3rbu.c 28246b647831409e84dfb8286fbeda55f1de89e934571509a23a67ada572d0c0
|
||||
F ext/rbu/sqlite3rbu.h e3a5bf21e09ca93ce4e8740e00d6a853e90a697968ec0ea98f40826938bdb68e
|
||||
F ext/rbu/test_rbu.c 8b6e64e486c28c41ef29f6f4ea6be7b3091958987812784904f5e903f6b56418
|
||||
F ext/recover/dbdata.c 10d3c56968a9af6853722a47280805ad1564714d79ea45ac6f7da14bb57fd137
|
||||
@@ -540,7 +541,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 +556,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 +572,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
|
||||
@@ -581,7 +583,7 @@ F ext/wasm/SQLTester/SQLTester.mjs 6b3c52ed36a5573ca4883176f326332a8d4c0cecf5efd
|
||||
F ext/wasm/SQLTester/SQLTester.run.mjs 57f2adb33f43f2784abbf8026c1bfd049d8013af1998e7dcb8b50c89ffc332e0
|
||||
F ext/wasm/SQLTester/index.html 64f3435084c7d6139b08d1f2a713828a73f68de2ae6a3112cbb5980d991ba06f
|
||||
F ext/wasm/SQLTester/touint8array.c 2d5ece04ec1393a6a60c4bf96385bda5e1a10ad49f3038b96460fc5e5aa7e536
|
||||
F ext/wasm/api/EXPORTED_FUNCTIONS.c-pp de2ce128aebeff9ef4161cff7a0ff0089be866121bcb8941ad44a38a65f1d436
|
||||
F ext/wasm/api/EXPORTED_FUNCTIONS.c-pp 189935d0106bca86661efc991ab13e1d5d6e1f55ec34dc7b5055a99321397edd
|
||||
F ext/wasm/api/README.md a905d5c6bfc3e2df875bd391d6d6b7b48d41b43bdee02ad115b47244781a7e81
|
||||
F ext/wasm/api/extern-post-js.c-pp.js 80accc53cc6ea1e61c721595f42ba95baa7c7ea636807d9507e69403301f8c54
|
||||
F ext/wasm/api/extern-pre-js.js cc61c09c7a24a07dbecb4c352453c3985170cec12b4e7e7e7a4d11d43c5c8f41
|
||||
@@ -591,15 +593,15 @@ F ext/wasm/api/post-js-footer.js a50c1a2c4d008aede7b2aa1f18891a7ee71437c2f415b8a
|
||||
F ext/wasm/api/post-js-header.js f35d2dcf1ab7f22a93d565f8e0b622a2934fc4e743edf3b708e4dd8140eeff55
|
||||
F ext/wasm/api/pre-js.c-pp.js d6bf82f83f60caa2904bddb95a29cb738b310f672d2796cdc5fe54463ab0d6cd
|
||||
F ext/wasm/api/sqlite3-api-glue.c-pp.js 31a721ada7225838a61310a9f3f797fa5275353f8e9b0ae769d85b437be061f5
|
||||
F ext/wasm/api/sqlite3-api-oo1.c-pp.js 5f203f5bb5d48a9e43ec51e791dc411c24dca825842bfb6a2d979d871bf8cfaf
|
||||
F ext/wasm/api/sqlite3-api-prologue.js 4336f02ac24ba58e68e355adb9da2804a1eef15a4aee961fa813c7d812a56b54
|
||||
F ext/wasm/api/sqlite3-api-oo1.c-pp.js 35e4727010f15fd72ead0dd1eb4e3c2c9bb1cc60e51544cbdff1f7c14f209de2
|
||||
F ext/wasm/api/sqlite3-api-prologue.js 29ca376ff5d5f189714cf10b2b93b136e91b06ec8616579b53b2af9dfb4796bf
|
||||
F ext/wasm/api/sqlite3-api-worker1.c-pp.js 1fa34e9b0e3b90a8898e4f700d7125e44c81877f182627bb8564b97989bc6e78
|
||||
F ext/wasm/api/sqlite3-license-version-header.js 98d90255a12d02214db634e041c8e7f2f133d9361a8ebf000ba9c9af4c6761cc
|
||||
F ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js 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
|
||||
@@ -620,16 +622,16 @@ F ext/wasm/demo-worker1-promiser.c-pp.js d210aa1e8a74ea6244fe2290de5710bb55b3a9e
|
||||
F ext/wasm/demo-worker1.html 2c178c1890a2beb5a5fecb1453e796d067a4b8d3d2a04d65ca2eb1ab2c68ef5d
|
||||
F ext/wasm/demo-worker1.js fdfa90aa9d6b402bfed802cf1595fe4da6cc834ac38c8ff854bf1ee01f5ff9bb
|
||||
F ext/wasm/example_extra_init.c 2347cd69d19d839ef4e5e77b7855103a7fe3ef2af86f2e8c95839afd8b05862f
|
||||
F ext/wasm/fiddle/fiddle-worker.js 6c72acac2d381480bc9f5eb538e3f2faf2c1f72dd4fcbd05d3b409818a9a8fd5
|
||||
F ext/wasm/fiddle/fiddle.js 84fd75967e0af8b69d3dd849818342227d0f81d13db92e0dcbc63649b31a4893
|
||||
F ext/wasm/fiddle/index.c-pp.html 02f063ef30b8124f311029855c4439e77bc6505d1bf65a163d88c064a63ee9d9
|
||||
F ext/wasm/fiddle/fiddle-worker.js e45bfe9ce4cf0d0270ca0ed254af8deecc7d46c399db4a56fd1d0846d5e258ec
|
||||
F ext/wasm/fiddle/fiddle.js 2a0984cc4a35e6889c0d84ee9bf853317d5545ddb3966dfb995bbe589f923c4c
|
||||
F ext/wasm/fiddle/index.c-pp.html 5fd1f462864710d1b00d27fc4bc6190cb846cc865d7cc93b99644423f2c4cc84
|
||||
F ext/wasm/index-dist.html db23748044e286773f2768eec287669501703b5d5f72755e8db73607dc54d290
|
||||
F ext/wasm/index.html 5bf6cf1b0a3c8b9f5f54d77f2219d7ae87a15162055ce308109c49b1dcab4239
|
||||
F ext/wasm/jaccwabyt/jaccwabyt.js 4e2b797dc170851c9c530c3567679f4aa509eec0fab73b466d945b00b356574b
|
||||
F ext/wasm/jaccwabyt/jaccwabyt.md 6aa90fa1a973d0ad10d077088bea163b241d8470c75eafdef87620a1de1dea41
|
||||
F ext/wasm/libcmpp.c 0e2cec7de7c9cbe7941e6a4dc0c123cec736578a3eeae7828ac18706acd3cea6
|
||||
F ext/wasm/mkdist.sh f8883b077a2ca47cf92e6f0ce305fbf72ca648c3501810125056c4b09c2d5554 x
|
||||
F ext/wasm/mkwasmbuilds.c d4479af2774a43104b819d9286961b7c09793ca39440e20191e693ceff21f911
|
||||
F ext/wasm/mkwasmbuilds.c 60706fb66db7f1e24d876e3cb2493484cfb27e7b103c7741c384505dd678769c
|
||||
F ext/wasm/module-symbols.html e54f42112e0aac2a31f850ab33e7f2630a2ea4f63496f484a12469a2501e07e2
|
||||
F ext/wasm/scratchpad-wasmfs.html a3d7388f3c4b263676b58b526846e9d02dfcb4014ff29d3a5040935286af5b96
|
||||
F ext/wasm/scratchpad-wasmfs.mjs 66034b9256b218de59248aad796760a1584c1dd842231505895eff00dbd57c63
|
||||
@@ -646,8 +648,8 @@ F ext/wasm/test-opfs-vfs.js 1618670e466f424aa289859fe0ec8ded223e42e9e69b5c851f80
|
||||
F ext/wasm/tester1-worker.c-pp.html 7171022e7f4da8f46e5f50ea81dd6ce840b9235c47653a5deeb3764ccc2fe472
|
||||
F ext/wasm/tester1.c-pp.html bd927ccf51ddd65e924660a0487add99e1b044afe03950e49d87ccf44efdddb6
|
||||
F ext/wasm/tester1.c-pp.js 581be6f3228351bc77512ba743912d1ad52f40dde1fef1a943fd568b0cfc51b1
|
||||
F ext/wasm/tests/opfs/concurrency/index.html c8ac239f6fb45440adbdddb33a0fde2c61a20799189d60b8926be702a27dd226
|
||||
F ext/wasm/tests/opfs/concurrency/test.js 46c772bc18abb0fcbb058d57b5aaee9e7938f948ecdd802c6ca0850ad3519f92
|
||||
F ext/wasm/tests/opfs/concurrency/index.html 706eab6308343c04ac2360aba6001af4ffaf46d8f33a0ccd02c64d93e3216a43
|
||||
F ext/wasm/tests/opfs/concurrency/test.js 6919778fceaac1b7cc78caf41d796f545d2c4433b31188aa9689f05b5ad28828
|
||||
F ext/wasm/tests/opfs/concurrency/worker.js 704d82c5e287e47f612349e027765943a58ad967dcf178fb5a1c3a8eaafb09af
|
||||
F ext/wasm/tests/opfs/sahpool/digest-worker.js b0ab6218588f1f0a6d15a363b493ceaf29bfb87804d9e0165915a9996377cf79
|
||||
F ext/wasm/tests/opfs/sahpool/digest.html 206d08a34dc8bd570b2581d3d9ab3ecad3201b516a598dd096dcf3cf8cd81df8
|
||||
@@ -655,7 +657,7 @@ F ext/wasm/tests/opfs/sahpool/index.html be736567fd92d3ecb9754c145755037cbbd2bca
|
||||
F ext/wasm/tests/opfs/sahpool/sahpool-pausing.js f264925cfc82155de38cecb3d204c36e0f6991460fff0cb7c15079454679a4e2
|
||||
F ext/wasm/tests/opfs/sahpool/sahpool-worker.js bd25a43fc2ab2d1bafd8f2854ad3943ef673f7c3be03e95ecf1612ff6e8e2a61
|
||||
F magic.txt 5ade0bc977aa135e79e3faaea894d5671b26107cc91e70783aa7dc83f22f3ba0
|
||||
F main.mk 64479b612d66a3f1a3ab498a3a40607937f614168987d8cda8320fa8be517fac
|
||||
F main.mk 48f6b3557cefd79e5cfae1f15e32d6a0dffd7b689c582a9a7b3920a4ee18affd
|
||||
F make.bat a136fd0b1c93e89854a86d5f4edcf0386d211e5d5ec2434480f6eea436c7420c
|
||||
F mptest/config01.test 3c6adcbc50b991866855f1977ff172eb6d901271
|
||||
F mptest/config02.test 4415dfe36c48785f751e16e32c20b077c28ae504
|
||||
@@ -673,31 +675,31 @@ F src/auth.c ebec42df26b34a62b6750d30d9c2c03554a1c522020182476f7729a439fef04f
|
||||
F src/backup.c 5c97e8023aab1ce14a42387eb3ae00ba5a0644569e3476f38661fa6f824c3523
|
||||
F src/bitvec.c e242d4496774dfc88fa278177dd23b607dce369ccafb3f61b41638eea2c9b399
|
||||
F src/btmutex.c 30dada73a819a1ef5b7583786370dce1842e12e1ad941e4d05ac29695528daea
|
||||
F src/btree.c fb350c445316c1cc0529703c0b76450770a1de0ab0440641a56b19f05d6fefbe
|
||||
F src/btree.c 216ffbe197e330118a2999adc7d3f09b0e2eeb163df8746ba9a2b27fed3d4335
|
||||
F src/btree.h e823c46d87f63d904d735a24b76146d19f51f04445ea561f71cc3382fd1307f0
|
||||
F src/btreeInt.h 9c0f9ea5c9b5f4dcaea18111d43efe95f2ac276cd86d770dce10fd99ccc93886
|
||||
F src/build.c f370ed7458c1c3258bf8d83abf4af7130b2ba3a76536022e2b4d42973c53f70e
|
||||
F src/build.c 8581de0af3b6c448f5d64e2d18a91ac1e7057b3bcb8b8827e1240f80d87486a4
|
||||
F src/callback.c 3605bbf02bd7ed46c79cd48346db4a32fc51d67624400539c0532f4eead804ad
|
||||
F src/carray.c 3efe3982d5fb323334c29328a4e189ccaef6b95612a6084ad5fa124fd5db1179
|
||||
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
|
||||
F src/complete.c f216b970ce99c5a657556cf1f17e7ddd494515d3beb63df426bf59ff43bd3d9a
|
||||
F src/date.c 61e92f1f7e2e88e1cd91e91dc69eb2b2854e7877254470f9fabd776bfac922b8
|
||||
F src/dbpage.c c9ea81c11727f27e02874611e92773e68e2a90a875ef2404b084564c235fd91f
|
||||
F src/dbstat.c 73362c0df0f40ad5523a6f5501224959d0976757b511299bf892313e79d14f5c
|
||||
F src/delete.c 1f2268d6fe3c78fc1bf794ba65d7026498b78e2342ffaf85825dedae546e6fde
|
||||
F src/expr.c 51e9c77ff5d9a21439e611fe6571a3cd50387e526e13c5614fd407e5b8571930
|
||||
F src/expr.c 68400681c5f6e41231d2c85abf6bb432aeeb2e36c4abdf90eb7b78551a5ce0f3
|
||||
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
|
||||
F src/fkey.c 931f74cec1dc8038a0217ef340c91ce147dd1bbed08dc40c47ee0ec6edfffb08
|
||||
F src/func.c 6e7de3551ae0f8205006e5109f025223246edd20186d54d90746dee7c1c5c093
|
||||
F src/func.c 706ac012bf87d8ad7416a56a1d2b1f19e5dea03506a4606a01aa9d3bacf392c7
|
||||
F src/global.c a19e4b1ca1335f560e9560e590fc13081e21f670643367f99cb9e8f9dc7d615b
|
||||
F src/hash.c 03c8c0f4be9e8bcb6de65aa26d34a61d48a9430747084a69f9469fbb00ea52ca
|
||||
F src/hash.h 46b92795a95bfefb210f52f0c316e9d7cdbcdd7e7fcfb0d8be796d3a5767cddf
|
||||
F src/hwtime.h 21c2cf1f736e7b97502c3674d0c386db3f06870d6f10d0cf8174e2a4b8cb726e
|
||||
F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
|
||||
F src/insert.c dfd311b0ac2d4f6359e62013db67799757f4d2cc56cca5c10f4888acfbbfa3fd
|
||||
F src/json.c 7401618493219bb605408be48d2ea5ed5c9055f1c3b733268331eb0174048746
|
||||
F src/json.c 5027b856cd9b621dc9ba66b211e21a440ccdc63cefdefb44c51e7d3ac550d1a4
|
||||
F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa
|
||||
F src/loadext.c 56a542244fbefc739a2ef57fac007c16b2aefdb4377f584e9547db2ce3e071f9
|
||||
F src/main.c 31a13302193fbd51279c7e69cdfa0320d0de7629f9151e0964c1d320e8bdd7a4
|
||||
F src/loadext.c 78d5b06f18996ffa1203129b28fea043f63a87a4117539678f1d761c30b4ff65
|
||||
F src/main.c 6180079f53ccdd784df2eddc3751f49ea7153c5959bee792b19ad9f4bdbcf437
|
||||
F src/malloc.c 422f7e0498e1c9ef967f06283b6f2c0b16db6b905d8e06f6dbc8baaa3e4e6c5a
|
||||
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
|
||||
F src/mem1.c 3bb59158c38e05f6270e761a9f435bf19827a264c13d1631c58b84bdc96d73b2
|
||||
@@ -718,10 +720,10 @@ F src/os.h 1ff5ae51d339d0e30d8a9d814f4b8f8e448169304d83a7ed9db66a65732f3e63
|
||||
F src/os_common.h 6c0eb8dd40ef3e12fe585a13e709710267a258e2c8dd1c40b1948a1d14582e06
|
||||
F src/os_kv.c e7d96727db5b67e39d590a68cc61c86daf4c093c36c011a09ebfb521182ec28d
|
||||
F src/os_setup.h 8efc64eda6a6c2f221387eefc2e7e45fd5a3d5c8337a7a83519ba4fbd2957ae2
|
||||
F src/os_unix.c fa5e09b4df35ad845440cad67b86908cfe1fd4c28c51915f82e23633d1992bf4
|
||||
F src/os_unix.c a07dce662f6c4e18098f6faa9f7ec7cf311f56ee9151bed2aad4dcd55852c9e2
|
||||
F src/os_win.c 0d553b6e8b92c8eb85e7f1b4a8036fe8638c8b32c9ad8d9d72a861c10f81b4c5
|
||||
F src/os_win.h 5e168adf482484327195d10f9c3bce3520f598e04e07ffe62c9c5a8067c1037b
|
||||
F src/pager.c fe34fd22ec251436985d7b6ebdd05bf238a17901c2cb23d3d28974dd2361a912
|
||||
F src/pager.c fbec9063ea139dfa5d94ce540671752b89f8e8dc38f8a1f614bab1aa04a2dd40
|
||||
F src/pager.h 6137149346e6c8a3ddc1eeb40aee46381e9bc8b0fcc6dda8a1efde993c2275b8
|
||||
F src/parse.y 3b784d6083380a950e3b1b32ce5ddd303e8c7c209d8ab788df2c62aaf9ee8eb3
|
||||
F src/pcache.c 588cc3c5ccaaadde689ed35ce5c5c891a1f7b1f4d1f56f6cf0143b74d8ee6484
|
||||
@@ -729,17 +731,17 @@ F src/pcache.h 092b758d2c5e4dabb30eae46d8dfad77c0f70b16bf3ff1943f7a232b0fe0d4ba
|
||||
F src/pcache1.c 131ca0daf4e66b4608d2945ae76d6ed90de3f60539afbd5ef9ec65667a5f2fcd
|
||||
F src/pragma.c 789ef67117b74b5be0a2db6681f7f0c55e6913791b9da309aefd280de2c8a74d
|
||||
F src/prepare.c f6a6e28a281bd1d1da12f47d370a81af46159b40f73bf7fa0b276b664f9c8b7d
|
||||
F src/printf.c 9cff219dba73b1aa9a8113e83e962f03f7bea8b6eb51cefb25bc468d5a69fb2d
|
||||
F src/printf.c d442fda86ad11da7923dbb354d3761229b5b51dbe06c5c208fa75e3411c79434
|
||||
F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c
|
||||
F src/resolve.c 928ff887f2a7c64275182060d94d06fdddbe32226c569781cf7e7edc6f58d7fd
|
||||
F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97
|
||||
F src/select.c ffe199f025a0dd74670d2a77232bdea364a4d7b36f32c64a6572d39ba6a11576
|
||||
F src/shell.c.in 4a9217005b76017bc90a08f87c45ea273d796273e0b0a3e4c621a5051a4ae95d
|
||||
F src/sqlite.h.in 4d657846d68a58b028f0c4c331b9d3b4a79306f25c3b0d04fb56060343f73d85
|
||||
F src/shell.c.in 4279e364fd909db808ab8fc46ed06f25e96aaa28726bf6342a9b74bde58bc813
|
||||
F src/sqlite.h.in 39d2e09114d2bdb7afd998f4a469c8f8cd065f8093835a7d0422f260fc78fb4f
|
||||
F src/sqlite3.rc 015537e6ac1eec6c7050e17b616c2ffe6f70fca241835a84a4f0d5937383c479
|
||||
F src/sqlite3ext.h 1b7a0ee438bb5c2896d0609c537e917d8057b3340f6ad004d2de44f03e3d3cca
|
||||
F src/sqliteInt.h 9716721fb57e32938a1d30a84560ce7633c63860a2209e188c87afad15d4b464
|
||||
F src/sqliteLimit.h 904a3f520362c7065c18165aaabd504fb13cc1b76cb411f38bd41ac219e4af1e
|
||||
F src/sqlite3ext.h 9788c301f95370fa30e808861f1d2e6f022a816ddbe2a4f67486784c1b31db2e
|
||||
F src/sqliteInt.h bc1cbc0c23dba35b324ae85a7dbb5fb182321bbd30857fb21f3d0cba049001a5
|
||||
F src/sqliteLimit.h c70656b67ab5b96741a8f1c812bdd80c81f2b1c1e443d0cc3ea8c33bb1f1a092
|
||||
F src/status.c 7565d63a79aa2f326339a24a0461a60096d0bd2bce711fefb50b5c89335f3592
|
||||
F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
|
||||
F src/tclsqlite.c 7401c73c917a4d1b380c896a324c8d8eb533a999559d9e339d479596553bebfd
|
||||
@@ -792,30 +794,30 @@ F src/test_vfs.c b4135c1308516adf0dfd494e6d6c33114e03732be899eace0502919b674586b
|
||||
F src/test_window.c 6d80e11fba89a1796525e6f0048ff0c7789aa2c6b0b11c80827dc1437bd8ea72
|
||||
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
|
||||
F src/threads.c 85d8b9f05f78211c61e3739ab5db761d7118766d1916ae7f2764735106bc4e13
|
||||
F src/tokenize.c 2bbf16801d8c59aaf5435b066364da9e39ec3a379084b8a697881e7e52733c63
|
||||
F src/tokenize.c e9d52d9f7374d82dadcd11726bea8a597d43709d6672704f3f0375bf1d726912
|
||||
F src/treeview.c feaa59f14db4f7b5aacca9c5ad5aeb562c1f98262c1ffd74371f4186ade91fc5
|
||||
F src/trigger.c 4bf3bfb3851d165e4404a9f9e69357345f3f7103378c07e07139fdd8aeb7bd20
|
||||
F src/update.c 3e5e7ff66fa19ebe4d1b113d480639a24cc1175adbefabbd1a948a07f28e37cf
|
||||
F src/upsert.c 215328c3f91623c520ec8672c44323553f12caeb4f01b1090ebdca99fdf7b4f1
|
||||
F src/utf.c 7267c3fb9e2467020507601af3354c2446c61f444387e094c779dccd5ca62165
|
||||
F src/util.c b7ec2de13f540ca184173f44845888f5b727f92b9d7255ca7309bec7ed0bf184
|
||||
F src/util.c 377af5da226519a0f374dc3c6d408c9d303a92943e3ae5986432c7d52e6679a2
|
||||
F src/vacuum.c d3d35d8ae893d419ade5fa196d761a83bddcbb62137a1a157ae751ef38b26e82
|
||||
F src/vdbe.c dbafc6f5762f9ae90d9dc9ed065a31743a8ceafbdbfb1a0a3a228921fb3cc36a
|
||||
F src/vdbe.c 6c57525d7db0232d52687d30da1093db0c152f14206c2ef1adf0c19a09d863e3
|
||||
F src/vdbe.h 70e862ac8a11b590f8c1eaac17a0078429d42bc4ea3f757a9af0f451dd966a71
|
||||
F src/vdbeInt.h c31ba4dc8d280c2b1dc89c6fcee68f2555e3813ab34279552c20b964c0e338b1
|
||||
F src/vdbeapi.c 6cdcbe5c7afa754c998e73d2d5d2805556268362914b952811bdfb9c78a37cf1
|
||||
F src/vdbeaux.c 81687c55682b9f4d942186695f4f7fa4743c564a985e0889def52eded9076d61
|
||||
F src/vdbeaux.c 8749b5f4f6d65e048ba78143d2dfc6898f65010ecef213891094e8166d1557da
|
||||
F src/vdbeblob.c b3f0640db9642fbdc88bd6ebcc83d6009514cafc98f062f675f2c8d505d82692
|
||||
F src/vdbemem.c 05610ea8423c4c852a9039e47fb6a2706d4d848758602ebf30da6c3212344695
|
||||
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
|
||||
F src/where.c a00d35adeb2550249ba02f24e50eecfb99cba34c8d7d5299b295a591219a2e73
|
||||
F src/whereInt.h 8d94cb116c9e06205c3d5ac87af065fc044f8cf08bfdccd94b6ea1c1308e65da
|
||||
F src/wherecode.c 676cb6cb02878643e817d9917a2d3522b83a3736b2cedd3dc8a01d7bb92af6c2
|
||||
F src/whereexpr.c e9f7185fba366d9365aa7a97329609e4cf00b3dd0400d069fbaa5187350c17c6
|
||||
@@ -1126,9 +1128,10 @@ F test/fkey_malloc.test 594a7ea1fbab553c036c70813cd8bd9407d63749
|
||||
F test/fordelete.test ba98f14446b310f9c9d935b97ec748753d0144a28b356ba30d1f4f6958fdde5c
|
||||
F test/fork-test.c 9ac2e6423a1d38df3d6be0e8ac15608b545de21e2b19d9d876254c5931b63edb
|
||||
F test/format4.test eeae341953db8b6bda7f549044797c3278a6cc345d11ada81471671b654f8ef4
|
||||
F test/fp-speed-1.c b37de94eba034e1703668816225f54510ec60fb0685406608cc707afe6b8234d
|
||||
F test/fp-speed-1.c 34a2fe8dc30d0b24bb3e7c16efca0a30452287da6caff7dde86eef882db155a4
|
||||
F test/fp-speed-2.c 15830b061832bb51f68f0985cf7a06f4f5d49eb25cc399854f1ff60d6a878ee9
|
||||
F test/fpconv1.test 63f352682fa65601a326563ad633086df6ab194e6ed5e7366786f38a525a7fd7
|
||||
F test/fptest01.sql 210562ad8d5a7895f26273dd3be56561a41bcb51d78a28a337af0f1ceaa3bb8d
|
||||
F test/fptest01.sql 3d84f10bb1cc220b59207354c887d720289903adeb9972a29d6bfcb3fec0df95
|
||||
F test/fts-9fd058691.test 78b887e30ae6816df0e1fed6259de4b5a64ad33c
|
||||
F test/fts3.test 672a040ea57036fb4b6fdc09027c18d7d24ab654
|
||||
F test/fts3_common.tcl dffad248f9ce090800e272017d2898005c28ee6314fc1dd5550643a02666907a
|
||||
@@ -1351,7 +1354,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
|
||||
@@ -1512,7 +1515,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
|
||||
@@ -1617,7 +1620,8 @@ F test/sharedA.test 64bdd21216dda2c6a3bd3475348ccdc108160f34682c97f2f51c19fc0e21
|
||||
F test/sharedB.test 1a84863d7a2204e0d42f2e1606577c5e92e4473fa37ea0f5bdf829e4bf8ee707
|
||||
F test/shared_err.test 32634e404a3317eeb94abc7a099c556a346fdb8fb3858dbe222a4cbb8926a939
|
||||
F test/sharedlock.test 5ede3c37439067c43b0198f580fd374ebf15d304
|
||||
F test/shell1.test eda2e527435f139224dda67db6bbd2466597408d4fe5883d647d67fa32d88f7c
|
||||
F test/shell-prompt.sql 5c18599f2b7566172007005206471aefb7e0be593e8f52d37b9ab03a12aa84a6
|
||||
F test/shell1.test c84eff209f93ad17ccdf7e1634969fc8231684254edeb21d9b13d67c3179cdb5
|
||||
F test/shell2.test dc541d2681503e55466a24d35a4cbf8ca5b90b8fcdef37fc4db07373a67d31d3
|
||||
F test/shell3.test 91efdd545097a61a1f72cf79c9ad5b49da080f3f10282eaf4c3c272cd1012db2
|
||||
F test/shell4.test e25580a792b7b54560c3a76b6968bd8189261f38979fe28e6bc6312c5db280db
|
||||
@@ -1627,7 +1631,7 @@ F test/shell7.test 43fd8e511c533bab5232e95c7b4be93b243451709e89582600d4b6e67693d
|
||||
F test/shell8.test 38c9e4d7e85d2a3ecfacaa9f6cda4f7a81bf4fffb5f3f37f9cd76827c6883192
|
||||
F test/shell9.test c0e8871061a92151450b3332279a893b516fa73a6c46d4f51a0998407cbf8c89
|
||||
F test/shellA.test 05cdaafa1f79913654487ce3aefa038d4106245d58f52e02faf506140a76d480
|
||||
F test/shellB.test 31df04230f6062069bb7c5d0e5c5439ca44448fa9da1a55aa461a4b872fe6bd9
|
||||
F test/shellB.test 82622da7783c32ce931138bec3d5016e802d70361b9f9364b5d49c1dfc2f5af9
|
||||
F test/shmlock.test 9f1f729a7fe2c46c88b156af819ac9b72c0714ac6f7246638a73c5752b5fd13c
|
||||
F test/shortread1.test bb591ef20f0fd9ed26d0d12e80eee6d7ac8897a3
|
||||
F test/show_speedtest1_rtree.tcl 32e6c5f073d7426148a6936a0408f4b5b169aba5
|
||||
@@ -1712,8 +1716,8 @@ F test/temptrigfault.tes fc5918e64f3867156fefe7cfca9d8e1f495134a5229b2b511b0dc11
|
||||
F test/temptrigger.test a00f258ed8d21a0e8fd4f322f15e8cfb5cef2e43655670e07a753e3fb4769d61
|
||||
F test/tester.tcl 2d943f60200e0a36bcd3f1f0baf181a751cd3604ef6b6bd4c8dc39b4e8a53116
|
||||
F test/testloadext.c 862b848783eaed9985fbce46c65cd214664376b549fae252b364d5d1ef350a27
|
||||
F test/testrunner.tcl 78d67079fc39caf2af3fd9d4c30bdac78dae7ec50b9fc802835e7a5189581e07 x
|
||||
F test/testrunner_data.tcl 078e251983c8fc573567125147655f68132210f226c92922daf21fb913779717
|
||||
F test/testrunner.tcl 3b6cbceb4d7f0226d51a7fde247cc5592565953568c18155c8c3a454d93bee71 x
|
||||
F test/testrunner_data.tcl 48c8a230fcada37f4809f95c2ba49e44bc3d520b6165c09173249c6e65b01cc1
|
||||
F test/testrunner_estwork.tcl 81e2ae10238f50540f42fbf2d94913052a99bfb494b69e546506323f195dcff9
|
||||
F test/thread001.test a0985c117eab62c0c65526e9fa5d1360dd1cac5b03bde223902763274ce21899
|
||||
F test/thread002.test c24c83408e35ba5a952a3638b7ac03ccdf1ce4409289c54a050ac4c5f1de7502
|
||||
@@ -2137,7 +2141,7 @@ F tool/mkamalzip.tcl 8aa5ebe7973c8b8774062d34e15fea9815c4cc2ceea3a9b184695f00591
|
||||
F tool/mkautoconfamal.sh 06fbe090b81c24e592c1f22b404334f805ba74d482a9260f2ac81e6f3d3386d8
|
||||
F tool/mkccode.tcl c42a8f8cf78f92e83795d5447460dbce7aaf78a3bbf9082f1507dc71a3665f3c x
|
||||
F tool/mkcombo.tcl 2a5189b219c4a495e1ff7fc980bd568d3cfb82ae9d50c84e77f7a161e96fc132
|
||||
F tool/mkctimec.tcl 3fb5cad05922f5da61262cb6bcd5868a34e94a49ca8833ae2d7796e7df075576 x
|
||||
F tool/mkctimec.tcl 68f3ee9e2e6a06524b25d79b5b61a883053466080a39da59e0a0697f0c4d9a3b x
|
||||
F tool/mkfptab.c 24ea40113f96584caca3f6dd06b4ad5adffa0f39023910cb83fa7ef2ffa9b0ba
|
||||
F tool/mkkeywordhash.c 82d5af1d0e677900739fba59155cddac172d8c712c2d91ab73d6e6bcb30060f0
|
||||
F tool/mkmsvcmin.tcl d76c45efda1cce2d4005bcea7b8a22bb752e3256009f331120fb4fecb14ebb7a
|
||||
@@ -2195,8 +2199,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee
|
||||
F tool/warnings.sh a554d13f6e5cf3760f041b87939e3d616ec6961859c3245e8ef701d1eafc2ca2
|
||||
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
|
||||
F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c
|
||||
P 6c3dc2430adef061b458b6d9159628bb8debfd4d63876d5d5e7493afb799d97f
|
||||
R 0c1564cd8bd4be660fcfe28f92df6384
|
||||
P fdba76df2b3a5b4d56ba79f80fd8b16d5faebca1fb07a266262be2ea635e6f94
|
||||
R 11ac4a0e6010f18fd1adc28138c24819
|
||||
U drh
|
||||
Z c76030a82efd805d9e5d4b632bb41994
|
||||
Z 0f53747329f642cf306c269a12fd15f3
|
||||
# Remove this line to create a well-formed Fossil manifest.
|
||||
|
||||
+2
-2
@@ -1,2 +1,2 @@
|
||||
branch optimize-atof
|
||||
tag optimize-atof
|
||||
branch analyze-sql-func
|
||||
tag analyze-sql-func
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
8c3a1b450d6d5778004b9fb0e92b4f3f90d3e06ff87276370d01a45b7d607d23
|
||||
a138e44a243466f8679e9652421f8c893a4a1bc0addc86736588d9aee51cf090
|
||||
|
||||
+3
-3
@@ -5939,12 +5939,12 @@ moveto_table_finish:
|
||||
** zero if the cell is less than or equal pIdxKey. Return positive
|
||||
** if unknown.
|
||||
**
|
||||
** Return value negative: Cell at pCur[idx] less than pIdxKey
|
||||
** Return value negative: Cell at pPage[idx] less than pIdxKey
|
||||
**
|
||||
** Return value is zero: Cell at pCur[idx] equals pIdxKey
|
||||
** Return value is zero: Cell at pPage[idx] equals pIdxKey
|
||||
**
|
||||
** Return value positive: Nothing is known about the relationship
|
||||
** of the cell at pCur[idx] and pIdxKey.
|
||||
** of the cell at pPage[idx] and pIdxKey.
|
||||
**
|
||||
** This routine is part of an optimization. It is always safe to return
|
||||
** a positive value as that will cause the optimization to be skipped.
|
||||
|
||||
+1
-2
@@ -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;
|
||||
}
|
||||
|
||||
+91
-10
@@ -49,12 +49,51 @@ extern const char sqlite3IsEbcdicIdChar[];
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Return TRUE if the given SQL string ends in a semicolon.
|
||||
** Return zero if the given SQL string is complete - if all comments,
|
||||
** string and blob literals, and quoted identifiers have been closed and
|
||||
** if the entire string ends with ";" and possible with ";END;" if the
|
||||
** string is a CREATE TRIGGER statement. A non-zero return indicates
|
||||
** that the string is incomplete. Bits of the return value indicate
|
||||
** what is missing and is needed to close out the statement.
|
||||
**
|
||||
** Special handling is require for CREATE TRIGGER statements.
|
||||
** Whenever the CREATE TRIGGER keywords are seen, the statement
|
||||
** must end with ";END;".
|
||||
**
|
||||
** Let the return code be a value R. R is split up into various
|
||||
** subfields, at byte boundaries:
|
||||
**
|
||||
** R = 0xwwwwwwww00xxyyzz
|
||||
**
|
||||
** In other words, zz is the least significant byte, yy is the next
|
||||
** most significant byte, xx is the third byte, wwwwwwww is a 32-bit
|
||||
** value from the middle.
|
||||
**
|
||||
** zz == SQLITE_OK Input is complete
|
||||
** zz == SQLITE_ERROR Input is incomplete
|
||||
** zz == SQLITE_MISUSE Input is a NULL pointer
|
||||
** zz != 0 New values for zz may be added in the future
|
||||
**
|
||||
** yy == 0x01 Need a semicolon at the end
|
||||
** yy == 0x02 Need "END" and a semicolon
|
||||
** yy == 0x03 Need semicolon, "END", and semicolon
|
||||
** yy != 0 New values for yy may be added in the future
|
||||
**
|
||||
** xx == '\'' Incomplete string or blob literal
|
||||
** xx == '"' Incomplete quoted identifier
|
||||
** xx == '`' Incompelte MySQL-style quoted identifier
|
||||
** xx == ']' Incomplete SQLServer-style quoted identifer
|
||||
** xx == '-' Incomplete SQL-style comment
|
||||
** xx == '/' Incomplete C-style comment
|
||||
** xx != 0 New values of xx may be added in the future
|
||||
**
|
||||
** wwwwwwww Interpret as a signed integer, the number
|
||||
** of unmatched "(". Negative means there are
|
||||
** more ")" and "(".
|
||||
**
|
||||
** ((R>>24)&0xff)!=0 New uses for the 4th byte may be added
|
||||
** in the future
|
||||
**
|
||||
** This implementation uses a state machine with 8 states:
|
||||
**
|
||||
** (0) INVALID We have not yet seen a non-whitespace character.
|
||||
@@ -101,9 +140,11 @@ extern const char sqlite3IsEbcdicIdChar[];
|
||||
** to recognize the end of a trigger can be omitted. All we have to do
|
||||
** is look for a semicolon that is not part of an string or comment.
|
||||
*/
|
||||
int sqlite3_complete(const char *zSql){
|
||||
sqlite3_int64 sqlite3_incomplete(const char *zSql){
|
||||
u8 state = 0; /* Current state, using numbers defined in header comment */
|
||||
u8 token; /* Value of the next token */
|
||||
u8 pending = 0; /* unmatched structure character */
|
||||
int nParen = 0; /* Nested parentheses */
|
||||
|
||||
#ifndef SQLITE_OMIT_TRIGGER
|
||||
/* A complex statement machine used to detect the end of a CREATE TRIGGER
|
||||
@@ -133,11 +174,21 @@ int sqlite3_complete(const char *zSql){
|
||||
/* 2 NORMAL: */ { 1, 2, 2, },
|
||||
};
|
||||
#endif /* SQLITE_OMIT_TRIGGER */
|
||||
/* Mapping state number to yy value for the return */
|
||||
static const u8 statemap[8] = {
|
||||
/* 0 INVALID */ 1,
|
||||
/* 1 START */ 0,
|
||||
/* 2 NORMAL */ 1,
|
||||
/* 3 EXPLAIN */ 1,
|
||||
/* 4 CREATE */ 1,
|
||||
/* 5 TRIGGER */ 3,
|
||||
/* 6 SEMI */ 2,
|
||||
/* 7 END */ 1,
|
||||
};
|
||||
|
||||
#ifdef SQLITE_ENABLE_API_ARMOR
|
||||
if( zSql==0 ){
|
||||
(void)SQLITE_MISUSE_BKPT;
|
||||
return 0;
|
||||
return SQLITE_MISUSE_BKPT;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -162,7 +213,10 @@ int sqlite3_complete(const char *zSql){
|
||||
}
|
||||
zSql += 2;
|
||||
while( zSql[0] && (zSql[0]!='*' || zSql[1]!='/') ){ zSql++; }
|
||||
if( zSql[0]==0 ) return 0;
|
||||
if( zSql[0]==0 ){
|
||||
pending = '/';
|
||||
goto incomplete_finish;
|
||||
}
|
||||
zSql++;
|
||||
token = tkWS;
|
||||
break;
|
||||
@@ -173,14 +227,20 @@ int sqlite3_complete(const char *zSql){
|
||||
break;
|
||||
}
|
||||
while( *zSql && *zSql!='\n' ){ zSql++; }
|
||||
if( *zSql==0 ) return state==1;
|
||||
if( *zSql==0 ){
|
||||
if( state!=1 ) pending = '-';
|
||||
goto incomplete_finish;
|
||||
}
|
||||
token = tkWS;
|
||||
break;
|
||||
}
|
||||
case '[': { /* Microsoft-style identifiers in [...] */
|
||||
zSql++;
|
||||
while( *zSql && *zSql!=']' ){ zSql++; }
|
||||
if( *zSql==0 ) return 0;
|
||||
if( *zSql==0 ){
|
||||
pending = ']';
|
||||
goto incomplete_finish;
|
||||
}
|
||||
token = tkOTHER;
|
||||
break;
|
||||
}
|
||||
@@ -190,7 +250,20 @@ int sqlite3_complete(const char *zSql){
|
||||
int c = *zSql;
|
||||
zSql++;
|
||||
while( *zSql && *zSql!=c ){ zSql++; }
|
||||
if( *zSql==0 ) return 0;
|
||||
if( *zSql==0 ){
|
||||
pending = c;
|
||||
goto incomplete_finish;
|
||||
}
|
||||
token = tkOTHER;
|
||||
break;
|
||||
}
|
||||
case '(': {
|
||||
nParen++;
|
||||
token = tkOTHER;
|
||||
break;
|
||||
}
|
||||
case ')': {
|
||||
nParen--;
|
||||
token = tkOTHER;
|
||||
break;
|
||||
}
|
||||
@@ -257,7 +330,15 @@ int sqlite3_complete(const char *zSql){
|
||||
state = trans[state][token];
|
||||
zSql++;
|
||||
}
|
||||
return state==1;
|
||||
incomplete_finish:
|
||||
if( state==1 ) nParen = 0;
|
||||
return (i64)((((u64)nParen)<<32) |
|
||||
((u64)pending<<16) |
|
||||
((u64)statemap[state]<<8) |
|
||||
(state!=1));
|
||||
}
|
||||
int sqlite3_complete(const char *zSql){
|
||||
return sqlite3_incomplete(zSql)==0;
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_UTF16
|
||||
@@ -279,7 +360,7 @@ int sqlite3_complete16(const void *zSql){
|
||||
sqlite3ValueSetStr(pVal, -1, zSql, SQLITE_UTF16NATIVE, SQLITE_STATIC);
|
||||
zSql8 = sqlite3ValueText(pVal, SQLITE_UTF8);
|
||||
if( zSql8 ){
|
||||
rc = sqlite3_complete(zSql8);
|
||||
rc = sqlite3_incomplete(zSql8)==0;
|
||||
}else{
|
||||
rc = SQLITE_NOMEM_BKPT;
|
||||
}
|
||||
|
||||
+1
-1
@@ -2650,7 +2650,7 @@ int sqlite3ExprIsConstant(Parse *pParse, Expr *p){
|
||||
** Walk an expression tree. Return non-zero if
|
||||
**
|
||||
** (1) the expression is constant, and
|
||||
** (2) the expression does originate in the ON or USING clause
|
||||
** (2) the expression does not originate in the ON or USING clause
|
||||
** of a LEFT JOIN, and
|
||||
** (3) the expression does not contain any EP_FixedCol TK_COLUMN
|
||||
** operands created by the constant propagation optimization.
|
||||
|
||||
+5
-12
@@ -1098,18 +1098,11 @@ void sqlite3QuoteValue(StrAccum *pStr, sqlite3_value *pValue, int bEscape){
|
||||
|
||||
switch( sqlite3_value_type(pValue) ){
|
||||
case SQLITE_FLOAT: {
|
||||
double r1, r2;
|
||||
const char *zVal;
|
||||
r1 = sqlite3_value_double(pValue);
|
||||
sqlite3_str_appendf(pStr, "%!0.15g", r1);
|
||||
zVal = sqlite3_str_value(pStr);
|
||||
if( zVal ){
|
||||
sqlite3AtoF(zVal, &r2);
|
||||
if( r1!=r2 ){
|
||||
sqlite3_str_reset(pStr);
|
||||
sqlite3_str_appendf(pStr, "%!0.20e", r1);
|
||||
}
|
||||
}
|
||||
/* ,--- Show infinity as 9.0e+999
|
||||
** |
|
||||
** | ,--- 17 precision guarantees round-trip
|
||||
** v v */
|
||||
sqlite3_str_appendf(pStr, "%!0.17g", sqlite3_value_double(pValue));
|
||||
break;
|
||||
}
|
||||
case SQLITE_INTEGER: {
|
||||
|
||||
+76
-28
@@ -313,7 +313,8 @@ struct JsonString {
|
||||
/* Allowed values for JsonString.eErr */
|
||||
#define JSTRING_OOM 0x01 /* Out of memory */
|
||||
#define JSTRING_MALFORMED 0x02 /* Malformed JSONB */
|
||||
#define JSTRING_ERR 0x04 /* Error already sent to sqlite3_result */
|
||||
#define JSTRING_TOODEEP 0x04 /* JSON nested too deep */
|
||||
#define JSTRING_ERR 0x08 /* Error already sent to sqlite3_result */
|
||||
|
||||
/* The "subtype" set for text JSON values passed through using
|
||||
** sqlite3_result_subtype() and sqlite3_value_subtype().
|
||||
@@ -403,7 +404,7 @@ struct JsonParse {
|
||||
**************************************************************************/
|
||||
static void jsonReturnStringAsBlob(JsonString*);
|
||||
static int jsonArgIsJsonb(sqlite3_value *pJson, JsonParse *p);
|
||||
static u32 jsonTranslateBlobToText(const JsonParse*,u32,JsonString*);
|
||||
static u32 jsonTranslateBlobToText(JsonParse*,u32,JsonString*);
|
||||
static void jsonReturnParse(sqlite3_context*,JsonParse*);
|
||||
static JsonParse *jsonParseFuncArg(sqlite3_context*,sqlite3_value*,u32);
|
||||
static void jsonParseFree(JsonParse*);
|
||||
@@ -561,6 +562,15 @@ static void jsonStringOom(JsonString *p){
|
||||
jsonStringReset(p);
|
||||
}
|
||||
|
||||
/* Report JSON nested too deep
|
||||
*/
|
||||
static void jsonStringTooDeep(JsonString *p){
|
||||
p->eErr |= JSTRING_TOODEEP;
|
||||
assert( p->pCtx!=0 );
|
||||
sqlite3_result_error(p->pCtx, "JSON nested too deep", -1);
|
||||
jsonStringReset(p);
|
||||
}
|
||||
|
||||
/* Enlarge pJson->zBuf so that it can hold at least N more bytes.
|
||||
** Return zero on success. Return non-zero on an OOM error
|
||||
*/
|
||||
@@ -877,6 +887,8 @@ static void jsonReturnString(
|
||||
}
|
||||
}else if( p->eErr & JSTRING_OOM ){
|
||||
sqlite3_result_error_nomem(p->pCtx);
|
||||
}else if( p->eErr & JSTRING_TOODEEP ){
|
||||
/* error already in p->pCtx */
|
||||
}else if( p->eErr & JSTRING_MALFORMED ){
|
||||
sqlite3_result_error(p->pCtx, "malformed JSON", -1);
|
||||
}
|
||||
@@ -2178,7 +2190,7 @@ static u32 jsonbPayloadSize(const JsonParse *pParse, u32 i, u32 *pSz){
|
||||
** The pOut->eErr JSTRING_OOM flag is set on a OOM.
|
||||
*/
|
||||
static u32 jsonTranslateBlobToText(
|
||||
const JsonParse *pParse, /* the complete parse of the JSON */
|
||||
JsonParse *pParse, /* the complete parse of the JSON */
|
||||
u32 i, /* Start rendering at this index */
|
||||
JsonString *pOut /* Write JSON here */
|
||||
){
|
||||
@@ -2360,10 +2372,14 @@ static u32 jsonTranslateBlobToText(
|
||||
jsonAppendChar(pOut, '[');
|
||||
j = i+n;
|
||||
iEnd = j+sz;
|
||||
if( ++pParse->iDepth > JSON_MAX_DEPTH ){
|
||||
jsonStringTooDeep(pOut);
|
||||
}
|
||||
while( j<iEnd && pOut->eErr==0 ){
|
||||
j = jsonTranslateBlobToText(pParse, j, pOut);
|
||||
jsonAppendChar(pOut, ',');
|
||||
}
|
||||
pParse->iDepth--;
|
||||
if( j>iEnd ) pOut->eErr |= JSTRING_MALFORMED;
|
||||
if( sz>0 ) jsonStringTrimOneChar(pOut);
|
||||
jsonAppendChar(pOut, ']');
|
||||
@@ -2374,10 +2390,14 @@ static u32 jsonTranslateBlobToText(
|
||||
jsonAppendChar(pOut, '{');
|
||||
j = i+n;
|
||||
iEnd = j+sz;
|
||||
if( ++pParse->iDepth > JSON_MAX_DEPTH ){
|
||||
jsonStringTooDeep(pOut);
|
||||
}
|
||||
while( j<iEnd && pOut->eErr==0 ){
|
||||
j = jsonTranslateBlobToText(pParse, j, pOut);
|
||||
jsonAppendChar(pOut, (x++ & 1) ? ',' : ':');
|
||||
}
|
||||
pParse->iDepth--;
|
||||
if( (x & 1)!=0 || j>iEnd ) pOut->eErr |= JSTRING_MALFORMED;
|
||||
if( sz>0 ) jsonStringTrimOneChar(pOut);
|
||||
jsonAppendChar(pOut, '}');
|
||||
@@ -2434,7 +2454,7 @@ static u32 jsonTranslateBlobToPrettyText(
|
||||
u32 i /* Start rendering at this index */
|
||||
){
|
||||
u32 sz, n, j, iEnd;
|
||||
const JsonParse *pParse = pPretty->pParse;
|
||||
JsonParse *pParse = pPretty->pParse;
|
||||
JsonString *pOut = pPretty->pOut;
|
||||
n = jsonbPayloadSize(pParse, i, &sz);
|
||||
if( n==0 ){
|
||||
@@ -2449,6 +2469,9 @@ static u32 jsonTranslateBlobToPrettyText(
|
||||
if( j<iEnd ){
|
||||
jsonAppendChar(pOut, '\n');
|
||||
pPretty->nIndent++;
|
||||
if( pPretty->nIndent >= JSON_MAX_DEPTH ){
|
||||
jsonStringTooDeep(pOut);
|
||||
}
|
||||
while( pOut->eErr==0 ){
|
||||
jsonPrettyIndent(pPretty);
|
||||
j = jsonTranslateBlobToPrettyText(pPretty, j);
|
||||
@@ -2470,6 +2493,10 @@ static u32 jsonTranslateBlobToPrettyText(
|
||||
if( j<iEnd ){
|
||||
jsonAppendChar(pOut, '\n');
|
||||
pPretty->nIndent++;
|
||||
if( pPretty->nIndent >= JSON_MAX_DEPTH ){
|
||||
jsonStringTooDeep(pOut);
|
||||
}
|
||||
pParse->iDepth = pPretty->nIndent;
|
||||
while( pOut->eErr==0 ){
|
||||
jsonPrettyIndent(pPretty);
|
||||
j = jsonTranslateBlobToText(pParse, j, pOut);
|
||||
@@ -2871,7 +2898,8 @@ static int jsonLabelCompare(
|
||||
#define JSON_LOOKUP_ERROR 0xffffffff
|
||||
#define JSON_LOOKUP_NOTFOUND 0xfffffffe
|
||||
#define JSON_LOOKUP_NOTARRAY 0xfffffffd
|
||||
#define JSON_LOOKUP_PATHERROR 0xfffffffc
|
||||
#define JSON_LOOKUP_TOODEEP 0xfffffffc
|
||||
#define JSON_LOOKUP_PATHERROR 0xfffffffb
|
||||
#define JSON_LOOKUP_ISERROR(x) ((x)>=JSON_LOOKUP_PATHERROR)
|
||||
|
||||
/* Forward declaration */
|
||||
@@ -2918,7 +2946,12 @@ static u32 jsonCreateEditSubstructure(
|
||||
pIns->eEdit = pParse->eEdit;
|
||||
pIns->nIns = pParse->nIns;
|
||||
pIns->aIns = pParse->aIns;
|
||||
pIns->iDepth = pParse->iDepth+1;
|
||||
if( pIns->iDepth >= JSON_MAX_DEPTH ){
|
||||
return JSON_LOOKUP_TOODEEP;
|
||||
}
|
||||
rc = jsonLookupStep(pIns, 0, zTail, 0);
|
||||
pParse->iDepth--;
|
||||
pParse->oom |= pIns->oom;
|
||||
}
|
||||
return rc; /* Error code only */
|
||||
@@ -3024,7 +3057,11 @@ static u32 jsonLookupStep(
|
||||
n = jsonbPayloadSize(pParse, v, &sz);
|
||||
if( n==0 || v+n+sz>iEnd ) return JSON_LOOKUP_ERROR;
|
||||
assert( j>0 );
|
||||
if( ++pParse->iDepth >= JSON_MAX_DEPTH ){
|
||||
return JSON_LOOKUP_TOODEEP;
|
||||
}
|
||||
rc = jsonLookupStep(pParse, v, &zPath[i], j);
|
||||
pParse->iDepth--;
|
||||
if( pParse->delta ) jsonAfterEditSizeAdjust(pParse, iRoot);
|
||||
return rc;
|
||||
}
|
||||
@@ -3110,7 +3147,11 @@ static u32 jsonLookupStep(
|
||||
iEnd = j+sz;
|
||||
while( j<iEnd ){
|
||||
if( kk==0 ){
|
||||
if( ++pParse->iDepth >= JSON_MAX_DEPTH ){
|
||||
return JSON_LOOKUP_TOODEEP;
|
||||
}
|
||||
rc = jsonLookupStep(pParse, j, &zPath[i+1], 0);
|
||||
pParse->iDepth--;
|
||||
if( pParse->delta ) jsonAfterEditSizeAdjust(pParse, iRoot);
|
||||
return rc;
|
||||
}
|
||||
@@ -3442,7 +3483,16 @@ static int jsonFunctionArgToBlob(
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate a bad path error.
|
||||
** Generate a path error.
|
||||
**
|
||||
** The specifics of the error are determined by the rc argument.
|
||||
**
|
||||
** rc error
|
||||
** ----------------- ----------------------
|
||||
** JSON_LOOKUP_ARRAY "not an array"
|
||||
** JSON_LOOKUP_TOODEEP "JSON nested too deep"
|
||||
** JSON_LOOKUP_ERROR "malformed JSON"
|
||||
** otherwise... "bad JSON path"
|
||||
**
|
||||
** If ctx is not NULL then push the error message into ctx and return NULL.
|
||||
** If ctx is NULL, then return the text of the error message.
|
||||
@@ -3455,6 +3505,10 @@ static char *jsonBadPathError(
|
||||
char *zMsg;
|
||||
if( rc==(int)JSON_LOOKUP_NOTARRAY ){
|
||||
zMsg = sqlite3_mprintf("not an array element: %Q", zPath);
|
||||
}else if( rc==(int)JSON_LOOKUP_ERROR ){
|
||||
zMsg = sqlite3_mprintf("malformed JSON");
|
||||
}else if( rc==(int)JSON_LOOKUP_TOODEEP ){
|
||||
zMsg = sqlite3_mprintf("JSON path too deep");
|
||||
}else{
|
||||
zMsg = sqlite3_mprintf("bad JSON path: %Q", zPath);
|
||||
}
|
||||
@@ -3517,6 +3571,7 @@ static void jsonInsertIntoBlob(
|
||||
p->nIns = ax.nBlob;
|
||||
p->aIns = ax.aBlob;
|
||||
p->delta = 0;
|
||||
p->iDepth = 0;
|
||||
rc = jsonLookupStep(p, 0, zPath+1, 0);
|
||||
}
|
||||
jsonParseReset(&ax);
|
||||
@@ -3529,11 +3584,7 @@ static void jsonInsertIntoBlob(
|
||||
|
||||
jsonInsertIntoBlob_patherror:
|
||||
jsonParseFree(p);
|
||||
if( rc==JSON_LOOKUP_ERROR ){
|
||||
sqlite3_result_error(ctx, "malformed JSON", -1);
|
||||
}else{
|
||||
jsonBadPathError(ctx, zPath, rc);
|
||||
}
|
||||
jsonBadPathError(ctx, zPath, rc);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -3973,10 +4024,8 @@ static void jsonArrayLengthFunc(
|
||||
if( JSON_LOOKUP_ISERROR(i) ){
|
||||
if( i==JSON_LOOKUP_NOTFOUND ){
|
||||
/* no-op */
|
||||
}else if( i==JSON_LOOKUP_PATHERROR ){
|
||||
jsonBadPathError(ctx, zPath, 0);
|
||||
}else{
|
||||
sqlite3_result_error(ctx, "malformed JSON", -1);
|
||||
jsonBadPathError(ctx, zPath, i);
|
||||
}
|
||||
eErr = 1;
|
||||
i = 0;
|
||||
@@ -4110,11 +4159,8 @@ static void jsonExtractFunc(
|
||||
jsonAppendSeparator(&jx);
|
||||
jsonAppendRawNZ(&jx, "null", 4);
|
||||
}
|
||||
}else if( j==JSON_LOOKUP_ERROR ){
|
||||
sqlite3_result_error(ctx, "malformed JSON", -1);
|
||||
goto json_extract_error;
|
||||
}else{
|
||||
jsonBadPathError(ctx, zPath, 0);
|
||||
jsonBadPathError(ctx, zPath, j);
|
||||
goto json_extract_error;
|
||||
}
|
||||
}
|
||||
@@ -4138,6 +4184,7 @@ json_extract_error:
|
||||
#define JSON_MERGE_BADTARGET 1 /* Malformed TARGET blob */
|
||||
#define JSON_MERGE_BADPATCH 2 /* Malformed PATCH blob */
|
||||
#define JSON_MERGE_OOM 3 /* Out-of-memory condition */
|
||||
#define JSON_MERGE_TOODEEP 4 /* Nested too deep */
|
||||
|
||||
/*
|
||||
** RFC-7396 MergePatch for two JSONB blobs.
|
||||
@@ -4189,7 +4236,8 @@ static int jsonMergePatch(
|
||||
JsonParse *pTarget, /* The JSON parser that contains the TARGET */
|
||||
u32 iTarget, /* Index of TARGET in pTarget->aBlob[] */
|
||||
const JsonParse *pPatch, /* The PATCH */
|
||||
u32 iPatch /* Index of PATCH in pPatch->aBlob[] */
|
||||
u32 iPatch, /* Index of PATCH in pPatch->aBlob[] */
|
||||
u32 iDepth /* Nesting depth */
|
||||
){
|
||||
u8 x; /* Type of a single node */
|
||||
u32 n, sz=0; /* Return values from jsonbPayloadSize() */
|
||||
@@ -4298,7 +4346,8 @@ static int jsonMergePatch(
|
||||
/* Algorithm line 12 */
|
||||
int rc, savedDelta = pTarget->delta;
|
||||
pTarget->delta = 0;
|
||||
rc = jsonMergePatch(pTarget, iTValue, pPatch, iPValue);
|
||||
if( iDepth>=JSON_MAX_DEPTH ) return JSON_MERGE_TOODEEP;
|
||||
rc = jsonMergePatch(pTarget, iTValue, pPatch, iPValue, iDepth+1);
|
||||
if( rc ) return rc;
|
||||
pTarget->delta += savedDelta;
|
||||
}
|
||||
@@ -4319,7 +4368,8 @@ static int jsonMergePatch(
|
||||
pTarget->aBlob[iTEnd+szNew] = 0x00;
|
||||
savedDelta = pTarget->delta;
|
||||
pTarget->delta = 0;
|
||||
rc = jsonMergePatch(pTarget, iTEnd+szNew,pPatch,iPValue);
|
||||
if( iDepth>=JSON_MAX_DEPTH ) return JSON_MERGE_TOODEEP;
|
||||
rc = jsonMergePatch(pTarget, iTEnd+szNew,pPatch,iPValue,iDepth+1);
|
||||
if( rc ) return rc;
|
||||
pTarget->delta += savedDelta;
|
||||
}
|
||||
@@ -4350,11 +4400,13 @@ static void jsonPatchFunc(
|
||||
if( pTarget==0 ) return;
|
||||
pPatch = jsonParseFuncArg(ctx, argv[1], 0);
|
||||
if( pPatch ){
|
||||
rc = jsonMergePatch(pTarget, 0, pPatch, 0);
|
||||
rc = jsonMergePatch(pTarget, 0, pPatch, 0, 0);
|
||||
if( rc==JSON_MERGE_OK ){
|
||||
jsonReturnParse(ctx, pTarget);
|
||||
}else if( rc==JSON_MERGE_OOM ){
|
||||
sqlite3_result_error_nomem(ctx);
|
||||
}else if( rc==JSON_MERGE_TOODEEP ){
|
||||
sqlite3_result_error(ctx, "JSON nested too deep", -1);
|
||||
}else{
|
||||
sqlite3_result_error(ctx, "malformed JSON", -1);
|
||||
}
|
||||
@@ -4442,10 +4494,8 @@ static void jsonRemoveFunc(
|
||||
if( JSON_LOOKUP_ISERROR(rc) ){
|
||||
if( rc==JSON_LOOKUP_NOTFOUND ){
|
||||
continue; /* No-op */
|
||||
}else if( rc==JSON_LOOKUP_PATHERROR ){
|
||||
jsonBadPathError(ctx, zPath, rc);
|
||||
}else{
|
||||
sqlite3_result_error(ctx, "malformed JSON", -1);
|
||||
jsonBadPathError(ctx, zPath, rc);
|
||||
}
|
||||
goto json_remove_done;
|
||||
}
|
||||
@@ -4542,10 +4592,8 @@ static void jsonTypeFunc(
|
||||
if( JSON_LOOKUP_ISERROR(i) ){
|
||||
if( i==JSON_LOOKUP_NOTFOUND ){
|
||||
/* no-op */
|
||||
}else if( i==JSON_LOOKUP_PATHERROR ){
|
||||
jsonBadPathError(ctx, zPath, 0);
|
||||
}else{
|
||||
sqlite3_result_error(ctx, "malformed JSON", -1);
|
||||
jsonBadPathError(ctx, zPath, i);
|
||||
}
|
||||
goto json_type_done;
|
||||
}
|
||||
|
||||
+3
-2
@@ -528,11 +528,12 @@ static const sqlite3_api_routines sqlite3Apis = {
|
||||
sqlite3_str_free,
|
||||
#ifdef SQLITE_ENABLE_CARRAY
|
||||
sqlite3_carray_bind,
|
||||
sqlite3_carray_bind_v2
|
||||
sqlite3_carray_bind_v2,
|
||||
#else
|
||||
0,
|
||||
0
|
||||
0,
|
||||
#endif
|
||||
sqlite3_incomplete
|
||||
};
|
||||
|
||||
/* True if x is the directory separator character
|
||||
|
||||
+13
-1
@@ -1136,7 +1136,8 @@ void sqlite3_set_last_insert_rowid(sqlite3 *db, sqlite3_int64 iRowid){
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the number of changes in the most recent call to sqlite3_exec().
|
||||
** Return the number of changes in the most recently executed DML
|
||||
** statement.
|
||||
*/
|
||||
sqlite3_int64 sqlite3_changes64(sqlite3 *db){
|
||||
#ifdef SQLITE_ENABLE_API_ARMOR
|
||||
@@ -4716,6 +4717,17 @@ int sqlite3_test_control(int op, ...){
|
||||
break;
|
||||
}
|
||||
|
||||
/* sqlite3_test_control(SQLITE_TESTCTRL_ATOF, const char *z, double *p);
|
||||
**
|
||||
** Test access to the sqlite3AtoF() routine.
|
||||
*/
|
||||
case SQLITE_TESTCTRL_ATOF: {
|
||||
const char *z = va_arg(ap,const char*);
|
||||
double *pR = va_arg(ap,double*);
|
||||
rc = sqlite3AtoF(z,pR);
|
||||
break;
|
||||
}
|
||||
|
||||
#if defined(SQLITE_DEBUG) && !defined(SQLITE_OMIT_WSD)
|
||||
/* sqlite3_test_control(SQLITE_TESTCTRL_TUNE, id, *piValue)
|
||||
**
|
||||
|
||||
+16
-1
@@ -6646,7 +6646,22 @@ static int unixOpen(
|
||||
|
||||
}else if( !zName ){
|
||||
/* If zName is NULL, the upper layer is requesting a temp file. */
|
||||
assert(isDelete && !isNewJrnl);
|
||||
assert( isDelete );
|
||||
assert( !isNewJrnl );
|
||||
assert( isExclusive );
|
||||
assert( isReadWrite );
|
||||
#if defined(__linux__) && defined(O_TMPFILE)
|
||||
/* On systems that support O_TMPFILE, use that flag to create a more
|
||||
** secure temporary file that cannot be accessed by other processes
|
||||
*/
|
||||
zName = unixTempFileDir();
|
||||
if( zName
|
||||
&& (fd = robust_open(zName, O_RDWR|O_CREAT|O_EXCL|O_TMPFILE, 0600))>=0
|
||||
){
|
||||
rc = fillInUnixFile(pVfs, fd, pFile, zPath, ctrlFlags);
|
||||
goto open_finished;
|
||||
}
|
||||
#endif
|
||||
rc = unixGetTempname(pVfs->mxPathname, zTmpname);
|
||||
if( rc!=SQLITE_OK ){
|
||||
return rc;
|
||||
|
||||
+4
-4
@@ -1993,7 +1993,7 @@ static int pagerFlushOnCommit(Pager *pPager, int bCommit){
|
||||
** database transaction.
|
||||
**
|
||||
** This routine is never called in PAGER_ERROR state. If it is called
|
||||
** in PAGER_NONE or PAGER_SHARED state and the lock held is less
|
||||
** in PAGER_OPEN or PAGER_READER state and the lock held is less
|
||||
** exclusive than a RESERVED lock, it is a no-op.
|
||||
**
|
||||
** Otherwise, any active savepoints are released.
|
||||
@@ -3754,7 +3754,7 @@ void sqlite3PagerSetBusyHandler(
|
||||
**
|
||||
** then the pager object page size is set to *pPageSize.
|
||||
**
|
||||
** If the page size is changed, then this function uses sqlite3PagerMalloc()
|
||||
** If the page size is changed, then this function uses sqlite3PageMalloc()
|
||||
** to obtain a new Pager.pTmpSpace buffer. If this allocation attempt
|
||||
** fails, SQLITE_NOMEM is returned and the page size remains unchanged.
|
||||
** In all other cases, SQLITE_OK is returned.
|
||||
@@ -5101,8 +5101,8 @@ sqlite3_file *sqlite3_database_file_object(const char *zName){
|
||||
|
||||
|
||||
/*
|
||||
** This function is called after transitioning from PAGER_UNLOCK to
|
||||
** PAGER_SHARED state. It tests if there is a hot journal present in
|
||||
** This function is called while transitioning from PAGER_OPEN to a
|
||||
** higher state. It tests if there is a hot journal present in
|
||||
** the file-system for the given pager. A hot journal is one that
|
||||
** needs to be played back. According to this function, a hot-journal
|
||||
** file exists if the following criteria are met:
|
||||
|
||||
+98
-37
@@ -165,7 +165,7 @@ static char *printfTempBuf(sqlite3_str *pAccum, sqlite3_int64 n){
|
||||
sqlite3StrAccumSetError(pAccum, SQLITE_TOOBIG);
|
||||
return 0;
|
||||
}
|
||||
z = sqlite3DbMallocRaw(pAccum->db, n);
|
||||
z = sqlite3_malloc(n);
|
||||
if( z==0 ){
|
||||
sqlite3StrAccumSetError(pAccum, SQLITE_NOMEM);
|
||||
}
|
||||
@@ -496,9 +496,11 @@ void sqlite3_str_vappendf(
|
||||
}while( longvalue>0 );
|
||||
}
|
||||
length = (int)(&zOut[nOut-1]-bufpt);
|
||||
while( precision>length ){
|
||||
*(--bufpt) = '0'; /* Zero pad */
|
||||
length++;
|
||||
if( precision>length ){ /* zero pad */
|
||||
int nn = precision-length;
|
||||
bufpt -= nn;
|
||||
memset(bufpt,'0',nn);
|
||||
length = precision;
|
||||
}
|
||||
if( cThousand ){
|
||||
int nn = (length - 1)/3; /* Number of "," to insert */
|
||||
@@ -529,6 +531,7 @@ void sqlite3_str_vappendf(
|
||||
FpDecode s;
|
||||
int iRound;
|
||||
int j;
|
||||
i64 szBufNeeded; /* Size needed to hold the output */
|
||||
|
||||
if( bArgList ){
|
||||
realvalue = getDoubleArg(pArgList);
|
||||
@@ -617,17 +620,31 @@ void sqlite3_str_vappendf(
|
||||
}else{
|
||||
e2 = s.iDP - 1;
|
||||
}
|
||||
bufpt = buf;
|
||||
{
|
||||
i64 szBufNeeded; /* Size of a temporary buffer needed */
|
||||
szBufNeeded = MAX(e2,0)+(i64)precision+(i64)width+15;
|
||||
if( cThousand && e2>0 ) szBufNeeded += (e2+2)/3;
|
||||
if( szBufNeeded > etBUFSIZE ){
|
||||
bufpt = zExtra = printfTempBuf(pAccum, szBufNeeded);
|
||||
if( bufpt==0 ) return;
|
||||
|
||||
szBufNeeded = MAX(e2,0)+(i64)precision+(i64)width+10;
|
||||
if( cThousand && e2>0 ) szBufNeeded += (e2+2)/3;
|
||||
if( szBufNeeded + pAccum->nChar >= pAccum->nAlloc ){
|
||||
if( pAccum->mxAlloc==0 && pAccum->accError==0 ){
|
||||
/* Unable to allocate space in pAccum, perhaps because it
|
||||
** is coming from sqlite3_snprintf() or similar. We'll have
|
||||
** to render into temporary space and the memcpy() it over. */
|
||||
bufpt = sqlite3_malloc(szBufNeeded);
|
||||
if( bufpt==0 ){
|
||||
sqlite3StrAccumSetError(pAccum, SQLITE_NOMEM);
|
||||
return;
|
||||
}
|
||||
zExtra = bufpt;
|
||||
}else if( sqlite3StrAccumEnlarge(pAccum, szBufNeeded)<szBufNeeded ){
|
||||
width = length = 0;
|
||||
break;
|
||||
}else{
|
||||
bufpt = pAccum->zText + pAccum->nChar;
|
||||
}
|
||||
}else{
|
||||
bufpt = pAccum->zText + pAccum->nChar;
|
||||
}
|
||||
zOut = bufpt;
|
||||
|
||||
flag_dp = (precision>0 ?1:0) | flag_alternateform | flag_altform2;
|
||||
/* The sign in front of the number */
|
||||
if( prefix ){
|
||||
@@ -635,12 +652,24 @@ void sqlite3_str_vappendf(
|
||||
}
|
||||
/* Digits prior to the decimal point */
|
||||
j = 0;
|
||||
assert( s.n>0 );
|
||||
if( e2<0 ){
|
||||
*(bufpt++) = '0';
|
||||
}else{
|
||||
}else if( cThousand ){
|
||||
for(; e2>=0; e2--){
|
||||
*(bufpt++) = j<s.n ? s.z[j++] : '0';
|
||||
if( cThousand && (e2%3)==0 && e2>1 ) *(bufpt++) = ',';
|
||||
if( (e2%3)==0 && e2>1 ) *(bufpt++) = ',';
|
||||
}
|
||||
}else{
|
||||
j = e2+1;
|
||||
if( j>s.n ) j = s.n;
|
||||
memcpy(bufpt, s.z, j);
|
||||
bufpt += j;
|
||||
e2 -= j;
|
||||
if( e2>=0 ){
|
||||
memset(bufpt, '0', e2+1);
|
||||
bufpt += e2+1;
|
||||
e2 = -1;
|
||||
}
|
||||
}
|
||||
/* The decimal point */
|
||||
@@ -649,12 +678,26 @@ void sqlite3_str_vappendf(
|
||||
}
|
||||
/* "0" digits after the decimal point but before the first
|
||||
** significant digit of the number */
|
||||
for(e2++; e2<0 && precision>0; precision--, e2++){
|
||||
*(bufpt++) = '0';
|
||||
if( e2<(-1) && precision>0 ){
|
||||
int nn = -1-e2;
|
||||
if( nn>precision ) nn = precision;
|
||||
memset(bufpt, '0', nn);
|
||||
bufpt += nn;
|
||||
precision -= nn;
|
||||
}
|
||||
/* Significant digits after the decimal point */
|
||||
while( (precision--)>0 ){
|
||||
*(bufpt++) = j<s.n ? s.z[j++] : '0';
|
||||
if( precision>0 ){
|
||||
int nn = s.n - j;
|
||||
if( NEVER(nn>precision) ) nn = precision;
|
||||
if( nn>0 ){
|
||||
memcpy(bufpt, s.z+j, nn);
|
||||
bufpt += nn;
|
||||
precision -= nn;
|
||||
}
|
||||
if( precision>0 && !flag_rtz ){
|
||||
memset(bufpt, '0', precision);
|
||||
bufpt += precision;
|
||||
}
|
||||
}
|
||||
/* Remove trailing zeros and the "." if no digits follow the "." */
|
||||
if( flag_rtz && flag_dp ){
|
||||
@@ -684,27 +727,39 @@ void sqlite3_str_vappendf(
|
||||
*(bufpt++) = (char)(exp/10+'0'); /* 10's digit */
|
||||
*(bufpt++) = (char)(exp%10+'0'); /* 1's digit */
|
||||
}
|
||||
*bufpt = 0;
|
||||
|
||||
/* The converted number is in buf[] and zero terminated. Output it.
|
||||
** Note that the number is in the usual order, not reversed as with
|
||||
** integer conversions. */
|
||||
length = (int)(bufpt-zOut);
|
||||
bufpt = zOut;
|
||||
|
||||
/* Special case: Add leading zeros if the flag_zeropad flag is
|
||||
** set and we are not left justified */
|
||||
if( flag_zeropad && !flag_leftjustify && length < width){
|
||||
int i;
|
||||
int nPad = width - length;
|
||||
for(i=width; i>=nPad; i--){
|
||||
bufpt[i] = bufpt[i-nPad];
|
||||
assert( length <= szBufNeeded );
|
||||
if( length<width ){
|
||||
i64 nPad = width - length;
|
||||
if( flag_leftjustify ){
|
||||
memset(bufpt, ' ', nPad);
|
||||
}else if( !flag_zeropad ){
|
||||
memmove(zOut+nPad, zOut, length);
|
||||
memset(zOut, ' ', nPad);
|
||||
}else{
|
||||
int adj = prefix!=0;
|
||||
memmove(zOut+nPad+adj, zOut+adj, length-adj);
|
||||
memset(zOut+adj, '0', nPad);
|
||||
}
|
||||
i = prefix!=0;
|
||||
while( nPad-- ) bufpt[i++] = '0';
|
||||
length = width;
|
||||
}
|
||||
break;
|
||||
|
||||
if( zExtra==0 ){
|
||||
/* The result is being rendered directory into pAccum. This
|
||||
** is the command and fast case */
|
||||
pAccum->nChar += length;
|
||||
zOut[length] = 0;
|
||||
continue;
|
||||
}else{
|
||||
/* We were unable to render directly into pAccum because we
|
||||
** couldn't allocate sufficient memory. We need to memcpy()
|
||||
** the rendering (or some prefix thereof) into the output
|
||||
** buffer. */
|
||||
bufpt[0] = 0;
|
||||
bufpt = zExtra;
|
||||
break;
|
||||
}
|
||||
}
|
||||
case etSIZE:
|
||||
if( !bArgList ){
|
||||
@@ -748,10 +803,9 @@ void sqlite3_str_vappendf(
|
||||
i64 nCopyBytes;
|
||||
if( nPrior > precision-1 ) nPrior = precision - 1;
|
||||
nCopyBytes = length*nPrior;
|
||||
if( nCopyBytes + pAccum->nChar >= pAccum->nAlloc ){
|
||||
sqlite3StrAccumEnlarge(pAccum, nCopyBytes);
|
||||
if( sqlite3StrAccumEnlargeIfNeeded(pAccum, nCopyBytes) ){
|
||||
break;
|
||||
}
|
||||
if( pAccum->accError ) break;
|
||||
sqlite3_str_append(pAccum,
|
||||
&pAccum->zText[pAccum->nChar-nCopyBytes], nCopyBytes);
|
||||
precision -= nPrior;
|
||||
@@ -1098,6 +1152,13 @@ int sqlite3StrAccumEnlarge(StrAccum *p, i64 N){
|
||||
return (int)N;
|
||||
}
|
||||
|
||||
int sqlite3StrAccumEnlargeIfNeeded(StrAccum *p, i64 N){
|
||||
if( N + p->nChar >= p->nAlloc ){
|
||||
sqlite3StrAccumEnlarge(p, N);
|
||||
}
|
||||
return p->accError;
|
||||
}
|
||||
|
||||
/*
|
||||
** Append N copies of character c to the given string buffer.
|
||||
*/
|
||||
|
||||
+961
-698
File diff suppressed because it is too large
Load Diff
+78
-62
@@ -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
|
||||
@@ -1290,6 +1290,12 @@ struct sqlite3_io_methods {
|
||||
#define SQLITE_SET_LOCKPROXYFILE SQLITE_FCNTL_SET_LOCKPROXYFILE
|
||||
#define SQLITE_LAST_ERRNO SQLITE_FCNTL_LAST_ERRNO
|
||||
|
||||
/* reserved file-control numbers:
|
||||
** 101
|
||||
** 102
|
||||
** 103
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
** CAPI3REF: Mutex Handle
|
||||
@@ -1711,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()].
|
||||
**
|
||||
@@ -2277,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>
|
||||
@@ -2658,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.
|
||||
@@ -2670,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
|
||||
@@ -2950,8 +2960,9 @@ int sqlite3_is_interrupted(sqlite3*);
|
||||
** These routines are useful during command-line input to determine if the
|
||||
** currently entered text seems to form a complete SQL statement or
|
||||
** if additional input is needed before sending the text into
|
||||
** SQLite for parsing. ^These routines return 1 if the input string
|
||||
** appears to be a complete SQL statement. ^A statement is judged to be
|
||||
** SQLite for parsing. ^The sqlite3_complete(X) and sqlite3_complete16(X)
|
||||
** routines return 1 if the input string X appears to be a complete SQL
|
||||
** statement. ^A statement is judged to be
|
||||
** complete if it ends with a semicolon token and is not a prefix of a
|
||||
** well-formed CREATE TRIGGER statement. ^Semicolons that are embedded within
|
||||
** string literals or quoted identifier names or comments are not
|
||||
@@ -2959,11 +2970,21 @@ int sqlite3_is_interrupted(sqlite3*);
|
||||
** embedded) and thus do not count as a statement terminator. ^Whitespace
|
||||
** and comments that follow the final semicolon are ignored.
|
||||
**
|
||||
** ^These routines return 0 if the statement is incomplete. ^If a
|
||||
** memory allocation fails, then SQLITE_NOMEM is returned.
|
||||
** ^The sqlite3_complete(X) and sqlite3_complete16(X) routines return 0
|
||||
** if the statement is incomplete. ^If a memory allocation fails, then
|
||||
** SQLITE_NOMEM is returned.
|
||||
**
|
||||
** ^These routines do not parse the SQL statements and thus
|
||||
** will not detect syntactically incorrect SQL.
|
||||
** The [sqlite3_incomplete(X)] routine is similar to [sqlite3_complete(X)]
|
||||
** except that sqlite3_incomplete(X) returns 0 if the input X is complete
|
||||
** and non-zero if X is incomplete. The non-zero return from
|
||||
** sqlite3_incomplete(X) contains additional information about what is
|
||||
** needed to complete the input X. The sqlite3_incomplete(X) interface
|
||||
** is only available for UTF-8 text.
|
||||
**
|
||||
** ^None of these routines do a full parse the SQL statements and thus
|
||||
** will not detect syntactically incorrect SQL. They only determine if
|
||||
** input text has properly terminated comments, string literals, and
|
||||
** quoted identifiers, and if the statement ends with a semicolon.
|
||||
**
|
||||
** ^(If SQLite has not been initialized using [sqlite3_initialize()] prior
|
||||
** to invoking sqlite3_complete16() then sqlite3_initialize() is invoked
|
||||
@@ -2971,14 +2992,15 @@ int sqlite3_is_interrupted(sqlite3*);
|
||||
** then the return value from sqlite3_complete16() will be non-zero
|
||||
** regardless of whether or not the input SQL is complete.)^
|
||||
**
|
||||
** The input to [sqlite3_complete()] must be a zero-terminated
|
||||
** UTF-8 string.
|
||||
** The X input to [sqlite3_complete(X)] and [sqlite3_incomplete(X)]
|
||||
** must be a zero-terminated UTF-8 string.
|
||||
**
|
||||
** The input to [sqlite3_complete16()] must be a zero-terminated
|
||||
** UTF-16 string in native byte order.
|
||||
*/
|
||||
int sqlite3_complete(const char *sql);
|
||||
int sqlite3_complete16(const void *sql);
|
||||
sqlite3_int64 sqlite3_incomplete(const char *sql);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Register A Callback To Handle SQLITE_BUSY Errors
|
||||
@@ -5850,8 +5872,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[n]
|
||||
@@ -6103,26 +6126,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→UTF16 or UTF16→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*);
|
||||
@@ -6149,7 +6168,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).
|
||||
@@ -6280,17 +6300,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
|
||||
@@ -7607,7 +7627,7 @@ int sqlite3_enable_load_extension(sqlite3 *db, int onoff);
|
||||
** <blockquote><pre>
|
||||
** int xEntryPoint(
|
||||
** sqlite3 *db,
|
||||
** const char **pzErrMsg,
|
||||
** char **pzErrMsg,
|
||||
** const struct sqlite3_api_routines *pThunk
|
||||
** );
|
||||
** </pre></blockquote>)^
|
||||
@@ -8357,13 +8377,6 @@ int sqlite3_vfs_unregister(sqlite3_vfs*);
|
||||
** SQLITE_MUTEX_W32 implementations are appropriate for use on Unix
|
||||
** and Windows.
|
||||
**
|
||||
** If SQLite is compiled with the SQLITE_MUTEX_APPDEF preprocessor
|
||||
** macro defined (with "-DSQLITE_MUTEX_APPDEF=1"), then no mutex
|
||||
** implementation is included with the library. In this case the
|
||||
** application must supply a custom mutex implementation using the
|
||||
** [SQLITE_CONFIG_MUTEX] option of the sqlite3_config() function
|
||||
** before calling sqlite3_initialize() or any other public sqlite3_
|
||||
** function that calls sqlite3_initialize().
|
||||
**
|
||||
** ^The sqlite3_mutex_alloc() routine allocates a new
|
||||
** mutex and returns a pointer to it. ^The sqlite3_mutex_alloc()
|
||||
@@ -8718,6 +8731,7 @@ int sqlite3_test_control(int op, ...);
|
||||
#define SQLITE_TESTCTRL_TUNE 32
|
||||
#define SQLITE_TESTCTRL_LOGEST 33
|
||||
#define SQLITE_TESTCTRL_USELONGDOUBLE 34 /* NOT USED */
|
||||
#define SQLITE_TESTCTRL_ATOF 34
|
||||
#define SQLITE_TESTCTRL_LAST 34 /* Largest TESTCTRL */
|
||||
|
||||
/*
|
||||
@@ -10409,7 +10423,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 +10433,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 +11288,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
|
||||
|
||||
@@ -376,6 +376,8 @@ struct sqlite3_api_routines {
|
||||
void (*str_free)(sqlite3_str*);
|
||||
int (*carray_bind)(sqlite3_stmt*,int,void*,int,int,void(*)(void*));
|
||||
int (*carray_bind_v2)(sqlite3_stmt*,int,void*,int,int,void(*)(void*),void*);
|
||||
/* Version 3.54.0 and later */
|
||||
sqlite3_int64 (*incomplete)(const char*);
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -719,6 +721,8 @@ typedef int (*sqlite3_loadext_entry)(
|
||||
#define sqlite3_str_free sqlite3_api->str_free
|
||||
#define sqlite3_carray_bind sqlite3_api->carray_bind
|
||||
#define sqlite3_carray_bind_v2 sqlite3_api->carray_bind_v2
|
||||
/* Version 3.54.0 and later */
|
||||
#define sqlite3_incomplete sqlite3_api->incomplete
|
||||
#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
|
||||
|
||||
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
|
||||
|
||||
+12
-6
@@ -4828,17 +4828,22 @@ struct PrintfArguments {
|
||||
sqlite3_value **apArg; /* The argument values */
|
||||
};
|
||||
|
||||
/*
|
||||
** Maxium number of base-10 digits in an unsigned 64-bit integer
|
||||
*/
|
||||
#define SQLITE_U64_DIGITS 20
|
||||
|
||||
/*
|
||||
** An instance of this object receives the decoding of a floating point
|
||||
** value into an approximate decimal representation.
|
||||
*/
|
||||
struct FpDecode {
|
||||
int n; /* Significant digits in the decode */
|
||||
int iDP; /* Location of the decimal point */
|
||||
char *z; /* Start of significant digits */
|
||||
char zBuf[20]; /* Storage for significant digits */
|
||||
char sign; /* '+' or '-' */
|
||||
char isSpecial; /* 1: Infinity 2: NaN */
|
||||
int n; /* Significant digits in the decode */
|
||||
int iDP; /* Location of the decimal point */
|
||||
char *z; /* Start of significant digits */
|
||||
char zBuf[SQLITE_U64_DIGITS+1]; /* Storage for significant digits */
|
||||
char sign; /* '+' or '-' */
|
||||
char isSpecial; /* 1: Infinity 2: NaN */
|
||||
};
|
||||
|
||||
void sqlite3FpDecode(FpDecode*,double,int,int);
|
||||
@@ -5526,6 +5531,7 @@ char *sqlite3RCStrResize(char*,u64);
|
||||
|
||||
void sqlite3StrAccumInit(StrAccum*, sqlite3*, char*, int, int);
|
||||
int sqlite3StrAccumEnlarge(StrAccum*, i64);
|
||||
int sqlite3StrAccumEnlargeIfNeeded(StrAccum*, i64);
|
||||
char *sqlite3StrAccumFinish(StrAccum*);
|
||||
void sqlite3StrAccumSetError(StrAccum*, u8);
|
||||
void sqlite3ResultStrAccum(sqlite3_context*,StrAccum*);
|
||||
|
||||
@@ -232,6 +232,10 @@
|
||||
# undef SQLITE_MAX_DEFAULT_PAGE_SIZE
|
||||
# define SQLITE_MAX_DEFAULT_PAGE_SIZE SQLITE_MAX_PAGE_SIZE
|
||||
#endif
|
||||
#if SQLITE_MAX_DEFAULT_PAGE_SIZE<SQLITE_DEFAULT_PAGE_SIZE
|
||||
# undef SQLITE_MAX_DEFAULT_PAGE_SIZE
|
||||
# define SQLITE_MAX_DEFAULT_PAGE_SIZE SQLITE_DEFAULT_PAGE_SIZE
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
|
||||
+1
-1
@@ -734,7 +734,7 @@ int sqlite3RunParser(Parse *pParse, const char *zSql){
|
||||
}
|
||||
if( pParse->zErrMsg || (pParse->rc!=SQLITE_OK && pParse->rc!=SQLITE_DONE) ){
|
||||
if( pParse->zErrMsg==0 ){
|
||||
pParse->zErrMsg = sqlite3MPrintf(db, "%s", sqlite3ErrStr(pParse->rc));
|
||||
pParse->zErrMsg = sqlite3DbStrDup(db, sqlite3ErrStr(pParse->rc));
|
||||
}
|
||||
if( (pParse->prepFlags & SQLITE_PREPARE_DONT_LOG)==0 ){
|
||||
sqlite3_log(pParse->rc, "%s in \"%s\"", pParse->zErrMsg, pParse->zTail);
|
||||
|
||||
+160
-66
@@ -19,8 +19,15 @@
|
||||
#include <stdarg.h>
|
||||
#ifndef SQLITE_OMIT_FLOATING_POINT
|
||||
#include <math.h>
|
||||
|
||||
/* Work around a bug in older Microsoft compilers
|
||||
** Forum post 2026-04-10T06:33:11z */
|
||||
#if !defined(INFINITY) && defined(_MSC_VER)
|
||||
# define INFINITY HUGE_VAL
|
||||
#endif
|
||||
|
||||
#endif /* SQLITE_OMIT_FLOATING_POINT */
|
||||
|
||||
/*
|
||||
** Calls to sqlite3FaultSim() are used to simulate a failure during testing,
|
||||
** or to bypass normal error detection during testing in order to let
|
||||
@@ -465,11 +472,12 @@ u8 sqlite3StrIHash(const char *z){
|
||||
*/
|
||||
static u64 sqlite3Multiply128(u64 a, u64 b, u64 *pLo){
|
||||
#if (defined(__GNUC__) || defined(__clang__)) \
|
||||
&& (defined(__x86_64__) || defined(__aarch64__) || defined(__riscv))
|
||||
&& (defined(__x86_64__) || defined(__aarch64__) || defined(__riscv)) \
|
||||
&& !defined(SQLITE_DISABLE_INTRINSIC)
|
||||
__uint128_t r = (__uint128_t)a * b;
|
||||
*pLo = (u64)r;
|
||||
return (u64)(r>>64);
|
||||
#elif defined(_MSC_VER) && defined(_M_X64)
|
||||
#elif defined(_WIN64) && !defined(SQLITE_DISABLE_INTRINSIC)
|
||||
*pLo = a*b;
|
||||
return __umulh(a, b);
|
||||
#else
|
||||
@@ -500,17 +508,19 @@ static u64 sqlite3Multiply128(u64 a, u64 b, u64 *pLo){
|
||||
*/
|
||||
static u64 sqlite3Multiply160(u64 a, u32 aLo, u64 b, u32 *pLo){
|
||||
#if (defined(__GNUC__) || defined(__clang__)) \
|
||||
&& (defined(__x86_64__) || defined(__aarch64__) || defined(__riscv))
|
||||
&& (defined(__x86_64__) || defined(__aarch64__) || defined(__riscv)) \
|
||||
&& !defined(SQLITE_DISABLE_INTRINSIC)
|
||||
__uint128_t r = (__uint128_t)a * b;
|
||||
r += ((__uint128_t)aLo * b) >> 32;
|
||||
*pLo = (r>>32)&0xffffffff;
|
||||
return r>>64;
|
||||
#elif defined(_MSC_VER) && defined(_M_X64)
|
||||
#elif defined(_WIN64) && !defined(SQLITE_DISABLE_INTRINSIC)
|
||||
u64 r1_hi = __umulh(a,b);
|
||||
u64 r1_lo = a*b;
|
||||
u64 r2 = (__umulh((u64)aLo,b)<<32) + ((aLo*b)>>32);
|
||||
r1_hi += _addcarry_u64(0, r1_lo, r2, &r1_lo);
|
||||
*pLo = r1_lo>>32;
|
||||
u64 t = r1_lo + r2;
|
||||
if( t<r1_lo ) r1_hi++;
|
||||
*pLo = t>>32;
|
||||
return r1_hi;
|
||||
#else
|
||||
u64 x2 = a>>32;
|
||||
@@ -722,7 +732,8 @@ static int pwr2to10(int p){ return (p*78913) >> 18; }
|
||||
** Count leading zeros for a 64-bit unsigned integer.
|
||||
*/
|
||||
static int countLeadingZeros(u64 m){
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
#if (defined(__GNUC__) || defined(__clang__)) \
|
||||
&& !defined(SQLITE_DISABLE_INTRINSIC)
|
||||
return __builtin_clzll(m);
|
||||
#else
|
||||
int n = 0;
|
||||
@@ -820,25 +831,31 @@ static double sqlite3Fp10Convert2(u64 d, int p){
|
||||
**
|
||||
** Return positive if the result is a valid real number (or integer) and
|
||||
** zero or negative if the string is empty or contains extraneous text.
|
||||
** More specifically:
|
||||
** Lower bits of the return value contain addition information about the
|
||||
** parse:
|
||||
**
|
||||
** 1 => The input string is a pure integer
|
||||
** 2 or more => The input has a decimal point or eNNN clause
|
||||
** 0 or less => The input string is not well-formed
|
||||
** -1 => The input is not well-formed, but it does begin
|
||||
** with a well-formed floating-point literal (with
|
||||
** a "." or a "eNNN" suffix or both) followed by
|
||||
** other extraneous text.
|
||||
** 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 => Set if there are more than about 19 significant
|
||||
** digits in the input.
|
||||
**
|
||||
** Valid numbers are in one of these formats:
|
||||
** 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
|
||||
** result is only zero if no prefix of the input could be interpreted as
|
||||
** a number.
|
||||
**
|
||||
** Leading and trailing whitespace is ignored. Valid numbers are in
|
||||
** one of the formats below:
|
||||
**
|
||||
** [+-]digits[E[+-]digits]
|
||||
** [+-]digits.[digits][E[+-]digits]
|
||||
** [+-].digits[E[+-]digits]
|
||||
**
|
||||
** Leading and trailing whitespace is ignored for the purpose of determining
|
||||
** validity.
|
||||
**
|
||||
** Algorithm sketch: Compute an unsigned 64-bit integer s and a base-10
|
||||
** exponent d such that the value encoding by the input is s*pow(10,d).
|
||||
** Then invoke sqlite3Fp10Convert2() to calculated the closest possible
|
||||
@@ -859,20 +876,20 @@ int sqlite3AtoF(const char *zIn, double *pResult){
|
||||
int neg = 0; /* True for a negative value */
|
||||
u64 s = 0; /* mantissa */
|
||||
int d = 0; /* Value is s * pow(10,d) */
|
||||
int seenDigit = 0; /* true if any digits seen */
|
||||
int seenFP = 0; /* True if we've seen a "." or a "e" */
|
||||
int mState = 0; /* 1: digit seen 2: fp 4: hard-zero */
|
||||
unsigned v; /* Value of a single digit */
|
||||
|
||||
start_of_text:
|
||||
if( (v = (unsigned)z[0] - '0')<10 ){
|
||||
parse_integer_part:
|
||||
seenDigit = 1;
|
||||
mState = 1;
|
||||
s = v;
|
||||
z++;
|
||||
while( (v = (unsigned)z[0] - '0')<10 ){
|
||||
s = s*10 + v;
|
||||
z++;
|
||||
if( s>=(LARGEST_INT64-9)/10 ){
|
||||
if( s>=(LARGEST_UINT64-9)/10 ){
|
||||
mState = 9;
|
||||
while( sqlite3Isdigit(z[0]) ){ z++; d++; }
|
||||
break;
|
||||
}
|
||||
@@ -894,20 +911,22 @@ int sqlite3AtoF(const char *zIn, double *pResult){
|
||||
/* if decimal point is present */
|
||||
if( *z=='.' ){
|
||||
z++;
|
||||
seenFP = 1;
|
||||
if( sqlite3Isdigit(z[0]) ){
|
||||
seenDigit = 1;
|
||||
mState |= 1;
|
||||
do{
|
||||
if( s<((LARGEST_INT64-9)/10) ){
|
||||
if( s<(LARGEST_UINT64-9)/10 ){
|
||||
s = s*10 + z[0] - '0';
|
||||
d--;
|
||||
}else{
|
||||
mState = 11;
|
||||
}
|
||||
z++;
|
||||
}while( sqlite3Isdigit(z[0]) );
|
||||
}while( sqlite3Isdigit(*++z) );
|
||||
}else if( mState==0 ){
|
||||
*pResult = 0.0;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if( !seenDigit ){
|
||||
mState |= 2;
|
||||
}else if( mState==0 ){
|
||||
*pResult = 0.0;
|
||||
return 0;
|
||||
}
|
||||
@@ -931,7 +950,7 @@ int sqlite3AtoF(const char *zIn, double *pResult){
|
||||
if( (v = (unsigned)z[0] - '0')<10 ){
|
||||
int exp = v;
|
||||
z++;
|
||||
seenFP = 1;
|
||||
mState |= 2;
|
||||
while( (v = (unsigned)z[0] - '0')<10 ){
|
||||
exp = exp<10000 ? (exp*10 + v) : 10000;
|
||||
z++;
|
||||
@@ -943,29 +962,31 @@ int sqlite3AtoF(const char *zIn, double *pResult){
|
||||
}
|
||||
}
|
||||
|
||||
/* skip trailing spaces */
|
||||
while( sqlite3Isspace(*z) ) z++;
|
||||
|
||||
/* Convert s*pow(10,d) into real */
|
||||
*pResult = s ? sqlite3Fp10Convert2(s,d) : 0.0;
|
||||
if( s==0 ){
|
||||
*pResult = 0.0;
|
||||
mState |= 4;
|
||||
}else{
|
||||
*pResult = sqlite3Fp10Convert2(s,d);
|
||||
}
|
||||
if( neg ) *pResult = -*pResult;
|
||||
assert( !sqlite3IsNaN(*pResult) );
|
||||
|
||||
/* return true if number and no extra non-whitespace characters after */
|
||||
if( z[0]==0 ){
|
||||
return seenFP+1;
|
||||
}else if( seenFP ){
|
||||
return -1; /* Prefix is a floating point number */
|
||||
}else{
|
||||
return 0; /* Prefix is just an integer */
|
||||
return mState;
|
||||
}
|
||||
if( sqlite3Isspace(z[0]) ){
|
||||
do{ z++; }while( sqlite3Isspace(*z) );
|
||||
if( z[0]==0 ){
|
||||
return mState;
|
||||
}
|
||||
}
|
||||
return 0xfffffff0 | mState;
|
||||
#else
|
||||
return !sqlite3Atoi64(z, pResult, strlen(z), SQLITE_UTF8);
|
||||
return sqlite3Atoi64(z, pResult, strlen(z), SQLITE_UTF8)==0;
|
||||
#endif /* SQLITE_OMIT_FLOATING_POINT */
|
||||
}
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(default : 4756)
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Digit pairs used to convert a U64 or I64 into text, two digits
|
||||
@@ -987,6 +1008,69 @@ static const union {
|
||||
"90919293949596979899"
|
||||
};
|
||||
|
||||
/*
|
||||
** ARMv6, ARMv7, PPC32 are known to not support hardware u64 division.
|
||||
*/
|
||||
#if (defined(__arm__) && !defined(__aarch64__)) || \
|
||||
(defined(__ppc__) && !defined(__ppc64__))
|
||||
# define SQLITE_AVOID_U64_DIVIDE 1
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_AVOID_U64_DIVIDE
|
||||
/*
|
||||
** Render an unsigned 64-bit integer as text onto the end of a 2-byte
|
||||
** aligned buffer that is SQLITE_U64_DIGIT+1 bytes long. The last byte
|
||||
** of the buffer will be filled with a \000 byte.
|
||||
**
|
||||
** Return the index into the buffer of the first byte.
|
||||
**
|
||||
** This routine is used on platforms where u64-division is slow because
|
||||
** it is not available in hardware and has to be emulated in software.
|
||||
** It seeks to minimize the number of u64 divisions and use u32 divisions
|
||||
** instead. It is slower on platforms that have hardware u64 division,
|
||||
** but much faster on platforms that do not.
|
||||
*/
|
||||
static int sqlite3UInt64ToText(u64 v, char *zOut){
|
||||
u32 x32, kk;
|
||||
int i;
|
||||
zOut[SQLITE_U64_DIGITS] = 0;
|
||||
i = SQLITE_U64_DIGITS;
|
||||
assert( TWO_BYTE_ALIGNMENT(&sqlite3DigitPairs.a[0]) );
|
||||
assert( TWO_BYTE_ALIGNMENT(zOut) );
|
||||
while( (v>>32)!=0 ){
|
||||
u32 y, x0, x1, y0, y1;
|
||||
x32 = v % 100000000;
|
||||
v = v / 100000000;
|
||||
y = x32 % 10000;
|
||||
x32 /= 10000;
|
||||
x1 = x32 / 100;
|
||||
x0 = x32 % 100;
|
||||
y1 = y / 100;
|
||||
y0 = y % 100;
|
||||
assert( i>=8 );
|
||||
i -= 8;
|
||||
*(u16*)(&zOut[i]) = *(u16*)&sqlite3DigitPairs.a[x1*2];
|
||||
*(u16*)(&zOut[i+2]) = *(u16*)&sqlite3DigitPairs.a[x0*2];
|
||||
*(u16*)(&zOut[i+4]) = *(u16*)&sqlite3DigitPairs.a[y1*2];
|
||||
*(u16*)(&zOut[i+6]) = *(u16*)&sqlite3DigitPairs.a[y0*2];
|
||||
}
|
||||
x32 = v;
|
||||
while( x32>=10 ){
|
||||
kk = x32 % 100;
|
||||
x32 = x32 / 100;
|
||||
assert( TWO_BYTE_ALIGNMENT(&sqlite3DigitPairs.a[kk*2]) );
|
||||
assert( i>=2 );
|
||||
i -= 2;
|
||||
assert( TWO_BYTE_ALIGNMENT(&zOut[i]) );
|
||||
*(u16*)(&zOut[i]) = *(u16*)&sqlite3DigitPairs.a[kk*2];
|
||||
}
|
||||
if( x32 ){
|
||||
assert( i>0 );
|
||||
zOut[--i] = x32 + '0';
|
||||
}
|
||||
return i;
|
||||
}
|
||||
#endif /* defined(SQLITE_AVOID_U64_DIVIDE) */
|
||||
|
||||
/*
|
||||
** Render an signed 64-bit integer as text. Store the result in zOut[] and
|
||||
@@ -1000,7 +1084,7 @@ int sqlite3Int64ToText(i64 v, char *zOut){
|
||||
int i;
|
||||
u64 x;
|
||||
union {
|
||||
char a[23];
|
||||
char a[SQLITE_U64_DIGITS+1];
|
||||
u16 forceAlignment;
|
||||
} u;
|
||||
if( v>0 ){
|
||||
@@ -1012,6 +1096,9 @@ int sqlite3Int64ToText(i64 v, char *zOut){
|
||||
}else{
|
||||
x = (v==SMALLEST_INT64) ? ((u64)1)<<63 : (u64)-v;
|
||||
}
|
||||
#ifdef SQLITE_AVOID_U64_DIVIDE
|
||||
i = sqlite3UInt64ToText(x, u.a);
|
||||
#else
|
||||
i = sizeof(u.a)-1;
|
||||
u.a[i] = 0;
|
||||
while( x>=10 ){
|
||||
@@ -1025,6 +1112,7 @@ int sqlite3Int64ToText(i64 v, char *zOut){
|
||||
if( x ){
|
||||
u.a[--i] = x + '0';
|
||||
}
|
||||
#endif /* SQLITE_AVOID_U64_DIVIDE */
|
||||
if( v<0 ) u.a[--i] = '-';
|
||||
memcpy(zOut, &u.a[i], sizeof(u.a)-i);
|
||||
return sizeof(u.a)-1-i;
|
||||
@@ -1081,8 +1169,8 @@ int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc){
|
||||
int incr;
|
||||
u64 u = 0;
|
||||
int neg = 0; /* assume positive */
|
||||
int i;
|
||||
int c = 0;
|
||||
int i, j;
|
||||
unsigned int c = 0;
|
||||
int nonNum = 0; /* True if input contains UTF16 with high byte non-zero */
|
||||
int rc; /* Baseline return code */
|
||||
const char *zStart;
|
||||
@@ -1110,8 +1198,8 @@ int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc){
|
||||
}
|
||||
zStart = zNum;
|
||||
while( zNum<zEnd && zNum[0]=='0' ){ zNum+=incr; } /* Skip leading zeros. */
|
||||
for(i=0; &zNum[i]<zEnd && (c=zNum[i])>='0' && c<='9'; i+=incr){
|
||||
u = u*10 + c - '0';
|
||||
for(i=0; &zNum[i]<zEnd && (c=(unsigned)zNum[i]-'0')<=9; i+=incr){
|
||||
u = u*10 + c;
|
||||
}
|
||||
testcase( i==18*incr );
|
||||
testcase( i==19*incr );
|
||||
@@ -1148,14 +1236,14 @@ int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc){
|
||||
return rc;
|
||||
}else{
|
||||
/* zNum is a 19-digit numbers. Compare it against 9223372036854775808. */
|
||||
c = i>19*incr ? 1 : compare2pow63(zNum, incr);
|
||||
if( c<0 ){
|
||||
j = i>19*incr ? 1 : compare2pow63(zNum, incr);
|
||||
if( j<0 ){
|
||||
/* zNum is less than 9223372036854775808 so it fits */
|
||||
assert( u<=LARGEST_INT64 );
|
||||
return rc;
|
||||
}else{
|
||||
*pNum = neg ? SMALLEST_INT64 : LARGEST_INT64;
|
||||
if( c>0 ){
|
||||
if( j>0 ){
|
||||
/* zNum is greater than 9223372036854775808 so it overflows */
|
||||
return 2;
|
||||
}else{
|
||||
@@ -1344,37 +1432,43 @@ void sqlite3FpDecode(FpDecode *p, double r, int iRound, int mxRound){
|
||||
/* Extract significant digits, start at the right-most slot in p->zBuf
|
||||
** and working back to the right. "i" keeps track of the next slot in
|
||||
** which to store a digit. */
|
||||
i = sizeof(p->zBuf)-1;
|
||||
zBuf = p->zBuf;
|
||||
assert( sizeof(p->zBuf)==SQLITE_U64_DIGITS+1 );
|
||||
assert( v>0 );
|
||||
zBuf = p->zBuf;
|
||||
#ifdef SQLITE_AVOID_U64_DIVIDE
|
||||
i = sqlite3UInt64ToText(v, zBuf);
|
||||
#else
|
||||
i = SQLITE_U64_DIGITS;
|
||||
while( v>=10 ){
|
||||
int kk = (v%100)*2;
|
||||
assert( TWO_BYTE_ALIGNMENT(&sqlite3DigitPairs.a[kk]) );
|
||||
assert( TWO_BYTE_ALIGNMENT(&zBuf[i-1]) );
|
||||
*(u16*)(&zBuf[i-1]) = *(u16*)&sqlite3DigitPairs.a[kk];
|
||||
assert( TWO_BYTE_ALIGNMENT(&zBuf[i]) );
|
||||
assert( i-2>=0 );
|
||||
*(u16*)(&zBuf[i-2]) = *(u16*)&sqlite3DigitPairs.a[kk];
|
||||
i -= 2;
|
||||
v /= 100;
|
||||
}
|
||||
if( v ){
|
||||
assert( v<10 );
|
||||
zBuf[i--] = v + '0';
|
||||
assert( i>0 );
|
||||
zBuf[--i] = v + '0';
|
||||
}
|
||||
assert( i>=0 && i<sizeof(p->zBuf)-1 );
|
||||
n = sizeof(p->zBuf) - 1 - i; /* Total number of digits extracted */
|
||||
#endif /* SQLITE_AVOID_U64_DIVIDE */
|
||||
assert( i>=0 && i<SQLITE_U64_DIGITS );
|
||||
n = SQLITE_U64_DIGITS - i; /* Total number of digits extracted */
|
||||
assert( n>0 );
|
||||
assert( n<sizeof(p->zBuf) );
|
||||
testcase( n==sizeof(p->zBuf)-1 );
|
||||
assert( n<=SQLITE_U64_DIGITS );
|
||||
p->iDP = n + exp;
|
||||
if( iRound<=0 ){
|
||||
iRound = p->iDP - iRound;
|
||||
if( iRound==0 && zBuf[i+1]>='5' ){
|
||||
if( iRound==0 && zBuf[i]>='5' ){
|
||||
iRound = 1;
|
||||
zBuf[i--] = '0';
|
||||
zBuf[--i] = '0';
|
||||
n++;
|
||||
p->iDP++;
|
||||
}
|
||||
}
|
||||
z = &zBuf[i+1]; /* z points to the first digit */
|
||||
z = &zBuf[i]; /* z points to the first digit */
|
||||
if( iRound>0 && (iRound<n || n>mxRound) ){
|
||||
if( iRound>mxRound ) iRound = mxRound;
|
||||
if( iRound==17 ){
|
||||
@@ -1401,7 +1495,7 @@ void sqlite3FpDecode(FpDecode *p, double r, int iRound, int mxRound){
|
||||
int jj, kk;
|
||||
u64 v2;
|
||||
assert( z[0]!='0' );
|
||||
for(jj=14; z[jj-1]=='0'; jj--){}
|
||||
for(jj=13; z[jj-1]=='0'; jj--){}
|
||||
v2 = z[0] - '0';
|
||||
for(kk=1; kk<jj; kk++) v2 = (v2*10) + z[kk] - '0';
|
||||
if( r==sqlite3Fp10Convert2(v2, exp + n - jj) ){
|
||||
|
||||
+3
-3
@@ -357,7 +357,7 @@ static void applyNumericAffinity(Mem *pRec, int bTryForInt){
|
||||
assert( (pRec->flags & (MEM_Str|MEM_Int|MEM_Real|MEM_IntReal))==MEM_Str );
|
||||
rc = sqlite3MemRealValueRC(pRec, &rValue);
|
||||
if( rc<=0 ) return;
|
||||
if( rc==1 && alsoAnInt(pRec, rValue, &pRec->u.i) ){
|
||||
if( (rc&2)==0 && alsoAnInt(pRec, rValue, &pRec->u.i) ){
|
||||
pRec->flags |= MEM_Int;
|
||||
}else{
|
||||
pRec->u.r = rValue;
|
||||
@@ -475,13 +475,13 @@ static u16 SQLITE_NOINLINE computeNumericType(Mem *pMem){
|
||||
}
|
||||
rc = sqlite3MemRealValueRC(pMem, &pMem->u.r);
|
||||
if( rc<=0 ){
|
||||
if( rc==0 && sqlite3Atoi64(pMem->z, &ix, pMem->n, pMem->enc)<=1 ){
|
||||
if( (rc&2)==0 && sqlite3Atoi64(pMem->z, &ix, pMem->n, pMem->enc)<=1 ){
|
||||
pMem->u.i = ix;
|
||||
return MEM_Int;
|
||||
}else{
|
||||
return MEM_Real;
|
||||
}
|
||||
}else if( rc==1 && sqlite3Atoi64(pMem->z, &ix, pMem->n, pMem->enc)==0 ){
|
||||
}else if( (rc&2)==0 && sqlite3Atoi64(pMem->z, &ix, pMem->n, pMem->enc)==0 ){
|
||||
pMem->u.i = ix;
|
||||
return MEM_Int;
|
||||
}
|
||||
|
||||
+7
-8
@@ -1900,7 +1900,6 @@ static void displayP4Expr(StrAccum *p, Expr *pExpr){
|
||||
#if VDBE_DISPLAY_P4
|
||||
/*
|
||||
** Compute a string that describes the P4 parameter for an opcode.
|
||||
** Use zTemp for any required temporary buffer space.
|
||||
*/
|
||||
char *sqlite3VdbeDisplayP4(sqlite3 *db, Op *pOp){
|
||||
char *zP4 = 0;
|
||||
@@ -5450,12 +5449,12 @@ static int vdbeIsMatchingIndexKey(
|
||||
){
|
||||
u8 *aRec = 0;
|
||||
u32 nRec = 0;
|
||||
Mem mem;
|
||||
Mem m;
|
||||
int rc = SQLITE_OK;
|
||||
|
||||
memset(&mem, 0, sizeof(mem));
|
||||
mem.enc = p->pKeyInfo->enc;
|
||||
mem.db = p->pKeyInfo->db;
|
||||
memset(&m, 0, sizeof(m));
|
||||
m.enc = p->pKeyInfo->enc;
|
||||
m.db = p->pKeyInfo->db;
|
||||
nRec = sqlite3BtreePayloadSize(pCur);
|
||||
if( nRec>0x7fffffff ){
|
||||
return SQLITE_CORRUPT_BKPT;
|
||||
@@ -5497,9 +5496,9 @@ static int vdbeIsMatchingIndexKey(
|
||||
if( (idxRec+nSerial)>nRec ){
|
||||
rc = SQLITE_CORRUPT_BKPT;
|
||||
}else{
|
||||
sqlite3VdbeSerialGet(&aRec[idxRec], iSerial, &mem);
|
||||
if( vdbeSkipField(mask, ii, &p->aMem[ii], &mem, bInt)==0 ){
|
||||
res = sqlite3MemCompare(&mem, &p->aMem[ii], p->pKeyInfo->aColl[ii]);
|
||||
sqlite3VdbeSerialGet(&aRec[idxRec], iSerial, &m);
|
||||
if( vdbeSkipField(mask, ii, &p->aMem[ii], &m, bInt)==0 ){
|
||||
res = sqlite3MemCompare(&m, &p->aMem[ii], p->pKeyInfo->aColl[ii]);
|
||||
if( res!=0 ) break;
|
||||
}
|
||||
}
|
||||
|
||||
+26
-7
@@ -658,9 +658,21 @@ i64 sqlite3VdbeIntValue(const Mem *pMem){
|
||||
|
||||
/*
|
||||
** This routine implements the uncommon and slower path for
|
||||
** sqlite3MemValueRC(). It is broken out into a separate
|
||||
** no-inline routine so that the main routine can avoid unnecessary
|
||||
** sqlite3MemRealValueRC() that has to deal with input strings
|
||||
** that are not UTF8 or that are not zero-terminated. It is
|
||||
** broken out into a separate no-inline routine so that the
|
||||
** main sqlite3MemRealValueRC() routine can avoid unnecessary
|
||||
** stack pushes.
|
||||
**
|
||||
** A text->float translation of pMem->z is written into *pValue.
|
||||
**
|
||||
** Result code invariants:
|
||||
**
|
||||
** rc==0 => ERROR: Input string not well-formed, or OOM
|
||||
** rc<0 => Some prefix of the input is well-formed
|
||||
** rc>0 => All of the input is well-formed
|
||||
** (rc&2)==0 => The number is expressed as an integer, with no
|
||||
** decimal point or eNNN suffix.
|
||||
*/
|
||||
static SQLITE_NOINLINE int sqlite3MemRealValueRCSlowPath(
|
||||
Mem *pMem,
|
||||
@@ -706,15 +718,22 @@ static SQLITE_NOINLINE int sqlite3MemRealValueRCSlowPath(
|
||||
}
|
||||
|
||||
/*
|
||||
** Invoke sqlite3AtoF() on the text value of pMem and return the
|
||||
** double result. If sqlite3AtoF() returns an error code, write
|
||||
** that code into *pRC if (*pRC)!=NULL.
|
||||
** Invoke sqlite3AtoF() on the text value of pMem. Write the
|
||||
** translation of the text input into *pValue.
|
||||
**
|
||||
** The caller must ensure that pMem->db!=0 and that pMem is in
|
||||
** mode MEM_Str or MEM_Blob.
|
||||
**
|
||||
** Result code invariants:
|
||||
**
|
||||
** rc==0 => ERROR: Input string not well-formed, or OOM
|
||||
** rc<0 => Some prefix of the input is well-formed
|
||||
** rc>0 => All of the input is well-formed
|
||||
** (rc&2)==0 => The number is expressed as an integer, with no
|
||||
** 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;
|
||||
@@ -883,7 +902,7 @@ int sqlite3VdbeMemNumerify(Mem *pMem){
|
||||
assert( (pMem->flags & (MEM_Blob|MEM_Str))!=0 );
|
||||
assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
|
||||
rc = sqlite3MemRealValueRC(pMem, &pMem->u.r);
|
||||
if( ((rc==0 || rc==1) && sqlite3Atoi64(pMem->z, &ix, pMem->n, pMem->enc)<=1)
|
||||
if( ((rc&2)==0 && sqlite3Atoi64(pMem->z, &ix, pMem->n, pMem->enc)<2)
|
||||
|| sqlite3RealSameAsInt(pMem->u.r, (ix = sqlite3RealToI64(pMem->u.r)))
|
||||
){
|
||||
pMem->u.i = ix;
|
||||
|
||||
@@ -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
@@ -163,7 +163,7 @@ int sqlite3WhereBreakLabel(WhereInfo *pWInfo){
|
||||
** If the ONEPASS optimization is used (if this routine returns true)
|
||||
** then also write the indices of open cursors used by ONEPASS
|
||||
** into aiCur[0] and aiCur[1]. iaCur[0] gets the cursor of the data
|
||||
** table and iaCur[1] gets the cursor used by an auxiliary index.
|
||||
** table and aiCur[1] gets the cursor used by an auxiliary index.
|
||||
** Either value may be -1, indicating that cursor is not used.
|
||||
** Any cursors returned will have been opened for writing.
|
||||
**
|
||||
|
||||
+78
-25
@@ -2,6 +2,9 @@
|
||||
** Performance testing of floating-point binary-to-decimal conversion for
|
||||
** SQLite versus the standard library.
|
||||
**
|
||||
** This module compares library sprintf() against SQLite's sqlite3_snprintf().
|
||||
** To go the other direction (decimal-to-binary) see fp-speed-2.c.
|
||||
**
|
||||
** To compile:
|
||||
**
|
||||
** make sqlite3.c
|
||||
@@ -10,9 +13,17 @@
|
||||
**
|
||||
** To run the test:
|
||||
**
|
||||
** time ./a.out 0 10000000 <-- standard library
|
||||
** time ./a.out 1 10000000 <-- SQLite
|
||||
** ./a.out 10000000
|
||||
*/
|
||||
#include "sqlite3.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#ifdef _WIN32
|
||||
# include <windows.h>
|
||||
#else
|
||||
# include <sys/time.h>
|
||||
#endif
|
||||
|
||||
static double aVal[] = {
|
||||
-1.0163830486285643089e+063,
|
||||
+0.0049243807391586981e-019,
|
||||
@@ -117,38 +128,80 @@ static double aVal[] = {
|
||||
};
|
||||
#define NN (sizeof(aVal)/sizeof(aVal[0]))
|
||||
|
||||
#include "sqlite3.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
/* Return the current wall-clock time in microseconds since the
|
||||
** Unix epoch (1970-01-01T00:00:00Z)
|
||||
*/
|
||||
static sqlite3_int64 timeOfDay(void){
|
||||
#if defined(_WIN64) && _WIN32_WINNT >= _WIN32_WINNT_WIN8
|
||||
sqlite3_uint64 t;
|
||||
FILETIME tm;
|
||||
GetSystemTimePreciseAsFileTime(&tm);
|
||||
t = ((sqlite3_uint64)tm.dwHighDateTime<<32) |
|
||||
(sqlite3_uint64)tm.dwLowDateTime;
|
||||
t += 116444736000000000LL;
|
||||
t /= 10;
|
||||
return t;
|
||||
#elif defined(_WIN32)
|
||||
static sqlite3_vfs *clockVfs = 0;
|
||||
sqlite3_int64 t;
|
||||
if( clockVfs==0 ) clockVfs = sqlite3_vfs_find(0);
|
||||
if( clockVfs==0 ) return 0; /* Never actually happens */
|
||||
if( clockVfs->iVersion>=2 && clockVfs->xCurrentTimeInt64!=0 ){
|
||||
clockVfs->xCurrentTimeInt64(clockVfs, &t);
|
||||
}else{
|
||||
double r;
|
||||
clockVfs->xCurrentTime(clockVfs, &r);
|
||||
t = (sqlite3_int64)(r*86400000.0);
|
||||
}
|
||||
return t*1000;
|
||||
#else
|
||||
struct timeval sNow;
|
||||
(void)gettimeofday(&sNow,0);
|
||||
return ((sqlite3_int64)sNow.tv_sec)*1000000 + sNow.tv_usec;
|
||||
#endif
|
||||
}
|
||||
|
||||
int main(int argc, char **argv){
|
||||
int i;
|
||||
int cnt;
|
||||
int fg;
|
||||
static const char *zFmt = "%.17g";
|
||||
sqlite3_int64 tm1, tm2;
|
||||
char zBuf[1000];
|
||||
|
||||
if( argc!=3 ){
|
||||
fprintf(stderr, "Usage: %s FLAG COUNT\n", argv[0]);
|
||||
if( argc!=2 ){
|
||||
printf("Usage: %s COUNT\n", argv[0]);
|
||||
printf("Suggested value for COUNT is 10 million\n");
|
||||
return 1;
|
||||
}
|
||||
cnt = atoi(argv[1]);
|
||||
if( cnt<100 ){
|
||||
printf("Minimum COUNT value is 100");
|
||||
return 1;
|
||||
}
|
||||
cnt = atoi(argv[2]);
|
||||
fg = atoi(argv[1]);
|
||||
|
||||
switch( fg % 3 ){
|
||||
case 0: {
|
||||
printf("Doing %d calls to C-lib sprintf()\n", cnt);
|
||||
for(i=0; i<cnt; i++){
|
||||
sprintf(zBuf, "%.26g", aVal[i%NN]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
printf("Doing %d calls to sqlite3_snprintf()\n", cnt);
|
||||
for(i=0; i<cnt; i++){
|
||||
sqlite3_snprintf(sizeof(zBuf), zBuf, "%!.26g", aVal[i%NN]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
printf("C-library sprintf(\"%s\"): ", zFmt);
|
||||
fflush(stdout);
|
||||
tm1 = timeOfDay();
|
||||
for(i=0; i<cnt; i++){
|
||||
sprintf(zBuf, zFmt, aVal[i%NN]);
|
||||
}
|
||||
tm1 = timeOfDay() - tm1;
|
||||
printf("%6.1f ns/call, %9.6f sec total\n", tm1*1.0e+3/(double)cnt,tm1*1.0e-6);
|
||||
|
||||
printf("sqlite3_snprintf(\"%s\"): ", zFmt);
|
||||
tm2 = timeOfDay();
|
||||
for(i=0; i<cnt; i++){
|
||||
sqlite3_snprintf(sizeof(zBuf), zBuf, zFmt, aVal[i%NN]);
|
||||
}
|
||||
tm2 = timeOfDay() - tm2;
|
||||
printf("%6.1f ns/call, %9.6f sec total\n", tm2*1.0e+3/(double)cnt,tm2*1.0e-6);
|
||||
|
||||
if( tm1 < tm2 ){
|
||||
printf("sprintf() is about %g times faster than sqlite3_snprintf()\n",
|
||||
(double)tm2/(double)tm1);
|
||||
}else{
|
||||
printf("sqlite3_snprintf() is about %g times faster than sprintf()\n",
|
||||
(double)tm1/(double)tm2);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,263 @@
|
||||
/*
|
||||
** Performance testing of floating-point decimal-to-binary conversion for
|
||||
** SQLite versus the standard library.
|
||||
**
|
||||
** This module compares library atof() against SQLite's sqlite3AtoF().
|
||||
** To go the other direction (binary-to-decimal) see fp-speed-1.c.
|
||||
**
|
||||
** To compile:
|
||||
**
|
||||
** make sqlite3.c
|
||||
** gcc -Os -c sqlite3.c
|
||||
** gcc -I. -Os test/fp-speed-2.c sqlite3.o -ldl -lm -lpthread
|
||||
**
|
||||
** To run the test:
|
||||
**
|
||||
** ./a.out 10000000
|
||||
**
|
||||
** Notes:
|
||||
**
|
||||
** * A first loop is run to measure the testing overhead. This
|
||||
** overhead is then subtracted from the times of subsequent loops
|
||||
** so that the estimates are for the calls to atof() or
|
||||
** sqlite3AtoF() only.
|
||||
*/
|
||||
#include "sqlite3.h"
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#ifdef _WIN32
|
||||
# include <windows.h>
|
||||
#else
|
||||
# include <sys/time.h>
|
||||
#endif
|
||||
|
||||
static const char *aVal[] = {
|
||||
"-1.01638304862856430",
|
||||
"+0.00492438073915869",
|
||||
"+7.38187324073439948",
|
||||
"+7.06785952192257171",
|
||||
"+9.28072663198500256",
|
||||
"+5.88710508619333946",
|
||||
"-2.29980236212596628",
|
||||
"-1.59035819249108474",
|
||||
"+2.43134418168449782",
|
||||
"-3.82909873289453990",
|
||||
"+1.87879140627440013",
|
||||
"+0.72706535604871466",
|
||||
"+0.06395776979131836",
|
||||
"+5.22923388793158619",
|
||||
"+6.37476826728722313",
|
||||
"+8.69723395383291069",
|
||||
"-9.50744860515976919",
|
||||
"-8.64802578453687530",
|
||||
"-3.56575957757974703",
|
||||
"-7.83231061797317613",
|
||||
"+7.78138752741208003",
|
||||
"-1.87397189283601965",
|
||||
"+8.68981459155933572",
|
||||
"+6.05667663598778378",
|
||||
"+4.17033792171481606",
|
||||
"+2.12838712887466515",
|
||||
"-6.83952360838918106",
|
||||
"-6.21142997639395291",
|
||||
"-2.07535257426146373",
|
||||
"+5.87274598039442902",
|
||||
"+8.58889910620021018",
|
||||
"+6.86244610313559176",
|
||||
"-3.30539867566709051",
|
||||
"-4.35968431527634449",
|
||||
"+0.08341395201040996",
|
||||
"-8.85819865489042224",
|
||||
"-3.66220954287276982",
|
||||
"-6.69658522970250632",
|
||||
"+1.82041693474064884",
|
||||
"+6.52345080386490003",
|
||||
"+1.59230060182190114",
|
||||
"+1.73625552916563894",
|
||||
"+7.28754319768547858",
|
||||
"+1.28358801059589267",
|
||||
"+8.05162533203208194",
|
||||
"+6.63246333993811454",
|
||||
"-1.71265000702800620",
|
||||
"+1.69957383415837123",
|
||||
"+7.60487669237386637",
|
||||
"+0.61591172354494550",
|
||||
"+5.75448943554159432",
|
||||
"+8.29702285926905818",
|
||||
"-6.55319253601630674",
|
||||
"+5.83213346061870300",
|
||||
"+5.65571665095718917",
|
||||
"+0.33227897084384087",
|
||||
"-7.12106487766986866",
|
||||
"-9.67212625267063433",
|
||||
"-3.45839165713773950",
|
||||
"+4.78960943232147507",
|
||||
"-9.69260280400041378",
|
||||
"+7.06838482753813854",
|
||||
"-5.29701141821629619",
|
||||
"-4.42870212009053932",
|
||||
"+0.07288911557328087",
|
||||
"-9.18554620258794474",
|
||||
"+3.72941262341310077",
|
||||
"+2.68574218827927192",
|
||||
"-4.70706073336246853",
|
||||
"+7.21758207682793342",
|
||||
"-8.36784125342611634",
|
||||
"+2.21748443042418221",
|
||||
"+0.19498245886068610",
|
||||
"-9.73340529556720719",
|
||||
"-9.77938877669369998",
|
||||
"-5.15611645874169315",
|
||||
"-7.50489935777651747",
|
||||
"+7.35560765686877845",
|
||||
"-5.06816285755335998",
|
||||
"+1.52097056420277478",
|
||||
"-7.59897825350482960",
|
||||
"+1.36541372033897758",
|
||||
"-1.64417205546513720",
|
||||
"-4.90424331961411259",
|
||||
"-7.70636119616491307",
|
||||
"+0.16994274609307662",
|
||||
"+8.33743178495722168",
|
||||
"-5.23553304804695800",
|
||||
"-3.85100459421941479",
|
||||
"-6.35136225443263398",
|
||||
"+2.38693034844544289",
|
||||
"+3.83527158716203602",
|
||||
"-3.12631204931368879",
|
||||
"-5.57947970025564908",
|
||||
"-8.81098744795956043",
|
||||
"-4.37273601202032169",
|
||||
"-3.11099511896685399",
|
||||
"-9.48418780317042682",
|
||||
"-3.73984516683044072",
|
||||
"+4.89840420089159599",
|
||||
};
|
||||
#define NN (sizeof(aVal)/sizeof(aVal[0]))
|
||||
|
||||
/* Return the current wall-clock time in microseconds since the
|
||||
** Unix epoch (1970-01-01T00:00:00Z)
|
||||
*/
|
||||
static sqlite3_int64 timeOfDay(void){
|
||||
#if defined(_WIN64) && _WIN32_WINNT >= _WIN32_WINNT_WIN8
|
||||
sqlite3_uint64 t;
|
||||
FILETIME tm;
|
||||
GetSystemTimePreciseAsFileTime(&tm);
|
||||
t = ((sqlite3_uint64)tm.dwHighDateTime<<32) |
|
||||
(sqlite3_uint64)tm.dwLowDateTime;
|
||||
t += 116444736000000000LL;
|
||||
t /= 10;
|
||||
return t;
|
||||
#elif defined(_WIN32)
|
||||
static sqlite3_vfs *clockVfs = 0;
|
||||
sqlite3_int64 t;
|
||||
if( clockVfs==0 ) clockVfs = sqlite3_vfs_find(0);
|
||||
if( clockVfs==0 ) return 0; /* Never actually happens */
|
||||
if( clockVfs->iVersion>=2 && clockVfs->xCurrentTimeInt64!=0 ){
|
||||
clockVfs->xCurrentTimeInt64(clockVfs, &t);
|
||||
}else{
|
||||
double r;
|
||||
clockVfs->xCurrentTime(clockVfs, &r);
|
||||
t = (sqlite3_int64)(r*86400000.0);
|
||||
}
|
||||
return t*1000;
|
||||
#else
|
||||
struct timeval sNow;
|
||||
(void)gettimeofday(&sNow,0);
|
||||
return ((sqlite3_int64)sNow.tv_sec)*1000000 + sNow.tv_usec;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate text of the i-th test floating-point literal.
|
||||
*/
|
||||
static int fpLiteral(int i, char *z){
|
||||
int e, ex, len, ix;
|
||||
ex = i%401;
|
||||
e = ex - 200;
|
||||
len = (i/401)%16 + 4;
|
||||
ix = (i/(401*16))%NN;
|
||||
memcpy(z, aVal[ix], len);
|
||||
z[len++] = 'e';
|
||||
if( e<0 ){
|
||||
z[len++] = '-';
|
||||
e = -e;
|
||||
}else{
|
||||
z[len++] = '+';
|
||||
}
|
||||
z[len++] = e/100 + '0';
|
||||
z[len++] = (e/10)%10 + '0';
|
||||
z[len++] = e%10 + '0';
|
||||
z[len] = 0;
|
||||
return ex;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv){
|
||||
int i;
|
||||
int cnt;
|
||||
sqlite3_int64 tm[3];
|
||||
double arSum[401];
|
||||
char z[1000];
|
||||
|
||||
if( argc!=2 ){
|
||||
printf("Usage: %s COUNT\n", argv[0]);
|
||||
printf("Suggested value for COUNT is 10 million\n");
|
||||
return 1;
|
||||
}
|
||||
cnt = atoi(argv[1]);
|
||||
if( cnt<100 ){
|
||||
printf("Minimum COUNT value is 100");
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("test-overhead: ");
|
||||
fflush(stdout);
|
||||
memset(arSum, 0, sizeof(arSum));
|
||||
tm[2] = timeOfDay();
|
||||
for(i=0; i<cnt; i++){
|
||||
double r = (double)i;
|
||||
int ex = fpLiteral(i,z);
|
||||
arSum[ex] += r;
|
||||
}
|
||||
tm[2] = timeOfDay() - tm[2];
|
||||
for(i=1; i<=400; i++) arSum[0] += arSum[i];
|
||||
printf("%6.1f ns/test, %9.6f sec total\n", tm[2]*1e3/cnt, tm[2]*1e-6);
|
||||
|
||||
printf("C-lib atof(): ");
|
||||
fflush(stdout);
|
||||
memset(arSum, 0, sizeof(arSum));
|
||||
tm[0] = timeOfDay();
|
||||
for(i=0; i<cnt; i++){
|
||||
int ex = fpLiteral(i,z);
|
||||
arSum[ex] += atof(z);
|
||||
}
|
||||
tm[0] = timeOfDay() - tm[0] - tm[2];
|
||||
for(i=1; i<=400; i++) arSum[0] += arSum[i];
|
||||
printf("%6.1f ns/test, %9.6f sec net", tm[0]*1e3/cnt, tm[0]*1e-6);
|
||||
printf(", cksum: %g\n", arSum[0]);
|
||||
|
||||
printf("sqlite3AtoF(): ");
|
||||
fflush(stdout);
|
||||
memset(arSum, 0, sizeof(arSum));
|
||||
tm[1] = timeOfDay();
|
||||
for(i=0; i<cnt; i++){
|
||||
double r = 0.0;
|
||||
int ex = fpLiteral(i,z);
|
||||
sqlite3_test_control(SQLITE_TESTCTRL_ATOF, z, &r);
|
||||
arSum[ex] += r;
|
||||
}
|
||||
tm[1] = timeOfDay() - tm[1] - tm[2];
|
||||
for(i=1; i<=400; i++) arSum[0] += arSum[i];
|
||||
printf("%6.1f ns/test, %9.6f sec net", tm[1]*1e3/cnt, tm[1]*1e-6);
|
||||
printf(", cksum: %g\n", arSum[0]);
|
||||
|
||||
if( tm[0] < tm[1] ){
|
||||
printf("atof() is about %g times faster than sqlite3AtoF()\n",
|
||||
(double)tm[1]/(double)tm[0]);
|
||||
}else{
|
||||
printf("sqlite3AtoF() is about %g times faster than atof()\n",
|
||||
(double)tm[0]/(double)tm[1]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
+111
-1
@@ -11,7 +11,21 @@
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
# Floating-point to text conversions
|
||||
# Floating-point <-> text conversions
|
||||
#
|
||||
# FAILURES IN THIS SCRIPT ARE NOT NECESSARILY THE FAULT OF SQLITE.
|
||||
#
|
||||
# Some of the tests below use the system strtod() function as
|
||||
# an oracle of truth. These tests assume that the system strtod()
|
||||
# is always correct. That is the case for Win11, Macs, most Linux
|
||||
# boxes and so forth. But it possible to find a machine for which
|
||||
# is not true. (One example, is Macs from around 2005.) On such
|
||||
# machines, some of these tests might fail.
|
||||
#
|
||||
# So, in other words, a failure in any of the tests below does not
|
||||
# necessarily mean that SQLite is wrong. It might mean that the
|
||||
# strtod() function in the standard library of the machine on which
|
||||
# the test is running is wrong.
|
||||
#
|
||||
|
||||
# Verify that binary64 -> text -> binary64 conversions round-trip
|
||||
@@ -74,3 +88,99 @@ WITH
|
||||
fp(r) AS (SELECT ieee754_from_int(n) FROM fpint)
|
||||
SELECT r FROM fp WHERE r<>strtod(r||'');
|
||||
.check ''
|
||||
|
||||
# Comparing SQLite's text-to-double conversion against strtod()
|
||||
# for 200,000 random floating-point literals.
|
||||
#
|
||||
.param set $N 50_000
|
||||
.testcase 300
|
||||
WITH RECURSIVE fp(n,x) AS MATERIALIZED (
|
||||
VALUES(1,'1234.5789')
|
||||
UNION ALL
|
||||
SELECT n+1, format('%.*s.%.*se%+d',
|
||||
(n%3)+1,
|
||||
random()%1000,
|
||||
abs(random()%16)+1,
|
||||
abs(random()),
|
||||
random()%308)
|
||||
FROM fp WHERE n<$N
|
||||
) SELECT x FROM fp WHERE (x+0.0)<>strtod(x);
|
||||
.check ''
|
||||
.testcase 301
|
||||
WITH RECURSIVE fp(n,x) AS MATERIALIZED (
|
||||
VALUES(1,'1234.5789')
|
||||
UNION ALL
|
||||
SELECT n+1, format('%.*s.%.*s',
|
||||
(n%3)+1,
|
||||
random()%1000,
|
||||
abs(random()%16)+1,
|
||||
abs(random()))
|
||||
FROM fp WHERE n<$N
|
||||
) SELECT x FROM fp WHERE (x+0.0)<>strtod(x);
|
||||
.check ''
|
||||
.testcase 302
|
||||
WITH RECURSIVE fp(n,x) AS MATERIALIZED (
|
||||
VALUES(1,'1234.5789')
|
||||
UNION ALL
|
||||
SELECT n+1, format('%.*s.%.*s',
|
||||
abs(random()%7)+1,
|
||||
random(),
|
||||
abs(random()%10)+1,
|
||||
abs(random()))
|
||||
FROM fp WHERE n<$N
|
||||
) SELECT x FROM fp WHERE (x+0.0)<>strtod(x);
|
||||
.check ''
|
||||
.testcase 303
|
||||
WITH RECURSIVE fp(n,x) AS MATERIALIZED (
|
||||
VALUES(1,'1234.5789')
|
||||
UNION ALL
|
||||
SELECT n+1, format('%de%+03d',
|
||||
random(),
|
||||
random()%308)
|
||||
FROM fp WHERE n<$N
|
||||
) SELECT x FROM fp WHERE (x+0.0)<>strtod(x);
|
||||
.check ''
|
||||
|
||||
# Another 500,000 comparisions between SQLite and strtod() from completely
|
||||
# random floating point literals.
|
||||
#
|
||||
.testcase 310
|
||||
WITH RECURSIVE fp(n,x) AS MATERIALIZED (
|
||||
SELECT 1, format('%+.*g',abs(random()%18), ieee754_from_int(random()))
|
||||
UNION ALL
|
||||
SELECT n+1, format('%+.*g',abs(random()%18), ieee754_from_int(random()))
|
||||
FROM fp WHERE n<$N*2
|
||||
) SELECT x FROM fp WHERE (x+0.0)<>strtod(x);
|
||||
.check ''
|
||||
.testcase 311
|
||||
WITH RECURSIVE fp(n,x) AS MATERIALIZED (
|
||||
SELECT 1, format('%+.*g',abs(random()%18), ieee754_from_int(random()))
|
||||
UNION ALL
|
||||
SELECT n+1, format('%+.*g',abs(random()%18), ieee754_from_int(random()))
|
||||
FROM fp WHERE n<$N*2
|
||||
) SELECT x FROM fp WHERE (x+0.0)<>strtod(x);
|
||||
.check ''
|
||||
.testcase 312
|
||||
WITH RECURSIVE fp(n,x) AS MATERIALIZED (
|
||||
SELECT 1, format('%+.*g',abs(random()%18), ieee754_from_int(random()))
|
||||
UNION ALL
|
||||
SELECT n+1, format('%+.*g',abs(random()%18), ieee754_from_int(random()))
|
||||
FROM fp WHERE n<$N*2
|
||||
) SELECT x FROM fp WHERE (x+0.0)<>strtod(x);
|
||||
.check ''
|
||||
.testcase 313
|
||||
WITH RECURSIVE fp(n,x) AS MATERIALIZED (
|
||||
SELECT 1, format('%+.*g',abs(random()%18), ieee754_from_int(random()))
|
||||
UNION ALL
|
||||
SELECT n+1, format('%+.*g',abs(random()%18), ieee754_from_int(random()))
|
||||
FROM fp WHERE n<$N*2
|
||||
) SELECT x FROM fp WHERE (x+0.0)<>strtod(x);
|
||||
.check ''
|
||||
.testcase 314
|
||||
WITH RECURSIVE fp(n,x) AS MATERIALIZED (
|
||||
SELECT 1, format('%+.*g',abs(random()%18), ieee754_from_int(random()))
|
||||
UNION ALL
|
||||
SELECT n+1, format('%+.*g',abs(random()%18), ieee754_from_int(random()))
|
||||
FROM fp WHERE n<$N*2
|
||||
) SELECT x FROM fp WHERE (x+0.0)<>strtod(x);
|
||||
.check ''
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
#
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
#!sqlite3
|
||||
#
|
||||
# 2026-04-11
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
# Tests for the .prompt command and prompt rendering.
|
||||
#
|
||||
# ./sqlite3 test/shell-prompt.sql
|
||||
#
|
||||
|
||||
.testcase setup
|
||||
.open -new test.db
|
||||
.mode list -quote off -escape ascii
|
||||
.prompt --hard-reset
|
||||
.check ''
|
||||
|
||||
.testcase 100
|
||||
.prompt
|
||||
.check ''
|
||||
|
||||
.testcase 110
|
||||
.prompt --show
|
||||
.check <<END
|
||||
Main prompt: 'SQLite /f> '
|
||||
Continuation: '/B.../H> '
|
||||
END
|
||||
.testcase 111
|
||||
.prompt 'abc> ' '123> ' -show
|
||||
.check <<END
|
||||
Main prompt: 'abc> '
|
||||
Continuation: '123> '
|
||||
END
|
||||
.testcase 112
|
||||
.prompt -- --first --second
|
||||
.prompt --show
|
||||
.check <<END
|
||||
Main prompt: '--first'
|
||||
Continuation: '--second'
|
||||
END
|
||||
.testcase 113
|
||||
.prompt --reset --show
|
||||
.check <<END
|
||||
Main prompt: 'SQLite /f> '
|
||||
Continuation: '/B.../H> '
|
||||
END
|
||||
|
||||
.testcase 120 --error-prefix ERROR:
|
||||
.prompt show
|
||||
.check <<END
|
||||
ERROR: .prompt show
|
||||
ERROR: ^--- use quotes around the prompt string
|
||||
END
|
||||
|
||||
.testcase 121
|
||||
.prompt 'show'
|
||||
.check ''
|
||||
.testcase 122
|
||||
.prompt --show
|
||||
.check <<END
|
||||
Main prompt: 'show'
|
||||
Continuation: '/B.../H> '
|
||||
END
|
||||
|
||||
.testcase 130
|
||||
.prompt --reset
|
||||
.help prompt
|
||||
.check <<END
|
||||
.prompt MAIN CONTINUE Replace the standard prompts
|
||||
--hard-reset Unset SQLITE_PS1/2 and then --reset
|
||||
--reset Revert to default prompts
|
||||
--show Show the current prompt strings
|
||||
-- No more options. Subsequent args are prompts
|
||||
END
|
||||
|
||||
.testcase 140 --error-prefix ERROR:
|
||||
.prompt --xyz
|
||||
.check <<END
|
||||
ERROR: .prompt --xyz
|
||||
ERROR: ^--- unknown option
|
||||
END
|
||||
|
||||
|
||||
.testcase 1000
|
||||
SELECT shell_prompt_test(NULL);
|
||||
.check 'SQLite test.db> ';
|
||||
.testcase 1001
|
||||
SELECT shell_prompt_test(NULL,'SELECT');
|
||||
.check ' ...;> ';
|
||||
.testcase 1002
|
||||
SELECT shell_prompt_test(NULL,'SELECT ((("');
|
||||
.check ' ...")));> ';
|
||||
.testcase 1003
|
||||
SELECT shell_prompt_test(NULL,'SELECT ((()[');
|
||||
.check ' ...]));> ';
|
||||
.testcase 1004
|
||||
SELECT shell_prompt_test(NULL,'SELECT ''');
|
||||
.check " ...';> ";
|
||||
.testcase 1005
|
||||
SELECT shell_prompt_test(NULL,'CREATE TRIGGER t1 BEGIN');
|
||||
.check " ...;END;> ";
|
||||
.testcase 1006
|
||||
SELECT shell_prompt_test(NULL,'CREATE TRIGGER t1 BEGIN SELECT ((([');
|
||||
.check " ...])));END;> ";
|
||||
.testcase 1007
|
||||
SELECT shell_prompt_test(NULL,'CREATE TRIGGER t1 BEGIN SELECT ((/*a(((''bc');
|
||||
.check " ...*/));END;> ";
|
||||
.testcase 1008
|
||||
SELECT shell_prompt_test(NULL,'CREATE TRIGGER t1 BEGIN SELECT 1;');
|
||||
.check " ...END;> ";
|
||||
|
||||
.testcase 2000
|
||||
.prompt 'SQLite/x-txn$/:>/; '
|
||||
SELECT shell_prompt_test(NULL);
|
||||
.check 'SQLite> ';
|
||||
.testcase 2001
|
||||
BEGIN;
|
||||
SELECT shell_prompt_test(NULL);
|
||||
.check 'SQLite-txn$ ';
|
||||
.testcase 2002
|
||||
ROLLBACK;
|
||||
SELECT shell_prompt_test(NULL);
|
||||
.check 'SQLite> ';
|
||||
.testcase 2003
|
||||
.prompt -- '--show '
|
||||
SELECT shell_prompt_test(NULL);
|
||||
.check '--show ';
|
||||
.testcase 2004
|
||||
.prompt --reset
|
||||
SELECT shell_prompt_test(NULL);
|
||||
.check 'SQLite test.db> ';
|
||||
|
||||
.testcase
|
||||
+2
-1
@@ -548,7 +548,8 @@ do_test shell1-3.17.3 {
|
||||
do_test shell1-3.17.4 {
|
||||
# too many arguments
|
||||
catchcmd "test.db" ".prompt FOO BAR BAD"
|
||||
} {0 {}}
|
||||
} {1 {line 1: .prompt FOO BAR BAD
|
||||
line 1: ^--- extra argument}}
|
||||
|
||||
# .quit Exit this program
|
||||
do_test shell1-3.18.1 {
|
||||
|
||||
@@ -49,5 +49,8 @@ ifcapable vtab {
|
||||
do_clitest intck01.sql
|
||||
}
|
||||
do_clitest fptest01.sql
|
||||
unset -nocomplain ::env(SQLITE_PS1)
|
||||
unset -nocomplain ::env(SQLITE_PS2)
|
||||
do_clitest shell-prompt.sql
|
||||
|
||||
finish_test
|
||||
|
||||
+64
-8
@@ -97,15 +97,16 @@ proc usage {} {
|
||||
Usage:
|
||||
$a0 ?SWITCHES? ?PERMUTATION? ?PATTERNS?
|
||||
$a0 PERMUTATION FILE
|
||||
$a0 clean
|
||||
$a0 errors ?-v|--verbose? ?-s|--summary? ?PATTERN?
|
||||
$a0 estwork
|
||||
$a0 halt
|
||||
$a0 help
|
||||
$a0 joblist ?PATTERN?
|
||||
$a0 njob ?NJOB?
|
||||
$a0 retest
|
||||
$a0 script ?-msvc? CONFIG
|
||||
$a0 status ?-d SECS? ?--cls?
|
||||
$a0 halt
|
||||
$a0 estwork
|
||||
|
||||
where SWITCHES are:
|
||||
--buildonly Build test exes but do not run tests
|
||||
@@ -141,7 +142,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
|
||||
@@ -158,6 +162,12 @@ of the tests. Use the "-d N" option to have the status display clear the
|
||||
screen and repeat every N seconds. The "njob" command may be used to query
|
||||
or modify the number of sub-processes the test script uses to run tests.
|
||||
|
||||
The "halt" command modifies the database so that all tasks are marked
|
||||
as complete. Testing will halt when all tests currently running complete.
|
||||
|
||||
The "clean" command removes files and directories created by a prior
|
||||
invocation of testrunner.tcl.
|
||||
|
||||
The "script" command outputs the script used to build a configuration.
|
||||
Add the "-msvc" option for a Windows-compatible script. For a list of
|
||||
available configurations enter "$a0 script help".
|
||||
@@ -457,6 +467,32 @@ if {([llength $argv]==2 || [llength $argv]==1)
|
||||
}
|
||||
#--------------------------------------------------------------------------
|
||||
|
||||
#--------------------------------------------------------------------------
|
||||
# Check if this is the "clean" command:
|
||||
#
|
||||
if {([llength $argv]==2 || [llength $argv]==1)
|
||||
&& [string compare -nocase clean [lindex $argv 0]]==0
|
||||
} {
|
||||
set pattern {_(fuzzcheck|sessionfuzz|sqlite3|testfixture)}
|
||||
foreach f [glob testrun_*] {
|
||||
if {[file isdir $f] && [regexp $pattern $f]} {
|
||||
file delete -force $f
|
||||
}
|
||||
}
|
||||
foreach f [glob testdir*] {
|
||||
if {[file isdir $f] && [regexp {^testdir[0-9]+$} $f]} {
|
||||
file delete -force $f
|
||||
}
|
||||
}
|
||||
foreach f [glob testrunner.db*] {
|
||||
file delete -force $f
|
||||
}
|
||||
file delete -force testrunner.log
|
||||
exit
|
||||
}
|
||||
|
||||
#--------------------------------------------------------------------------
|
||||
|
||||
#--------------------------------------------------------------------------
|
||||
# Check if this is the "halt" command:
|
||||
#
|
||||
@@ -1124,10 +1160,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 +1186,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
|
||||
}
|
||||
|
||||
@@ -1155,7 +1210,7 @@ proc job_matches_any_pattern {patternlist jobcmd} {
|
||||
#
|
||||
# e.g
|
||||
#
|
||||
# {1 /home/user/sqlite/test/testrunner_bld_xyz All-Debug}
|
||||
# {1 /home/user/sqlite/test/testrun_xyz All-Debug}
|
||||
#
|
||||
proc add_tcl_jobs {build config patternlist {shelldepid ""}} {
|
||||
global TRG
|
||||
@@ -1221,7 +1276,8 @@ proc add_build_job {buildname target {postcmd ""} {depid ""}} {
|
||||
global TRG
|
||||
|
||||
set dirname "[string tolower [string map {- _} $buildname]]_$target"
|
||||
set dirname "testrunner_bld_$dirname"
|
||||
regsub {\.exe$} $dirname {} dirname
|
||||
set dirname "testrun_$dirname"
|
||||
|
||||
set cmd "$TRG(makecmd) $target"
|
||||
if {$postcmd!=""} {
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -276,6 +276,7 @@ set boolean_defnil_options {
|
||||
SQLITE_SECURE_DELETE
|
||||
SQLITE_SMALL_STACK
|
||||
SQLITE_SOUNDEX
|
||||
SQLITE_STRICT_SUBTYPE
|
||||
SQLITE_SUBSTR_COMPATIBILITY
|
||||
SQLITE_TCL
|
||||
SQLITE_TEST
|
||||
|
||||
Reference in New Issue
Block a user