Compare commits
95 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3aed7dc446 | |||
| 4ebc7fdcf4 | |||
| a5495355c4 | |||
| df3e207501 | |||
| 535b1f2875 | |||
| a7200804eb | |||
| 0d979c217f | |||
| e9af8caac0 | |||
| 606c64a543 | |||
| eefe3aa9ad | |||
| fcef193a82 | |||
| 8e7ffc09f5 | |||
| 9ad63c0f4e | |||
| d4b74b9fac | |||
| 7ff8b558e8 | |||
| bb6d2a5f07 | |||
| 217c590688 | |||
| fc19b2ca8a | |||
| 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 | |||
| dfd31e158c | |||
| cc19c1dafd | |||
| 99571bf3c3 | |||
| 3c1f727603 | |||
| d9e70f2b90 | |||
| 4c78799bb0 | |||
| 958b6a52e5 | |||
| f62cff6a9e | |||
| f163bfba4e | |||
| b0a4b69b95 | |||
| bd580270a5 | |||
| de4ef2dc70 | |||
| 0cb7603d4c | |||
| 28cfb1e4a7 | |||
| 915a55444b | |||
| 58012b85b0 | |||
| a2d80200b1 | |||
| 08eb5e9e51 | |||
| b425ebdd4f | |||
| 345bc91673 | |||
| 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
|
||||
|
||||
@@ -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:
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
+45
-20
@@ -517,7 +517,7 @@ static void fts5SetEstimatedRows(sqlite3_index_info *pIdxInfo, i64 nRow){
|
||||
if( sqlite3_libversion_number()>=3008002 )
|
||||
#endif
|
||||
{
|
||||
pIdxInfo->estimatedRows = nRow;
|
||||
pIdxInfo->estimatedRows = MAX(1, nRow);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -586,19 +586,30 @@ static int fts5UsePatternMatch(
|
||||
** a) If a MATCH operator is present, the cost depends on the other
|
||||
** constraints also present. As follows:
|
||||
**
|
||||
** * No other constraints: cost=1000.0
|
||||
** * One rowid range constraint: cost=750.0
|
||||
** * Both rowid range constraints: cost=500.0
|
||||
** * An == rowid constraint: cost=100.0
|
||||
** * No other constraints: cost=50000.0
|
||||
** * One rowid range constraint: cost=37500.0
|
||||
** * Both rowid range constraints: cost=30000.0
|
||||
** * An == rowid constraint: cost=25000.0
|
||||
**
|
||||
** b) Otherwise, if there is no MATCH:
|
||||
**
|
||||
** * No other constraints: cost=1000000.0
|
||||
** * One rowid range constraint: cost=750000.0
|
||||
** * Both rowid range constraints: cost=250000.0
|
||||
** * An == rowid constraint: cost=10.0
|
||||
** * No other constraints: cost=3000000.0
|
||||
** * One rowid range constraints: cost=2250000.0
|
||||
** * Both rowid range constraint: cost=750000.0
|
||||
** * An == rowid constraint: cost=25.0
|
||||
**
|
||||
** Costs are not modified by the ORDER BY clause.
|
||||
**
|
||||
** The ratios used in case (a) are based on informal results obtained from
|
||||
** the tool/fts5cost.tcl script. The "MATCH and ==" combination has the
|
||||
** cost set quite high because the query may be a prefix query. Unless
|
||||
** there is a prefix index, prefix queries with rowid constraints are much
|
||||
** more expensive than non-prefix queries with rowid constraints.
|
||||
**
|
||||
** The estimated rows returned is set to the cost/40. For simple queries,
|
||||
** experimental results show that cost/4 might be about right. But for
|
||||
** more complex queries that use multiple terms the number of rows might
|
||||
** be far fewer than this. So we compromise and use cost/40.
|
||||
*/
|
||||
static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
|
||||
Fts5Table *pTab = (Fts5Table*)pVTab;
|
||||
@@ -724,21 +735,35 @@ static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
|
||||
|
||||
/* Calculate the estimated cost based on the flags set in idxFlags. */
|
||||
if( bSeenEq ){
|
||||
pInfo->estimatedCost = nSeenMatch ? 1000.0 : 25.0;
|
||||
fts5SetUniqueFlag(pInfo);
|
||||
pInfo->estimatedCost = nSeenMatch ? 25000.0 : 25.0;
|
||||
fts5SetEstimatedRows(pInfo, 1);
|
||||
fts5SetUniqueFlag(pInfo);
|
||||
}else{
|
||||
if( bSeenLt && bSeenGt ){
|
||||
pInfo->estimatedCost = nSeenMatch ? 5000.0 : 750000.0;
|
||||
}else if( bSeenLt || bSeenGt ){
|
||||
pInfo->estimatedCost = nSeenMatch ? 7500.0 : 2250000.0;
|
||||
i64 nEstRows;
|
||||
if( nSeenMatch ){
|
||||
if( bSeenLt && bSeenGt ){
|
||||
pInfo->estimatedCost = 50000.0;
|
||||
}else if( bSeenLt || bSeenGt ){
|
||||
pInfo->estimatedCost = 37500.0;
|
||||
}else{
|
||||
pInfo->estimatedCost = 50000.0;
|
||||
}
|
||||
nEstRows = (i64)(pInfo->estimatedCost / 40.0);
|
||||
for(i=1; i<nSeenMatch; i++){
|
||||
pInfo->estimatedCost *= 2.5;
|
||||
nEstRows = nEstRows / 2;
|
||||
}
|
||||
}else{
|
||||
pInfo->estimatedCost = nSeenMatch ? 10000.0 : 3000000.0;
|
||||
if( bSeenLt && bSeenGt ){
|
||||
pInfo->estimatedCost = 750000.0;
|
||||
}else if( bSeenLt || bSeenGt ){
|
||||
pInfo->estimatedCost = 2250000.0;
|
||||
}else{
|
||||
pInfo->estimatedCost = 3000000.0;
|
||||
}
|
||||
nEstRows = (i64)(pInfo->estimatedCost / 4.0);
|
||||
}
|
||||
for(i=1; i<nSeenMatch; i++){
|
||||
pInfo->estimatedCost *= 0.4;
|
||||
}
|
||||
fts5SetEstimatedRows(pInfo, (i64)(pInfo->estimatedCost / 4.0));
|
||||
fts5SetEstimatedRows(pInfo, nEstRows);
|
||||
}
|
||||
|
||||
pInfo->idxNum = idxFlags;
|
||||
|
||||
@@ -65,5 +65,14 @@ do_eqp_test 1.4 {
|
||||
`--SCAN vt VIRTUAL TABLE INDEX 0:=
|
||||
}
|
||||
|
||||
do_eqp_test 1.5 {
|
||||
SELECT * FROM vt, t1
|
||||
WHERE vt.rowid = t1.rowid AND vt MATCH ? AND b = ?
|
||||
} {
|
||||
QUERY PLAN
|
||||
|--SCAN vt VIRTUAL TABLE INDEX 0:M1
|
||||
`--SEARCH t1 USING INTEGER PRIMARY KEY (rowid=?)
|
||||
}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -0,0 +1,153 @@
|
||||
#
|
||||
# 2026 March 20
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#--------------------------------------------------------------------------
|
||||
#
|
||||
# This script extracts the documentation for the API used by fts5 auxiliary
|
||||
# functions from header file fts5.h. It outputs html text on stdout that
|
||||
# is included in the documentation on the web.
|
||||
#
|
||||
|
||||
|
||||
sqlite3 db fts5cost.db
|
||||
|
||||
# Create an IPK table with 1,000,000 entries. Short records.
|
||||
#
|
||||
set res [list [catch { db eval {SELECT count(*) FROM t1} } msg] $msg]
|
||||
if {$res!="0 1000000"} {
|
||||
db eval {
|
||||
PRAGMA mmap_size = 1000000000; -- 1GB
|
||||
DROP TABLE IF EXISTS t1;
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY, b TEXT);
|
||||
WITH s(i) AS (
|
||||
SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<1_000_000
|
||||
)
|
||||
INSERT INTO t1 SELECT i, hex(randomblob(8)) FROM s;
|
||||
}
|
||||
}
|
||||
|
||||
# Create an FTS5 table with 1,000,000 entries. Each row contains a single
|
||||
# column containing a document of 100 terms chosen pseudo-randomly from
|
||||
# a vocabularly of 2000.
|
||||
set res [list [catch { db eval {SELECT count(*) FROM f1} } msg] $msg]
|
||||
if {$res!="0 1000000"} {
|
||||
set nVocab 2000
|
||||
set nTerm 100
|
||||
db eval {
|
||||
BEGIN;
|
||||
DROP TABLE IF EXISTS vocab1;
|
||||
CREATE TABLE vocab1(w);
|
||||
}
|
||||
for {set ii 0} {$ii<$nVocab} {incr ii} {
|
||||
set word [format %06x [expr {int(abs(rand()) * 0xFFFFFF)}]]
|
||||
db eval { INSERT INTO vocab1 VALUES($word) }
|
||||
lappend lVocab $word
|
||||
}
|
||||
db func doc doc
|
||||
proc doc {} {
|
||||
for {set ii 0} {$ii<$::nTerm} {incr ii} {
|
||||
lappend ret [lindex $::lVocab [expr int(abs(rand())*$::nVocab)]]
|
||||
}
|
||||
set ret
|
||||
}
|
||||
db eval {
|
||||
DROP TABLE IF EXISTS f1;
|
||||
CREATE VIRTUAL TABLE f1 USING fts5(x);
|
||||
WITH s(i) AS (
|
||||
SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<1_000_000
|
||||
)
|
||||
INSERT INTO f1(rowid, x) SELECT i, doc() FROM s;
|
||||
COMMIT;
|
||||
}
|
||||
} else {
|
||||
set lVocab [db eval { SELECT * FROM vocab1 }]
|
||||
set nVocab [llength $lVocab]
|
||||
}
|
||||
|
||||
proc rowid_query {n} {
|
||||
set rowid 654
|
||||
for {set ii 0} {$ii<$n} {incr ii} {
|
||||
db eval { SELECT b FROM t1 WHERE a = $rowid }
|
||||
set rowid [expr {($rowid + 7717) % 1000000}]
|
||||
}
|
||||
}
|
||||
|
||||
proc rowid_query_fts {n} {
|
||||
set rowid 654
|
||||
for {set ii 0} {$ii<$n} {incr ii} {
|
||||
db eval { SELECT * FROM f1 WHERE rowid = $rowid }
|
||||
set rowid [expr {($rowid + 7717) % 1000000}]
|
||||
}
|
||||
}
|
||||
|
||||
proc match_query_fts {n} {
|
||||
set idx 654
|
||||
for {set ii 0} {$ii<$n} {incr ii} {
|
||||
set match [lrange $::lVocab $idx $idx+1]
|
||||
db eval { SELECT * FROM f1($match) }
|
||||
set idx [expr {($idx + 7717) % $::nVocab}]
|
||||
}
|
||||
}
|
||||
|
||||
proc prefix_query_fts {n} {
|
||||
set idx 654
|
||||
for {set ii 0} {$ii<$n} {incr ii} {
|
||||
set match "[lindex $::lVocab $idx]*"
|
||||
db eval { SELECT * FROM f1($match) }
|
||||
set idx [expr {($idx + 7717) % $::nVocab}]
|
||||
}
|
||||
}
|
||||
|
||||
proc match_rowid_query_fts {n} {
|
||||
set idx 654
|
||||
for {set ii 0} {$ii<$n} {incr ii} {
|
||||
set match "[lindex $::lVocab $idx]"
|
||||
db eval { SELECT * FROM f1($match) WHERE rowid=500000 }
|
||||
set idx [expr {($idx + 7717) % $::nVocab}]
|
||||
}
|
||||
}
|
||||
|
||||
proc prefix_rowid_query_fts {n} {
|
||||
set idx 654
|
||||
for {set ii 0} {$ii<$n} {incr ii} {
|
||||
set match "[lindex $::lVocab $idx]*"
|
||||
db eval { SELECT * FROM f1($match) WHERE rowid=500000 }
|
||||
set idx [expr {($idx + 7717) % $::nVocab}]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
proc mytime {cmd div} {
|
||||
set tm [time $cmd]
|
||||
expr {[lindex $tm 0] / $div}
|
||||
}
|
||||
|
||||
#set us [mytime { match_rowid_query_fts 1000 } 1000]
|
||||
#puts "1000 match/rowid queries on fts5 table: ${us} per query"
|
||||
|
||||
set us [mytime { prefix_rowid_query_fts 1000 } 1000]
|
||||
puts "1000 prefix/rowid queries on fts5 table: ${us} per query"
|
||||
|
||||
set us [mytime { match_query_fts 10 } 10]
|
||||
puts "10 match queries on fts5 table: ${us} per query"
|
||||
|
||||
set us [mytime { prefix_query_fts 10 } 10]
|
||||
puts "10 prefix queries on fts5 table: ${us} per query"
|
||||
|
||||
set us [mytime { prefix_rowid_query_fts 1000 } 1000]
|
||||
puts "1000 prefix/rowid queries on fts5 table: ${us} per query"
|
||||
|
||||
set us [mytime { rowid_query 10000 } 10000]
|
||||
puts "10000 by-rowid queries on normal table: ${us} per query"
|
||||
|
||||
set us [mytime { rowid_query_fts 10000 } 10000]
|
||||
puts "10000 by-rowid queries on fts5 table: ${us} per query"
|
||||
|
||||
|
||||
+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;
|
||||
|
||||
+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;
|
||||
|
||||
+9
-8
@@ -64,6 +64,7 @@ SQLITE_EXTENSION_INIT1
|
||||
|
||||
#ifndef SQLITEINT_H
|
||||
typedef sqlite3_int64 i64;
|
||||
typedef sqlite3_uint64 u64;
|
||||
#endif
|
||||
|
||||
/* Max size of the error message in a CsvReader */
|
||||
@@ -128,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;
|
||||
@@ -221,7 +222,7 @@ static char *csv_read_one_field(CsvReader *p){
|
||||
}
|
||||
if( c=='"' ){
|
||||
int pc, ppc;
|
||||
int startLine = p->nLine;
|
||||
i64 startLine = p->nLine;
|
||||
pc = ppc = 0;
|
||||
while( 1 ){
|
||||
c = csv_getc(p);
|
||||
@@ -325,7 +326,7 @@ typedef struct CsvCursor {
|
||||
sqlite3_vtab_cursor base; /* Base class. Must be first */
|
||||
CsvReader rdr; /* The CsvReader object */
|
||||
char **azVal; /* Value of the current row */
|
||||
int *aLen; /* Length of each entry */
|
||||
i64 *aLen; /* Length of each entry */
|
||||
sqlite3_int64 iRowid; /* The current rowid. Negative for EOF */
|
||||
} CsvCursor;
|
||||
|
||||
@@ -497,7 +498,7 @@ static int csvtabConnect(
|
||||
CsvTable *pNew = 0; /* The CsvTable object to construct */
|
||||
int bHeader = -1; /* header= flags. -1 means not seen yet */
|
||||
int rc = SQLITE_OK; /* Result code from this routine */
|
||||
int i, j; /* Loop counters */
|
||||
u64 i, j; /* Loop counters */
|
||||
#ifdef SQLITE_TEST
|
||||
int tstFlags = 0; /* Value for testflags=N parameter */
|
||||
#endif
|
||||
@@ -516,7 +517,7 @@ static int csvtabConnect(
|
||||
assert( sizeof(azPValue)==sizeof(azParam) );
|
||||
memset(&sRdr, 0, sizeof(sRdr));
|
||||
memset(azPValue, 0, sizeof(azPValue));
|
||||
for(i=3; i<argc; i++){
|
||||
for(i=3; i<(u64)argc; i++){
|
||||
const char *z = argv[i];
|
||||
const char *zValue;
|
||||
for(j=0; j<sizeof(azParam)/sizeof(azParam[0]); j++){
|
||||
@@ -563,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));
|
||||
@@ -709,12 +710,12 @@ static int csvtabOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
|
||||
CsvTable *pTab = (CsvTable*)p;
|
||||
CsvCursor *pCur;
|
||||
size_t nByte;
|
||||
nByte = sizeof(*pCur) + (sizeof(char*)+sizeof(int))*pTab->nCol;
|
||||
nByte = sizeof(*pCur) + (sizeof(char*)+sizeof(i64))*pTab->nCol;
|
||||
pCur = sqlite3_malloc64( nByte );
|
||||
if( pCur==0 ) return SQLITE_NOMEM;
|
||||
memset(pCur, 0, nByte);
|
||||
pCur->azVal = (char**)&pCur[1];
|
||||
pCur->aLen = (int*)&pCur->azVal[pTab->nCol];
|
||||
pCur->aLen = (i64*)&pCur->azVal[pTab->nCol];
|
||||
*ppCursor = &pCur->base;
|
||||
if( csv_reader_open(&pCur->rdr, pTab->zFilename, pTab->zData) ){
|
||||
csv_xfer_error(pTab, &pCur->rdr);
|
||||
|
||||
+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;
|
||||
|
||||
+2
-2
@@ -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";
|
||||
}
|
||||
@@ -828,7 +828,6 @@ static void re_bytecode_func(
|
||||
int i;
|
||||
int n;
|
||||
char *z;
|
||||
(void)argc;
|
||||
static const char *ReOpName[] = {
|
||||
"EOF",
|
||||
"MATCH",
|
||||
@@ -851,6 +850,7 @@ static void re_bytecode_func(
|
||||
"ATSTART",
|
||||
};
|
||||
|
||||
(void)argc;
|
||||
zPattern = (const char*)sqlite3_value_text(argv[0]);
|
||||
if( zPattern==0 ) return;
|
||||
zErr = re_compile(&pRe, zPattern, re_maxnfa(re_maxlen(context)),
|
||||
|
||||
+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);
|
||||
|
||||
+22
-9
@@ -115,6 +115,7 @@ struct sqlite3_qrf_spec {
|
||||
short int nScreenWidth; /* Maximum overall table width */
|
||||
short int nLineLimit; /* Maximum number of lines for any row */
|
||||
short int nTitleLimit; /* Maximum number of characters in a title */
|
||||
unsigned int nMultiInsert; /* Add rows to one INSERT until size exceeds */
|
||||
int nCharLimit; /* Maximum number of characters in a cell */
|
||||
int nWidth; /* Number of entries in aWidth[] */
|
||||
int nAlign; /* Number of entries in aAlignment[] */
|
||||
@@ -381,7 +382,16 @@ can improve readability. The nTitleLimit setting currently only
|
||||
works for **Box**, **Column**, **Line**, **Markdown**, and **Table**
|
||||
styles, though that limitation might change in future releases.
|
||||
|
||||
### 2.9 Word Wrapping In Columnar Styles (nWrap, bWordWrap)
|
||||
### 2.9 Multiple Tuples Per INSERT In QRF_STYLE_Insert (nMultiInsert)
|
||||
|
||||
If the sqlite3_qrf_spec.nMultiInsert value is positive, then the
|
||||
QRF_STYLE_Insert output mode will generate multiple tuples in
|
||||
each INSERT statement until the total number of bytes in the
|
||||
statement exceeds nMultiInsert. A value of a few thousand is
|
||||
recommended here, in order to generate SQL output that is parsed
|
||||
and inserted at maximum speed by SQLite.
|
||||
|
||||
### 2.10 Word Wrapping In Columnar Styles (nWrap, bWordWrap)
|
||||
|
||||
When using columnar formatting modes (QRF_STYLE_Box, QRF_STYLE_Column,
|
||||
QRF_STYLE_Markdown, or QRF_STYLE_Table), the formatter attempts to limit
|
||||
@@ -400,7 +410,7 @@ anywhere, including in the middle of a word.
|
||||
For narrow columns and wide words, it might sometimes be necessary to split
|
||||
a column in the middle of a word, even when bWordWrap is QRF_Yes.
|
||||
|
||||
### 2.10 Helping The Output To Fit On The Terminal (nScreenWidth)
|
||||
### 2.11 Helping The Output To Fit On The Terminal (nScreenWidth)
|
||||
|
||||
The sqlite3_qrf_spec.nScreenWidth field can be set the number of
|
||||
characters that will fit on one line on the viewer output device.
|
||||
@@ -420,7 +430,7 @@ The nScreenWidth field currently only makes a difference in
|
||||
columnar styles (**Box**, **Column**, **Markdown**, and **Table**)
|
||||
and in the **Line** style.
|
||||
|
||||
### 2.11 Individual Column Width (nWidth and aWidth)
|
||||
### 2.12 Individual Column Width (nWidth and aWidth)
|
||||
|
||||
The sqlite3_qrf_spec.aWidth field is a pointer to an array of
|
||||
signed 16-bit integers that control the width of individual columns
|
||||
@@ -458,7 +468,7 @@ Again, negative values for aWidth\[\] entries are supported for
|
||||
backwards compatibility only, and are not recommended for new
|
||||
applications.
|
||||
|
||||
### 2.12 Alignment (nAlignment, aAlignment, eDfltAlign, eTitleAlign)
|
||||
### 2.13 Alignment (nAlignment, aAlignment, eDfltAlign, eTitleAlign)
|
||||
|
||||
Some cells in a display table might contain a lot of text and thus
|
||||
be wide, or they might contain newline characters or be wrapped by
|
||||
@@ -537,7 +547,7 @@ specify a vertical alignment, then values are top-aligned
|
||||
The vertical alignment settings are currently ignored and
|
||||
the vertical alignment is always QRF_ALIGN_Top.*
|
||||
|
||||
### 2.13 Row and Column Separator Strings
|
||||
### 2.14 Row and Column Separator Strings
|
||||
|
||||
The sqlite3_qrf_spec.zColumnSep and sqlite3_qrf_spec.zRowSep strings
|
||||
are alternative column and row separator character sequences. If not
|
||||
@@ -545,18 +555,18 @@ specified (if these pointers are left as NULL) then appropriate defaults
|
||||
are used. Some output styles have hard-coded column and row separators
|
||||
and these settings are ignored for those styles.
|
||||
|
||||
### 2.14 The Output Table Name
|
||||
### 2.15 The Output Table Name
|
||||
|
||||
The sqlite3_qrf_spec.zTableName value is the name of the output table
|
||||
when eStyle is QRF_STYLE_Insert.
|
||||
|
||||
### 2.15 The Rendering Of NULL (zNull)
|
||||
### 2.16 The Rendering Of NULL (zNull)
|
||||
|
||||
If a value is NULL then show the NULL using the string
|
||||
found in sqlite3_qrf_spec.zNull. If zNull is itself a NULL pointer
|
||||
then NULL values are rendered as an empty string.
|
||||
|
||||
### 2.16 Optional Value Rendering Callback
|
||||
### 2.17 Optional Value Rendering Callback
|
||||
|
||||
If the sqlite3_qrf_spec.xRender field is not NULL, then each
|
||||
sqlite3_value coming out of the query is first passed to the
|
||||
@@ -709,7 +719,10 @@ the `<TABLE>..</TABLE>` around the outside.
|
||||
The **Insert** style generates a series of SQL "INSERT" statements
|
||||
that will inserts the data that is output into a table whose name is defined
|
||||
by the zTableName field of `sqlite3_qrf_spec`. If zTableName is NULL,
|
||||
then a substitute name is used.
|
||||
then a substitute name is used. If nMultiInsert is positive, then the
|
||||
output will add multiple rows to each INSERT statement until the size
|
||||
of the INSERT statement exceeds nMultiInsert bytes before starting
|
||||
a new INSERT statement.
|
||||
|
||||
The **Json** and **JObject** styles generates JSON text for the query result.
|
||||
The **Json** style produces a JSON array of structures with one
|
||||
|
||||
+6
-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;
|
||||
@@ -2564,7 +2566,7 @@ static void qrfOneSimpleRow(Qrf *p){
|
||||
break;
|
||||
}
|
||||
case QRF_STYLE_Insert: {
|
||||
unsigned int mxIns = p->spec.iVersion>=2 ? p->spec.nMultiInsert : 0;
|
||||
unsigned int mxIns = p->spec.nMultiInsert;
|
||||
int szStart = sqlite3_str_length(p->pOut);
|
||||
if( p->u.nIns==0 || p->u.nIns>=mxIns ){
|
||||
if( p->u.nIns ){
|
||||
@@ -2712,7 +2714,7 @@ static void qrfInitialize(
|
||||
size_t sz; /* Size of pSpec[], based on pSpec->iVersion */
|
||||
memset(p, 0, sizeof(*p));
|
||||
p->pzErr = pzErr;
|
||||
if( pSpec->iVersion>2 ){
|
||||
if( pSpec->iVersion>1 ){
|
||||
qrfError(p, SQLITE_ERROR,
|
||||
"unusable sqlite3_qrf_spec.iVersion (%d)",
|
||||
pSpec->iVersion);
|
||||
|
||||
+3
-4
@@ -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
|
||||
@@ -42,6 +42,7 @@ struct sqlite3_qrf_spec {
|
||||
short int nScreenWidth; /* Maximum overall table width */
|
||||
short int nLineLimit; /* Maximum number of lines for any row */
|
||||
short int nTitleLimit; /* Maximum number of characters in a title */
|
||||
unsigned int nMultiInsert; /* Add rows to one INSERT until size exceeds */
|
||||
int nCharLimit; /* Maximum number of characters in a cell */
|
||||
int nWidth; /* Number of entries in aWidth[] */
|
||||
int nAlign; /* Number of entries in aAlignment[] */
|
||||
@@ -56,8 +57,6 @@ struct sqlite3_qrf_spec {
|
||||
void *pRenderArg; /* First argument to the xRender callback */
|
||||
void *pWriteArg; /* First argument to the xWrite callback */
|
||||
char **pzOutput; /* Storage location for output string */
|
||||
/* Fields below are only available if iVersion>=2 */
|
||||
unsigned int nMultiInsert; /* Add rows to one INSERT until size exceeds */
|
||||
/* Additional fields may be added in the future */
|
||||
};
|
||||
|
||||
|
||||
@@ -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]));
|
||||
|
||||
@@ -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){
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
C Minor\soptimization\sto\serror\smessage\sgeneration\sin\sintegrity_check.
|
||||
D 2026-03-18T18:14:14.851
|
||||
C Make\suse\sof\sO_TMPFILE\sfor\smore\ssecure\stemporary\sfile\screation,\swhen\sthat\noption\sis\savailable.
|
||||
D 2026-04-09T14:12:09.859
|
||||
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 Makefile.msc 92391304cf70f4c178b127aa83b88637abd28d1b83ede451616144037ea1d3dd
|
||||
F README.md f49fbd826941842e348242f3ab62f240c985ceafdf8fbe576abf4eb75317468c
|
||||
F VERSION 31435e19ded2aae3c1c67dacf06a995a37fd1b253baec5899b78d64cd29db4f7
|
||||
F art/icon-243x273.gif 9750b734f82fdb3dc43127753d5e6fbf3b62c9f4e136c2fbf573b2f57ea87af5
|
||||
F art/icon-80x90.gif 65509ce3e5f86a9cd64fe7fca2d23954199f31fe44c1e09e208c80fb83d87031
|
||||
@@ -47,7 +47,7 @@ F autosetup/find_tclconfig.tcl e64886ffe3b982d4df42cd28ed91fe0b5940c2c5785e126c1
|
||||
F autosetup/jimsh0.c 916bbdf8023fbda9937afae57d81a853d8c2ea00f2320aa27becbc33574f963d
|
||||
F autosetup/pkg-config.tcl 4e635bf39022ff65e0d5434339dd41503ea48fc53822c9c5bde88b02d3d952ba
|
||||
F autosetup/proj.tcl ce301197f364f7ce2acabbbd84b43d19e917ec73653157ca134a06f32d322712
|
||||
F autosetup/sqlite-config.tcl b215e97ad734f148069da3efd57ac8b2b2b893e6f08d20dd1eceff1e8b95313d
|
||||
F autosetup/sqlite-config.tcl 8fecce2838b7e7d990d161d08998034f3e3b0b2ddf4d7a99dbfafba9c902e302
|
||||
F autosetup/system.tcl 51d4be76cd9a9074704b584e5c9cbba616202c8468cf9ba8a4f8294a7ab1dba9
|
||||
F autosetup/teaish/README.txt b40071e6f8506500a2f7f71d5fc69e0bf87b9d7678dd9da1e5b4d0acbf40b1ca
|
||||
F autosetup/teaish/core.tcl e014dd95900c7f9a34e8e0f460f47e94841059827bce8b4c49668b0c7ae3f1a0
|
||||
@@ -56,7 +56,7 @@ F autosetup/teaish/tester.tcl 1799514c2652db49561b3386c5242b94534d1663f2cfac861a
|
||||
F configure 9a00b21dfd13757bbfb8d89b30660a89ec1f8f3a79402b8f9f9b6fc475c3303a x
|
||||
F contrib/sqlitecon.tcl eb4c6578e08dd353263958da0dc620f8400b869a50d06e271ab0be85a51a08d3
|
||||
F doc/F2FS.txt c1d4a0ae9711cfe0e1d8b019d154f1c29e0d3abfe820787ba1e9ed7691160fcd
|
||||
F doc/compile-for-unix.md c8f05bf9ff8c588c501515eb11642540572203e53d0b5eb5bf60983acdd47643
|
||||
F doc/compile-for-unix.md ebd6e461c71d43291e7e8c6487c9c2716bd997053556ec757509011e77e25581
|
||||
F doc/compile-for-windows.md 36601c95fa4070eebfe757684271d17a7c4a586912ba706d0b5e7817e1df54ad
|
||||
F doc/json-enhancements.md e356fc834781f1f1aa22ee300027a270b2c960122468499bf347bb123ce1ea4f
|
||||
F doc/jsonb.md acd77fc3a709f51242655ad7803510c886aa8304202fa9cf2abc5f5c4e9d7ae5
|
||||
@@ -114,7 +114,7 @@ F ext/fts5/fts5_config.c bfba970fe1e4eed18ee57c8d51458e226db9a960ddf775c5e50e3d7
|
||||
F ext/fts5/fts5_expr.c 71d48e8cf0358deace4949276647d317ff7665db6db09f40b81e2e7fe6664c7c
|
||||
F ext/fts5/fts5_hash.c d5871df92ce3fa210a650cf419ee916b87c29977e86084d06612edf772bff6f5
|
||||
F ext/fts5/fts5_index.c f8cfa37bb7397e5ede20242e4c9cb030bc8b4584ce3f23a5e2495038c0ae64bd
|
||||
F ext/fts5/fts5_main.c 6889f1373c469d515e792fb3d783c2218e63c560433ebd66edc0f740ab086c1b
|
||||
F ext/fts5/fts5_main.c b0fed47b3b4420ba6810373480a75bc28a9c0b7d16478d19a396436fb3ff17d7
|
||||
F ext/fts5/fts5_storage.c 19bc7c4cbe1e6a2dd9849ef7d84b5ca1fcbf194cefc3e386b901e00e08bf05c2
|
||||
F ext/fts5/fts5_tcl.c 2be6cc14f9448f720fd4418339cd202961a0801ea9424cb3d9de946f8f5a051c
|
||||
F ext/fts5/fts5_test_mi.c 4308d5658cb1f5eee5998dcbaac7d5bdf7a2ef43c8192ca6e0c843f856ccee26
|
||||
@@ -202,7 +202,7 @@ F ext/fts5/test/fts5hash.test fd3e0367fbf0b0944d6936fdb22696350f57b9871069c67662
|
||||
F ext/fts5/test/fts5integrity.test 613efcebe16b2d7a4096f03bcfb164f79a000b3354420ceda4a6f3e035090789
|
||||
F ext/fts5/test/fts5integrity2.test 4c3636615c0201232c44a8105d5cb14fd5499fd0ee3014d7ffd7e83aac76ece8
|
||||
F ext/fts5/test/fts5interrupt.test af7834ac6c2e71c05aea42d92f272eef3655e89b7a14a5620a2cd9de35e2e8ea
|
||||
F ext/fts5/test/fts5join.test 48b7ed36956948c5b8456c8bcaa5b087808d99000675918a43c4f51a925f1514
|
||||
F ext/fts5/test/fts5join.test 3791e30d034050281191cd8141d969849f6c060135f1e3938fea3eea955f9da9
|
||||
F ext/fts5/test/fts5lastrowid.test f36298a1fb9f988bde060a274a7ce638faa9c38a31400f8d2d27ea9373e0c4a1
|
||||
F ext/fts5/test/fts5leftjoin.test 1c14b51f4d1344a89e488160882f05a2246dd7e70c5cf077c8fb473e03c66338
|
||||
F ext/fts5/test/fts5limits.test 8ab67cf5d311c124b6ceb0062d0297767176df4572d955fce79fa43004dff01c
|
||||
@@ -271,6 +271,7 @@ F ext/fts5/test/fts5update2.test c5baa76799ac605ebb8e5e21035db2014b396cef25c903e
|
||||
F ext/fts5/test/fts5version.test 44ab35566267b7618c090443de2d9ad84f633df5d20bf72e9bad199ae5fced84
|
||||
F ext/fts5/test/fts5vocab.test 2a2bdb60d0998fa3124d541b6d30b019504918dc43a6584645b63a24be72f992
|
||||
F ext/fts5/test/fts5vocab2.test 4265137a3747b27deb1e2e2bde5654120c6de72bfed3238e67806d85af60fc4c
|
||||
F ext/fts5/tool/fts5cost.tcl 188a802e69422619c526698b92f0e5935f7d00b964e155bf4d5b4d4094989f60
|
||||
F ext/fts5/tool/fts5speed.tcl b0056f91a55b2d1a3684ec05729de92b042e2f85
|
||||
F ext/fts5/tool/fts5txt2db.tcl c0d43c8590656f8240e622b00957b3a0facc49482411a9fdc2870b45c0c82f9f
|
||||
F ext/fts5/tool/loadfts5.tcl 95b03429ee6b138645703c6ca192c3ac96eaf093
|
||||
@@ -356,28 +357,28 @@ F ext/jni/src/tests/000-000-sanity.test c3427a0e0ac84d7cbe4c95fdc1cd4b61f9ddcf43
|
||||
F ext/jni/src/tests/000-001-ignored.test e17e874c6ab3c437f1293d88093cf06286083b65bf162317f91bbfd92f961b70
|
||||
F ext/jni/src/tests/900-001-fts.test bf0ce17a8d082773450e91f2388f5bbb2dfa316d0b676c313c637a91198090f0
|
||||
F ext/misc/README.md 6243cdc4d7eb791c41ef0716f3980b8b5f6aa8c61ff76a3958cbf0031c6ebfa7
|
||||
F ext/misc/amatch.c 0e0124c1e03ee4cb99b25969f6b7b39c53a847b8bf12279efbcb896b0df1059a
|
||||
F ext/misc/amatch.c 8d237cc014b3736922c26a76a451050d244aa4980c47c531f368f817b1e77b49
|
||||
F ext/misc/anycollseq.c 5ffdfde9829eeac52219136ad6aa7cd9a4edb3b15f4f2532de52f4a22525eddb
|
||||
F ext/misc/appendvfs.c 9642c7a194a2a25dca7ad3e36af24a0a46d7702168c4ad7e59c9f9b0e16a3824
|
||||
F ext/misc/base64.c 313bd363214ba732198f205eead2f445e5caf6248f0384bc29a0430e1edc497f
|
||||
F ext/misc/base85.c 6fff354a637554f2574dbcf32d5f18898a98d4bb0ba0d73a2af91f6e87d02b62
|
||||
F ext/misc/base64.c 1445761667c16356e827fc6418294c869468be934429aaa8315035e76dd58acf
|
||||
F ext/misc/base85.c c713c7c81b05558c488cbdd8c68d612d5a97f9f0b8adf1167148dd7c89ce3f96
|
||||
F ext/misc/basexx.c 89ad6b76558efbceb627afd5e2ef1d84b2e96d9aaf9b7ecb20e3d00b51be6fcf
|
||||
F ext/misc/blobio.c a867c4c4617f6ec223a307ebfe0eabb45e0992f74dd47722b96f3e631c0edb2a
|
||||
F ext/misc/btreeinfo.c 13bc9e9f1c13cde370d0e4a6a2683e9f1926a4cead7fb72c71871b11a06d78a1
|
||||
F ext/misc/cksumvfs.c 9d7d0cf1a8893ac5d48922bfe9f3f217b4a61a6265f559263a02bb2001259913
|
||||
F ext/misc/closure.c 5559daf1daf742228431db929d1aa86dd535a4224cc634a81d2fd0d1e6ad7839
|
||||
F ext/misc/completion.c fd94e8231bb286a2eef7225368938565162daa72a8e8d06f946cc30ce15bf600
|
||||
F ext/misc/closure.c c983987a8d7846c3e52b1885ed3e20af7d4ca52a81a8f94ec6d1cd68f93acc86
|
||||
F ext/misc/completion.c 3f5db28e88c3313103b2dd86d910a2944fd500c46754e473493968ce81e994a4
|
||||
F ext/misc/compress.c 8191118b9b73e7796c961790db62d35d9b0fb724b045e005a5713dc9e0795565
|
||||
F ext/misc/csv.c e82124eabee0e692d7b90ab8b2c34fadbf7b375279f102567fa06e4da4b771bf
|
||||
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
|
||||
@@ -385,24 +386,24 @@ F ext/misc/noop.c f1a21cc9b7a4e667e5c8458d80ba680b8bd4315a003f256006046879f679c5
|
||||
F ext/misc/normalize.c fbb144a861809686ff2b5b6eee8bb2e1207f9bf13ce7376e5273c700a1eafbd5
|
||||
F ext/misc/pcachetrace.c f4227ce03fb16aa8d6f321b72dd051097419d7a028a9853af048bee7645cb405
|
||||
F ext/misc/percentile.c 72e05a21db20a2fa85264b99515941f00ae698824c9db82d7edfbb16cea8ec80
|
||||
F ext/misc/prefixes.c 82645f79229877afab08c8b08ca1e7fa31921280906b90a61c294e4f540cd2a6
|
||||
F ext/misc/qpvtab.c fc189e127f68f791af90a487f4460ec91539a716daf45a0c357e963fd47cc06c
|
||||
F ext/misc/prefixes.c aa15fd268e7d1336d1a1d4bc79265860d1d2ad68bba4cbcab61f83e4989dc68c
|
||||
F ext/misc/qpvtab.c 470a5fffba005c8e1994209e59c1848122351e19522de71beb68d666c4fa39a5
|
||||
F ext/misc/randomjson.c ef835fc64289e76ac4873b85fe12f9463a036168d7683cf2b773e36e6262c4ed
|
||||
F ext/misc/regexp.c 69bd45f6931bdc6801c1059b65a3e8b15ba88255e6abe387a34b653ce17e8908
|
||||
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
|
||||
@@ -410,18 +411,18 @@ F ext/misc/unionvtab.c 716d385256d5fb4beea31b0efede640807e423e85c9784d21d22f0cce
|
||||
F ext/misc/urifuncs.c f71360d14fa9e7626b563f1f781c6148109462741c5235ac63ae0f8917b9c751
|
||||
F ext/misc/uuid.c 5bb2264c1b64d163efa46509544fd7500cb8769cb7c16dd52052da8d961505cf
|
||||
F ext/misc/vfslog.c 3932ab932eeb2601dbc4447cb14d445aaa9fbe43b863ef5f014401c3420afd20
|
||||
F ext/misc/vfsstat.c 0b23c0a69a2b63dc0ef0af44f9c1fc977300c480a1f7a9814500369d8211f56e
|
||||
F ext/misc/vfstrace.c 0e4b8b17ac0675ea90f6d168d8214687e06ca3efbc0060aad4814994d82b41fb
|
||||
F ext/misc/vtablog.c 402496fb38add7dd2c50f2a0ad20f83a9916ceab48dcd31e62ad621e663c83ac
|
||||
F ext/misc/vtshim.c e5bce24ab8c532f4fdc600148718fe1802cb6ed57417f1c1032d8961f72b0e8f
|
||||
F ext/misc/wholenumber.c 0fa0c082676b7868bf2fa918e911133f2b349bcdceabd1198bba5f65b4fc0668
|
||||
F ext/misc/vfsstat.c 2b21efa93062ce814fbe28e6dff2acfafa4073a14b8d02cacfb4da1d604d05a5
|
||||
F ext/misc/vfstrace.c fc8c393a8316a8c20867b7e6e92908c4f81060c9e1f24d6ad9aefdc91c01dd13
|
||||
F ext/misc/vtablog.c 6c0c11c4822ab6c1a205718ea7c6d1bb561d96b27104b9c1fe84d01aa62d6c9c
|
||||
F ext/misc/vtshim.c f5ab480d1e33fa46a0b138359bedc9979e32798d72348e04bbe6093f9ae95c7b
|
||||
F ext/misc/wholenumber.c aa5e6d786fe8d79bc100ea0e852249c026a91ae65a5c1bcb2b869cd1a7cdd6d5
|
||||
F ext/misc/windirent.h 02211ce51f3034c675f2dbf4d228194d51b3ee05734678bad5106fff6292e60c
|
||||
F ext/misc/zipfile.c c8ee04e1b349270b5df401ad732f5d7c387146e69b33c02fa90322760cc6fee0
|
||||
F ext/misc/zipfile.c 5a583b5e72b4d777dc9f845529e6bd185d58024b633aafc93588679c78719700
|
||||
F ext/misc/zorder.c bddff2e1b9661a90c95c2a9a9c7ecd8908afab5763256294dd12d609d4664eee
|
||||
F ext/qrf/README.md e6e0ce2700acf6fd06312b42726a8f08ca240f30e1b122bff87c71c602046352
|
||||
F ext/qrf/README.md 9e644615d7d7b77ef7e9db798765679e50c5ed12eda48bce21c9ef9eb4715e9d
|
||||
F ext/qrf/dev-notes.md e68a6d91ce4c7eb296ef2daadc2bb79c95c317ad15b9fafe40850c67b29c2430
|
||||
F ext/qrf/qrf.c 668456bdcfa1ad7914f21ee3846404494efbdfc8b6b6557a2ec27a17e1f92b29
|
||||
F ext/qrf/qrf.h 2b27cb8079131ac3af2134e9e2ee9621b41d97bcb546fead41b9e1a12a3567a7
|
||||
F ext/qrf/qrf.c 9bef1f01e0c33a8693a9a7c1b666b8dee1aa60b8bc880d562eb4dfff551a6009
|
||||
F ext/qrf/qrf.h fbb223ff5789b324b3e9c22e787e4c1f53e217cff7cc5a243164d4b2e8410f4b
|
||||
F ext/rbu/rbu.c 801450b24eaf14440d8fd20385aacc751d5c9d6123398df41b1b5aa804bf4ce8
|
||||
F ext/rbu/rbu1.test 25870dd7db7eb5597e2b4d6e29e7a7e095abf332660f67d89959552ce8f8f255
|
||||
F ext/rbu/rbu10.test 7c22caa32c2ff26983ca8320779a31495a6555737684af7aba3daaf762ef3363
|
||||
@@ -539,7 +540,7 @@ F ext/session/session8.test 326f3273abf9d5d2d7d559eee8f5994c4ea74a5d935562454605
|
||||
F ext/session/session9.test 0c4a8fbe7a5031f50855f020f3408e1f07fd7859f1daa1629eadcec3422072d6
|
||||
F ext/session/sessionA.test 1feeab0b8e03527f08f2f1defb442da25480138f
|
||||
F ext/session/sessionB.test c4fb7f8a688787111606e123a555f18ee04f65bb9f2a4bb2aa71d55ce4e6d02c
|
||||
F ext/session/sessionC.test c3fade0a460d898fa42e9077b88e45c0d24ead3150268e145c8e19aeafc24ba1
|
||||
F ext/session/sessionC.test 2bd42225efdf5f5b1a20f75b672665bcd4f67e2a6d7ddf7420fe7bf523ba41f8
|
||||
F ext/session/sessionD.test 470ff917dc849e2eb78142ade63aaabd729d773833cff0ff01bca0eda68a21ce
|
||||
F ext/session/sessionE.test b2010949c9d7415306f64e3c2072ddabc4b8250c98478d3c0c4d064bce83111d
|
||||
F ext/session/sessionF.test d37ed800881e742c208df443537bf29aa49fd56eac520d0f0c6df3e6320f3401
|
||||
@@ -554,11 +555,12 @@ F ext/session/sessionat.test 00c8badb35e43a2f12a716d2734a44d614ff62361979b6b8541
|
||||
F ext/session/sessionbig.test 47c381e7acfabeef17d98519a3080d69151723354d220afa2053852182ca7adf
|
||||
F ext/session/sessionblob.test 87faf667870b72f08e91969abd9f52a383ab7b514506ee194d64a39d8faff00a
|
||||
F ext/session/sessionchange.test 6618cb1c1338a4b6df173b6ac42d09623fb71269962abf23ebb7617fe9f45a50
|
||||
F ext/session/sessionchange2.test 6b5b7e3d1cc4ede43817f7fb68e3771aac4aa6500adb21a458b3e5a9fd841f83
|
||||
F ext/session/sessionconflict.test 19e4a53795c4c930bfec49e809311e09b2a9e202d9446e56d7a8b139046a0c07 x
|
||||
F ext/session/sessiondiff.test e89f7aedcdd89e5ebac3a455224eb553a171e9586fc3e1e6a7b3388d2648ba8d
|
||||
F ext/session/sessionfault.test c2b43d01213b389a3f518e90775fca2120812ba51e50444c4066962263e45c11
|
||||
F ext/session/sessionfault2.test b0d6a7c1d7398a7e800d84657404909c7d385965ea8576dc79ed344c46fbf41c
|
||||
F ext/session/sessionfault3.test ce0b5d182133935c224d72507dbf1c5be1a1febf7e85d0b0fbd6d2f724b32b96
|
||||
F ext/session/sessionfault3.test 9397819ec25b0960c5bc03c78613f9cb5cacc970f83e817aec1775c2a839a787
|
||||
F ext/session/sessioninvert.test 9018f6a7387ac745084b6374c5e1aa14d648b372e6e1181cfab3df632b662d26 x
|
||||
F ext/session/sessionmem.test f2a735db84a3e9e19f571033b725b0b2daf847f3f28b1da55a0c1a4e74f1de09
|
||||
F ext/session/sessionnoact.test 4c7ae5c7d351cb5323bca62b6b095592ad24bd90a6713c178b62ab0063d23e19
|
||||
@@ -569,9 +571,9 @@ F ext/session/sessionrowid.test 85187c2f1b38861a5844868126f69f9ec62223a03449a98a
|
||||
F ext/session/sessionsize.test 8fcf4685993c3dbaa46a24183940ab9f5aa9ed0d23e5fb63bfffbdb56134b795
|
||||
F ext/session/sessionstat1.test 5e718d5888c0c49bbb33a7a4f816366db85f59f6a4f97544a806421b85dc2dec
|
||||
F ext/session/sessionwor.test 6fd9a2256442cebde5b2284936ae9e0d54bde692d0f5fd009ecef8511f4cf3fc
|
||||
F ext/session/sqlite3session.c 6ebd02be470f36d41c4bd78927f39d507b62051ba025eacaed9936c769902a07
|
||||
F ext/session/sqlite3session.h 7404723606074fcb2afdc6b72c206072cdb2b7d8ba097ca1559174a80bc26f7a
|
||||
F ext/session/test_session.c 190110e3bd9463717248dec1272b44fe9943e57b7646d0b4200dcf11e4dccee6
|
||||
F ext/session/sqlite3session.c d5c91d5b07d2b8e860f2782ae23f7b44ce929280e00645418ee84a0fd14525b2
|
||||
F ext/session/sqlite3session.h 063e7bf7be2fff874456f452a224b5b3013b25682d108933b0351c93a1279b9c
|
||||
F ext/session/test_session.c 2a02a68b522e2f3d4a64b2a4733af54b0f3e500769aeccd5bcbdd440103db069
|
||||
F ext/wasm/GNUmakefile 68c750f173106d9d63f12c1edf1256c6f4bad9894b155da5db64322f4912de4b
|
||||
F ext/wasm/README-dist.txt f01081a850ce38a56706af6b481e3a7878e24e42b314cfcd4b129f0f8427066a
|
||||
F ext/wasm/README.md 2e87804e12c98f1d194b7a06162a88441d33bb443efcfe00dc6565a780d2f259
|
||||
@@ -594,11 +596,11 @@ F ext/wasm/api/sqlite3-api-oo1.c-pp.js 5f203f5bb5d48a9e43ec51e791dc411c24dca8258
|
||||
F ext/wasm/api/sqlite3-api-prologue.js 4336f02ac24ba58e68e355adb9da2804a1eef15a4aee961fa813c7d812a56b54
|
||||
F ext/wasm/api/sqlite3-api-worker1.c-pp.js 1fa34e9b0e3b90a8898e4f700d7125e44c81877f182627bb8564b97989bc6e78
|
||||
F ext/wasm/api/sqlite3-license-version-header.js 98d90255a12d02214db634e041c8e7f2f133d9361a8ebf000ba9c9af4c6761cc
|
||||
F ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js 3f85af55609f1452b29c476e59893cbeed417c59560795f50911318e916083b1
|
||||
F ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js 25e31482b04293a33d7599f1459eb552b3eb36ca10c02c816122d3308bf80cb2
|
||||
F ext/wasm/api/sqlite3-vfs-helper.c-pp.js 3f828cc66758acb40e9c5b4dcfd87fd478a14c8fb7f0630264e6c7fa0e57515d
|
||||
F ext/wasm/api/sqlite3-vfs-kvvfs.c-pp.js 27fb135ba3b805b66c90a7333b56080345bf1db79335c3e48b6d01ad7aa09607
|
||||
F ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js 1c742ed92c0515c8ef97d2b132feb01168252bfd847fed5d52607d8a42d23c6a
|
||||
F ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js 0d95dc35dfb518f0cd7bac993289a7f0753fe39c60fd6f0a5742b3f55c6e6347
|
||||
F ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js 3dbd918ef037cd8fa9c7b4dccb3c8637b228638654c429e7df6acab5981c75e2
|
||||
F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js 3da8fe72dc9e76614a9c102b92e777ce03f81d788b607701c828d8fcbac44b06
|
||||
F ext/wasm/api/sqlite3-vtab-helper.c-pp.js 366596d8ff73d4cefb938bbe95bc839d503c3fab6c8335ce4bf52f0d8a7dee81
|
||||
F ext/wasm/api/sqlite3-wasm.c ddf9d435b2e901eaceb805ff694e9609c2f32b5cf89a4f164e734a6fa303fdd2
|
||||
@@ -645,8 +647,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
|
||||
@@ -654,7 +656,7 @@ F ext/wasm/tests/opfs/sahpool/index.html be736567fd92d3ecb9754c145755037cbbd2bca
|
||||
F ext/wasm/tests/opfs/sahpool/sahpool-pausing.js f264925cfc82155de38cecb3d204c36e0f6991460fff0cb7c15079454679a4e2
|
||||
F ext/wasm/tests/opfs/sahpool/sahpool-worker.js bd25a43fc2ab2d1bafd8f2854ad3943ef673f7c3be03e95ecf1612ff6e8e2a61
|
||||
F magic.txt 5ade0bc977aa135e79e3faaea894d5671b26107cc91e70783aa7dc83f22f3ba0
|
||||
F main.mk 64479b612d66a3f1a3ab498a3a40607937f614168987d8cda8320fa8be517fac
|
||||
F main.mk bf77c630aeef4ed4b9270e1fd52c35147b529412c00b74ed6eb8aca3466763f6
|
||||
F make.bat a136fd0b1c93e89854a86d5f4edcf0386d211e5d5ec2434480f6eea436c7420c
|
||||
F mptest/config01.test 3c6adcbc50b991866855f1977ff172eb6d901271
|
||||
F mptest/config02.test 4415dfe36c48785f751e16e32c20b077c28ae504
|
||||
@@ -675,7 +677,7 @@ F src/btmutex.c 30dada73a819a1ef5b7583786370dce1842e12e1ad941e4d05ac29695528daea
|
||||
F src/btree.c fb350c445316c1cc0529703c0b76450770a1de0ab0440641a56b19f05d6fefbe
|
||||
F src/btree.h e823c46d87f63d904d735a24b76146d19f51f04445ea561f71cc3382fd1307f0
|
||||
F src/btreeInt.h 9c0f9ea5c9b5f4dcaea18111d43efe95f2ac276cd86d770dce10fd99ccc93886
|
||||
F src/build.c b993e4adef4c4cdfd7abf62e2676c467bb1923f25f40c3c7ab2a7bfbace3de7f
|
||||
F src/build.c 8581de0af3b6c448f5d64e2d18a91ac1e7057b3bcb8b8827e1240f80d87486a4
|
||||
F src/callback.c 3605bbf02bd7ed46c79cd48346db4a32fc51d67624400539c0532f4eead804ad
|
||||
F src/carray.c 3efe3982d5fb323334c29328a4e189ccaef6b95612a6084ad5fa124fd5db1179
|
||||
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
|
||||
@@ -686,17 +688,17 @@ F src/delete.c 1f2268d6fe3c78fc1bf794ba65d7026498b78e2342ffaf85825dedae546e6fde
|
||||
F src/expr.c 51e9c77ff5d9a21439e611fe6571a3cd50387e526e13c5614fd407e5b8571930
|
||||
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 06cc944d51ecbdde04f465ea220034cab76dcce4e20b95d2201f6f3e2c89a854
|
||||
F src/json.c 5027b856cd9b621dc9ba66b211e21a440ccdc63cefdefb44c51e7d3ac550d1a4
|
||||
F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa
|
||||
F src/loadext.c 56a542244fbefc739a2ef57fac007c16b2aefdb4377f584e9547db2ce3e071f9
|
||||
F src/main.c 31a13302193fbd51279c7e69cdfa0320d0de7629f9151e0964c1d320e8bdd7a4
|
||||
F src/main.c 387bb9d0216d6d35b221481ba8e661d94ad043060cd89581b6422c269ce680a0
|
||||
F src/malloc.c 422f7e0498e1c9ef967f06283b6f2c0b16db6b905d8e06f6dbc8baaa3e4e6c5a
|
||||
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
|
||||
F src/mem1.c 3bb59158c38e05f6270e761a9f435bf19827a264c13d1631c58b84bdc96d73b2
|
||||
@@ -717,7 +719,7 @@ 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
|
||||
@@ -728,20 +730,20 @@ 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 41fb76fcb5ed7e16aaddc659d3b23891abebea45549fe125fc2e6ec380cc7175
|
||||
F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c
|
||||
F src/resolve.c 928ff887f2a7c64275182060d94d06fdddbe32226c569781cf7e7edc6f58d7fd
|
||||
F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97
|
||||
F src/select.c ffe199f025a0dd74670d2a77232bdea364a4d7b36f32c64a6572d39ba6a11576
|
||||
F src/shell.c.in 9b655b63ff8c15f04b23632d648cc2a7285882e6c2126fb9357b5b70e2454a0e
|
||||
F src/sqlite.h.in 4d657846d68a58b028f0c4c331b9d3b4a79306f25c3b0d04fb56060343f73d85
|
||||
F src/shell.c.in a3288615aba1b375f7dca9801874c806e8d0d047dfe4e9253a944f4b47c7459e
|
||||
F src/sqlite.h.in e2915e4a86d5e0783afb5cb72411df38d987c7f3c5aa2d5441b8e74d30b649d8
|
||||
F src/sqlite3.rc 015537e6ac1eec6c7050e17b616c2ffe6f70fca241835a84a4f0d5937383c479
|
||||
F src/sqlite3ext.h 1b7a0ee438bb5c2896d0609c537e917d8057b3340f6ad004d2de44f03e3d3cca
|
||||
F src/sqliteInt.h 9716721fb57e32938a1d30a84560ce7633c63860a2209e188c87afad15d4b464
|
||||
F src/sqliteLimit.h 904a3f520362c7065c18165aaabd504fb13cc1b76cb411f38bd41ac219e4af1e
|
||||
F src/sqliteInt.h bc1cbc0c23dba35b324ae85a7dbb5fb182321bbd30857fb21f3d0cba049001a5
|
||||
F src/sqliteLimit.h c70656b67ab5b96741a8f1c812bdd80c81f2b1c1e443d0cc3ea8c33bb1f1a092
|
||||
F src/status.c 7565d63a79aa2f326339a24a0461a60096d0bd2bce711fefb50b5c89335f3592
|
||||
F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
|
||||
F src/tclsqlite.c 71230da35d81b7234c5e4dc3747ca2302390884b051052956deb3dbf680a6ed4
|
||||
F src/tclsqlite.c 7401c73c917a4d1b380c896a324c8d8eb533a999559d9e339d479596553bebfd
|
||||
F src/tclsqlite.h 614b3780a62522bc9f8f2b9fb22689e8009958e7aa77e572d0f3149050af348a
|
||||
F src/test1.c 3e3b013f59ffcb57dce00c90d55907072d71d4e970cb0a590cb261efe11bae9c
|
||||
F src/test2.c 2b9ab96bba63a1c369d5769390475259ad210f144a877805f2e32e563f9e93c1
|
||||
@@ -791,30 +793,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 0dbd633bdc509a1c967e4b49b1555820494d936131017634d7dec96c0b8343ce
|
||||
F src/util.c 4f0abc15f63829e12cdfeeb490faf25ac65894b0bcc20d660e3f3757b8e2360b
|
||||
F src/vacuum.c d3d35d8ae893d419ade5fa196d761a83bddcbb62137a1a157ae751ef38b26e82
|
||||
F src/vdbe.c 01e380d1847dd934f9c6c73b2bb9df68915b3f917e63244f6f02c95641ca3acb
|
||||
F src/vdbe.c 6c57525d7db0232d52687d30da1093db0c152f14206c2ef1adf0c19a09d863e3
|
||||
F src/vdbe.h 70e862ac8a11b590f8c1eaac17a0078429d42bc4ea3f757a9af0f451dd966a71
|
||||
F src/vdbeInt.h f7157f110f88f1d9d8338c292faf23a9129f6712563ade2b408537c95e17bdef
|
||||
F src/vdbeInt.h c31ba4dc8d280c2b1dc89c6fcee68f2555e3813ab34279552c20b964c0e338b1
|
||||
F src/vdbeapi.c 6cdcbe5c7afa754c998e73d2d5d2805556268362914b952811bdfb9c78a37cf1
|
||||
F src/vdbeaux.c 81687c55682b9f4d942186695f4f7fa4743c564a985e0889def52eded9076d61
|
||||
F src/vdbeblob.c b3f0640db9642fbdc88bd6ebcc83d6009514cafc98f062f675f2c8d505d82692
|
||||
F src/vdbemem.c 317ec5e870ddb16951b606c9fe8be22baef22ecbe46f58fdefc259662238afb7
|
||||
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 406d9ec8d12f646c28c4b4a645ea20329eb343b19cfa3dcd8aab938066c4ae66
|
||||
F src/where.c bffca5e4ef20d0bfbdc24f1dc13fd3f955284225a8ad25a4454635f6be39aad0
|
||||
F src/whereInt.h 8d94cb116c9e06205c3d5ac87af065fc044f8cf08bfdccd94b6ea1c1308e65da
|
||||
F src/wherecode.c 676cb6cb02878643e817d9917a2d3522b83a3736b2cedd3dc8a01d7bb92af6c2
|
||||
F src/whereexpr.c e9f7185fba366d9365aa7a97329609e4cf00b3dd0400d069fbaa5187350c17c6
|
||||
@@ -875,7 +877,7 @@ F test/attach2.test 6d1e3a457ce260d6fc8e5945c07fba6c76dc2aa90e1c701f067b50ee88f7
|
||||
F test/attach3.test c59d92791070c59272e00183b7353eeb94915976
|
||||
F test/attach4.test 00e754484859998d124d144de6d114d920f2ed6ca2f961e6a7f4183c714f885e
|
||||
F test/attachmalloc.test 67309af95c6b765c13e7d2279d7fccbef78e6eb0565d75d51cefd5dc88784549
|
||||
F test/auth.test 5b8558a40571ebc55c1581cb7cec3b2348a699542a0a51b83ef21c6a953d95e3
|
||||
F test/auth.test 2a01bf5bf3a0f10adf8ae3a3fd2c05af8a8c1b7a52fae227adb4ccd931915b5c
|
||||
F test/auth2.test 9eb7fce9f34bf1f50d3f366fb3e606be5a2000a1
|
||||
F test/auth3.test 76d20a7fa136d63bcfcf8bcb65c0b1455ed71078d81f22bcd0550d3eb18594ab
|
||||
F test/autoanalyze1.test b9cc3f32a990fa56669b668d237c6d53e983554ae80c0604992e18869a0b2dec
|
||||
@@ -1125,9 +1127,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
|
||||
@@ -1350,7 +1353,7 @@ F test/jrnlmode3.test 556b447a05be0e0963f4311e95ab1632b11c9eaa
|
||||
F test/json/README.md de59d5ba0bd2796d797115688630a6405bbf43a2891bad445ac6b9f38b83f236
|
||||
F test/json/json-generator.tcl dc0dd0f393800c98658fc4c47eaa6af29d4e17527380cd28656fb261bddc8a3f
|
||||
F test/json/json-q1.txt 65f9d1cdcc4cffa9823fb73ed936aae5658700cd001fde448f68bfb91c807307
|
||||
F test/json/json-speed-check.sh 7d5898808ce7542762318306ae6075a30f5e7ee115c4a409f487e123afe91d88 x
|
||||
F test/json/json-speed-check.sh 45862b216f1f8bbf16d74e2ad6ea20c773ee77774b299a7e0f76a22eb98e91f1 x
|
||||
F test/json/jsonb-q1.txt 1e180fe6491efab307e318b22879e3a736ac9a96539bbde7911a13ee5b33abc7
|
||||
F test/json101.test cf53254f0f0c1399a01b21fc58fee0e63a12a556be91b9ee9faccdb8b82c083c
|
||||
F test/json102.test ea5c9811e408e115c8fc539548deef431fda4924c23cacd79dd4b783f4449f07
|
||||
@@ -1511,7 +1514,7 @@ F test/pragma5.test 7b33fc43e2e41abf17f35fb73f71b49671a380ea92a6c94b6ce530a25f8d
|
||||
F test/pragma6.test c5ec577ba087954b4dfa619a3cbe97b155b60a0af487527abe89b10fc17e6512
|
||||
F test/pragmafault.test 275edaf3161771d37de60e5c2b412627ac94cef11739236bec12ed1258b240f8
|
||||
F test/prefixes.test b524a1c44bffec225b9aec98bd728480352aa8532ac4c15771fb85e8beef65d9
|
||||
F test/printf.test 685fec5a0c5af2490ab0632775a301554361d674211d690f5bee0a97b05333de
|
||||
F test/printf.test bcb093ef5cbd17e2d94d93d62045ee61ed0f465c1ca123f284774e474e73a9ea
|
||||
F test/printf2.test 3f55c1871a5a65507416076f6eb97e738d5210aeda7595a74ee895f2224cce60
|
||||
F test/progress.test ebab27f670bd0d4eb9d20d49cef96e68141d92fb
|
||||
F test/ptrchng.test ef1aa72d6cf35a2bbd0869a649b744e9d84977fc
|
||||
@@ -1560,7 +1563,7 @@ F test/rowvalue6.test d19b54feb604d5601f8614b15e214e0774c01087
|
||||
F test/rowvalue7.test 06ec0aca725bf683313d03793aa2943bc7f45a901848c7056a9665b769c8fc38
|
||||
F test/rowvalue8.test 5900eddad9e2c3c2e26f1a95f74aafc1232ee5e0
|
||||
F test/rowvalue9.test 7499a8fd7ca3a3f0e19d94e135355439aa2b596f86b775ca8de79672da2ca378
|
||||
F test/rowvalueA.test 1c5ed13f3b0641452ae35e6488d6ecc16cefce99f2adf7c07c513530e2aac6b7
|
||||
F test/rowvalueA.test 7d28bf6c2f8a2af8adbba2c4eda9136a4dd36250b8966ba05b34c0954f78efd7
|
||||
F test/rowvaluefault.test 963ae9cdaed30a85a29668dd514e639f3556cae903ee9f172ea972d511c54fff
|
||||
F test/rowvaluevtab.test cd9747bb3f308086944c07968f547ad6b05022e698d80b9ffbdfe09ce0b8da6f
|
||||
F test/rtree.test 0c8d9dd458d6824e59683c19ab2ffa9ef946f798
|
||||
@@ -1711,8 +1714,8 @@ F test/temptrigfault.tes fc5918e64f3867156fefe7cfca9d8e1f495134a5229b2b511b0dc11
|
||||
F test/temptrigger.test a00f258ed8d21a0e8fd4f322f15e8cfb5cef2e43655670e07a753e3fb4769d61
|
||||
F test/tester.tcl 2d943f60200e0a36bcd3f1f0baf181a751cd3604ef6b6bd4c8dc39b4e8a53116
|
||||
F test/testloadext.c 862b848783eaed9985fbce46c65cd214664376b549fae252b364d5d1ef350a27
|
||||
F test/testrunner.tcl 78d67079fc39caf2af3fd9d4c30bdac78dae7ec50b9fc802835e7a5189581e07 x
|
||||
F test/testrunner_data.tcl 078e251983c8fc573567125147655f68132210f226c92922daf21fb913779717
|
||||
F test/testrunner.tcl 6b232f0d4825dec8b967754503080fc9609fad077f582d02f86bd2d95bec4110 x
|
||||
F test/testrunner_data.tcl 48c8a230fcada37f4809f95c2ba49e44bc3d520b6165c09173249c6e65b01cc1
|
||||
F test/testrunner_estwork.tcl 81e2ae10238f50540f42fbf2d94913052a99bfb494b69e546506323f195dcff9
|
||||
F test/thread001.test a0985c117eab62c0c65526e9fa5d1360dd1cac5b03bde223902763274ce21899
|
||||
F test/thread002.test c24c83408e35ba5a952a3638b7ac03ccdf1ce4409289c54a050ac4c5f1de7502
|
||||
@@ -2082,7 +2085,7 @@ F test/with1.test 31db84788e0429885b63995149fab57d32e26196b752a3a926249ae74c0add
|
||||
F test/with2.test 181674a6cc86a601ca2ac052741cdfad5b529e07e870435d2f6cdb92d589ff17
|
||||
F test/with3.test e30369ea27aa27eb1bda4c5e510c8a9f782c8afd2ab99d1a02b8a7f25a5d3e65
|
||||
F test/with4.test 257be66c0c67fee1defbbac0f685c3465e2cad037f21ce65f23f86084f198205
|
||||
F test/with5.test 6248213c41fab36290b5b73aa3f937309dfba337004d9d8434c3fabc8c7d4be8
|
||||
F test/with5.test 0e5e141fee75aa170289467542a2ffd71933d4fb006bfb135275b1787bdc8fbe
|
||||
F test/with6.test 281e4861b5e517f6c3c2f08517a520c1e2ee7c11966545d3901f258a4fe8ef76
|
||||
F test/withM.test 693b61765f2b387b5e3e24a4536e2e82de15ff64
|
||||
F test/without_rowid1.test f6e75e32821eb423ac3812434d12bdd8098f17e3b2206da61575e1db77f82428
|
||||
@@ -2136,7 +2139,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
|
||||
@@ -2191,11 +2194,14 @@ F tool/vdbe-compress.tcl fa2f37ab39b2a0087fafb6a7f3ce19503e25e624ffa8ed9951717ab
|
||||
F tool/vdbe_profile.tcl 3ac5a4a9449f4baf77059358ea050db3e34395ccf59c5464d29b91746d5b961e
|
||||
F tool/version-info.c 33d0390ef484b3b1cb685d59362be891ea162123cea181cb8e6d2cf6ddf2700c
|
||||
F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee87c1b31a7
|
||||
F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98
|
||||
F tool/warnings.sh a554d13f6e5cf3760f041b87939e3d616ec6961859c3245e8ef701d1eafc2ca2
|
||||
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
|
||||
F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c
|
||||
P a270c6cc0eea8a8a2cf1ce30d724b2f12b11a1c343cd8520bd7843f4e62878f8
|
||||
R 26ade8ca132e7215ac38ba62aa36e2a7
|
||||
P 4525003a53a7fc63ca75c59b22c79608659ca12f0131f52c18637f829977f20b
|
||||
R 8620cf4411d3ee800e21795293030726
|
||||
T *branch * o_tmpfile
|
||||
T *sym-o_tmpfile *
|
||||
T -sym-trunk *
|
||||
U drh
|
||||
Z 05abd0005f3d08ed3533335ee2e75034
|
||||
Z c35d74d8270d74b882ed210a9b661389
|
||||
# Remove this line to create a well-formed Fossil manifest.
|
||||
|
||||
+2
-2
@@ -1,2 +1,2 @@
|
||||
branch idxdelete-tolerance
|
||||
tag idxdelete-tolerance
|
||||
branch o_tmpfile
|
||||
tag o_tmpfile
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
e0fa7c500052af9d36cb2d232131ef93361403187f4a60f53279b102c7a95860
|
||||
094fc6da0768ea0ec4b4d3dc020cd6025aab341550d6cea6be7487ac570f9171
|
||||
|
||||
+80
-89
@@ -2494,9 +2494,10 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
|
||||
if( !hasColumn(pPk->aiColumn, j, i)
|
||||
&& (pTab->aCol[i].colFlags & COLFLAG_VIRTUAL)==0
|
||||
){
|
||||
const char *zColl = sqlite3ColumnColl(&pTab->aCol[i]);
|
||||
assert( j<pPk->nColumn );
|
||||
pPk->aiColumn[j] = i;
|
||||
pPk->azColl[j] = sqlite3StrBINARY;
|
||||
pPk->azColl[j] = zColl ? zColl : sqlite3StrBINARY;
|
||||
j++;
|
||||
}
|
||||
}
|
||||
@@ -5522,8 +5523,7 @@ void sqlite3RowidConstraint(
|
||||
}
|
||||
|
||||
/*
|
||||
** Check to see if pIndex uses the collating sequence pColl. Return
|
||||
** true if it does and false if it does not.
|
||||
** Return true if any column of pIndex uses the zColl collation
|
||||
*/
|
||||
#ifndef SQLITE_OMIT_REINDEX
|
||||
static int collationMatch(const char *zColl, Index *pIndex){
|
||||
@@ -5531,8 +5531,8 @@ static int collationMatch(const char *zColl, Index *pIndex){
|
||||
assert( zColl!=0 );
|
||||
for(i=0; i<pIndex->nColumn; i++){
|
||||
const char *z = pIndex->azColl[i];
|
||||
assert( z!=0 || pIndex->aiColumn[i]<0 );
|
||||
if( pIndex->aiColumn[i]>=0 && 0==sqlite3StrICmp(z, zColl) ){
|
||||
assert( z!=0 );
|
||||
if( 0==sqlite3StrICmp(z, zColl) ){
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@@ -5540,73 +5540,39 @@ static int collationMatch(const char *zColl, Index *pIndex){
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Recompute all indices of pTab that use the collating sequence pColl.
|
||||
** If pColl==0 then recompute all indices of pTab.
|
||||
*/
|
||||
#ifndef SQLITE_OMIT_REINDEX
|
||||
static void reindexTable(Parse *pParse, Table *pTab, char const *zColl){
|
||||
if( !IsVirtual(pTab) ){
|
||||
Index *pIndex; /* An index associated with pTab */
|
||||
|
||||
for(pIndex=pTab->pIndex; pIndex; pIndex=pIndex->pNext){
|
||||
if( zColl==0 || collationMatch(zColl, pIndex) ){
|
||||
int iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
|
||||
sqlite3BeginWriteOperation(pParse, 0, iDb);
|
||||
sqlite3RefillIndex(pParse, pIndex, -1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Recompute all indices of all tables in all databases where the
|
||||
** indices use the collating sequence pColl. If pColl==0 then recompute
|
||||
** all indices everywhere.
|
||||
*/
|
||||
#ifndef SQLITE_OMIT_REINDEX
|
||||
static void reindexDatabases(Parse *pParse, char const *zColl){
|
||||
Db *pDb; /* A single database */
|
||||
int iDb; /* The database index number */
|
||||
sqlite3 *db = pParse->db; /* The database connection */
|
||||
HashElem *k; /* For looping over tables in pDb */
|
||||
Table *pTab; /* A table in the database */
|
||||
|
||||
assert( sqlite3BtreeHoldsAllMutexes(db) ); /* Needed for schema access */
|
||||
for(iDb=0, pDb=db->aDb; iDb<db->nDb; iDb++, pDb++){
|
||||
assert( pDb!=0 );
|
||||
for(k=sqliteHashFirst(&pDb->pSchema->tblHash); k; k=sqliteHashNext(k)){
|
||||
pTab = (Table*)sqliteHashData(k);
|
||||
reindexTable(pParse, pTab, zColl);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Generate code for the REINDEX command.
|
||||
**
|
||||
** REINDEX -- 1
|
||||
** REINDEX <collation> -- 2
|
||||
** REINDEX ?<database>.?<tablename> -- 3
|
||||
** REINDEX ?<database>.?<indexname> -- 4
|
||||
** REINDEX ?<database>.?<indexname> -- 3
|
||||
** REINDEX ?<database>.?<tablename> -- 4
|
||||
** REINDEX EXPRESSIONS -- 5
|
||||
**
|
||||
** Form 1 causes all indices in all attached databases to be rebuilt.
|
||||
** Form 2 rebuilds all indices in all databases that use the named
|
||||
** Form 1 causes all indexes in all attached databases to be rebuilt.
|
||||
** Form 2 rebuilds all indexes in all databases that use the named
|
||||
** collating function. Forms 3 and 4 rebuild the named index or all
|
||||
** indices associated with the named table.
|
||||
** indexes associated with the named table, respectively. Form 5
|
||||
** rebuilds all expression indexes in addition to all collations,
|
||||
** indexes, or tables named "EXPRESSIONS".
|
||||
**
|
||||
** If the name is ambiguous such that it matches two or more of
|
||||
** forms 2 through 5, then rebuild the union of all matching indexes,
|
||||
** taken care to avoid rebuilding the same index more than once.
|
||||
*/
|
||||
#ifndef SQLITE_OMIT_REINDEX
|
||||
void sqlite3Reindex(Parse *pParse, Token *pName1, Token *pName2){
|
||||
CollSeq *pColl; /* Collating sequence to be reindexed, or NULL */
|
||||
char *z; /* Name of a table or index */
|
||||
const char *zDb; /* Name of the database */
|
||||
Table *pTab; /* A table in the database */
|
||||
Index *pIndex; /* An index associated with pTab */
|
||||
int iDb; /* The database index number */
|
||||
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 */
|
||||
sqlite3 *db = pParse->db; /* The database connection */
|
||||
Token *pObjName; /* Name of the table or index to be reindexed */
|
||||
int bMatch = 0; /* At least one name match */
|
||||
const char *zColl = 0; /* Rebuild indexes using this collation */
|
||||
Table *pReTab = 0; /* Rebuild all indexes of this table */
|
||||
Index *pReIndex = 0; /* Rebuild this index */
|
||||
int isExprIdx = 0; /* Rebuild all expression indexes */
|
||||
int bAll = 0; /* Rebuild all indexes */
|
||||
|
||||
/* Read the database schema. If an error occurs, leave an error message
|
||||
** and code in pParse and return NULL. */
|
||||
@@ -5615,41 +5581,66 @@ void sqlite3Reindex(Parse *pParse, Token *pName1, Token *pName2){
|
||||
}
|
||||
|
||||
if( pName1==0 ){
|
||||
reindexDatabases(pParse, 0);
|
||||
return;
|
||||
/* rebuild all indexes */
|
||||
bMatch = 1;
|
||||
bAll = 1;
|
||||
}else if( NEVER(pName2==0) || pName2->z==0 ){
|
||||
char *zColl;
|
||||
assert( pName1->z );
|
||||
zColl = sqlite3NameFromToken(pParse->db, pName1);
|
||||
if( !zColl ) return;
|
||||
pColl = sqlite3FindCollSeq(db, ENC(db), zColl, 0);
|
||||
if( pColl ){
|
||||
reindexDatabases(pParse, zColl);
|
||||
sqlite3DbFree(db, zColl);
|
||||
return;
|
||||
z = sqlite3NameFromToken(pParse->db, pName1);
|
||||
if( z==0 ) return;
|
||||
}else{
|
||||
iReDb = sqlite3TwoPartName(pParse, pName1, pName2, &pObjName);
|
||||
if( iReDb<0 ) return;
|
||||
z = sqlite3NameFromToken(db, pObjName);
|
||||
if( z==0 ) return;
|
||||
zDb = db->aDb[iReDb].zDbSName;
|
||||
}
|
||||
if( !bAll ){
|
||||
if( zDb==0 && sqlite3StrICmp(z, "expressions")==0 ){
|
||||
isExprIdx = 1;
|
||||
bMatch = 1;
|
||||
}
|
||||
if( zDb==0 && sqlite3FindCollSeq(db, ENC(db), z, 0)!=0 ){
|
||||
zColl = z;
|
||||
bMatch = 1;
|
||||
}
|
||||
if( zColl==0 && (pReTab = sqlite3FindTable(db, z, zDb))!=0 ){
|
||||
bMatch = 1;
|
||||
}
|
||||
if( zColl==0 && (pReIndex = sqlite3FindIndex(db, z, zDb))!=0 ){
|
||||
bMatch = 1;
|
||||
}
|
||||
sqlite3DbFree(db, zColl);
|
||||
}
|
||||
iDb = sqlite3TwoPartName(pParse, pName1, pName2, &pObjName);
|
||||
if( iDb<0 ) return;
|
||||
z = sqlite3NameFromToken(db, pObjName);
|
||||
if( z==0 ) return;
|
||||
zDb = pName2->n ? db->aDb[iDb].zDbSName : 0;
|
||||
pTab = sqlite3FindTable(db, z, zDb);
|
||||
if( pTab ){
|
||||
reindexTable(pParse, pTab, 0);
|
||||
sqlite3DbFree(db, z);
|
||||
return;
|
||||
if( bMatch ){
|
||||
int iDb;
|
||||
HashElem *k;
|
||||
Table *pTab;
|
||||
Index *pIdx;
|
||||
Db *pDb;
|
||||
for(iDb=0, pDb=db->aDb; iDb<db->nDb; iDb++, pDb++){
|
||||
assert( pDb!=0 );
|
||||
if( iReDb>=0 && iReDb!=iDb ) continue;
|
||||
for(k=sqliteHashFirst(&pDb->pSchema->tblHash); k; k=sqliteHashNext(k)){
|
||||
pTab = (Table*)sqliteHashData(k);
|
||||
if( IsVirtual(pTab) ) continue;
|
||||
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
||||
if( bAll
|
||||
|| pTab==pReTab
|
||||
|| pIdx==pReIndex
|
||||
|| (isExprIdx && pIdx->bHasExpr)
|
||||
|| (zColl!=0 && collationMatch(zColl,pIdx))
|
||||
){
|
||||
sqlite3BeginWriteOperation(pParse, 0, iDb);
|
||||
sqlite3RefillIndex(pParse, pIdx, -1);
|
||||
}
|
||||
} /* End loop over indexes of pTab */
|
||||
} /* End loop over tables of iDb */
|
||||
} /* End loop over databases */
|
||||
}else{
|
||||
sqlite3ErrorMsg(pParse, "unable to identify the object to be reindexed");
|
||||
}
|
||||
pIndex = sqlite3FindIndex(db, z, zDb);
|
||||
sqlite3DbFree(db, z);
|
||||
if( pIndex ){
|
||||
iDb = sqlite3SchemaToIndex(db, pIndex->pTable->pSchema);
|
||||
sqlite3BeginWriteOperation(pParse, 0, iDb);
|
||||
sqlite3RefillIndex(pParse, pIndex, -1);
|
||||
return;
|
||||
}
|
||||
sqlite3ErrorMsg(pParse, "unable to identify the object to be reindexed");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
+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: {
|
||||
|
||||
+83
-38
@@ -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
|
||||
*/
|
||||
@@ -850,6 +860,7 @@ static void jsonReturnString(
|
||||
){
|
||||
assert( (pParse!=0)==(ctx!=0) );
|
||||
assert( ctx==0 || ctx==p->pCtx );
|
||||
jsonStringTerminate(p);
|
||||
if( p->eErr==0 ){
|
||||
int flags = SQLITE_PTR_TO_INT(sqlite3_user_data(p->pCtx));
|
||||
if( flags & JSON_BLOB ){
|
||||
@@ -857,7 +868,7 @@ static void jsonReturnString(
|
||||
}else if( p->bStatic ){
|
||||
sqlite3_result_text64(p->pCtx, p->zBuf, p->nUsed,
|
||||
SQLITE_TRANSIENT, SQLITE_UTF8);
|
||||
}else if( jsonStringTerminate(p) ){
|
||||
}else{
|
||||
if( pParse && pParse->bJsonIsRCStr==0 && pParse->nBlobAlloc>0 ){
|
||||
int rc;
|
||||
pParse->zJson = sqlite3RCStrRef(p->zBuf);
|
||||
@@ -873,11 +884,11 @@ static void jsonReturnString(
|
||||
sqlite3_result_text64(p->pCtx, sqlite3RCStrRef(p->zBuf), p->nUsed,
|
||||
sqlite3RCStrUnref,
|
||||
SQLITE_UTF8);
|
||||
}else{
|
||||
sqlite3_result_error_nomem(p->pCtx);
|
||||
}
|
||||
}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);
|
||||
}
|
||||
@@ -2088,12 +2099,8 @@ static int jsonConvertTextToBlob(
|
||||
*/
|
||||
static void jsonReturnStringAsBlob(JsonString *pStr){
|
||||
JsonParse px;
|
||||
assert( pStr->eErr==0 );
|
||||
memset(&px, 0, sizeof(px));
|
||||
jsonStringTerminate(pStr);
|
||||
if( pStr->eErr ){
|
||||
sqlite3_result_error_nomem(pStr->pCtx);
|
||||
return;
|
||||
}
|
||||
px.zJson = pStr->zBuf;
|
||||
px.nJson = pStr->nUsed;
|
||||
px.db = sqlite3_context_db_handle(pStr->pCtx);
|
||||
@@ -2183,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 */
|
||||
){
|
||||
@@ -2365,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, ']');
|
||||
@@ -2379,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, '}');
|
||||
@@ -2439,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 ){
|
||||
@@ -2454,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);
|
||||
@@ -2475,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);
|
||||
@@ -2876,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 */
|
||||
@@ -2923,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 */
|
||||
@@ -3029,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;
|
||||
}
|
||||
@@ -3115,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;
|
||||
}
|
||||
@@ -3447,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.
|
||||
@@ -3460,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);
|
||||
}
|
||||
@@ -3522,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);
|
||||
@@ -3534,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;
|
||||
}
|
||||
|
||||
@@ -3978,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;
|
||||
@@ -4115,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;
|
||||
}
|
||||
}
|
||||
@@ -4143,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.
|
||||
@@ -4194,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() */
|
||||
@@ -4303,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;
|
||||
}
|
||||
@@ -4324,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;
|
||||
}
|
||||
@@ -4355,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);
|
||||
}
|
||||
@@ -4447,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;
|
||||
}
|
||||
@@ -4547,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;
|
||||
}
|
||||
@@ -4808,7 +4851,8 @@ static void jsonArrayCompute(sqlite3_context *ctx, int isFinal){
|
||||
pStr = (JsonString*)sqlite3_aggregate_context(ctx, 0);
|
||||
if( pStr ){
|
||||
pStr->pCtx = ctx;
|
||||
jsonAppendChar(pStr, ']');
|
||||
jsonAppendRawNZ(pStr, "]", 2);
|
||||
jsonStringTrimOneChar(pStr);
|
||||
if( pStr->eErr ){
|
||||
jsonReturnString(pStr, 0, 0);
|
||||
return;
|
||||
@@ -4931,7 +4975,8 @@ static void jsonObjectCompute(sqlite3_context *ctx, int isFinal){
|
||||
int flags = SQLITE_PTR_TO_INT(sqlite3_user_data(ctx));
|
||||
pStr = (JsonString*)sqlite3_aggregate_context(ctx, 0);
|
||||
if( pStr ){
|
||||
jsonAppendChar(pStr, '}');
|
||||
jsonAppendRawNZ(pStr, "}", 2);
|
||||
jsonStringTrimOneChar(pStr);
|
||||
pStr->pCtx = ctx;
|
||||
if( pStr->eErr ){
|
||||
jsonReturnString(pStr, 0, 0);
|
||||
|
||||
+11
@@ -4716,6 +4716,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;
|
||||
|
||||
+76
-39
@@ -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,15 @@ 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( sqlite3StrAccumEnlargeIfNeeded(pAccum, szBufNeeded) ){
|
||||
width = length = 0;
|
||||
break;
|
||||
}
|
||||
zOut = bufpt;
|
||||
bufpt = zOut = pAccum->zText + pAccum->nChar;
|
||||
|
||||
flag_dp = (precision>0 ?1:0) | flag_alternateform | flag_altform2;
|
||||
/* The sign in front of the number */
|
||||
if( prefix ){
|
||||
@@ -635,12 +636,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 +662,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 +711,31 @@ 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;
|
||||
pAccum->nChar += length;
|
||||
zOut[length] = 0;
|
||||
|
||||
/* Floating point conversions render directly into the output
|
||||
** buffer. Hence, don't just break out of the switch(). Bypass the
|
||||
** output buffer writing that occurs after the switch() by continuing
|
||||
** to the next character in the format string. */
|
||||
continue;
|
||||
}
|
||||
case etSIZE:
|
||||
if( !bArgList ){
|
||||
@@ -748,11 +779,10 @@ 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,
|
||||
sqlite3_str_append(pAccum,
|
||||
&pAccum->zText[pAccum->nChar-nCopyBytes], nCopyBytes);
|
||||
precision -= nPrior;
|
||||
nPrior *= 2;
|
||||
@@ -1098,6 +1128,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.
|
||||
*/
|
||||
|
||||
+802
-776
File diff suppressed because it is too large
Load Diff
+58
-54
@@ -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
|
||||
@@ -5850,8 +5860,9 @@ int sqlite3_create_window_function(
|
||||
** of the strings must be aligned to a 2-byte boundary.
|
||||
**
|
||||
** [[SQLITE_UTF8_ZT]] <dt>SQLITE_UTF8_ZT</dt><dd>This option can only be
|
||||
** used to specify the text encoding to strings input to [sqlite3_result_text64()]
|
||||
** and [sqlite3_bind_text64()]. It means that the input string (call it "z")
|
||||
** used to specify the text encoding to strings input to
|
||||
** [sqlite3_result_text64()] and [sqlite3_bind_text64()].
|
||||
** The SQLITE_UTF8_ZT encoding means that the input string (call it "z")
|
||||
** is UTF-8 encoded and that it is zero-terminated. If the length parameter
|
||||
** (call it "n") is non-negative, this encoding option means that the caller
|
||||
** guarantees that z array contains at least n+1 bytes and that the z[n]
|
||||
@@ -6103,26 +6114,22 @@ SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int64,int),
|
||||
** the SQL function that supplied the [sqlite3_value*] parameters.
|
||||
**
|
||||
** As long as the input parameter is correct, these routines can only
|
||||
** fail if an out-of-memory error occurs during a format conversion.
|
||||
** Only the following subset of interfaces are subject to out-of-memory
|
||||
** errors:
|
||||
**
|
||||
** <ul>
|
||||
** <li> sqlite3_value_blob()
|
||||
** <li> sqlite3_value_text()
|
||||
** <li> sqlite3_value_text16()
|
||||
** <li> sqlite3_value_text16le()
|
||||
** <li> sqlite3_value_text16be()
|
||||
** <li> sqlite3_value_bytes()
|
||||
** <li> sqlite3_value_bytes16()
|
||||
** </ul>
|
||||
**
|
||||
** fail if an out-of-memory error occurs while trying to do a
|
||||
** UTF8→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 +6156,8 @@ int sqlite3_value_frombind(sqlite3_value*);
|
||||
** of the value X, assuming that X has type TEXT.)^ If sqlite3_value_type(X)
|
||||
** returns something other than SQLITE_TEXT, then the return value from
|
||||
** sqlite3_value_encoding(X) is meaningless. ^Calls to
|
||||
** [sqlite3_value_text(X)], [sqlite3_value_text16(X)], [sqlite3_value_text16be(X)],
|
||||
** [sqlite3_value_text(X)], [sqlite3_value_text16(X)],
|
||||
** [sqlite3_value_text16be(X)],
|
||||
** [sqlite3_value_text16le(X)], [sqlite3_value_bytes(X)], or
|
||||
** [sqlite3_value_bytes16(X)] might change the encoding of the value X and
|
||||
** thus change the return from subsequent calls to sqlite3_value_encoding(X).
|
||||
@@ -6280,17 +6288,17 @@ sqlite3 *sqlite3_context_db_handle(sqlite3_context*);
|
||||
** query execution, under some circumstances the associated auxiliary data
|
||||
** might be preserved. An example of where this might be useful is in a
|
||||
** regular-expression matching function. The compiled version of the regular
|
||||
** expression can be stored as auxiliary data associated with the pattern string.
|
||||
** Then as long as the pattern string remains the same,
|
||||
** expression can be stored as auxiliary data associated with the pattern
|
||||
** string. Then as long as the pattern string remains the same,
|
||||
** the compiled regular expression can be reused on multiple
|
||||
** invocations of the same function.
|
||||
**
|
||||
** ^The sqlite3_get_auxdata(C,N) interface returns a pointer to the auxiliary data
|
||||
** associated by the sqlite3_set_auxdata(C,N,P,X) function with the Nth argument
|
||||
** value to the application-defined function. ^N is zero for the left-most
|
||||
** function argument. ^If there is no auxiliary data
|
||||
** associated with the function argument, the sqlite3_get_auxdata(C,N) interface
|
||||
** returns a NULL pointer.
|
||||
** ^The sqlite3_get_auxdata(C,N) interface returns a pointer to the auxiliary
|
||||
** data associated by the sqlite3_set_auxdata(C,N,P,X) function with the
|
||||
** Nth argument value to the application-defined function. ^N is zero
|
||||
** for the left-most function argument. ^If there is no auxiliary data
|
||||
** associated with the function argument, the sqlite3_get_auxdata(C,N)
|
||||
** interface returns a NULL pointer.
|
||||
**
|
||||
** ^The sqlite3_set_auxdata(C,N,P,X) interface saves P as auxiliary data for the
|
||||
** N-th argument of the application-defined function. ^Subsequent
|
||||
@@ -7607,7 +7615,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 +8365,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 +8719,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 +10411,8 @@ const char *sqlite3_vtab_collation(sqlite3_index_info*,int);
|
||||
** <tr>
|
||||
** <td valign="top">sqlite3_vtab_distinct() return value
|
||||
** <td valign="top">Rows are returned in aOrderBy order
|
||||
** <td valign="top">Rows with the same value in all aOrderBy columns are adjacent
|
||||
** <td valign="top">Rows with the same value in all aOrderBy columns are
|
||||
** adjacent
|
||||
** <td valign="top">Duplicates over all colUsed columns may be omitted
|
||||
** <tr><td>0<td>yes<td>yes<td>no
|
||||
** <tr><td>1<td>no<td>yes<td>no
|
||||
@@ -10418,8 +10421,8 @@ const char *sqlite3_vtab_collation(sqlite3_index_info*,int);
|
||||
** </table>
|
||||
**
|
||||
** ^For the purposes of comparing virtual table output values to see if the
|
||||
** values are the same value for sorting purposes, two NULL values are considered
|
||||
** to be the same. In other words, the comparison operator is "IS"
|
||||
** values are the same value for sorting purposes, two NULL values are
|
||||
** considered to be the same. In other words, the comparison operator is "IS"
|
||||
** (or "IS NOT DISTINCT FROM") and not "==".
|
||||
**
|
||||
** If a virtual table implementation is unable to meet the requirements
|
||||
@@ -11273,12 +11276,13 @@ int sqlite3_deserialize(
|
||||
**
|
||||
** The sqlite3_carray_bind_v2(S,I,P,N,F,X,D) interface binds an array value to
|
||||
** parameter that is the first argument of the [carray() table-valued function].
|
||||
** The S parameter is a pointer to the [prepared statement] that uses the carray()
|
||||
** functions. I is the parameter index to be bound. I must be the index of the
|
||||
** parameter that is the first argument to the carray() table-valued function.
|
||||
** P is a pointer to the array to be bound, and N is the number of elements in
|
||||
** the array. The F argument is one of constants [SQLITE_CARRAY_INT32],
|
||||
** [SQLITE_CARRAY_INT64], [SQLITE_CARRAY_DOUBLE], [SQLITE_CARRAY_TEXT],
|
||||
** The S parameter is a pointer to the [prepared statement] that uses the
|
||||
** carray() functions. I is the parameter index to be bound. I must be the
|
||||
** index of the parameter that is the first argument to the carray()
|
||||
** table-valued function. P is a pointer to the array to be bound, and N
|
||||
** is the number of elements in the array. The F argument is one of
|
||||
** constants [SQLITE_CARRAY_INT32], [SQLITE_CARRAY_INT64],
|
||||
** [SQLITE_CARRAY_DOUBLE], [SQLITE_CARRAY_TEXT],
|
||||
** or [SQLITE_CARRAY_BLOB] to indicate the datatype of the array P.
|
||||
**
|
||||
** If the X argument is not a NULL pointer or one of the special
|
||||
|
||||
+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
@@ -2136,7 +2136,7 @@ static int dbQrf(SqliteDb *pDb, int objc, Tcl_Obj *const*objv){
|
||||
};
|
||||
|
||||
memset(&qrf, 0, sizeof(qrf));
|
||||
qrf.iVersion = 2;
|
||||
qrf.iVersion = 1;
|
||||
qrf.pzOutput = &zResult;
|
||||
for(i=2; i<objc; i++){
|
||||
const char *zArg = Tcl_GetString(objv[i]);
|
||||
|
||||
+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);
|
||||
|
||||
+246
-120
@@ -465,11 +465,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
|
||||
@@ -499,6 +500,22 @@ static u64 sqlite3Multiply128(u64 a, u64 b, u64 *pLo){
|
||||
** The lower 64 bits of A*B are discarded.
|
||||
*/
|
||||
static u64 sqlite3Multiply160(u64 a, u32 aLo, u64 b, u32 *pLo){
|
||||
#if (defined(__GNUC__) || defined(__clang__)) \
|
||||
&& (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(_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);
|
||||
u64 t = r1_lo + r2;
|
||||
if( t<r1_lo ) r1_hi++;
|
||||
*pLo = t>>32;
|
||||
return r1_hi;
|
||||
#else
|
||||
u64 x2 = a>>32;
|
||||
u64 x1 = a&0xffffffff;
|
||||
u64 x0 = aLo;
|
||||
@@ -520,6 +537,7 @@ static u64 sqlite3Multiply160(u64 a, u32 aLo, u64 b, u32 *pLo){
|
||||
r3 += r2>>32;
|
||||
*pLo = r2&0xffffffff;
|
||||
return (r4<<32) + r3;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -707,7 +725,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;
|
||||
@@ -749,46 +768,50 @@ static void sqlite3Fp2Convert10(u64 m, int e, int n, u64 *pD, int *pP){
|
||||
|
||||
/*
|
||||
** Return an IEEE754 floating point value that approximates d*pow(10,p).
|
||||
**
|
||||
** The (current) algorithm is adapted from the work of Ross Cox at
|
||||
** https://github.com/rsc/fpfmt
|
||||
*/
|
||||
static double sqlite3Fp10Convert2(u64 d, int p){
|
||||
int b, lp, e, adj, s;
|
||||
u32 pwr10l, mid1;
|
||||
u64 pwr10h, x, hi, lo, sticky, u, m;
|
||||
double r;
|
||||
if( p<POWERSOF10_FIRST ) return 0.0;
|
||||
if( p>POWERSOF10_LAST ) return INFINITY;
|
||||
int b = 64 - countLeadingZeros(d);
|
||||
int lp = pwr10to2(p);
|
||||
int e = 53 - b - lp;
|
||||
b = 64 - countLeadingZeros(d);
|
||||
lp = pwr10to2(p);
|
||||
e = 53 - b - lp;
|
||||
if( e > 1074 ){
|
||||
if( e>=1130 ) return 0.0;
|
||||
e = 1074;
|
||||
}
|
||||
int s = -(e-(64-b) + lp + 3);
|
||||
u32 pwr10l;
|
||||
u64 pwr10h = powerOfTen(p, &pwr10l);
|
||||
s = -(e-(64-b) + lp + 3);
|
||||
pwr10h = powerOfTen(p, &pwr10l);
|
||||
if( pwr10l!=0 ){
|
||||
pwr10h++;
|
||||
pwr10l = ~pwr10l;
|
||||
}
|
||||
u64 x = d<<(64-b);
|
||||
u64 lo;
|
||||
u64 hi = sqlite3Multiply128(x,pwr10h,&lo);
|
||||
u32 mid1 = lo>>32;
|
||||
u64 sticky = 1;
|
||||
x = d<<(64-b);
|
||||
hi = sqlite3Multiply128(x,pwr10h,&lo);
|
||||
mid1 = lo>>32;
|
||||
sticky = 1;
|
||||
if( (hi & (U64_BIT(s)-1))==0 ) {
|
||||
u32 mid2 = sqlite3Multiply128(x,((u64)pwr10l)<<32,&lo)>>32;
|
||||
sticky = (mid1-mid2 > 1);
|
||||
hi -= mid1 < mid2;
|
||||
}
|
||||
u64 u = (hi>>s) | sticky;
|
||||
int adj = (u >= U64_BIT(55)-2);
|
||||
u = (hi>>s) | sticky;
|
||||
adj = (u >= U64_BIT(55)-2);
|
||||
if( adj ){
|
||||
u = (u>>adj) | (u&1);
|
||||
e -= adj;
|
||||
}
|
||||
u64 m = (u + 1 + ((u>>2)&1)) >> 2;
|
||||
m = (u + 1 + ((u>>2)&1)) >> 2;
|
||||
if( e<=(-972) ) return INFINITY;
|
||||
if((m & U64_BIT(52)) != 0){
|
||||
m = (m & ~U64_BIT(52)) | ((u64)(1075-e)<<52);
|
||||
}
|
||||
double r;
|
||||
memcpy(&r,&m,8);
|
||||
return r;
|
||||
}
|
||||
@@ -799,134 +822,164 @@ static double sqlite3Fp10Convert2(u64 d, int p){
|
||||
**
|
||||
** z[] must be UTF-8 and zero-terminated.
|
||||
**
|
||||
** Return TRUE if the result is a valid real number (or integer) and FALSE
|
||||
** if the string is empty or contains extraneous text. More specifically
|
||||
** return
|
||||
** 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 a valid number
|
||||
** -1 => Not a valid number, but has a valid prefix which
|
||||
** includes a decimal point and/or an eNNN clause
|
||||
** 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.
|
||||
** Lower bits of the return value contain addition information about the
|
||||
** parse:
|
||||
**
|
||||
** Valid numbers are in one of these formats:
|
||||
** 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.
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
** If some prefix of the input string is a valid number, this routine
|
||||
** returns FALSE but it still converts the prefix and writes the result
|
||||
** into *pResult.
|
||||
** 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
|
||||
** IEEE754 double. The sign is added back afterwards, if the input string
|
||||
** starts with a "-". The use of an unsigned 64-bit s mantissa means that
|
||||
** only about the first 19 significant digits of the input can contribute
|
||||
** to the result. This can result in suboptimal rounding decisions when
|
||||
** correct rounding requires more than 19 input digits. For example,
|
||||
** this routine renders "3500000000000000.2500001" as
|
||||
** 3500000000000000.0 instead of 3500000000000000.5 because the decision
|
||||
** to round up instead of using banker's rounding to round down is determined
|
||||
** by the 23rd significant digit, which this routine ignores. It is not
|
||||
** possible to do better without some kind of BigNum.
|
||||
*/
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(disable : 4756)
|
||||
#endif
|
||||
int sqlite3AtoF(const char *z, double *pResult){
|
||||
int sqlite3AtoF(const char *zIn, double *pResult){
|
||||
#ifndef SQLITE_OMIT_FLOATING_POINT
|
||||
/* sign * significand * (10 ^ (esign * exponent)) */
|
||||
int neg = 0; /* True for a negative value */
|
||||
u64 s = 0; /* mantissa */
|
||||
int d = 0; /* Value is s * pow(10,d) */
|
||||
int nDigit = 0; /* Number of digits processed */
|
||||
int eType = 1; /* 1: pure integer, 2+: fractional */
|
||||
const unsigned char *z = (const unsigned char*)zIn;
|
||||
int neg = 0; /* True for a negative value */
|
||||
u64 s = 0; /* mantissa */
|
||||
int d = 0; /* Value is s * pow(10,d) */
|
||||
int mState = 0; /* 1: digit seen 2: fp 4: hard-zero */
|
||||
unsigned v; /* Value of a single digit */
|
||||
|
||||
*pResult = 0.0; /* Default return value, in case of an error */
|
||||
|
||||
/* skip leading spaces */
|
||||
while( sqlite3Isspace(*z) ) z++;
|
||||
|
||||
/* get sign of significand */
|
||||
if( *z=='-' ){
|
||||
start_of_text:
|
||||
if( (v = (unsigned)z[0] - '0')<10 ){
|
||||
parse_integer_part:
|
||||
mState = 1;
|
||||
s = v;
|
||||
z++;
|
||||
while( (v = (unsigned)z[0] - '0')<10 ){
|
||||
s = s*10 + v;
|
||||
z++;
|
||||
if( s>=(LARGEST_UINT64-9)/10 ){
|
||||
mState = 9;
|
||||
while( sqlite3Isdigit(z[0]) ){ z++; d++; }
|
||||
break;
|
||||
}
|
||||
}
|
||||
}else if( z[0]=='-' ){
|
||||
neg = 1;
|
||||
z++;
|
||||
}else if( *z=='+' ){
|
||||
if( (v = (unsigned)z[0] - '0')<10 ) goto parse_integer_part;
|
||||
}else if( z[0]=='+' ){
|
||||
z++;
|
||||
}
|
||||
|
||||
/* copy max significant digits to significand */
|
||||
while( sqlite3Isdigit(*z) ){
|
||||
s = s*10 + (*z - '0');
|
||||
z++; nDigit++;
|
||||
if( s>=((LARGEST_INT64-9)/10) ){
|
||||
/* skip non-significant significand digits
|
||||
** (increase exponent by d to shift decimal left) */
|
||||
while( sqlite3Isdigit(*z) ){ z++; d++; }
|
||||
}
|
||||
if( (v = (unsigned)z[0] - '0')<10 ) goto parse_integer_part;
|
||||
}else if( sqlite3Isspace(z[0]) ){
|
||||
do{ z++; }while( sqlite3Isspace(z[0]) );
|
||||
goto start_of_text;
|
||||
}else{
|
||||
s = 0;
|
||||
}
|
||||
|
||||
/* if decimal point is present */
|
||||
if( *z=='.' ){
|
||||
z++;
|
||||
eType++;
|
||||
/* copy digits from after decimal to significand
|
||||
** (decrease exponent by d to shift decimal right) */
|
||||
while( sqlite3Isdigit(*z) ){
|
||||
if( s<((LARGEST_INT64-9)/10) ){
|
||||
s = s*10 + (*z - '0');
|
||||
d--;
|
||||
nDigit++;
|
||||
}
|
||||
z++;
|
||||
if( sqlite3Isdigit(z[0]) ){
|
||||
mState |= 1;
|
||||
do{
|
||||
if( s<(LARGEST_UINT64-9)/10 ){
|
||||
s = s*10 + z[0] - '0';
|
||||
d--;
|
||||
}else{
|
||||
mState = 11;
|
||||
}
|
||||
}while( sqlite3Isdigit(*++z) );
|
||||
}else if( mState==0 ){
|
||||
*pResult = 0.0;
|
||||
return 0;
|
||||
}
|
||||
mState |= 2;
|
||||
}else if( mState==0 ){
|
||||
*pResult = 0.0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* if exponent is present */
|
||||
if( *z=='e' || *z=='E' ){
|
||||
int esign = 1; /* sign of exponent */
|
||||
int esign;
|
||||
z++;
|
||||
eType++;
|
||||
|
||||
|
||||
/* get sign of exponent */
|
||||
if( *z=='-' ){
|
||||
esign = -1;
|
||||
z++;
|
||||
}else if( *z=='+' ){
|
||||
z++;
|
||||
}else{
|
||||
esign = +1;
|
||||
if( *z=='+' ){
|
||||
z++;
|
||||
}
|
||||
}
|
||||
/* copy digits to exponent */
|
||||
if( sqlite3Isdigit(*z) ){
|
||||
int exp = *z - '0';
|
||||
if( (v = (unsigned)z[0] - '0')<10 ){
|
||||
int exp = v;
|
||||
z++;
|
||||
while( sqlite3Isdigit(*z) ){
|
||||
exp = exp<10000 ? (exp*10 + (*z - '0')) : 10000;
|
||||
mState |= 2;
|
||||
while( (v = (unsigned)z[0] - '0')<10 ){
|
||||
exp = exp<10000 ? (exp*10 + v) : 10000;
|
||||
z++;
|
||||
}
|
||||
d += esign*exp;
|
||||
}else{
|
||||
eType = -1;
|
||||
z--; /* Leave z[0] at 'e' or '+' or '-',
|
||||
** so that the return is 0 or -1 */
|
||||
}
|
||||
}
|
||||
|
||||
/* skip trailing spaces */
|
||||
while( sqlite3Isspace(*z) ) z++;
|
||||
|
||||
/* Zero is a special case */
|
||||
/* Convert s*pow(10,d) into real */
|
||||
if( s==0 ){
|
||||
*pResult = neg ? -0.0 : +0.0;
|
||||
*pResult = 0.0;
|
||||
mState |= 4;
|
||||
}else{
|
||||
*pResult = sqlite3Fp10Convert2(s,d);
|
||||
if( neg ) *pResult = -*pResult;
|
||||
assert( !sqlite3IsNaN(*pResult) );
|
||||
}
|
||||
if( neg ) *pResult = -*pResult;
|
||||
assert( !sqlite3IsNaN(*pResult) );
|
||||
|
||||
/* return true if number and no extra non-whitespace characters after */
|
||||
if( z[0]==0 && nDigit>0 ){
|
||||
return eType;
|
||||
}else if( eType>=2 && nDigit>0 ){
|
||||
return -1;
|
||||
}else{
|
||||
return 0;
|
||||
if( z[0]==0 ){
|
||||
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
|
||||
@@ -948,6 +1001,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
|
||||
@@ -961,7 +1077,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 ){
|
||||
@@ -973,6 +1089,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 ){
|
||||
@@ -986,6 +1105,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;
|
||||
@@ -1042,8 +1162,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;
|
||||
@@ -1071,8 +1191,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 );
|
||||
@@ -1109,14 +1229,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{
|
||||
@@ -1305,37 +1425,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 ){
|
||||
@@ -1362,7 +1488,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) ){
|
||||
|
||||
+5
-5
@@ -355,9 +355,9 @@ static void applyNumericAffinity(Mem *pRec, int bTryForInt){
|
||||
double rValue;
|
||||
int rc;
|
||||
assert( (pRec->flags & (MEM_Str|MEM_Int|MEM_Real|MEM_IntReal))==MEM_Str );
|
||||
rValue = sqlite3MemRealValueRC(pRec, &rc);
|
||||
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;
|
||||
@@ -473,15 +473,15 @@ static u16 SQLITE_NOINLINE computeNumericType(Mem *pMem){
|
||||
pMem->u.i = 0;
|
||||
return MEM_Int;
|
||||
}
|
||||
pMem->u.r = sqlite3MemRealValueRC(pMem, &rc);
|
||||
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;
|
||||
}
|
||||
|
||||
+1
-1
@@ -656,7 +656,7 @@ int sqlite3IntFloatCompare(i64,double);
|
||||
i64 sqlite3VdbeIntValue(const Mem*);
|
||||
int sqlite3VdbeMemIntegerify(Mem*);
|
||||
double sqlite3VdbeRealValue(Mem*);
|
||||
SQLITE_NOINLINE double sqlite3MemRealValueRC(Mem*, int*);
|
||||
int sqlite3MemRealValueRC(Mem*, double*);
|
||||
int sqlite3VdbeBooleanValue(Mem*, int ifNull);
|
||||
void sqlite3VdbeIntegerAffinity(Mem*);
|
||||
int sqlite3VdbeMemRealify(Mem*);
|
||||
|
||||
+73
-26
@@ -657,32 +657,36 @@ i64 sqlite3VdbeIntValue(const Mem *pMem){
|
||||
}
|
||||
|
||||
/*
|
||||
** 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.
|
||||
** This routine implements the uncommon and slower path for
|
||||
** 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.
|
||||
**
|
||||
** The caller must ensure that pMem->db!=0 and that pMem is in
|
||||
** mode MEM_Str or MEM_Blob.
|
||||
** 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.
|
||||
*/
|
||||
SQLITE_NOINLINE double sqlite3MemRealValueRC(Mem *pMem, int *pRC){
|
||||
double val = (double)0;
|
||||
int rc = 0;
|
||||
assert( pMem->db!=0 );
|
||||
assert( pMem->flags & (MEM_Str|MEM_Blob) );
|
||||
if( pMem->z==0 ){
|
||||
/* no-op */
|
||||
}else if( pMem->enc==SQLITE_UTF8
|
||||
&& ((pMem->flags & MEM_Term)!=0 || sqlite3VdbeMemZeroTerminateIfAble(pMem))
|
||||
){
|
||||
rc = sqlite3AtoF(pMem->z, &val);
|
||||
}else if( pMem->n==0 ){
|
||||
/* no-op */
|
||||
}else if( pMem->enc==SQLITE_UTF8 ){
|
||||
static SQLITE_NOINLINE int sqlite3MemRealValueRCSlowPath(
|
||||
Mem *pMem,
|
||||
double *pValue
|
||||
){
|
||||
int rc = SQLITE_OK;
|
||||
*pValue = 0.0;
|
||||
if( pMem->enc==SQLITE_UTF8 ){
|
||||
char *zCopy = sqlite3DbStrNDup(pMem->db, pMem->z, pMem->n);
|
||||
if( zCopy ){
|
||||
rc = sqlite3AtoF(zCopy, &val);
|
||||
rc = sqlite3AtoF(zCopy, pValue);
|
||||
sqlite3DbFree(pMem->db, zCopy);
|
||||
}
|
||||
return rc;
|
||||
}else{
|
||||
int n, i, j;
|
||||
char *zCopy;
|
||||
@@ -705,13 +709,56 @@ SQLITE_NOINLINE double sqlite3MemRealValueRC(Mem *pMem, int *pRC){
|
||||
}
|
||||
assert( j<=n/2 );
|
||||
zCopy[j] = 0;
|
||||
rc = sqlite3AtoF(zCopy, &val);
|
||||
rc = sqlite3AtoF(zCopy, pValue);
|
||||
if( i<n ) rc = -100;
|
||||
sqlite3DbFree(pMem->db, zCopy);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
if( pRC ) *pRC = rc;
|
||||
return val;
|
||||
}
|
||||
|
||||
/*
|
||||
** 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){
|
||||
testcase( pMem->db==0 );
|
||||
assert( pMem->flags & (MEM_Str|MEM_Blob) );
|
||||
if( pMem->z==0 ){
|
||||
*pValue = 0.0;
|
||||
return 0;
|
||||
}else if( pMem->enc==SQLITE_UTF8
|
||||
&& ((pMem->flags & MEM_Term)!=0 || sqlite3VdbeMemZeroTerminateIfAble(pMem))
|
||||
){
|
||||
return sqlite3AtoF(pMem->z, pValue);
|
||||
}else if( pMem->n==0 ){
|
||||
*pValue = 0.0;
|
||||
return 0;
|
||||
}else{
|
||||
return sqlite3MemRealValueRCSlowPath(pMem, pValue);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** This routine acts as a bridge from sqlite3VdbeRealValue() to
|
||||
** sqlite3VdbeRealValueRC, allowing sqlite3VdbeRealValue() to avoid
|
||||
** stuffing values onto the stack.
|
||||
*/
|
||||
static SQLITE_NOINLINE double sqlite3MemRealValueNoRC(Mem *pMem){
|
||||
double r;
|
||||
(void)sqlite3MemRealValueRC(pMem, &r);
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -730,7 +777,7 @@ double sqlite3VdbeRealValue(Mem *pMem){
|
||||
testcase( pMem->flags & MEM_IntReal );
|
||||
return (double)pMem->u.i;
|
||||
}else if( pMem->flags & (MEM_Str|MEM_Blob) ){
|
||||
return sqlite3MemRealValueRC(pMem, 0);
|
||||
return sqlite3MemRealValueNoRC(pMem);
|
||||
}else{
|
||||
/* (double)0 In case of SQLITE_OMIT_FLOATING_POINT... */
|
||||
return (double)0;
|
||||
@@ -854,8 +901,8 @@ int sqlite3VdbeMemNumerify(Mem *pMem){
|
||||
sqlite3_int64 ix;
|
||||
assert( (pMem->flags & (MEM_Blob|MEM_Str))!=0 );
|
||||
assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
|
||||
pMem->u.r = sqlite3MemRealValueRC(pMem, &rc);
|
||||
if( ((rc==0 || rc==1) && sqlite3Atoi64(pMem->z, &ix, pMem->n, pMem->enc)<=1)
|
||||
rc = sqlite3MemRealValueRC(pMem, &pMem->u.r);
|
||||
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;
|
||||
}
|
||||
|
||||
+15
-5
@@ -2449,11 +2449,16 @@ void sqlite3WhereClausePrint(WhereClause *pWC){
|
||||
void sqlite3WhereLoopPrint(const WhereLoop *p, const WhereClause *pWC){
|
||||
WhereInfo *pWInfo;
|
||||
if( pWC ){
|
||||
int nb;
|
||||
SrcItem *pItem;
|
||||
Table *pTab;
|
||||
Bitmask mAll;
|
||||
|
||||
pWInfo = pWC->pWInfo;
|
||||
int nb = 1+(pWInfo->pTabList->nSrc+3)/4;
|
||||
SrcItem *pItem = pWInfo->pTabList->a + p->iTab;
|
||||
Table *pTab = pItem->pSTab;
|
||||
Bitmask mAll = (((Bitmask)1)<<(nb*4)) - 1;
|
||||
nb = 1+(pWInfo->pTabList->nSrc+3)/4;
|
||||
pItem = pWInfo->pTabList->a + p->iTab;
|
||||
pTab = pItem->pSTab;
|
||||
mAll = (((Bitmask)1)<<(nb*4)) - 1;
|
||||
sqlite3DebugPrintf("%c%2d.%0*llx.%0*llx", p->cId,
|
||||
p->iTab, nb, p->maskSelf, nb, p->prereq & mAll);
|
||||
sqlite3DebugPrintf(" %12s",
|
||||
@@ -4167,7 +4172,12 @@ static int whereLoopAddBtree(
|
||||
whereLoopOutputAdjust(pWC, pNew, rSize);
|
||||
if( pSrc->fg.isSubquery ){
|
||||
if( pSrc->fg.viaCoroutine ) pNew->wsFlags |= WHERE_COROUTINE;
|
||||
pNew->u.btree.pOrderBy = pSrc->u4.pSubq->pSelect->pOrderBy;
|
||||
/* Do not set btree.pOrderBy for a recursive CTE. In this case
|
||||
** the ORDER BY clause does not determine the overall order that
|
||||
** rows are emitted from the CTE in. */
|
||||
if( (pSrc->u4.pSubq->pSelect->selFlags & SF_Recursive)==0 ){
|
||||
pNew->u.btree.pOrderBy = pSrc->u4.pSubq->pSelect->pOrderBy;
|
||||
}
|
||||
}else if( pSrc->fg.fromExists ){
|
||||
pNew->nOut = 0;
|
||||
}
|
||||
|
||||
+4
-4
@@ -1922,8 +1922,8 @@ do_test auth-1.283 {
|
||||
execsql {
|
||||
REINDEX BINARY;
|
||||
}
|
||||
set ::authargs
|
||||
} {t3_idx1 {} main {} sqlite_autoindex_t3_1 {} main {}}
|
||||
lsort -unique $::authargs
|
||||
} {{} main sqlite_autoindex_t3_1 t3_idx1 t3_idx2}
|
||||
do_test auth-1.284 {
|
||||
set ::authargs {}
|
||||
execsql {
|
||||
@@ -1963,8 +1963,8 @@ ifcapable tempdb {
|
||||
execsql {
|
||||
REINDEX BINARY;
|
||||
}
|
||||
set ::authargs
|
||||
} {t3_idx1 {} temp {} sqlite_autoindex_t3_1 {} temp {}}
|
||||
lsort -unique $::authargs
|
||||
} {{} sqlite_autoindex_t3_1 t3_idx1 t3_idx2 temp}
|
||||
do_test auth-1.290 {
|
||||
set ::authargs {}
|
||||
execsql {
|
||||
|
||||
+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
|
||||
#
|
||||
|
||||
@@ -96,6 +96,30 @@ do_execsql_test 3.3 {
|
||||
SELECT * FROM x2 CROSS JOIN x1 WHERE (1234, x2.y) > (x1.a, x1.b);
|
||||
} {1234 abc 1234 ABCD}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test the fix for forum post https://sqlite.org/forum/forumpost/7a308e933d
|
||||
#
|
||||
do_execsql_test 4.0 {
|
||||
CREATE TABLE t1 (a PRIMARY KEY, b COLLATE NOCASE) WITHOUT ROWID;
|
||||
INSERT INTO t1 VALUES ('BBB', 'a');
|
||||
}
|
||||
do_execsql_test 4.1 {
|
||||
SELECT * FROM t1 WHERE (t1.a, t1.b) <= ('BBB', 'CCC');
|
||||
} {BBB a}
|
||||
|
||||
do_execsql_test 4.2 {
|
||||
DROP TABLE t1;
|
||||
CREATE TABLE t0 (c0);
|
||||
INSERT INTO t0 VALUES ('True');
|
||||
|
||||
CREATE TABLE t1 (c0 COLLATE NOCASE, c1 PRIMARY KEY) WITHOUT ROWID;
|
||||
INSERT INTO t1 VALUES ('a', 1);
|
||||
INSERT INTO t1 VALUES ('a', 'True');
|
||||
}
|
||||
|
||||
do_execsql_test 4.3 {
|
||||
SELECT * FROM t0, t1 WHERE (t1.c1, t1.c0) <= (t0.c0, t0.c0);
|
||||
} {True a 1 True a True}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
+26
-4
@@ -141,7 +141,10 @@ are run. Otherwise, each pattern is interpreted as a glob pattern. Only
|
||||
those tcl tests for which the final component of the filename matches at
|
||||
least one specified pattern are run. The glob wildcard '*' is prepended
|
||||
to the pattern if it does not start with '^' and appended to every
|
||||
pattern that does not end with '$'.
|
||||
pattern that does not end with '$'. If PATTERN begins with "~", then it
|
||||
is an anti-pattern that only matches tests that do not match PATTERN.
|
||||
Tests or only run if they match one or more patterns and match no
|
||||
anti-patterns.
|
||||
|
||||
If no PATTERN arguments are present, then various fuzztest, threadtest
|
||||
and other tests are run as part of the "release" permutation. These are
|
||||
@@ -1124,10 +1127,21 @@ proc add_job {args} {
|
||||
#
|
||||
# An empty patternlist matches everything
|
||||
#
|
||||
# Entries of patternlist that begin with "~" mean "match anything that
|
||||
# does not match the following pattern". For example, a patternlist
|
||||
# of {fuzzcheck ~san} will match "fuzzcheck" but not "fuzzcheck-asan".
|
||||
#
|
||||
proc job_matches_any_pattern {patternlist jobcmd} {
|
||||
set bMatch 0
|
||||
set bMiss 0
|
||||
if {[llength $patternlist]==0} {return 1}
|
||||
foreach p $patternlist {
|
||||
if {[string index $p 0] eq "~"} {
|
||||
set p [string range $p 1 end]
|
||||
set not 1
|
||||
} else {
|
||||
set not 0
|
||||
}
|
||||
set p [string trim $p *]
|
||||
if {[string index $p 0]=="^"} {
|
||||
set p [string range $p 1 end]
|
||||
@@ -1139,11 +1153,19 @@ proc job_matches_any_pattern {patternlist jobcmd} {
|
||||
} else {
|
||||
set p "$p*"
|
||||
}
|
||||
if {[string match $p $jobcmd]} {
|
||||
set bMatch 1
|
||||
break
|
||||
if {$not} {
|
||||
if {[string match $p $jobcmd]} {return 0}
|
||||
} else {
|
||||
if {[string match $p $jobcmd]} {
|
||||
set bMatch 1
|
||||
} else {
|
||||
set bMiss 1
|
||||
}
|
||||
}
|
||||
}
|
||||
if {!$bMiss} {
|
||||
set bMatch 1
|
||||
}
|
||||
return $bMatch
|
||||
}
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -190,5 +190,26 @@ do_execsql_test 220 {
|
||||
SELECT x FROM closure ORDER BY +x;
|
||||
} {1 2 3 4 5 6 7 8 9 11 13}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Forum: https://sqlite.org/forum/forumpost/deb1eadf4d677bd5
|
||||
#
|
||||
# For a recursive CTE, do not assume rows are delivered in the order
|
||||
# specified by the ORDER BY clause. In this case ORDER BY governs the
|
||||
# order in which the queue is processed, not the overall order in which
|
||||
# rows are emitted by the CTE.
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 300 {
|
||||
CREATE TABLE tree(id INTEGER PRIMARY KEY, parent INTEGER);
|
||||
INSERT INTO tree VALUES(3, 1);
|
||||
INSERT INTO tree VALUES(2, 3);
|
||||
}
|
||||
|
||||
do_execsql_test 310 {
|
||||
WITH RECURSIVE tt(ii) AS (
|
||||
VALUES(1) UNION ALL SELECT id FROM tree, tt WHERE parent=ii ORDER BY id
|
||||
)
|
||||
SELECT * FROM tt ORDER BY ii;
|
||||
} {1 2 3}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -68,6 +68,7 @@ gcc -c $WARNING_OPTS -std=c99 \
|
||||
echo '**** Optimized -O3. Includes FTS4/5, GEOPOLY, JSON1 ******'
|
||||
echo '****' $WARNING_OPTS
|
||||
gcc -O3 -c $WARNING_OPTS -std=c99 \
|
||||
-Wdeclaration-after-statement \
|
||||
-DHAVE_STDINT_H \
|
||||
-DSQLITE_ENABLE_FTS4 \
|
||||
-DSQLITE_ENABLE_FTS5 \
|
||||
|
||||
Reference in New Issue
Block a user