diff --git a/Makefile.in b/Makefile.in
index 028f615cd7..3d9a566505 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -669,7 +669,7 @@ ossshell$(TEXE): $(TOP)/test/ossfuzz.c $(TOP)/test/ossshell.c sqlite3.c sqlite3.
$(TOP)/test/ossfuzz.c sqlite3.c $(TLIBS)
sessionfuzz$(TEXE): $(TOP)/test/sessionfuzz.c sqlite3.c sqlite3.h
- $(CC) $(CFLAGS) -I. -o $@ $(TOP)/test/sessionfuzz.c $(TLIBS)
+ $(LTLINK) -o $@ $(TOP)/test/sessionfuzz.c $(TLIBS)
dbfuzz$(TEXE): $(TOP)/test/dbfuzz.c sqlite3.c sqlite3.h
$(LTLINK) -o $@ $(DBFUZZ_OPT) $(TOP)/test/dbfuzz.c sqlite3.c $(TLIBS)
@@ -685,7 +685,8 @@ DBFUZZ2_OPTS = \
-DSQLITE_EANBLE_FTS5
dbfuzz2: $(TOP)/test/dbfuzz2.c sqlite3.c sqlite3.h
- clang-6.0 -I. -g -O0 -fsanitize=fuzzer,undefined,address -o dbfuzz2 \
+ clang-6.0 $(OPT_FEATURE_FLAGS) $(OPTS) -I. -g -O0 \
+ -fsanitize=fuzzer,undefined,address -o dbfuzz2 \
$(DBFUZZ2_OPTS) $(TOP)/test/dbfuzz2.c sqlite3.c
mkdir -p dbfuzz2-dir
cp $(TOP)/test/dbfuzz2-seed* dbfuzz2-dir
@@ -1189,6 +1190,7 @@ TESTFIXTURE_FLAGS += -DSQLITE_SERIES_CONSTRAINT_VERIFY=1
TESTFIXTURE_FLAGS += -DSQLITE_DEFAULT_PAGE_SIZE=1024
TESTFIXTURE_FLAGS += -DSQLITE_ENABLE_STMTVTAB
TESTFIXTURE_FLAGS += -DSQLITE_ENABLE_DBPAGE_VTAB
+TESTFIXTURE_FLAGS += -DSQLITE_ENABLE_DESERIALIZE
TESTFIXTURE_SRC0 = $(TESTSRC2) libsqlite3.la
TESTFIXTURE_SRC1 = sqlite3.c
@@ -1291,6 +1293,9 @@ dbdump$(TEXE): $(TOP)/ext/misc/dbdump.c sqlite3.lo
$(LTLINK) -DDBDUMP_STANDALONE -o $@ \
$(TOP)/ext/misc/dbdump.c sqlite3.lo $(TLIBS)
+dbtotxt$(TEXE): $(TOP)/tool/dbtotxt.c
+ $(LTLINK)-o $@ $(TOP)/tool/dbtotxt.c
+
showdb$(TEXE): $(TOP)/tool/showdb.c sqlite3.lo
$(LTLINK) -o $@ $(TOP)/tool/showdb.c sqlite3.lo $(TLIBS)
diff --git a/Makefile.msc b/Makefile.msc
index 3b95d088d2..179215ecf4 100644
--- a/Makefile.msc
+++ b/Makefile.msc
@@ -2298,6 +2298,7 @@ TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_DEFAULT_PAGE_SIZE=1024
TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_ENABLE_STMTVTAB=1
TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_ENABLE_DBPAGE_VTAB=1
TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_ENABLE_JSON1=1
+TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_ENABLE_DESERIALIZE=1
TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) $(TEST_CCONV_OPTS)
TESTFIXTURE_SRC0 = $(TESTEXT) $(TESTSRC2)
@@ -2425,6 +2426,9 @@ testloadext.lo: $(TOP)\src\test_loadext.c $(SQLITE3H)
testloadext.dll: testloadext.lo
$(LD) $(LDFLAGS) $(LTLINKOPTS) $(LTLIBPATHS) /DLL /OUT:$@ testloadext.lo
+dbtotxt.exe: $(TOP)\tool\dbtotxt.c
+ $(LTLINK) $(NO_WARN) $(TOP)\tool\dbtotxt.c /link $(LDFLAGS) $(LTLINKOPTS)
+
showdb.exe: $(TOP)\tool\showdb.c $(SQLITE3C) $(SQLITE3H)
$(LTLINK) $(NO_WARN) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION \
$(TOP)\tool\showdb.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS)
diff --git a/ext/fts3/fts3_unicode2.c b/ext/fts3/fts3_unicode2.c
index 41027b2546..c0395d9cf6 100644
--- a/ext/fts3/fts3_unicode2.c
+++ b/ext/fts3/fts3_unicode2.c
@@ -178,28 +178,29 @@ static int remove_diacritic(int c, int bComplex){
62830, 62890, 62924, 62974, 63032, 63050, 63082, 63118,
63182, 63242, 63274, 63310, 63368, 63390,
};
+#define HIBIT ((char)0x80)
char aChar[] = {
- '\0', 'a'|0x00, 'c'|0x00, 'e'|0x00, 'i'|0x00, 'n'|0x00,
- 'o'|0x00, 'u'|0x00, 'y'|0x00, 'y'|0x00, 'a'|0x00, 'c'|0x00,
- 'd'|0x00, 'e'|0x00, 'e'|0x00, 'g'|0x00, 'h'|0x00, 'i'|0x00,
- 'j'|0x00, 'k'|0x00, 'l'|0x00, 'n'|0x00, 'o'|0x00, 'r'|0x00,
- 's'|0x00, 't'|0x00, 'u'|0x00, 'u'|0x00, 'w'|0x00, 'y'|0x00,
- 'z'|0x00, 'o'|0x00, 'u'|0x00, 'a'|0x00, 'i'|0x00, 'o'|0x00,
- 'u'|0x00, 'u'|0x80, 'a'|0x80, 'g'|0x00, 'k'|0x00, 'o'|0x00,
- 'o'|0x80, 'j'|0x00, 'g'|0x00, 'n'|0x00, 'a'|0x80, 'a'|0x00,
- 'e'|0x00, 'i'|0x00, 'o'|0x00, 'r'|0x00, 'u'|0x00, 's'|0x00,
- 't'|0x00, 'h'|0x00, 'a'|0x00, 'e'|0x00, 'o'|0x80, 'o'|0x00,
- 'o'|0x80, 'y'|0x00, '\0', '\0', '\0', '\0',
- '\0', '\0', '\0', '\0', 'a'|0x00, 'b'|0x00,
- 'c'|0x80, 'd'|0x00, 'd'|0x00, 'e'|0x80, 'e'|0x00, 'e'|0x80,
- 'f'|0x00, 'g'|0x00, 'h'|0x00, 'h'|0x00, 'i'|0x00, 'i'|0x80,
- 'k'|0x00, 'l'|0x00, 'l'|0x80, 'l'|0x00, 'm'|0x00, 'n'|0x00,
- 'o'|0x80, 'p'|0x00, 'r'|0x00, 'r'|0x80, 'r'|0x00, 's'|0x00,
- 's'|0x80, 't'|0x00, 'u'|0x00, 'u'|0x80, 'v'|0x00, 'w'|0x00,
- 'w'|0x00, 'x'|0x00, 'y'|0x00, 'z'|0x00, 'h'|0x00, 't'|0x00,
- 'w'|0x00, 'y'|0x00, 'a'|0x00, 'a'|0x80, 'a'|0x80, 'a'|0x80,
- 'e'|0x00, 'e'|0x80, 'e'|0x80, 'i'|0x00, 'o'|0x00, 'o'|0x80,
- 'o'|0x80, 'o'|0x80, 'u'|0x00, 'u'|0x80, 'u'|0x80, 'y'|0x00,
+ '\0', 'a', 'c', 'e', 'i', 'n',
+ 'o', 'u', 'y', 'y', 'a', 'c',
+ 'd', 'e', 'e', 'g', 'h', 'i',
+ 'j', 'k', 'l', 'n', 'o', 'r',
+ 's', 't', 'u', 'u', 'w', 'y',
+ 'z', 'o', 'u', 'a', 'i', 'o',
+ 'u', 'u'|HIBIT, 'a'|HIBIT, 'g', 'k', 'o',
+ 'o'|HIBIT, 'j', 'g', 'n', 'a'|HIBIT, 'a',
+ 'e', 'i', 'o', 'r', 'u', 's',
+ 't', 'h', 'a', 'e', 'o'|HIBIT, 'o',
+ 'o'|HIBIT, 'y', '\0', '\0', '\0', '\0',
+ '\0', '\0', '\0', '\0', 'a', 'b',
+ 'c'|HIBIT, 'd', 'd', 'e'|HIBIT, 'e', 'e'|HIBIT,
+ 'f', 'g', 'h', 'h', 'i', 'i'|HIBIT,
+ 'k', 'l', 'l'|HIBIT, 'l', 'm', 'n',
+ 'o'|HIBIT, 'p', 'r', 'r'|HIBIT, 'r', 's',
+ 's'|HIBIT, 't', 'u', 'u'|HIBIT, 'v', 'w',
+ 'w', 'x', 'y', 'z', 'h', 't',
+ 'w', 'y', 'a', 'a'|HIBIT, 'a'|HIBIT, 'a'|HIBIT,
+ 'e', 'e'|HIBIT, 'e'|HIBIT, 'i', 'o', 'o'|HIBIT,
+ 'o'|HIBIT, 'o'|HIBIT, 'u', 'u'|HIBIT, 'u'|HIBIT, 'y',
};
unsigned int key = (((unsigned int)c)<<3) | 0x00000007;
diff --git a/ext/fts5/fts5.h b/ext/fts5/fts5.h
index 037da64d42..8273785b15 100644
--- a/ext/fts5/fts5.h
+++ b/ext/fts5/fts5.h
@@ -414,11 +414,11 @@ struct Fts5ExtensionApi {
** the tokenizer substitutes "first" for "1st" and the query works
** as expected.
**
-**
By adding multiple synonyms for a single term to the FTS index.
-** In this case, when tokenizing query text, the tokenizer may
-** provide multiple synonyms for a single term within the document.
-** FTS5 then queries the index for each synonym individually. For
-** example, faced with the query:
+** By querying the index for all synonyms of each query term
+** separately. In this case, when tokenizing query text, the
+** tokenizer may provide multiple synonyms for a single term
+** within the document. FTS5 then queries the index for each
+** synonym individually. For example, faced with the query:
**
**
** ... MATCH 'first place'
@@ -442,7 +442,7 @@ struct Fts5ExtensionApi {
** "place".
**
** This way, even if the tokenizer does not provide synonyms
-** when tokenizing query text (it should not - to do would be
+** when tokenizing query text (it should not - to do so would be
** inefficient), it doesn't matter if the user queries for
** 'first + place' or '1st + place', as there are entries in the
** FTS index corresponding to both forms of the first token.
diff --git a/ext/fts5/fts5_unicode2.c b/ext/fts5/fts5_unicode2.c
index 9d3ffdc972..8bb1cd94fb 100644
--- a/ext/fts5/fts5_unicode2.c
+++ b/ext/fts5/fts5_unicode2.c
@@ -47,28 +47,29 @@ static int fts5_remove_diacritic(int c, int bComplex){
62830, 62890, 62924, 62974, 63032, 63050, 63082, 63118,
63182, 63242, 63274, 63310, 63368, 63390,
};
+#define HIBIT ((char)0x80)
char aChar[] = {
- '\0', 'a'|0x00, 'c'|0x00, 'e'|0x00, 'i'|0x00, 'n'|0x00,
- 'o'|0x00, 'u'|0x00, 'y'|0x00, 'y'|0x00, 'a'|0x00, 'c'|0x00,
- 'd'|0x00, 'e'|0x00, 'e'|0x00, 'g'|0x00, 'h'|0x00, 'i'|0x00,
- 'j'|0x00, 'k'|0x00, 'l'|0x00, 'n'|0x00, 'o'|0x00, 'r'|0x00,
- 's'|0x00, 't'|0x00, 'u'|0x00, 'u'|0x00, 'w'|0x00, 'y'|0x00,
- 'z'|0x00, 'o'|0x00, 'u'|0x00, 'a'|0x00, 'i'|0x00, 'o'|0x00,
- 'u'|0x00, 'u'|0x80, 'a'|0x80, 'g'|0x00, 'k'|0x00, 'o'|0x00,
- 'o'|0x80, 'j'|0x00, 'g'|0x00, 'n'|0x00, 'a'|0x80, 'a'|0x00,
- 'e'|0x00, 'i'|0x00, 'o'|0x00, 'r'|0x00, 'u'|0x00, 's'|0x00,
- 't'|0x00, 'h'|0x00, 'a'|0x00, 'e'|0x00, 'o'|0x80, 'o'|0x00,
- 'o'|0x80, 'y'|0x00, '\0', '\0', '\0', '\0',
- '\0', '\0', '\0', '\0', 'a'|0x00, 'b'|0x00,
- 'c'|0x80, 'd'|0x00, 'd'|0x00, 'e'|0x80, 'e'|0x00, 'e'|0x80,
- 'f'|0x00, 'g'|0x00, 'h'|0x00, 'h'|0x00, 'i'|0x00, 'i'|0x80,
- 'k'|0x00, 'l'|0x00, 'l'|0x80, 'l'|0x00, 'm'|0x00, 'n'|0x00,
- 'o'|0x80, 'p'|0x00, 'r'|0x00, 'r'|0x80, 'r'|0x00, 's'|0x00,
- 's'|0x80, 't'|0x00, 'u'|0x00, 'u'|0x80, 'v'|0x00, 'w'|0x00,
- 'w'|0x00, 'x'|0x00, 'y'|0x00, 'z'|0x00, 'h'|0x00, 't'|0x00,
- 'w'|0x00, 'y'|0x00, 'a'|0x00, 'a'|0x80, 'a'|0x80, 'a'|0x80,
- 'e'|0x00, 'e'|0x80, 'e'|0x80, 'i'|0x00, 'o'|0x00, 'o'|0x80,
- 'o'|0x80, 'o'|0x80, 'u'|0x00, 'u'|0x80, 'u'|0x80, 'y'|0x00,
+ '\0', 'a', 'c', 'e', 'i', 'n',
+ 'o', 'u', 'y', 'y', 'a', 'c',
+ 'd', 'e', 'e', 'g', 'h', 'i',
+ 'j', 'k', 'l', 'n', 'o', 'r',
+ 's', 't', 'u', 'u', 'w', 'y',
+ 'z', 'o', 'u', 'a', 'i', 'o',
+ 'u', 'u'|HIBIT, 'a'|HIBIT, 'g', 'k', 'o',
+ 'o'|HIBIT, 'j', 'g', 'n', 'a'|HIBIT, 'a',
+ 'e', 'i', 'o', 'r', 'u', 's',
+ 't', 'h', 'a', 'e', 'o'|HIBIT, 'o',
+ 'o'|HIBIT, 'y', '\0', '\0', '\0', '\0',
+ '\0', '\0', '\0', '\0', 'a', 'b',
+ 'c'|HIBIT, 'd', 'd', 'e'|HIBIT, 'e', 'e'|HIBIT,
+ 'f', 'g', 'h', 'h', 'i', 'i'|HIBIT,
+ 'k', 'l', 'l'|HIBIT, 'l', 'm', 'n',
+ 'o'|HIBIT, 'p', 'r', 'r'|HIBIT, 'r', 's',
+ 's'|HIBIT, 't', 'u', 'u'|HIBIT, 'v', 'w',
+ 'w', 'x', 'y', 'z', 'h', 't',
+ 'w', 'y', 'a', 'a'|HIBIT, 'a'|HIBIT, 'a'|HIBIT,
+ 'e', 'e'|HIBIT, 'e'|HIBIT, 'i', 'o', 'o'|HIBIT,
+ 'o'|HIBIT, 'o'|HIBIT, 'u', 'u'|HIBIT, 'u'|HIBIT, 'y',
};
unsigned int key = (((unsigned int)c)<<3) | 0x00000007;
diff --git a/ext/rbu/rbu_common.tcl b/ext/rbu/rbu_common.tcl
index 2b263b7660..b5e63aafe5 100644
--- a/ext/rbu/rbu_common.tcl
+++ b/ext/rbu/rbu_common.tcl
@@ -86,12 +86,13 @@ proc step_rbu_legacy {target rbu} {
set rc
}
-proc do_rbu_vacuum_test {tn step} {
- forcedelete state.db
- uplevel [list do_test $tn.1 {
- if {$step==0} { sqlite3rbu_vacuum rbu test.db state.db }
+proc do_rbu_vacuum_test {tn step {statedb state.db}} {
+ forcedelete $statedb
+ if {$statedb=="" && $step==1} breakpoint
+ uplevel [list do_test $tn.1 [string map [list %state% $statedb] {
+ if {$step==0} { sqlite3rbu_vacuum rbu test.db {%state%}}
while 1 {
- if {$step==1} { sqlite3rbu_vacuum rbu test.db state.db }
+ if {$step==1} { sqlite3rbu_vacuum rbu test.db {%state%}}
set state [rbu state]
check_prestep_state test.db $state
set rc [rbu step]
@@ -100,7 +101,7 @@ proc do_rbu_vacuum_test {tn step} {
if {$step==1} { rbu close }
}
rbu close
- } {SQLITE_DONE}]
+ }] {SQLITE_DONE}]
uplevel [list do_execsql_test $tn.2 {
PRAGMA integrity_check
diff --git a/ext/rbu/rbuvacuum2.test b/ext/rbu/rbuvacuum2.test
index 4713580c70..6d6dfde9b9 100644
--- a/ext/rbu/rbuvacuum2.test
+++ b/ext/rbu/rbuvacuum2.test
@@ -16,8 +16,11 @@
source [file join [file dirname [info script]] rbu_common.tcl]
-foreach step {0 1} {
- set ::testprefix rbuvacuum2-$step
+foreach {step} {0 1} {
+foreach {ttt state} {
+ s state.db t test.db-vacuum n {}
+} {
+ set ::testprefix rbuvacuum2-$step$ttt
#-------------------------------------------------------------------------
# Test that a database that contains fts3 tables can be vacuumed.
@@ -29,7 +32,7 @@ foreach step {0 1} {
INSERT INTO t1 VALUES('fix this issue', 'at some point');
}
- do_rbu_vacuum_test 1.2 $step
+ do_rbu_vacuum_test 1.2 $step $state
do_execsql_test 1.3 {
SELECT * FROM t1;
@@ -46,7 +49,7 @@ foreach step {0 1} {
INSERT INTO t1 VALUES('a b c', 'x y z');
}
- do_rbu_vacuum_test 1.6 $step
+ do_rbu_vacuum_test 1.6 $step $state
do_execsql_test 1.7 {
INSERT INTO t1(t1) VALUES('integrity-check');
SELECT * FROM t1;
@@ -67,7 +70,7 @@ foreach step {0 1} {
INSERT INTO t1 VALUES('fix this issue', 'at some point');
}
- do_rbu_vacuum_test 2.2 $step
+ do_rbu_vacuum_test 2.2 $step $state
do_execsql_test 2.3 {
SELECT * FROM t1;
@@ -84,7 +87,7 @@ foreach step {0 1} {
INSERT INTO t1 VALUES('a b c', 'x y z');
}
- do_rbu_vacuum_test 2.6 $step
+ do_rbu_vacuum_test 2.6 $step $state
do_execsql_test 2.7 {
INSERT INTO t1(t1) VALUES('integrity-check');
SELECT * FROM t1;
@@ -107,7 +110,7 @@ foreach step {0 1} {
INSERT INTO rt VALUES(3, 55, 65);
}
- do_rbu_vacuum_test 3.2 $step
+ do_rbu_vacuum_test 3.2 $step $state
do_execsql_test 3.3 {
SELECT * FROM rt;
@@ -120,7 +123,7 @@ foreach step {0 1} {
SELECT rowid FROM rt WHERE x2>59 AND x1 < 59
} {2 3}
- do_rbu_vacuum_test 3.5 $step
+ do_rbu_vacuum_test 3.5 $step $state
do_execsql_test 3.6.1 {
SELECT rowid FROM rt WHERE x2>51 AND x1 < 51
@@ -147,7 +150,7 @@ foreach step {0 1} {
trigger tr1 t1 0 {CREATE TRIGGER tr1 AFTER INSERT ON t1 BEGIN SELECT 1; END}
}
- do_rbu_vacuum_test 4.3 $step
+ do_rbu_vacuum_test 4.3 $step $state
do_execsql_test 4.4 {
SELECT * FROM sqlite_master;
} {
@@ -157,6 +160,7 @@ foreach step {0 1} {
}
}
}
+}
#-------------------------------------------------------------------------
# Test that passing a NULL value as the second argument to
@@ -231,4 +235,9 @@ do_test 6.3 {
execsql { PRAGMA integrity_check }
} {ok}
+do_test 6.4 {
+ sqlite3rbu_vacuum rbu test.db test.db-vactmp
+ list [catch { rbu close } msg] $msg
+} {1 SQLITE_MISUSE}
+
finish_test
diff --git a/ext/rbu/sqlite3rbu.c b/ext/rbu/sqlite3rbu.c
index cd2f96c51b..7683c3464b 100644
--- a/ext/rbu/sqlite3rbu.c
+++ b/ext/rbu/sqlite3rbu.c
@@ -2477,7 +2477,7 @@ static void rbuOpenDatabase(sqlite3rbu *p, int *pbRetry){
if( *zExtra=='\0' ) zExtra = 0;
}
- zTarget = sqlite3_mprintf("file:%s-vacuum?rbu_memory=1%s%s",
+ zTarget = sqlite3_mprintf("file:%s-vactmp?rbu_memory=1%s%s",
sqlite3_db_filename(p->dbRbu, "main"),
(zExtra==0 ? "" : "&"), (zExtra==0 ? "" : zExtra)
);
@@ -3743,6 +3743,12 @@ sqlite3rbu *sqlite3rbu_vacuum(
const char *zState
){
if( zTarget==0 ){ return rbuMisuseError(); }
+ if( zState ){
+ int n = strlen(zState);
+ if( n>=7 && 0==memcmp("-vactmp", &zState[n-7], 7) ){
+ return rbuMisuseError();
+ }
+ }
/* TODO: Check that both arguments are non-NULL */
return openRbuHandle(0, zTarget, zState);
}
diff --git a/ext/rbu/sqlite3rbu.h b/ext/rbu/sqlite3rbu.h
index 1acbcca469..69d89500a0 100644
--- a/ext/rbu/sqlite3rbu.h
+++ b/ext/rbu/sqlite3rbu.h
@@ -333,7 +333,11 @@ SQLITE_API sqlite3rbu *sqlite3rbu_open(
** name of the state database is "-vacuum", where
** is the name of the target database file. In this case, on UNIX, if the
** state database is not already present in the file-system, it is created
-** with the same permissions as the target db is made.
+** with the same permissions as the target db is made.
+**
+** With an RBU vacuum, it is an SQLITE_MISUSE error if the name of the
+** state database ends with "-vactmp". This name is reserved for internal
+** use.
**
** This function does not delete the state database after an RBU vacuum
** is completed, even if it created it. However, if the call to
diff --git a/ext/rbu/test_rbu.c b/ext/rbu/test_rbu.c
index e0b4d77af0..6d04bfe8cc 100644
--- a/ext/rbu/test_rbu.c
+++ b/ext/rbu/test_rbu.c
@@ -273,6 +273,7 @@ static int SQLITE_TCLAPI test_sqlite3rbu_vacuum(
zCmd = Tcl_GetString(objv[1]);
zTarget = Tcl_GetString(objv[2]);
if( objc==4 ) zStateDb = Tcl_GetString(objv[3]);
+ if( zStateDb && zStateDb[0]=='\0' ) zStateDb = 0;
pRbu = sqlite3rbu_vacuum(zTarget, zStateDb);
Tcl_CreateObjCommand(interp, zCmd, test_sqlite3rbu_cmd, (ClientData)pRbu, 0);
diff --git a/ext/session/sqlite3session.c b/ext/session/sqlite3session.c
index fdd75818d8..6791c6fbd4 100644
--- a/ext/session/sqlite3session.c
+++ b/ext/session/sqlite3session.c
@@ -1161,7 +1161,7 @@ static void sessionPreupdateOneChange(
int iHash;
int bNull = 0;
int rc = SQLITE_OK;
- SessionStat1Ctx stat1 = {0};
+ SessionStat1Ctx stat1 = {{0,0,0,0,0},0};
if( pSession->rc ) return;
diff --git a/main.mk b/main.mk
index 270f9c48b4..3a6ff16d51 100644
--- a/main.mk
+++ b/main.mk
@@ -980,6 +980,9 @@ $(TEST_EXTENSION): $(TOP)/src/test_loadext.c
extensiontest: testfixture$(EXE) $(TEST_EXTENSION)
./testfixture$(EXE) $(TOP)/test/loadext.test
+dbtotxt$(EXE): $(TOP)/tool/dbtotxt.c
+ $(TCC) -o dbtotxt$(EXE) $(TOP)/tool/dbtotxt.c
+
showdb$(EXE): $(TOP)/tool/showdb.c sqlite3.o
$(TCC) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION -o showdb$(EXE) \
$(TOP)/tool/showdb.c sqlite3.o $(THREADLIB)
diff --git a/manifest b/manifest
index 60f0c0236a..735edc7a3f 100644
--- a/manifest
+++ b/manifest
@@ -1,10 +1,10 @@
-C Merge\sfixes\sfrom\strunk.
-D 2018-12-06T03:13:02.222
+C Merge\slatest\sbegin-concurrent\schanges\sinto\sthis\sbranch.
+D 2018-12-18T17:47:53.703
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
-F Makefile.in 68d0ba0f0b533d5bc84c78c13a6ce84ee81183a67014caa47a969e67f028fa1c
+F Makefile.in d8b254f8bb81bab43c340d70d17dc3babab40fcc8a348c8255881f780a45fee6
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
-F Makefile.msc b7d4a710fa3f0b8cfc532ff195b85dc1ba2a8ad34343cb3d67639f28f0a24306
+F Makefile.msc 3c4c7e94419ff28cb68850188c9d153b343aed4c5ebed5965426232ed67ff9d9
F README.md 377233394b905d3b2e2b33741289e093bc93f2e7adbe00923b2c5958c9a9edee
F VERSION 453e2f4529ca208196d5567db28d549d7151f79efd33f6e6cfe6e613e583a0be
F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50
@@ -97,7 +97,7 @@ F ext/fts3/fts3_tokenizer.c a22bf311a71f3efa9d7012d8cc48fc9b0f3dace7
F ext/fts3/fts3_tokenizer.h 64c6ef6c5272c51ebe60fc607a896e84288fcbc3
F ext/fts3/fts3_tokenizer1.c 5c98225a53705e5ee34824087478cf477bdb7004
F ext/fts3/fts3_unicode.c b1902e9ad47a6569fbb8ecb5ce52f20fe59b590d5c5e3bbdd56b10b03bdf632b
-F ext/fts3/fts3_unicode2.c 90e65f4291c8ecceee284ecc8d5d48734e95ecd4b008e06f36f14e77f93d655f
+F ext/fts3/fts3_unicode2.c e49f9e015f239bf5faf2f4fa483bbf1b08a9978f0ad1f31159d952f8b8a10d08
F ext/fts3/fts3_write.c a85bc4885fde7f1b44c9de013b62f7cd3332dc59e208053d878729b1d04745bc
F ext/fts3/fts3speed.tcl b54caf6a18d38174f1a6e84219950d85e98bb1e9
F ext/fts3/mkfts3amal.tcl 252ecb7fe6467854f2aa237bf2c390b74e71f100
@@ -108,7 +108,7 @@ F ext/fts3/unicode/UnicodeData.txt cd07314edb62d49fde34debdaf92fa2aa69011e7
F ext/fts3/unicode/mkunicode.tcl 2ea30d8122ccf1e33142c9cc8913d8cad9eb6668db359a228f10aeb37e2ab863
F ext/fts3/unicode/parseunicode.tcl a981bd6466d12dd17967515801c3ff23f74a281be1a03cf1e6f52a6959fc77eb
F ext/fts5/extract_api_docs.tcl a36e54ec777172ddd3f9a88daf593b00848368e0
-F ext/fts5/fts5.h 5edc74ca603d71284d475886e6e91b5c5cf2e8e93e9ba3a36ba2f2440ee97948
+F ext/fts5/fts5.h 4f5d19b7973dae23de368728f06d3eb1fe9f5cca2990366b40e9379996f35e61
F ext/fts5/fts5Int.h 39f12034b598df4e0f59bbe6cf03af03a905a534b04f182d155641a04e1eb797
F ext/fts5/fts5_aux.c ca666a3bbe07c5a3bbe9fffaea19c935a1efaf337333e28bad7bdd1971ffd093
F ext/fts5/fts5_buffer.c 1dd1ec0446b3acfc2d7d407eb894762a461613e2695273f48e449bfd13e973ff
@@ -122,7 +122,7 @@ F ext/fts5/fts5_tcl.c 39bcbae507f594aad778172fa914cad0f585bf92fd3b078c686e249282
F ext/fts5/fts5_test_mi.c 65864ba1e5c34a61d409c4c587e0bbe0466eb4f8f478d85dc42a92caad1338e6
F ext/fts5/fts5_test_tok.c 80de1a4b1a3caa216c3be8862440f0117a8357dd9b7cfc5a2a2ce11fe6eb64ae
F ext/fts5/fts5_tokenize.c ca2b6a033794945ac505241a86b0aa978709c23aa2e6121984d3e3ede96003c8
-F ext/fts5/fts5_unicode2.c 26519f47d567c5a9b08c376edd38f1b8a773b45ff29f1ffd81d9edfe20f96e18
+F ext/fts5/fts5_unicode2.c 03bc8ebf44d825d0b7ac519f7b16139cf8e879ae7a27e62fb6326f0d68e8bdd3
F ext/fts5/fts5_varint.c a5aceacda04dafcbae725413d7a16818ecd65738
F ext/fts5/fts5_vocab.c fbe38044889b2d2d99babeeef239c620fb0332bb928a84506ac748d81500b354
F ext/fts5/fts5parse.y eb526940f892ade5693f22ffd6c4f2702543a9059942772526eac1fde256bb05
@@ -330,7 +330,7 @@ F ext/rbu/rbu9.test 0e4d985e25620d61920597e8ea69c871c9e8c1f5a0be2ae9fa70bb641d74
F ext/rbu/rbuA.test b34a90cb495682c25b5fc03a9d5e7a4fc99541c29256f25e2e2a4f6542b4f5b3
F ext/rbu/rbuB.test 52b07158824c6927b7e25554ace92a695cdebfc296ae3d308ac386984aded9bc
F ext/rbu/rbuC.test 80f1cc2fb74f44b1128fd0ed8eedab3a76fefeb72a947860e2869ef76fc8dc6b
-F ext/rbu/rbu_common.tcl acfb7fbbaf8d46a9f6f6a5ec795616c84d705e1565d918afe43f0ff53ea0efa5
+F ext/rbu/rbu_common.tcl 4b3d033b3e3844292ae3a1aefc0e524e64b0db5a0e4310657919e4504ac3073f
F ext/rbu/rbucollate.test cac528a9a46318cba42e61258bb42660bbbf4fdb9a8c863de5a54ad0c658d197
F ext/rbu/rbucrash.test 000981a1fe8a6e4d9a684232f6a129e66a3ef595f5ed74655e2f9c68ffa613b4
F ext/rbu/rbucrash2.test efa143cc94228eb0266d3f1abfbee60a5838a84cef7cc3fcb8c145b74d96fd41
@@ -348,10 +348,10 @@ F ext/rbu/rbusave.test f4190a1a86fccf84f723af5c93813365ae33feda35845ba107b59683d
F ext/rbu/rbusplit.test b37e7b40b38760881dc9c854bd40b4744c6b6cd74990754eca3bda0f407051e8
F ext/rbu/rbutemplimit.test 7f408f49b90fa0a720d7599f3aec74a3c85e6cd78e56fdf726ce00af9147a341
F ext/rbu/rbuvacuum.test 55e101e90168c2b31df6c9638fe73dc7f7cc666b6142266d1563697d79f73534
-F ext/rbu/rbuvacuum2.test 0a7669bbabdaeed915f02f59f33fe20e13d4932ba2086fe00a82064d9424c80b
-F ext/rbu/sqlite3rbu.c 71f8c09948d09ec9c5a8dbe7127e8ef61ef0853e698b2650be2485ac7b9c75c8
-F ext/rbu/sqlite3rbu.h b42bcd4d8357268c6c39ab2a60b29c091e89328fa8cc49c8fac5ab8d007e79b2
-F ext/rbu/test_rbu.c baa23eb28457580673d2175e5f0c29ced0cd320ee819b13ad362398c53b96e90
+F ext/rbu/rbuvacuum2.test b8e5b51dc8b2c0153373d024c0936be3f66f9234acbd6d0baab0869d56b14e6b
+F ext/rbu/sqlite3rbu.c f722ed4177c9fb73f2f6f116240687ac7603735fa95ea63bff71827929d4c192
+F ext/rbu/sqlite3rbu.h 1dc88ab7bd32d0f15890ea08d23476c4198d3da3056985403991f8c9cd389812
+F ext/rbu/test_rbu.c 03f6f177096a5f822d68d8e4069ad8907fe572c62ff2d19b141f59742821828a
F ext/repair/README.md 92f5e8aae749a4dae14f02eea8e1bb42d4db2b6ce5e83dbcdd6b1446997e0c15
F ext/repair/checkfreelist.c 0dbae18c1b552f58d64f8969e4fb1e7f11930c60a8c2a9a8d50b7f15bdfd54bd
F ext/repair/checkindex.c 7d28c01a2e012ac64257d230fc452b2cafb78311a91a343633d01d95220f66f3
@@ -424,7 +424,7 @@ F ext/session/sessionstat1.test 218d351cf9fcd6648f125a26b607b140310160184723c266
F ext/session/sessionwor.test 07f0b304dc4df5454906069140bf6ec67edcaa3c548f3683354003cf2c22b64a
F ext/session/sqlite3changebatch.c d5553b79e012ee2cb06c0a96bdf9dfe19e66354390ea0036cc46c4953142d517
F ext/session/sqlite3changebatch.h e72016998c9a22d439ddfd547b69e1ebac810c24
-F ext/session/sqlite3session.c 133b7aec935c77c3ff669e65a85eb763503d1f7107ceb7fcc26df1a6cd8124dc
+F ext/session/sqlite3session.c 994b1b691f3e1ab72a9d3949c2ca7dca4db3d9dd5ece5e34f74953411b8d36f9
F ext/session/sqlite3session.h 2a449bb4ba954dd374bd8524af6187454f98fa1d61d16a9f6709ce0a191cf4f1
F ext/session/test_session.c 60e15d5db8ae7a0f521e70a7504ba1f74fc50548a25a5397808f487bc6a92b5d
F ext/userauth/sqlite3userauth.h 7f3ea8c4686db8e40b0a0e7a8e0b00fac13aa7a3
@@ -433,7 +433,7 @@ F ext/userauth/userauth.c f81aa5a3ecacf406f170c62a144405858f6f6de51dbdc0920134e6
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60
-F main.mk 7c4484f59dc2ccf831c9786b9eb4e8131d63b80328e1d92ddefaee6284f26386
+F main.mk be737c1457eec866ccf269800c54f9cf619d0d881a9c630936168d95fcfeef60
F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83
F mptest/config01.test 3c6adcbc50b991866855f1977ff172eb6d901271
F mptest/config02.test 4415dfe36c48785f751e16e32c20b077c28ae504
@@ -452,7 +452,7 @@ F src/auth.c 0fac71038875693a937e506bceb492c5f136dd7b1249fbd4ae70b4e8da14f9df
F src/backup.c 78d3cecfbe28230a3a9a1793e2ead609f469be43e8f486ca996006be551857ab
F src/bitvec.c 8433d9e98dd6f2ea3286e0d2fe5d65de1bfc18a706486eb2026b01be066b5806
F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6
-F src/btree.c 4a2184be69d491d4b0228d4e397d67cb0802bbec06e7615b485ea1af69a131f6
+F src/btree.c 1cd5a483fb171ed486ce6fa4d456e9da7af6f70a7806ee22fc6322746de98cea
F src/btree.h 1ed41c71481a1196a520064f2282bc13d768bbd8ae2850e319a3048f8ee7cb3d
F src/btreeInt.h 6c65e6c96f561596f6870c79a64d4706af81613881d7947e3f063e923f14115f
F src/build.c a5402bf34cb8e4cde86f6c6fc0356a5d26a6d561b647464c13ef3366f545b56e
@@ -463,7 +463,7 @@ F src/date.c ebe1dc7c8a347117bb02570f1a931c62dd78f4a2b1b516f4837d45b7d6426957
F src/dbpage.c 135eb3b5e74f9ef74bde5cec2571192c90c86984fa534c88bf4a055076fa19b7
F src/dbstat.c 3c8bd4e77f0244fd2bd7cc90acf116ad2f8e82d70e536637f35ac2bc99b726f9
F src/delete.c f7938125847e8ef485448db5fbad29acb2991381a02887dd854c1617315ab9fb
-F src/expr.c a3e90131d7f92b77a6a6ae2e71f0d2882237041ed11dbe3c914e5e278ddc2d24
+F src/expr.c b84c41530d97e28d5c43149d23d4492e26cd4e1e93abba1302d361e71a04b614
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
F src/fkey.c 972a4ba14296bef2303a0abbad1e3d82bc3c61f9e6ce4e8e9528bdee68748812
F src/func.c 8efa2c813b3f6a831a070311b5bcbc97993b79cbcd274bdb49bde56ccd3d37bc
@@ -474,8 +474,8 @@ F src/hwtime.h 747c1bbe9df21a92e9c50f3bbec1de841dc5e5da
F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
F src/insert.c f12f27eb606d601825be9a229a7390a8d64d40226697883f96de8e088d620055
F src/legacy.c 134ab3e3fae00a0f67a5187981d6935b24b337bcf0f4b3e5c9fa5763da95bf4e
-F src/loadext.c 9050dd153b5583804184be9c9dee9ebb554178d6db1f8ac280899e8aad9060e6
-F src/main.c 423fce7ca924c8aa04d2844de4775129109172aeb912eeb4606fb1157301297e
+F src/loadext.c e6f10875d52aca3b7e57ce1ec174aeafc9b6c00b43000cd30d791f9cb490b7a6
+F src/main.c 65f0e265a9f4f3b975f731247d035e15c4f805748d12c8a9ddd7a2d8d73a4789
F src/malloc.c 07295435093ce354c6d9063ac05a2eeae28bd251d2e63c48b3d67c12c76f7e18
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
F src/mem1.c c12a42539b1ba105e3707d0e628ad70e611040d8f5e38cf942cee30c867083de
@@ -500,28 +500,28 @@ F src/os_win.c 85d9e532d0444ab6c16d7431490c2e279e282aa0917b0e988996b1ae0de5c5a0
F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
F src/pager.c 79b8ced46a3c32be19ab4b00d8836292e460411d283a333cb008923c69fbca6a
F src/pager.h 389ba8f526d13026aa7081dc581aa742eb7207e3277e7106c522c5b65ad92590
-F src/parse.y 9281e9941d5df0f7978c4bfe1521090ba7363ac4535c79f57531ba0194904d43
+F src/parse.y 8206217fe7fa96652aa1b8a797246e23b30a9d4c1a5175d9c12b13750f51dc2f
F src/pcache.c 696a01f1a6370c1b50a09c15972bc3bee3333f8fcd1f2da8e9a76b1b062c59ee
F src/pcache.h 4f87acd914cef5016fae3030343540d75f5b85a1877eed1a2a19b9f284248586
-F src/pcache1.c ad0ffc5b35b0280d045ac569d34d4b842e3e6a4a118f6396b320987a0957afcc
-F src/pragma.c 4e056f042683b99c4ea0db395f68d051b1a95833ab40951c40d3ef7e1fee1354
+F src/pcache1.c ddc9fc7d9861cf3a1f30660264b76b1ae9e1dce5dbba085cf001d5cb6b41cf8c
+F src/pragma.c 96ce7dce4dc9cb2b7aa0e1b2ce7536870bdc00b10becc278245e775489447ea0
F src/pragma.h 7003ea8e45e5da0a7cd6d35846214f9ae9ecf5be66b268415ceea5855324af11
-F src/prepare.c 66b5f9791a3ef57131cbba58c33104ebea814a70a5cfcafabf5aed5a3e3858fe
+F src/prepare.c 0e8fc0deaf36da104e08d07ce7d97bc09ab57d078b399381532fec3fa1d3f2bb
F src/printf.c 0f1177cf1dd4d7827bf64d840768514ec76409abecaca9e8b577dbd065150381
F src/random.c f27af4099afaea7284ade5c206224dcfdb2334cfd119d018b470d46356b3f27d
-F src/resolve.c 976e7879286a1eecdc71ceff64f6d1b3f58c8f8096537ba668b3dc0887f410c1
+F src/resolve.c 72fe8cae7326b979e7258ab4c531956951e1a5f3fe8644c646abaec1b2eb6d95
F src/rowset.c d977b011993aaea002cab3e0bb2ce50cf346000dff94e944d547b989f4b1fe93
-F src/select.c e1cad752987c476a9d1d053682558caec048ea799ef7ba1b6e38e2266451010d
-F src/shell.c.in 1f0819e69fb1ebd2eb44695530dc43936608bf9b752981a0ffd4e2e4a9e3883d
-F src/sqlite.h.in 0880d9e366c2b0e1cbc40d32c2671e67c7bc7e9cb7f7298956c254ca8845c702
+F src/select.c ca760497a7a0263b29ca4001760eac53de7c05b0b9edb12adeae1a1c44466779
+F src/shell.c.in 207da30342db0b6fac8b2487abd60b059a5ea80cc9494bd1db76a1dd4aae7cca
+F src/sqlite.h.in 846968c2880c2223e0d65c544698fedcf45bbddc52693a9b020519725690e1fd
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
F src/sqlite3ext.h 960f1b86c3610fa23cb6a267572a97dcf286e77aa0dd3b9b23292ffaa1ea8683
-F src/sqliteInt.h c319213f1263293c6d569f73fc00fe4e7b1f95e20f5b626a624d0119046748de
+F src/sqliteInt.h 05dd8ce0e386ced2138087b618de585061c0da4475dfe14f578fbe254e1efd4b
F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b
F src/status.c 46e7aec11f79dad50965a5ca5fa9de009f7d6bde08be2156f1538a0a296d4d0e
F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34
F src/tclsqlite.c e72862a271348d779672b45a730c33fd0c535e630ff927e8ce4a0c908d1d28c6
-F src/test1.c 7928f1eb530dac8da21dc7f1e18935988f1f0e3e2a2d99993b522c4fb201d71b
+F src/test1.c 457b9b838edecaceb536f626418de90b2f27fdccb36dad2673e5022a9c5e1c33
F src/test2.c 3efb99ab7f1fc8d154933e02ae1378bac9637da5
F src/test3.c 61798bb0d38b915067a8c8e03f5a534b431181f802659a6616f9b4ff7d872644
F src/test4.c 18ec393bb4d0ad1de729f0b94da7267270f3d8e6
@@ -574,19 +574,19 @@ F src/test_windirent.h 90dfbe95442c9762357fe128dc7ae3dc199d006de93eb33ba3972e0a9
F src/test_window.c cdae419fdcea5bad6dcd9368c685abdad6deb59e9fc8b84b153de513d394ba3f
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c
-F src/tokenize.c 9e781e1ca80eefe7b5d6a9e2cd5c678c847da55fd6f093781fad7950934d4c83
+F src/tokenize.c c8af4feebd8bf5a4d60a14018d91f61013f658ec864dfce7661bae73d86b3191
F src/treeview.c 7b12ac059de54c939b6eb0dbffc9410c29c80d2470cee5cbe07d5ff9ea2d9253
F src/trigger.c d3d78568f37fb2e6cdcc2d1e7b60156f15b0b600adec55b83c5d42f6cad250bd
F src/update.c 31d5208f7c8b129a355ce797bdd2fd70511d18ca6883c77aa816eb4fe486b687
F src/upsert.c 0dd81b40206841814d46942a7337786932475f085716042d0cb2fc7791bf8ca4
F src/utf.c 810fbfebe12359f10bc2a011520a6e10879ab2a163bcb26c74768eab82ea62a5
F src/util.c d9eb0a6c4aae1b00a7369eadd7ca0bbe946cb4c953b6751aa20d357c2f482157
-F src/vacuum.c 8747a99e0687ae5cb3515b70a9d82bbd20370de9f097c7bd93a392ece3dea03c
-F src/vdbe.c d2672a54cc283e1425cc8c7c45271530b3686b8b5f06bf4426d9a5812e951abe
-F src/vdbe.h 5081dcc497777efe5e9ebe7330d283a044a005e4bdda2e2e984f03bf89a0d907
-F src/vdbeInt.h 437e6c6af679fdf157867eb83a8adc6cf5145d6774453c2214cfd0bd01d92980
-F src/vdbeapi.c 9709452bee82963e1f7f1f5d0c71db823d553f8dbb2c47a911c4983d537a1947
-F src/vdbeaux.c b3c364b1cfb9cda13bf86d571c572ff89ffefa89bbfc9a506731214a004789a8
+F src/vacuum.c ae2152420bad05336d86bb3b4a8a32ddb12b22ae19e5a976bee5f0a775429efb
+F src/vdbe.c 256dbfc0486462fda6d56daeac817c2d67c9823d89d139e3a673ce24b6fc2e20
+F src/vdbe.h 8990d668a89890a33326b0a29b992c4014b72f3b6cdcd9ee0e190593c247f9b0
+F src/vdbeInt.h 73f5051923f3f29779bfc374c0c68e23b8e5e3792def2e33e51b427edb890abd
+F src/vdbeapi.c 57a2d794a8833f269b878dbc24e955369bdb379af6c4e93ebc5ce1a20fa3daf4
+F src/vdbeaux.c 9f2a251e610ec962dca093e8d9644a5243be606c5f78a4a16582bd9edef50e1f
F src/vdbeblob.c f5c70f973ea3a9e915d1693278a5f890dc78594300cf4d54e64f2b0917c94191
F src/vdbemem.c 7b3305bc4a5139f4536ac9b5f61da0f915e49d2e3fdfa87dfdfa9d7aba8bc1e9
F src/vdbesort.c 90aad5a92608f2dd771c96749beabdb562c9d881131a860a7a5bccf66dc3be7f
@@ -599,8 +599,8 @@ F src/walker.c fb94aadc9099ff9c6506d0a8b88d51266005bcaa265403f3d7caf732a562eb66
F src/where.c 3818e8a736a05d2cb194e64399af707e367fbcc5c251d785804d02eaf121288e
F src/whereInt.h f125f29fca80890768e0b2caa14f95db74b2dacd3a122a168f97aa7b64d6968f
F src/wherecode.c c45f03aefc2266b990df0fc4d7acc4e27f56f881f4fc0fc355b7cbc4d7189da5
-F src/whereexpr.c 491f0894ad9903750cdecb7894437a0cabdffdd88f574d2b1c9ac85d14fe4b9c
-F src/window.c 6550e2850ebced51100ef83d49b00a1cf03f81a482dafedafb0320df647ed8fc
+F src/whereexpr.c 36b47f7261d6b6f1a72d774c113b74beddf6745aba1018e64b196e29db233442
+F src/window.c ea81ecd031ed2cbc14b7db6fd7f4bee2471b894feae5fea0547b15b1e2dd8fb2
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
F test/affinity2.test a6d901b436328bd67a79b41bb0ac2663918fe3bd
F test/affinity3.test 6a101af2fc945ce2912f6fe54dd646018551710d
@@ -732,7 +732,7 @@ F test/colmeta.test 2c765ea61ee37bc43bbe6d6047f89004e6508eb1
F test/colname.test fb28b3687e03625425bc216edf8b186ce974aa71008e2aa1f426a7dcb75a601d
F test/concfault.test 500f17c3fcfe7705114422bcc6ddd3c740001a43
F test/concurrent.test 86661967a680670127a62a819e60dc93c2d3d49043ac95b26dfa70d3e60dbde5
-F test/concurrent2.test 9dfbeb0a323733fe1d13443371734bb94a674dbf777f464365475903873111f8
+F test/concurrent2.test de748c7dd749c77e2af2c4b914b9b09a28ac09608042ca498c0251dc6f46aa1a
F test/concurrent3.test 530671ac706f6a1d0f4992dbdd33a86408330d03cd90fb9e82ecb1b27f5fd081
F test/concurrent4.test e0b12cd467137e50259df3b4f837507e82aaa07c35941c88664dc8ed1d089c44
F test/concurrent5.test 0c16cbf7446af162a14e6def30445e94016064eb994e5aa4ebb2bebc59554176
@@ -786,8 +786,9 @@ F test/dataversion1.test 6e5e86ac681f0782e766ebcb56c019ae001522d114e0e111e5ebf68
F test/date.test 9b73bbeb1b82d9c1f44dec5cf563bf7da58d2373
F test/date2.test 74c234bece1b016e94dd4ef9c8cc7a199a8806c0e2291cab7ba64bace6350b10
F test/dbfuzz.c 73047c920d6210e5912c87cdffd9a1c281d4252e
+F test/dbfuzz001.test 96b52856ffce5442e404847de33487db5ce49aa27778497a42328d5acf6859d7
F test/dbfuzz2-seed1.db e6225c6f3d7b63f9c5b6867146a5f329d997ab105bee64644dc2b3a2f2aebaee
-F test/dbfuzz2.c 652f85bac1770e927da139db513234a3eba308f72ac2f8b32f0093d7d19def70
+F test/dbfuzz2.c b8ed9b32a1f287505e55970e55203bedcb9170f137ecefa2254033c9faccdfba
F test/dbpage.test 650234ba683b9d82b899c6c51439819787e7609f17a0cc40e0080a7b6443bc38
F test/dbstatus.test cd83aa623b8aab477269bc94cf8aa90c1e195a144561dd04a1620770aaa8524e
F test/dbstatus2.test f5fe0afed3fa45e57cfa70d1147606c20d2ba23feac78e9a172f2fe8ab5b78ef
@@ -983,16 +984,17 @@ F test/fuzz-oss1.test e58330d01cbbd8215ee636b17a03fe220b37dbfa
F test/fuzz.test 96083052bf5765e4518c1ba686ce2bab785670d1
F test/fuzz2.test 76dc35b32b6d6f965259508508abce75a6c4d7e1
F test/fuzz3.test 9c813e6613b837cb7a277b0383cd66bfa07042b4cf0317157c35852f30043c31
+F test/fuzz4.test c229bcdb45518a89e1d208a21343e061503460ac69fae1539320a89f572eb634
F test/fuzz_common.tcl a87dfbb88c2a6b08a38e9a070dabd129e617b45b
F test/fuzz_malloc.test f348276e732e814802e39f042b1f6da6362a610af73a528d8f76898fde6b22f2
-F test/fuzzcheck.c fda41c0e4e667fae96b002410bb19cece7a33314264ed6bbc6d012909ee9fd58
+F test/fuzzcheck.c 6edb2a0b6c8113cdac10f8e35b891be1a1b08ebacb1c2e2f93876d4d056e8e15
F test/fuzzdata1.db 7ee3227bad0e7ccdeb08a9e6822916777073c664
F test/fuzzdata2.db 128b3feeb78918d075c9b14b48610145a0dd4c8d6f1ca7c2870c7e425f5bf31f
F test/fuzzdata3.db c6586d3e3cef0fbc18108f9bb649aa77bfc38aba
F test/fuzzdata4.db b502c7d5498261715812dd8b3c2005bad08b3a26e6489414bd13926cd3e42ed2
F test/fuzzdata5.db e35f64af17ec48926481cfaf3b3855e436bd40d1cfe2d59a9474cb4b748a52a5
F test/fuzzdata6.db 92a80e4afc172c24f662a10a612d188fb272de4a9bd19e017927c95f737de6d7
-F test/fuzzdata7.db a1bf54eb455e9772942abae1b2d1cf1e3d3659f0e5dd14f00792fd01411ae8ef
+F test/fuzzdata7.db c8c5ef745ce43eb24d6903bff63ddc336464b6b4f9dfae817e7ec2ea0e541dbd
F test/fuzzer1.test 3d4c4b7e547aba5e5511a2991e3e3d07166cfbb8
F test/fuzzer2.test a85ef814ce071293bce1ad8dffa217cbbaad4c14
F test/fuzzerfault.test 8792cd77fd5bce765b05d0c8e01b9edcf8af8536
@@ -1028,13 +1030,13 @@ F test/index2.test f835d5e13ca163bd78c4459ca15fd2e4ed487407
F test/index3.test 51685f39345462b84fcf77eb8537af847fdf438cc96b05c45d6aaca4e473ade0
F test/index4.test ab92e736d5946840236cd61ac3191f91a7856bf6
F test/index5.test 8621491915800ec274609e42e02a97d67e9b13e7
-F test/index6.test d07ea75b8c21f125c6f325522e8df8c05c91e9251ec923a31d0582b2ba4a617d
+F test/index6.test 6b3e6cd4bef343ed4541e74c55936ed112962a6552c085242612b598e12910a4
F test/index7.test 72b59b8ddc5c13f4962886b4011eb9975014317d17ef36c6297921362fb7dd98
F test/index8.test bc2e3db70e8e62459aaa1bd7e4a9b39664f8f9d7
F test/index9.test 0aa3e509dddf81f93380396e40e9bb386904c1054924ba8fa9bcdfe85a8e7721
F test/indexedby.test a52c8c6abfae4fbfb51d99440de4ca1840dbacc606b05e29328a2a8ba7cd914e
F test/indexexpr1.test 635261197bcdc19b9b2c59bbfa7227d525c00e9587faddb2d293c44d287ce60e
-F test/indexexpr2.test fc994dcd4b3da932d4add8e65ed7ca08166d541e00a46874cfacd98dfb93a31b
+F test/indexexpr2.test 8dd1f8f936cc4d246af605366886bbd251848b411378eb60887361d5302d9f54
F test/indexfault.test 31d4ab9a7d2f6e9616933eb079722362a883eb1d
F test/init.test 15c823093fdabbf7b531fe22cf037134d09587a7
F test/insert.test 5604b1ff5675cc84c34a5b315792b958f48c32edccc0dafcc81d3b776270b70a
@@ -1155,7 +1157,7 @@ F test/mutex2.test bfeaeac2e73095b2ac32285d2756e3a65e681660
F test/nan.test 437d40e6d0778b050d7750726c0cbd2c9936b81962926e8f8c48ca698f00f4d1
F test/nockpt.test 8c43b25af63b0bd620cf1b003529e37b6f1dc53bd22690e96a1bd73f78dde53a
F test/nolock.test f196cf8b8fbea4e2ca345140a2b3f3b0da45c76e
-F test/normalize.test 7fe7674d83e37c635ea2e88a27b54a0fe1afddb192d636d5672b1639859800f1
+F test/normalize.test 422027884ffb67ebba32bb78487c67cf67643496d19c077b07044bdba071a3f6
F test/notify1.test 669b2b743618efdc18ca4b02f45423d5d2304abf
F test/notify2.test 2ecabaa1305083856b7c39cf32816b612740c161
F test/notify3.test 10ff25cde502e72a92053a2f215d64bece4ef934
@@ -1289,7 +1291,7 @@ F test/sharedA.test 49d87ec54ab640fbbc3786ee3c01de94aaa482a3a9f834ad3fe92770eb69
F test/sharedB.test 16cc7178e20965d75278f410943109b77b2e645e
F test/shared_err.test 32634e404a3317eeb94abc7a099c556a346fdb8fb3858dbe222a4cbb8926a939
F test/sharedlock.test 5ede3c37439067c43b0198f580fd374ebf15d304
-F test/shell1.test d2bf5daeb6f449f0169c9ef3094db17a16a02199c5dcf1a635a3e79b07eb0edd
+F test/shell1.test 0378c4e9e800da6fbb3c86c0c8f2cf5efc9e4155b4b6447d27dc71de648fc0a1
F test/shell2.test e242a9912f44f4c23c3d1d802a83e934e84c853b
F test/shell3.test ac8c2b744014c3e9a0e26bfd829ab65f00923dc1a91ffd044863e9423cc91494
F test/shell4.test a6881d0ae226ded0df8ebdfa574c5aa6dc28d6884ccba1089dc56ed08b9e5ef4
@@ -1575,6 +1577,7 @@ F test/uri.test 3481026f00ade6dfe8adb7acb6e1e47b04369568
F test/uri2.test 9d3ba7a53ee167572d53a298ee4a5d38ec4a8fb7
F test/userauth01.test e740a2697a7b40d7c5003a7d7edaee16acd349a9
F test/utf16align.test 54cd35a27c005a9b6e7815d887718780b6a462ae
+F test/vacuum-into.test 181a8ae8c2479d88ebc118076e8cfbc062ad8f8a51b56a139bd12870a8a84c34
F test/vacuum.test ce91c39f7f91a4273bf620efad21086b5aa6ef1d
F test/vacuum2.test aa048abee196c16c9ba308465494009057b79f9b
F test/vacuum3.test 77ecdd54592b45a0bcb133339f99f1ae0ae94d0d
@@ -1668,7 +1671,7 @@ F test/win32heap.test 10fd891266bd00af68671e702317726375e5407561d859be1aa04696f2
F test/win32lock.test fbf107c91d8f5512be5a5b87c4c42ab9fdd54972
F test/win32longpath.test 169c75a3b2e43481f4a62122510210c67b08f26d
F test/win32nolock.test ac4f08811a562e45a5755e661f45ca85892bdbbc
-F test/window1.test 02e481ac48c445b43bab7b3cf1e4115165b5127a1aa29e14f5372922c836f1a4
+F test/window1.test 1003e19bebe06be286a38139ea5fc010b30c055cc1527824b09d609f89bbd93b
F test/window2.tcl 9bfa842d8a62b0d36dc8c1b5972206393c43847433c6d75940b87fec93ce3143
F test/window2.test 8e6d2a1b9f54dfebee1cde961c8590cd87b4db45c50f44947a211e1b63c2a05e
F test/window3.tcl 577a3b1ff913208e5248c04dab9df17fd760ce159a752789e26d0cb4a5f91823
@@ -1705,6 +1708,8 @@ F tool/build-shell.sh 950f47c6174f1eea171319438b93ba67ff5bf367
F tool/cg_anno.tcl f95b0006c52cf7f0496b506343415b6ee3cdcdd3 x
F tool/checkSpacing.c 810e51703529a204fc4e1eb060e9ab663e3c06d2
F tool/dbhash.c a06228aa21ebc4e6ea8daa486601d938499238a5
+F tool/dbtotxt.c 1655f60fd7b24a3e7a25d01cdb3a6a4785f30112213b08ff83a27ae7ef2dd13e
+F tool/dbtotxt.md c9a57af8739957ef36d2cfad5c4b1443ff3688ed33e4901ee200c8b651f43f3c
F tool/extract.c 054069d81b095fbdc189a6f5d4466e40380505e2
F tool/fast_vacuum.c 5ba0d6f5963a0a63bdc42840f678bad75b2ebce1
F tool/fragck.tcl 5265a95126abcf6ab357f7efa544787e5963f439
@@ -1795,7 +1800,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P 3793e5d5d60f909480c83bc2a6473d27e414d69b0c0e3289413c9bfd2f15bb08 1e13aaa29fb6324b60b3758bdab0491fdef9727e0de603d3da3e1885b52c5caa
-R dd458229efe2bd4f617c1d2a77c711e7
-U drh
-Z 9f16233ebedc8eefab041382026e8a62
+P f2083ee410b7504e8478f7373e76ded913e3a6a92cb7345b8c1ac27554f6edf8 123cbb3312917ad5b3c32556547c5b7e8ba4e2d2def8651ff80f9fc1bdc1875c
+R 121415d4c182782d4168d3f43c3faca4
+U dan
+Z c5e975ad0db2f2825cbe9c283ff86d0a
diff --git a/manifest.uuid b/manifest.uuid
index 039f6b3cde..fbd978a0c4 100644
--- a/manifest.uuid
+++ b/manifest.uuid
@@ -1 +1 @@
-f2083ee410b7504e8478f7373e76ded913e3a6a92cb7345b8c1ac27554f6edf8
\ No newline at end of file
+a93ca38b432e0c9fb2e00499cfc88d09f59f27f908f377d8ae99b6717e548a60
\ No newline at end of file
diff --git a/src/btree.c b/src/btree.c
index f4f7365b92..977e79d3e0 100644
--- a/src/btree.c
+++ b/src/btree.c
@@ -893,10 +893,15 @@ static int saveCursorKey(BtCursor *pCur){
/* Only the rowid is required for a table btree */
pCur->nKey = sqlite3BtreeIntegerKey(pCur);
}else{
- /* For an index btree, save the complete key content */
+ /* For an index btree, save the complete key content. It is possible
+ ** that the current key is corrupt. In that case, it is possible that
+ ** the sqlite3VdbeRecordUnpack() function may overread the buffer by
+ ** up to the size of 1 varint plus 1 8-byte value when the cursor
+ ** position is restored. Hence the 17 bytes of padding allocated
+ ** below. */
void *pKey;
pCur->nKey = sqlite3BtreePayloadSize(pCur);
- pKey = sqlite3Malloc( pCur->nKey );
+ pKey = sqlite3Malloc( pCur->nKey + 9 + 8 );
if( pKey ){
rc = sqlite3BtreePayload(pCur, 0, (int)pCur->nKey, pKey);
if( rc==SQLITE_OK ){
@@ -1232,6 +1237,13 @@ static void ptrmapPut(BtShared *pBt, Pgno key, u8 eType, Pgno parent, int *pRC){
*pRC = rc;
return;
}
+ if( ((char*)sqlite3PagerGetExtra(pDbPage))[0]!=0 ){
+ /* The first byte of the extra data is the MemPage.isInit byte.
+ ** If that byte is set, it means this page is also being used
+ ** as a btree page. */
+ *pRC = SQLITE_CORRUPT_BKPT;
+ goto ptrmap_exit;
+ }
offset = PTRMAP_PTROFFSET(iPtrmap, key);
if( offset<0 ){
*pRC = SQLITE_CORRUPT_BKPT;
@@ -1597,7 +1609,12 @@ static void ptrmapPutOvflPtr(MemPage *pPage, u8 *pCell, int *pRC){
assert( pCell!=0 );
pPage->xParseCell(pPage, pCell, &info);
if( info.nLocalaDataEnd, pCell, pCell+info.nLocal) ){
+ *pRC = SQLITE_CORRUPT_BKPT;
+ return;
+ }
+ ovfl = get4byte(&pCell[info.nSize-4]);
ptrmapPut(pPage->pBt, ovfl, PTRMAP_OVERFLOW1, pPage->pgno, pRC);
}
}
@@ -1652,19 +1669,14 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){
** reconstruct the entire page. */
if( (int)data[hdr+7]<=nMaxFrag ){
int iFree = get2byte(&data[hdr+1]);
+
+ /* If the initial freeblock offset were out of bounds, that would
+ ** have been detected by btreeInitPage() when it was computing the
+ ** number of free bytes on the page. */
+ assert( iFree<=usableSize-4 );
if( iFree ){
int iFree2 = get2byte(&data[iFree]);
-
- /* pageFindSlot() has already verified that free blocks are sorted
- ** in order of offset within the page, and that no block extends
- ** past the end of the page. Provided the two free slots do not
- ** overlap, this guarantees that the memmove() calls below will not
- ** overwrite the usableSize byte buffer, even if the database page
- ** is corrupt. */
- assert( iFree2==0 || iFree2>iFree );
- assert( iFree+get2byte(&data[iFree+2]) <= usableSize );
- assert( iFree2==0 || iFree2+get2byte(&data[iFree2+2]) <= usableSize );
-
+ if( iFree2>usableSize-4 ) return SQLITE_CORRUPT_PAGE(pPage);
if( 0==iFree2 || (data[iFree2]==0 && data[iFree2+1]==0) ){
u8 *pEnd = &data[cellOffset + nCell*2];
u8 *pAddr;
@@ -1675,9 +1687,9 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){
return SQLITE_CORRUPT_PAGE(pPage);
}
if( iFree2 ){
- assert( iFree+sz<=iFree2 ); /* Verified by pageFindSlot() */
+ if( iFree+sz>iFree2 ) return SQLITE_CORRUPT_PAGE(pPage);
sz2 = get2byte(&data[iFree2+2]);
- assert( iFree+sz+sz2+iFree2-(iFree+sz) <= usableSize );
+ if( iFree2+sz2 > usableSize ) return SQLITE_CORRUPT_PAGE(pPage);
memmove(&data[iFree+sz+sz2], &data[iFree+sz], iFree2-(iFree+sz));
sz += sz2;
}
@@ -7216,6 +7228,7 @@ static int rebuildPage(
for(i=0; i(uptr)pEnd ) return SQLITE_CORRUPT_BKPT;
pCell = &pTmp[pCell - aData];
}
pData -= szCell[i];
@@ -7510,8 +7523,7 @@ static int balance_quick(MemPage *pParent, MemPage *pPage, u8 *pSpace){
assert( sqlite3PagerIswriteable(pParent->pDbPage) );
assert( pPage->nOverflow==1 );
- /* This error condition is now caught prior to reaching this function */
- if( NEVER(pPage->nCell==0) ) return SQLITE_CORRUPT_BKPT;
+ if( pPage->nCell==0 ) return SQLITE_CORRUPT_BKPT; /* dbfuzz001.test */
/* Allocate a new page. This page will become the right-sibling of
** pPage. Make the parent page writable, so that the new divider cell
@@ -9092,6 +9104,7 @@ int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){
if( bPreserve ){
if( !pPage->leaf
|| (pPage->nFree+cellSizePtr(pPage,pCell)+2)>(int)(pBt->usableSize*2/3)
+ || pPage->nCell==1 /* See dbfuzz001.test for a test case */
){
/* A b-tree rebalance will be required after deleting this entry.
** Save the cursor key. */
@@ -9874,18 +9887,18 @@ static void checkList(
}
pOvflData = (unsigned char *)sqlite3PagerGetData(pOvflPage);
if( isFreeList ){
- int n = get4byte(&pOvflData[4]);
+ u32 n = (u32)get4byte(&pOvflData[4]);
#ifndef SQLITE_OMIT_AUTOVACUUM
if( pCheck->pBt->autoVacuum ){
checkPtrmap(pCheck, iPage, PTRMAP_FREEPAGE, 0);
}
#endif
- if( n>(int)pCheck->pBt->usableSize/4-2 ){
+ if( n>pCheck->pBt->usableSize/4-2 ){
checkAppendMsg(pCheck,
"freelist leaf count too big on page %d", iPage);
N--;
}else{
- for(i=0; ipBt->autoVacuum ){
@@ -10329,7 +10342,7 @@ char *sqlite3BtreeIntegrityCheck(
}
#endif
testcase( pBt->db->flags & SQLITE_CellSizeCk );
- pBt->db->flags &= ~SQLITE_CellSizeCk;
+ pBt->db->flags &= ~(u64)SQLITE_CellSizeCk;
for(i=0; (int)iop;
if( p->flags & EP_Generic ) break;
- if( (op==TK_AGG_COLUMN || op==TK_COLUMN
- || op==TK_REGISTER || op==TK_TRIGGER)
+ if( op==TK_REGISTER ) op = p->op2;
+ if( (op==TK_AGG_COLUMN || op==TK_COLUMN || op==TK_TRIGGER)
&& p->y.pTab!=0
){
/* op==TK_REGISTER && p->y.pTab!=0 happens when pExpr was originally
@@ -158,7 +158,7 @@ CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr){
p = p->pLeft;
continue;
}
- if( op==TK_COLLATE || (op==TK_REGISTER && p->op2==TK_COLLATE) ){
+ if( op==TK_COLLATE ){
pColl = sqlite3GetCollSeq(pParse, ENC(db), 0, p->u.zToken);
break;
}
@@ -1330,6 +1330,35 @@ static With *withDup(sqlite3 *db, With *p){
# define withDup(x,y) 0
#endif
+#ifndef SQLITE_OMIT_WINDOWFUNC
+/*
+** The gatherSelectWindows() procedure and its helper routine
+** gatherSelectWindowsCallback() are used to scan all the expressions
+** an a newly duplicated SELECT statement and gather all of the Window
+** objects found there, assembling them onto the linked list at Select->pWin.
+*/
+static int gatherSelectWindowsCallback(Walker *pWalker, Expr *pExpr){
+ if( pExpr->op==TK_FUNCTION && pExpr->y.pWin!=0 ){
+ assert( ExprHasProperty(pExpr, EP_WinFunc) );
+ pExpr->y.pWin->pNextWin = pWalker->u.pSelect->pWin;
+ pWalker->u.pSelect->pWin = pExpr->y.pWin;
+ }
+ return WRC_Continue;
+}
+static int gatherSelectWindowsSelectCallback(Walker *pWalker, Select *p){
+ return p==pWalker->u.pSelect ? WRC_Continue : WRC_Prune;
+}
+static void gatherSelectWindows(Select *p){
+ Walker w;
+ w.xExprCallback = gatherSelectWindowsCallback;
+ w.xSelectCallback = gatherSelectWindowsSelectCallback;
+ w.xSelectCallback2 = 0;
+ w.u.pSelect = p;
+ sqlite3WalkSelect(&w, p);
+}
+#endif
+
+
/*
** The following group of routines make deep copies of expressions,
** expression lists, ID lists, and select statements. The copies can
@@ -1497,6 +1526,7 @@ Select *sqlite3SelectDup(sqlite3 *db, Select *pDup, int flags){
#ifndef SQLITE_OMIT_WINDOWFUNC
pNew->pWin = 0;
pNew->pWinDefn = sqlite3WindowListDup(db, p->pWinDefn);
+ if( p->pWin ) gatherSelectWindows(pNew);
#endif
pNew->selId = p->selId;
*pp = pNew;
@@ -2413,6 +2443,7 @@ int sqlite3FindInIndex(
Bitmask colUsed; /* Columns of the index used */
Bitmask mCol; /* Mask for the current column */
if( pIdx->nColumnpPartIdxWhere!=0 ) continue;
/* Maximum nColumn is BMS-2, not BMS-1, so that we can compute
** BITMASK(nExpr) without overflowing */
testcase( pIdx->nColumn==BMS-2 );
@@ -4747,14 +4778,16 @@ int sqlite3ExprCompare(Parse *pParse, Expr *pA, Expr *pB, int iTab){
}
}
if( (pA->flags & EP_Distinct)!=(pB->flags & EP_Distinct) ) return 2;
- if( ALWAYS((combinedFlags & EP_TokenOnly)==0) ){
+ if( (combinedFlags & EP_TokenOnly)==0 ){
if( combinedFlags & EP_xIsSelect ) return 2;
if( (combinedFlags & EP_FixedCol)==0
&& sqlite3ExprCompare(pParse, pA->pLeft, pB->pLeft, iTab) ) return 2;
if( sqlite3ExprCompare(pParse, pA->pRight, pB->pRight, iTab) ) return 2;
if( sqlite3ExprListCompare(pA->x.pList, pB->x.pList, iTab) ) return 2;
- assert( (combinedFlags & EP_Reduced)==0 );
- if( pA->op!=TK_STRING && pA->op!=TK_TRUEFALSE ){
+ if( pA->op!=TK_STRING
+ && pA->op!=TK_TRUEFALSE
+ && (combinedFlags & EP_Reduced)==0
+ ){
if( pA->iColumn!=pB->iColumn ) return 2;
if( pA->iTable!=pB->iTable
&& (pA->iTable!=iTab || NEVER(pB->iTable>=0)) ) return 2;
diff --git a/src/loadext.c b/src/loadext.c
index 966d2ddac2..214390edd7 100644
--- a/src/loadext.c
+++ b/src/loadext.c
@@ -650,7 +650,7 @@ int sqlite3_enable_load_extension(sqlite3 *db, int onoff){
if( onoff ){
db->flags |= SQLITE_LoadExtension|SQLITE_LoadExtFunc;
}else{
- db->flags &= ~(SQLITE_LoadExtension|SQLITE_LoadExtFunc);
+ db->flags &= ~(u64)(SQLITE_LoadExtension|SQLITE_LoadExtFunc);
}
sqlite3_mutex_leave(db->mutex);
return SQLITE_OK;
diff --git a/src/main.c b/src/main.c
index 42d67b1302..585504b6c1 100644
--- a/src/main.c
+++ b/src/main.c
@@ -843,11 +843,11 @@ int sqlite3_db_config(sqlite3 *db, int op, ...){
if( aFlagOp[i].op==op ){
int onoff = va_arg(ap, int);
int *pRes = va_arg(ap, int*);
- u32 oldFlags = db->flags;
+ u64 oldFlags = db->flags;
if( onoff>0 ){
db->flags |= aFlagOp[i].mask;
}else if( onoff==0 ){
- db->flags &= ~aFlagOp[i].mask;
+ db->flags &= ~(u64)aFlagOp[i].mask;
}
if( oldFlags!=db->flags ){
sqlite3ExpirePreparedStatements(db, 0);
@@ -1310,7 +1310,7 @@ void sqlite3RollbackAll(sqlite3 *db, int tripCode){
/* Any deferred constraint violations have now been resolved. */
db->nDeferredCons = 0;
db->nDeferredImmCons = 0;
- db->flags &= ~SQLITE_DeferFKs;
+ db->flags &= ~(u64)SQLITE_DeferFKs;
/* If one has been configured, invoke the rollback-hook callback */
if( db->xRollbackCallback && (inTrans || !db->autoCommit) ){
@@ -1996,7 +1996,6 @@ void *sqlite3_trace(sqlite3 *db, void(*xTrace)(void*,const char*), void *pArg){
sqlite3_mutex_enter(db->mutex);
pOld = db->pTraceArg;
db->mTrace = xTrace ? SQLITE_TRACE_LEGACY : 0;
- if( db->xProfile ) db->mTrace |= SQLITE_TRACE_XPROFILE;
db->xTrace = (int(*)(u32,void*,void*,void*))xTrace;
db->pTraceArg = pArg;
sqlite3_mutex_leave(db->mutex);
@@ -2021,9 +2020,6 @@ int sqlite3_trace_v2(
if( mTrace==0 ) xTrace = 0;
if( xTrace==0 ) mTrace = 0;
db->mTrace = mTrace;
-#ifndef SQLITE_OMIT_DEPRECATED
- if( db->xProfile ) db->mTrace |= SQLITE_TRACE_XPROFILE;
-#endif
db->xTrace = xTrace;
db->pTraceArg = pArg;
sqlite3_mutex_leave(db->mutex);
@@ -2409,7 +2405,7 @@ const char *sqlite3_errmsg(sqlite3 *db){
z = sqlite3ErrStr(SQLITE_NOMEM_BKPT);
}else{
testcase( db->pErr==0 );
- z = (char*)sqlite3_value_text(db->pErr);
+ z = db->errCode ? (char*)sqlite3_value_text(db->pErr) : 0;
assert( !db->mallocFailed );
if( z==0 ){
z = sqlite3ErrStr(db->errCode);
diff --git a/src/parse.y b/src/parse.y
index 5aae351bc7..c97c70f33e 100644
--- a/src/parse.y
+++ b/src/parse.y
@@ -1382,8 +1382,12 @@ cmd ::= DROP INDEX ifexists(E) fullname(X). {sqlite3DropIndex(pParse, X, E);}
//
%ifndef SQLITE_OMIT_VACUUM
%ifndef SQLITE_OMIT_ATTACH
-cmd ::= VACUUM. {sqlite3Vacuum(pParse,0);}
-cmd ::= VACUUM nm(X). {sqlite3Vacuum(pParse,&X);}
+%type vinto {Expr*}
+%destructor vinto {sqlite3ExprDelete(pParse->db, $$);}
+cmd ::= VACUUM vinto(Y). {sqlite3Vacuum(pParse,0,Y);}
+cmd ::= VACUUM nm(X) vinto(Y). {sqlite3Vacuum(pParse,&X,Y);}
+vinto(A) ::= INTO expr(X). {A = X;}
+vinto(A) ::= . {A = 0;}
%endif SQLITE_OMIT_ATTACH
%endif SQLITE_OMIT_VACUUM
diff --git a/src/pcache1.c b/src/pcache1.c
index 6df0f15d13..13903216f6 100644
--- a/src/pcache1.c
+++ b/src/pcache1.c
@@ -477,6 +477,9 @@ static void pcache1FreePage(PgHdr1 *p){
** exists, this function falls back to sqlite3Malloc().
*/
void *sqlite3PageMalloc(int sz){
+ /* During rebalance operations on a corrupt database file, it is sometimes
+ ** (rarely) possible to overread the temporary page buffer by a few bytes.
+ ** Enlarge the allocation slightly so that this does not cause problems. */
return pcache1Alloc(sz);
}
diff --git a/src/pragma.c b/src/pragma.c
index ada652cf14..2f27d11005 100644
--- a/src/pragma.c
+++ b/src/pragma.c
@@ -816,7 +816,7 @@ void sqlite3Pragma(
if( sqlite3GetBoolean(zRight, size!=0) ){
db->flags |= SQLITE_CacheSpill;
}else{
- db->flags &= ~SQLITE_CacheSpill;
+ db->flags &= ~(u64)SQLITE_CacheSpill;
}
setAllPagerFlags(db);
}
diff --git a/src/prepare.c b/src/prepare.c
index c470a54bda..e06b7cb6ad 100644
--- a/src/prepare.c
+++ b/src/prepare.c
@@ -293,7 +293,7 @@ int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg, u32 mFlags){
** indices that the user might have created.
*/
if( iDb==0 && meta[BTREE_FILE_FORMAT-1]>=4 ){
- db->flags &= ~SQLITE_LegacyFileFmt;
+ db->flags &= ~(u64)SQLITE_LegacyFileFmt;
}
/* Read the schema information out of the schema tables
@@ -709,200 +709,6 @@ static int sqlite3LockAndPrepare(
return rc;
}
-#ifdef SQLITE_ENABLE_NORMALIZE
-
-/*
-** Attempt to estimate the final output buffer size needed for the fully
-** normalized version of the specified SQL string. This should take into
-** account any potential expansion that could occur (e.g. via IN clauses
-** being expanded, etc). This size returned is the total number of bytes
-** including the NUL terminator.
-*/
-static int estimateNormalizedSize(
- const char *zSql, /* The original SQL string */
- int nSql /* Length of original SQL string */
-){
- int nOut = nSql + 4;
- const char *z = zSql;
- while( nOut0 ){
- zOut[j++] = '"';
- continue;
- }else if( k==nToken-1 ){
- zOut[j++] = '"';
- continue;
- }
- }
- if( bKeyword ){
- zOut[j++] = sqlite3Toupper(zSql[iIn+k]);
- }else{
- zOut[j++] = sqlite3Tolower(zSql[iIn+k]);
- }
- }
- *piOut = j;
-}
-
-/*
-** Compute a normalization of the SQL given by zSql[0..nSql-1]. Return
-** the normalization in space obtained from sqlite3DbMalloc(). Or return
-** NULL if anything goes wrong or if zSql is NULL.
-*/
-char *sqlite3Normalize(
- Vdbe *pVdbe, /* VM being reprepared */
- const char *zSql, /* The original SQL string */
- int nSql /* Size of the input string in bytes */
-){
- sqlite3 *db; /* Database handle. */
- char *z; /* The output string */
- int nZ; /* Size of the output string in bytes */
- int i; /* Next character to read from zSql[] */
- int j; /* Next character to fill in on z[] */
- int tokenType = 0; /* Type of the next token */
- int prevTokenType = 0; /* Type of the previous token, except spaces */
- int n; /* Size of the next token */
- int nParen = 0; /* Nesting level of parenthesis */
- int iStartIN = 0; /* Start of RHS of IN operator in z[] */
- int nParenAtIN = 0; /* Value of nParent at start of RHS of IN operator */
-
- db = sqlite3VdbeDb(pVdbe);
- assert( db!=0 );
- if( zSql==0 ) return 0;
- nZ = estimateNormalizedSize(zSql, nSql);
- z = sqlite3DbMallocRawNN(db, nZ);
- if( z==0 ) goto normalizeError;
- for(i=j=0; i0 && nParen==nParenAtIN ){
- assert( iStartIN+6=0 );
- assert( nZ-1-j=0 );
- /* Fall through */
- }
- case TK_MINUS:
- case TK_SEMI:
- case TK_PLUS:
- case TK_STAR:
- case TK_SLASH:
- case TK_REM:
- case TK_EQ:
- case TK_LE:
- case TK_NE:
- case TK_LSHIFT:
- case TK_LT:
- case TK_RSHIFT:
- case TK_GT:
- case TK_GE:
- case TK_BITOR:
- case TK_CONCAT:
- case TK_COMMA:
- case TK_BITAND:
- case TK_BITNOT:
- case TK_DOT:
- case TK_IN:
- case TK_IS:
- case TK_NOT:
- case TK_NULL:
- case TK_ID: {
- if( tokenType==TK_NULL ){
- if( prevTokenType==TK_IS || prevTokenType==TK_NOT ){
- /* NULL is a keyword in this case, not a literal value */
- }else{
- /* Here the NULL is a literal value */
- z[j++] = '?';
- break;
- }
- }
- if( j>0 && sqlite3IsIdChar(z[j-1]) && sqlite3IsIdChar(zSql[i]) ){
- z[j++] = ' ';
- }
- if( tokenType==TK_ID ){
- int i2 = i, n2 = n;
- if( nParen==nParenAtIN ) iStartIN = 0;
- if( flags&SQLITE_TOKEN_QUOTED ){ i2++; n2-=2; }
- }
- copyNormalizedToken(zSql, i, n, flags, z, &j);
- break;
- }
- }
- }
- assert( j0 && z[j-1]==' ' ){ j--; }
- if( j>0 && z[j-1]!=';' ){ z[j++] = ';'; }
- z[j] = 0;
- assert( jop==TK_COLLATE ){
pDup = sqlite3ExprAddCollateString(pParse, pDup, pExpr->u.zToken);
}
-// ExprSetProperty(pDup, EP_Alias);
/* Before calling sqlite3ExprDelete(), set the EP_Static flag. This
** prevents ExprDelete() from deleting the Expr structure itself,
@@ -474,6 +473,25 @@ static int lookupName(
if( cnt==0 && zTab==0 ){
assert( pExpr->op==TK_ID );
if( ExprHasProperty(pExpr,EP_DblQuoted) ){
+ /* If a double-quoted identifier does not match any known column name,
+ ** then treat it as a string.
+ **
+ ** This hack was added in the early days of SQLite in a misguided attempt
+ ** to be compatible with MySQL 3.x, which used double-quotes for strings.
+ ** I now sorely regret putting in this hack. The effect of this hack is
+ ** that misspelled identifier names are silently converted into strings
+ ** rather than causing an error, to the frustration of countless
+ ** programmers. To all those frustrated programmers, my apologies.
+ **
+ ** Someday, I hope to get rid of this hack. Unfortunately there is
+ ** a huge amount of legacy SQL that uses it. So for now, we just
+ ** issue a warning.
+ */
+ sqlite3_log(SQLITE_WARNING,
+ "double-quoted string literal: \"%w\"", zCol);
+#ifdef SQLITE_ENABLE_NORMALIZE
+ sqlite3VdbeAddDblquoteStr(db, pParse->pVdbe, zCol);
+#endif
pExpr->op = TK_STRING;
pExpr->y.pTab = 0;
return WRC_Prune;
diff --git a/src/select.c b/src/select.c
index 5cd1630785..c0f962c371 100644
--- a/src/select.c
+++ b/src/select.c
@@ -2077,10 +2077,10 @@ void sqlite3SelectAddColumnTypeAndCollation(
Table *sqlite3ResultSetOfSelect(Parse *pParse, Select *pSelect){
Table *pTab;
sqlite3 *db = pParse->db;
- int savedFlags;
+ u64 savedFlags;
savedFlags = db->flags;
- db->flags &= ~SQLITE_FullColNames;
+ db->flags &= ~(u64)SQLITE_FullColNames;
db->flags |= SQLITE_ShortColNames;
sqlite3SelectPrep(pParse, pSelect, 0);
if( pParse->nErr ) return 0;
@@ -3461,6 +3461,7 @@ static Expr *substExpr(
ifNullRow.iTable = pSubst->iNewTable;
pCopy = &ifNullRow;
}
+ testcase( ExprHasProperty(pCopy, EP_Subquery) );
pNew = sqlite3ExprDup(db, pCopy, 0);
if( pNew && pSubst->isLeftJoin ){
ExprSetProperty(pNew, EP_CanBeNull);
@@ -4025,7 +4026,8 @@ static int flattenSubquery(
pParent->pOrderBy = pOrderBy;
pSub->pOrderBy = 0;
}
- pWhere = sqlite3ExprDup(db, pSub->pWhere, 0);
+ pWhere = pSub->pWhere;
+ pSub->pWhere = 0;
if( isLeftJoin>0 ){
setJoinExpr(pWhere, iNewParent);
}
diff --git a/src/shell.c.in b/src/shell.c.in
index 887c2fcf59..7048732389 100644
--- a/src/shell.c.in
+++ b/src/shell.c.in
@@ -1011,6 +1011,8 @@ struct ShellState {
unsigned mEqpLines; /* Mask of veritical lines in the EQP output graph */
int outCount; /* Revert to stdout when reaching zero */
int cnt; /* Number of records displayed so far */
+ int lineno; /* Line number of last line read from in */
+ FILE *in; /* Read commands from this stream */
FILE *out; /* Write results here */
FILE *traceOut; /* Output for sqlite3_trace() */
int nErr; /* Number of errors seen */
@@ -1066,6 +1068,7 @@ struct ShellState {
#define SHELL_OPEN_ZIPFILE 3 /* Use the zipfile virtual table */
#define SHELL_OPEN_READONLY 4 /* Open a normal database read-only */
#define SHELL_OPEN_DESERIALIZE 5 /* Open using sqlite3_deserialize() */
+#define SHELL_OPEN_HEXDB 6 /* Use "dbtotxt" output as data source */
/* Allowed values for ShellState.eTraceType
*/
@@ -3377,6 +3380,7 @@ static const char *(azHelp[]) = {
#endif
".backup ?DB? FILE Backup DB (default \"main\") to FILE",
" --append Use the appendvfs",
+ " --async Write to FILE without a journal and without fsync()",
".bail on|off Stop after hitting an error. Default OFF",
".binary on|off Turn binary output on or off. Default OFF",
".cd DIRECTORY Change the working directory to DIRECTORY",
@@ -3443,6 +3447,7 @@ static const char *(azHelp[]) = {
" --append Use appendvfs to append database to the end of FILE",
#ifdef SQLITE_ENABLE_DESERIALIZE
" --deserialize Load into memory useing sqlite3_deserialize()",
+ " --hexdb Load the output of \"dbtotxt\" as an in-memory database",
#endif
" --new Initialize FILE to an empty database",
" --readonly Open FILE readonly",
@@ -3592,7 +3597,7 @@ static int showHelp(FILE *out, const char *zPattern){
}
/* Forward reference */
-static int process_input(ShellState *p, FILE *in);
+static int process_input(ShellState *p);
/*
** Read the content of file zName into memory obtained from sqlite3_malloc64()
@@ -3722,6 +3727,94 @@ int deduceDatabaseType(const char *zName, int dfltZip){
return rc;
}
+#ifdef SQLITE_ENABLE_DESERIALIZE
+/*
+** Reconstruct an in-memory database using the output from the "dbtotxt"
+** program. Read content from the file in p->zDbFilename. If p->zDbFilename
+** is 0, then read from standard input.
+*/
+static unsigned char *readHexDb(ShellState *p, int *pnData){
+ unsigned char *a = 0;
+ int nLine;
+ int n = 0;
+ int pgsz = 0;
+ int iOffset = 0;
+ int j, k;
+ int rc;
+ FILE *in;
+ unsigned char x[16];
+ char zLine[1000];
+ if( p->zDbFilename ){
+ in = fopen(p->zDbFilename, "r");
+ if( in==0 ){
+ utf8_printf(stderr, "cannot open \"%s\" for reading\n", p->zDbFilename);
+ return 0;
+ }
+ nLine = 0;
+ }else{
+ in = p->in;
+ nLine = p->lineno;
+ }
+ *pnData = 0;
+ nLine++;
+ if( fgets(zLine, sizeof(zLine), in)==0 ) goto readHexDb_error;
+ rc = sscanf(zLine, "| size %d pagesize %d", &n, &pgsz);
+ if( rc!=2 ) goto readHexDb_error;
+ if( n<=0 ) goto readHexDb_error;
+ a = sqlite3_malloc( n );
+ if( a==0 ){
+ utf8_printf(stderr, "Out of memory!\n");
+ goto readHexDb_error;
+ }
+ memset(a, 0, n);
+ if( pgsz<512 || pgsz>65536 || (pgsz & (pgsz-1))!=0 ){
+ utf8_printf(stderr, "invalid pagesize\n");
+ goto readHexDb_error;
+ }
+ for(nLine++; fgets(zLine, sizeof(zLine), in)!=0; nLine++){
+ rc = sscanf(zLine, "| page %d offset %d", &j, &k);
+ if( rc==2 ){
+ iOffset = k;
+ continue;
+ }
+ if( strncmp(zLine, "| end ", 6)==0 ){
+ break;
+ }
+ rc = sscanf(zLine,"| %d: %hhx %hhx %hhx %hhx %hhx %hhx %hhx %hhx"
+ " %hhx %hhx %hhx %hhx %hhx %hhx %hhx %hhx",
+ &j, &x[0], &x[1], &x[2], &x[3], &x[4], &x[5], &x[6], &x[7],
+ &x[8], &x[9], &x[10], &x[11], &x[12], &x[13], &x[14], &x[15]);
+ if( rc==17 ){
+ k = iOffset+j;
+ if( k+16<=n ){
+ memcpy(a+k, x, 16);
+ }
+ }
+ }
+ *pnData = n;
+ if( in!=p->in ){
+ fclose(in);
+ }else{
+ p->lineno = nLine;
+ }
+ return a;
+
+readHexDb_error:
+ if( in!=stdin ){
+ fclose(in);
+ }else{
+ while( fgets(zLine, sizeof(zLine), p->in)!=0 ){
+ nLine++;
+ if(strncmp(zLine, "| end ", 6)==0 ) break;
+ }
+ p->lineno = nLine;
+ }
+ sqlite3_free(a);
+ utf8_printf(stderr,"Error on line %d of --hexdb input\n", nLine);
+ return 0;
+}
+#endif /* SQLITE_ENABLE_DESERIALIZE */
+
/* Flags for open_db().
**
** The default behavior of open_db() is to exit(1) if the database fails to
@@ -3755,6 +3848,7 @@ static void open_db(ShellState *p, int openFlags){
SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE, "apndvfs");
break;
}
+ case SHELL_OPEN_HEXDB:
case SHELL_OPEN_DESERIALIZE: {
sqlite3_open(0, &p->db);
break;
@@ -3809,10 +3903,21 @@ static void open_db(ShellState *p, int openFlags){
sqlite3_free(zSql);
}
#ifdef SQLITE_ENABLE_DESERIALIZE
- else if( p->openMode==SHELL_OPEN_DESERIALIZE ){
+ else
+ if( p->openMode==SHELL_OPEN_DESERIALIZE || p->openMode==SHELL_OPEN_HEXDB ){
+ int rc;
int nData = 0;
- unsigned char *aData = (unsigned char*)readFile(p->zDbFilename, &nData);
- int rc = sqlite3_deserialize(p->db, "main", aData, nData, nData,
+ unsigned char *aData;
+ if( p->openMode==SHELL_OPEN_DESERIALIZE ){
+ aData = (unsigned char*)readFile(p->zDbFilename, &nData);
+ }else{
+ aData = readHexDb(p, &nData);
+ if( aData==0 ){
+ utf8_printf(stderr, "Error in hexdb input\n");
+ return;
+ }
+ }
+ rc = sqlite3_deserialize(p->db, "main", aData, nData, nData,
SQLITE_DESERIALIZE_RESIZEABLE |
SQLITE_DESERIALIZE_FREEONCLOSE);
if( rc ){
@@ -5840,6 +5945,7 @@ static int do_meta_command(char *zLine, ShellState *p){
sqlite3 *pDest;
sqlite3_backup *pBackup;
int j;
+ int bAsync = 0;
const char *zVfs = 0;
for(j=1; jdb, zDb);
if( pBackup==0 ){
@@ -6740,7 +6853,9 @@ static int do_meta_command(char *zLine, ShellState *p){
#ifdef SQLITE_ENABLE_DESERIALIZE
}else if( optionMatch(z, "deserialize") ){
p->openMode = SHELL_OPEN_DESERIALIZE;
-#endif
+ }else if( optionMatch(z, "hexdb") ){
+ p->openMode = SHELL_OPEN_HEXDB;
+#endif /* SQLITE_ENABLE_DESERIALIZE */
}else if( z[0]=='-' ){
utf8_printf(stderr, "unknown option: %s\n", z);
rc = 1;
@@ -6749,7 +6864,7 @@ static int do_meta_command(char *zLine, ShellState *p){
}
/* If a filename is specified, try to open it first */
zNewFilename = nArg>iName ? sqlite3_mprintf("%s", azArg[iName]) : 0;
- if( zNewFilename ){
+ if( zNewFilename || p->openMode==SHELL_OPEN_HEXDB ){
if( newFlag ) shellDeleteFile(zNewFilename);
p->zDbFilename = zNewFilename;
open_db(p, OPEN_DB_KEEPALIVE);
@@ -6865,20 +6980,23 @@ static int do_meta_command(char *zLine, ShellState *p){
}else
if( c=='r' && n>=3 && strncmp(azArg[0], "read", n)==0 ){
- FILE *alt;
+ FILE *inSaved = p->in;
+ int savedLineno = p->lineno;
if( nArg!=2 ){
raw_printf(stderr, "Usage: .read FILE\n");
rc = 1;
goto meta_command_exit;
}
- alt = fopen(azArg[1], "rb");
- if( alt==0 ){
+ p->in = fopen(azArg[1], "rb");
+ if( p->in==0 ){
utf8_printf(stderr,"Error: cannot open \"%s\"\n", azArg[1]);
rc = 1;
}else{
- rc = process_input(p, alt);
- fclose(alt);
+ rc = process_input(p);
+ fclose(p->in);
}
+ p->in = inSaved;
+ p->lineno = savedLineno;
}else
if( c=='r' && n>=3 && strncmp(azArg[0], "restore", n)==0 ){
@@ -8219,7 +8337,7 @@ static int runOneSqlLine(ShellState *p, char *zSql, FILE *in, int startline){
**
** Return the number of errors.
*/
-static int process_input(ShellState *p, FILE *in){
+static int process_input(ShellState *p){
char *zLine = 0; /* A single input line */
char *zSql = 0; /* Accumulated SQL text */
int nLine; /* Length of current line */
@@ -8228,22 +8346,22 @@ static int process_input(ShellState *p, FILE *in){
int nSqlPrior = 0; /* Bytes of zSql[] used by prior line */
int rc; /* Error code */
int errCnt = 0; /* Number of errors seen */
- int lineno = 0; /* Current line number */
int startline = 0; /* Line number for start of current input */
- while( errCnt==0 || !bail_on_error || (in==0 && stdin_is_interactive) ){
+ p->lineno = 0;
+ while( errCnt==0 || !bail_on_error || (p->in==0 && stdin_is_interactive) ){
fflush(p->out);
- zLine = one_input_line(in, zLine, nSql>0);
+ zLine = one_input_line(p->in, zLine, nSql>0);
if( zLine==0 ){
/* End of input */
- if( in==0 && stdin_is_interactive ) printf("\n");
+ if( p->in==0 && stdin_is_interactive ) printf("\n");
break;
}
if( seenInterrupt ){
- if( in!=0 ) break;
+ if( p->in!=0 ) break;
seenInterrupt = 0;
}
- lineno++;
+ p->lineno++;
if( nSql==0 && _all_whitespace(zLine) ){
if( ShellHasFlag(p, SHFLG_Echo) ) printf("%s\n", zLine);
continue;
@@ -8275,7 +8393,7 @@ static int process_input(ShellState *p, FILE *in){
for(i=0; zLine[i] && IsSpace(zLine[i]); i++){}
assert( nAlloc>0 && zSql!=0 );
memcpy(zSql, zLine+i, nLine+1-i);
- startline = lineno;
+ startline = p->lineno;
nSql = nLine-i;
}else{
zSql[nSql++] = '\n';
@@ -8284,7 +8402,7 @@ static int process_input(ShellState *p, FILE *in){
}
if( nSql && line_contains_semicolon(&zSql[nSqlPrior], nSql-nSqlPrior)
&& sqlite3_complete(zSql) ){
- errCnt += runOneSqlLine(p, zSql, in, startline);
+ errCnt += runOneSqlLine(p, zSql, p->in, startline);
nSql = 0;
if( p->outCount ){
output_reset(p);
@@ -8298,7 +8416,7 @@ static int process_input(ShellState *p, FILE *in){
}
}
if( nSql && !_all_whitespace(zSql) ){
- errCnt += runOneSqlLine(p, zSql, in, startline);
+ errCnt += runOneSqlLine(p, zSql, p->in, startline);
}
free(zSql);
free(zLine);
@@ -8387,7 +8505,8 @@ static void process_sqliterc(
char *home_dir = NULL;
const char *sqliterc = sqliterc_override;
char *zBuf = 0;
- FILE *in = NULL;
+ FILE *inSaved = p->in;
+ int savedLineno = p->lineno;
if (sqliterc == NULL) {
home_dir = find_home_dir(0);
@@ -8399,14 +8518,16 @@ static void process_sqliterc(
zBuf = sqlite3_mprintf("%s/.sqliterc",home_dir);
sqliterc = zBuf;
}
- in = fopen(sqliterc,"rb");
- if( in ){
+ p->in = fopen(sqliterc,"rb");
+ if( p->in ){
if( stdin_is_interactive ){
utf8_printf(stderr,"-- Loading resources from %s\n",sqliterc);
}
- process_input(p,in);
- fclose(in);
+ process_input(p);
+ fclose(p->in);
}
+ p->in = inSaved;
+ p->lineno = savedLineno;
sqlite3_free(zBuf);
}
@@ -9018,14 +9139,16 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
#elif HAVE_LINENOISE
linenoiseSetCompletionCallback(linenoise_completion);
#endif
- rc = process_input(&data, 0);
+ data.in = 0;
+ rc = process_input(&data);
if( zHistory ){
shell_stifle_history(2000);
shell_write_history(zHistory);
free(zHistory);
}
}else{
- rc = process_input(&data, stdin);
+ data.in = stdin;
+ rc = process_input(&data);
}
}
set_table_name(&data, 0);
diff --git a/src/sqlite.h.in b/src/sqlite.h.in
index 69108a7d55..259dbb8a59 100644
--- a/src/sqlite.h.in
+++ b/src/sqlite.h.in
@@ -2991,9 +2991,9 @@ int sqlite3_set_authorizer(
** time is in units of nanoseconds, however the current implementation
** is only capable of millisecond resolution so the six least significant
** digits in the time are meaningless. Future versions of SQLite
-** might provide greater resolution on the profiler callback. The
-** sqlite3_profile() function is considered experimental and is
-** subject to change in future versions of SQLite.
+** might provide greater resolution on the profiler callback. Invoking
+** either [sqlite3_trace()] or [sqlite3_trace_v2()] will cancel the
+** profile callback.
*/
SQLITE_DEPRECATED void *sqlite3_trace(sqlite3*,
void(*xTrace)(void*,const char*), void*);
@@ -3629,14 +3629,13 @@ int sqlite3_limit(sqlite3*, int id, int newVal);
** deplete the limited store of lookaside memory. Future versions of
** SQLite may act on this hint differently.
**
-** [[SQLITE_PREPARE_NORMALIZE]] ^(SQLITE_PREPARE_NORMALIZE
-** The SQLITE_PREPARE_NORMALIZE flag indicates that a normalized
-** representation of the SQL statement should be calculated and then
-** associated with the prepared statement, which can be obtained via
-** the [sqlite3_normalized_sql()] interface.)^ The semantics used to
-** normalize a SQL statement are unspecified and subject to change.
-** At a minimum, literal values will be replaced with suitable
-** placeholders.
+** [[SQLITE_PREPARE_NORMALIZE]] SQLITE_PREPARE_NORMALIZE
+** The SQLITE_PREPARE_NORMALIZE flag is a no-op. This flag used
+** to be required for any prepared statement that wanted to use the
+** [sqlite3_normalized_sql()] interface. However, the
+** [sqlite3_normalized_sql()] interface is now available to all
+** prepared statements, regardless of whether or not they use this
+** flag.
**
*/
#define SQLITE_PREPARE_PERSISTENT 0x01
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index 6ab81c5593..6f06d3691d 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -3997,8 +3997,8 @@ Table *sqlite3LocateTableItem(Parse*,u32 flags,struct SrcList_item *);
Index *sqlite3FindIndex(sqlite3*,const char*, const char*);
void sqlite3UnlinkAndDeleteTable(sqlite3*,int,const char*);
void sqlite3UnlinkAndDeleteIndex(sqlite3*,int,const char*);
-void sqlite3Vacuum(Parse*,Token*);
-int sqlite3RunVacuum(char**, sqlite3*, int);
+void sqlite3Vacuum(Parse*,Token*,Expr*);
+int sqlite3RunVacuum(char**, sqlite3*, int, sqlite3_value*);
char *sqlite3NameFromToken(sqlite3*, Token*);
int sqlite3ExprCompare(Parse*,Expr*, Expr*, int);
int sqlite3ExprCompareSkip(Expr*, Expr*, int);
@@ -4269,9 +4269,6 @@ void sqlite3AlterFunctions(void);
void sqlite3AlterRenameTable(Parse*, SrcList*, Token*);
void sqlite3AlterRenameColumn(Parse*, SrcList*, Token*, Token*);
int sqlite3GetToken(const unsigned char *, int *);
-#ifdef SQLITE_ENABLE_NORMALIZE
-int sqlite3GetTokenNormalized(const unsigned char *, int *, int *);
-#endif
void sqlite3NestedParse(Parse*, const char*, ...);
void sqlite3ExpirePreparedStatements(sqlite3*, int);
int sqlite3CodeSubselect(Parse*, Expr *, int, int);
@@ -4430,7 +4427,7 @@ int sqlite3VdbeParameterIndex(Vdbe*, const char*, int);
int sqlite3TransferBindings(sqlite3_stmt *, sqlite3_stmt *);
void sqlite3ParserReset(Parse*);
#ifdef SQLITE_ENABLE_NORMALIZE
-char *sqlite3Normalize(Vdbe*, const char*, int);
+char *sqlite3Normalize(Vdbe*, const char*);
#endif
int sqlite3Reprepare(Vdbe*);
void sqlite3ExprListCheckLength(Parse*, ExprList*, const char*);
diff --git a/src/test1.c b/src/test1.c
index 49986de22d..fd47dd6a9d 100644
--- a/src/test1.c
+++ b/src/test1.c
@@ -7676,6 +7676,79 @@ static int SQLITE_TCLAPI test_mmap_warm(
}
}
+/*
+** Usage: decode_hexdb TEXT
+**
+** Example: db deserialize [decode_hexdb $output_of_dbtotxt]
+**
+** This routine returns a byte-array for an SQLite database file that
+** is constructed from a text input which is the output of the "dbtotxt"
+** utility.
+*/
+static int SQLITE_TCLAPI test_decode_hexdb(
+ void * clientData,
+ Tcl_Interp *interp,
+ int objc,
+ Tcl_Obj *CONST objv[]
+){
+ const char *zIn = 0;
+ unsigned char *a = 0;
+ int n = 0;
+ int lineno = 0;
+ int i, iNext;
+ int iOffset = 0;
+ int j, k;
+ int rc;
+ unsigned char x[16];
+ if( objc!=2 ){
+ Tcl_WrongNumArgs(interp, 1, objv, "HEXDB");
+ return TCL_ERROR;
+ }
+ zIn = Tcl_GetString(objv[1]);
+ for(i=0; zIn[i]; i=iNext){
+ lineno++;
+ for(iNext=i; zIn[iNext] && zIn[iNext]!='\n'; iNext++){}
+ if( zIn[iNext]=='\n' ) iNext++;
+ while( zIn[i]==' ' || zIn[i]=='\t' ){ i++; }
+ if( a==0 ){
+ int pgsz;
+ rc = sscanf(zIn+i, "| size %d pagesize %d", &n, &pgsz);
+ if( rc!=2 ) continue;
+ if( n<512 ){
+ Tcl_AppendResult(interp, "bad 'size' field", (void*)0);
+ return TCL_ERROR;
+ }
+ a = malloc( n );
+ if( a==0 ){
+ Tcl_AppendResult(interp, "out of memory", (void*)0);
+ return TCL_ERROR;
+ }
+ memset(a, 0, n);
+ continue;
+ }
+ rc = sscanf(zIn+i, "| page %d offset %d", &j, &k);
+ if( rc==2 ){
+ iOffset = k;
+ continue;
+ }
+ rc = sscanf(zIn+i,"| %d: %hhx %hhx %hhx %hhx %hhx %hhx %hhx %hhx"
+ " %hhx %hhx %hhx %hhx %hhx %hhx %hhx %hhx",
+ &j, &x[0], &x[1], &x[2], &x[3], &x[4], &x[5], &x[6], &x[7],
+ &x[8], &x[9], &x[10], &x[11], &x[12], &x[13], &x[14], &x[15]);
+ if( rc==17 ){
+ k = iOffset+j;
+ if( k+16<=n ){
+ memcpy(a+k, x, 16);
+ }
+ continue;
+ }
+ }
+ Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(a, n));
+ free(a);
+ return TCL_OK;
+}
+
+
/*
** Register commands with the TCL interpreter.
*/
@@ -7956,6 +8029,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
{ "atomic_batch_write", test_atomic_batch_write, 0 },
{ "sqlite3_mmap_warm", test_mmap_warm, 0 },
{ "sqlite3_config_sorterref", test_config_sorterref, 0 },
+ { "decode_hexdb", test_decode_hexdb, 0 },
};
static int bitmask_size = sizeof(Bitmask)*8;
static int longdouble_size = sizeof(LONGDOUBLE_TYPE);
diff --git a/src/tokenize.c b/src/tokenize.c
index 05ca86e74f..297f9ab002 100644
--- a/src/tokenize.c
+++ b/src/tokenize.c
@@ -545,73 +545,6 @@ int sqlite3GetToken(const unsigned char *z, int *tokenType){
return i;
}
-#ifdef SQLITE_ENABLE_NORMALIZE
-/*
-** Return the length (in bytes) of the token that begins at z[0].
-** Store the token type in *tokenType before returning. If flags has
-** SQLITE_TOKEN_NORMALIZE flag enabled, use the identifier token type
-** for keywords. Add SQLITE_TOKEN_QUOTED to flags if the token was
-** actually a quoted identifier. Add SQLITE_TOKEN_KEYWORD to flags
-** if the token was recognized as a keyword; this is useful when the
-** SQLITE_TOKEN_NORMALIZE flag is used, because it enables the caller
-** to differentiate between a keyword being treated as an identifier
-** (for normalization purposes) and an actual identifier.
-*/
-int sqlite3GetTokenNormalized(
- const unsigned char *z,
- int *tokenType,
- int *flags
-){
- int n;
- unsigned char iClass = aiClass[*z];
- if( iClass==CC_KYWD ){
- int i;
- for(i=1; aiClass[z[i]]<=CC_KYWD; i++){}
- if( IdChar(z[i]) ){
- /* This token started out using characters that can appear in keywords,
- ** but z[i] is a character not allowed within keywords, so this must
- ** be an identifier instead */
- i++;
- while( IdChar(z[i]) ){ i++; }
- *tokenType = TK_ID;
- return i;
- }
- *tokenType = TK_ID;
- n = keywordCode((char*)z, i, tokenType);
- /* If the token is no longer considered to be an identifier, then it is a
- ** keyword of some kind. Make the token back into an identifier and then
- ** set the SQLITE_TOKEN_KEYWORD flag. Several non-identifier tokens are
- ** used verbatim, including IN, IS, NOT, and NULL. */
- switch( *tokenType ){
- case TK_ID: {
- /* do nothing, handled by caller */
- break;
- }
- case TK_IN:
- case TK_IS:
- case TK_NOT:
- case TK_NULL: {
- *flags |= SQLITE_TOKEN_KEYWORD;
- break;
- }
- default: {
- *tokenType = TK_ID;
- *flags |= SQLITE_TOKEN_KEYWORD;
- break;
- }
- }
- }else{
- n = sqlite3GetToken(z, tokenType);
- /* If the token is considered to be an identifier and the character class
- ** of the first character is a quote, set the SQLITE_TOKEN_QUOTED flag. */
- if( *tokenType==TK_ID && (iClass==CC_QUOTE || iClass==CC_QUOTE2) ){
- *flags |= SQLITE_TOKEN_QUOTED;
- }
- }
- return n;
-}
-#endif /* SQLITE_ENABLE_NORMALIZE */
-
/*
** Run the parser on the given SQL string. The parser structure is
** passed in. An SQLITE_ status code is returned. If an error occurs
@@ -781,3 +714,138 @@ int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
assert( nErr==0 || pParse->rc!=SQLITE_OK );
return nErr;
}
+
+
+#ifdef SQLITE_ENABLE_NORMALIZE
+/*
+** Insert a single space character into pStr if the current string
+** ends with an identifier
+*/
+static void addSpaceSeparator(sqlite3_str *pStr){
+ if( pStr->nChar && sqlite3IsIdChar(pStr->zText[pStr->nChar-1]) ){
+ sqlite3_str_append(pStr, " ", 1);
+ }
+}
+
+/*
+** Compute a normalization of the SQL given by zSql[0..nSql-1]. Return
+** the normalization in space obtained from sqlite3DbMalloc(). Or return
+** NULL if anything goes wrong or if zSql is NULL.
+*/
+char *sqlite3Normalize(
+ Vdbe *pVdbe, /* VM being reprepared */
+ const char *zSql /* The original SQL string */
+){
+ sqlite3 *db; /* The database connection */
+ int i; /* Next unread byte of zSql[] */
+ int n; /* length of current token */
+ int tokenType; /* type of current token */
+ int prevType; /* Previous non-whitespace token */
+ int nParen; /* Number of nested levels of parentheses */
+ int iStartIN; /* Start of RHS of IN operator in z[] */
+ int nParenAtIN; /* Value of nParent at start of RHS of IN operator */
+ int j; /* Bytes of normalized SQL generated so far */
+ sqlite3_str *pStr; /* The normalized SQL string under construction */
+
+ db = sqlite3VdbeDb(pVdbe);
+ tokenType = -1;
+ nParen = iStartIN = nParenAtIN = 0;
+ pStr = sqlite3_str_new(db);
+ assert( pStr!=0 ); /* sqlite3_str_new() never returns NULL */
+ for(i=0; zSql[i] && pStr->accError==0; i+=n){
+ if( tokenType!=TK_SPACE ){
+ prevType = tokenType;
+ }
+ n = sqlite3GetToken((unsigned char*)zSql+i, &tokenType);
+ if( NEVER(n<=0) ) break;
+ switch( tokenType ){
+ case TK_SPACE: {
+ break;
+ }
+ case TK_NULL: {
+ if( prevType==TK_IS || prevType==TK_NOT ){
+ sqlite3_str_append(pStr, " NULL", 5);
+ break;
+ }
+ /* Fall through */
+ }
+ case TK_STRING:
+ case TK_INTEGER:
+ case TK_FLOAT:
+ case TK_VARIABLE:
+ case TK_BLOB: {
+ sqlite3_str_append(pStr, "?", 1);
+ break;
+ }
+ case TK_LP: {
+ nParen++;
+ if( prevType==TK_IN ){
+ iStartIN = pStr->nChar;
+ nParenAtIN = nParen;
+ }
+ sqlite3_str_append(pStr, "(", 1);
+ break;
+ }
+ case TK_RP: {
+ if( iStartIN>0 && nParen==nParenAtIN ){
+ assert( pStr->nChar>=iStartIN );
+ pStr->nChar = iStartIN+1;
+ sqlite3_str_append(pStr, "?,?,?", 5);
+ iStartIN = 0;
+ }
+ nParen--;
+ sqlite3_str_append(pStr, ")", 1);
+ break;
+ }
+ case TK_ID: {
+ iStartIN = 0;
+ j = pStr->nChar;
+ if( sqlite3Isquote(zSql[i]) ){
+ char *zId = sqlite3DbStrNDup(db, zSql+i, n);
+ int nId;
+ int eType = 0;
+ if( zId==0 ) break;
+ sqlite3Dequote(zId);
+ if( zSql[i]=='"' && sqlite3VdbeUsesDoubleQuotedString(pVdbe, zId) ){
+ sqlite3_str_append(pStr, "?", 1);
+ sqlite3DbFree(db, zId);
+ break;
+ }
+ nId = sqlite3Strlen30(zId);
+ if( sqlite3GetToken((u8*)zId, &eType)==nId && eType==TK_ID ){
+ addSpaceSeparator(pStr);
+ sqlite3_str_append(pStr, zId, nId);
+ }else{
+ sqlite3_str_appendf(pStr, "\"%w\"", zId);
+ }
+ sqlite3DbFree(db, zId);
+ }else{
+ addSpaceSeparator(pStr);
+ sqlite3_str_append(pStr, zSql+i, n);
+ }
+ while( jnChar ){
+ pStr->zText[j] = sqlite3Tolower(pStr->zText[j]);
+ j++;
+ }
+ break;
+ }
+ case TK_SELECT: {
+ iStartIN = 0;
+ /* fall through */
+ }
+ default: {
+ if( sqlite3IsIdChar(zSql[i]) ) addSpaceSeparator(pStr);
+ j = pStr->nChar;
+ sqlite3_str_append(pStr, zSql+i, n);
+ while( jnChar ){
+ pStr->zText[j] = sqlite3Toupper(pStr->zText[j]);
+ j++;
+ }
+ break;
+ }
+ }
+ }
+ if( tokenType!=TK_SEMI ) sqlite3_str_append(pStr, ";", 1);
+ return sqlite3_str_finish(pStr);
+}
+#endif /* SQLITE_ENABLE_NORMALIZE */
diff --git a/src/vacuum.c b/src/vacuum.c
index 7e0e43adca..e2e50de457 100644
--- a/src/vacuum.c
+++ b/src/vacuum.c
@@ -102,16 +102,16 @@ static int execSqlF(sqlite3 *db, char **pzErrMsg, const char *zSql, ...){
** transient would cause the database file to appear to be deleted
** following reboot.
*/
-void sqlite3Vacuum(Parse *pParse, Token *pNm){
+void sqlite3Vacuum(Parse *pParse, Token *pNm, Expr *pInto){
Vdbe *v = sqlite3GetVdbe(pParse);
int iDb = 0;
- if( v==0 ) return;
+ if( v==0 ) goto build_vacuum_end;
if( pNm ){
#ifndef SQLITE_BUG_COMPATIBLE_20160819
/* Default behavior: Report an error if the argument to VACUUM is
** not recognized */
iDb = sqlite3TwoPartName(pParse, pNm, pNm, &pNm);
- if( iDb<0 ) return;
+ if( iDb<0 ) goto build_vacuum_end;
#else
/* When SQLITE_BUG_COMPATIBLE_20160819 is defined, unrecognized arguments
** to VACUUM are silently ignored. This is a back-out of a bug fix that
@@ -123,21 +123,33 @@ void sqlite3Vacuum(Parse *pParse, Token *pNm){
#endif
}
if( iDb!=1 ){
- sqlite3VdbeAddOp1(v, OP_Vacuum, iDb);
+ int iIntoReg = 0;
+ if( pInto ){
+ iIntoReg = ++pParse->nMem;
+ sqlite3ExprCode(pParse, pInto, iIntoReg);
+ }
+ sqlite3VdbeAddOp2(v, OP_Vacuum, iDb, iIntoReg);
sqlite3VdbeUsesBtree(v, iDb);
}
+build_vacuum_end:
+ sqlite3ExprDelete(pParse->db, pInto);
return;
}
/*
** This routine implements the OP_Vacuum opcode of the VDBE.
*/
-int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db, int iDb){
+int sqlite3RunVacuum(
+ char **pzErrMsg, /* Write error message here */
+ sqlite3 *db, /* Database connection */
+ int iDb, /* Which attached DB to vacuum */
+ sqlite3_value *pOut /* Write results here, if not NULL */
+){
int rc = SQLITE_OK; /* Return code from service routines */
Btree *pMain; /* The database being vacuumed */
Btree *pTemp; /* The temporary database we vacuum into */
- u16 saved_mDbFlags; /* Saved value of db->mDbFlags */
- u32 saved_flags; /* Saved value of db->flags */
+ u32 saved_mDbFlags; /* Saved value of db->mDbFlags */
+ u64 saved_flags; /* Saved value of db->flags */
int saved_nChange; /* Saved value of db->nChange */
int saved_nTotalChange; /* Saved value of db->nTotalChange */
u8 saved_mTrace; /* Saved trace settings */
@@ -146,6 +158,7 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db, int iDb){
int nRes; /* Bytes of reserved space at the end of each page */
int nDb; /* Number of attached databases */
const char *zDbMain; /* Schema name of database to vacuum */
+ const char *zOut; /* Name of output file */
if( !db->autoCommit ){
sqlite3SetString(pzErrMsg, db, "cannot VACUUM from within a transaction");
@@ -155,6 +168,15 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db, int iDb){
sqlite3SetString(pzErrMsg, db,"cannot VACUUM - SQL statements in progress");
return SQLITE_ERROR;
}
+ if( pOut ){
+ if( sqlite3_value_type(pOut)!=SQLITE_TEXT ){
+ sqlite3SetString(pzErrMsg, db, "non-text filename");
+ return SQLITE_ERROR;
+ }
+ zOut = (const char*)sqlite3_value_text(pOut);
+ }else{
+ zOut = "";
+ }
/* Save the current value of the database flags so that it can be
** restored before returning. Then set the writable-schema flag, and
@@ -166,7 +188,7 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db, int iDb){
saved_mTrace = db->mTrace;
db->flags |= SQLITE_WriteSchema | SQLITE_IgnoreChecks;
db->mDbFlags |= DBFLAG_PreferBuiltin | DBFLAG_Vacuum;
- db->flags &= ~(SQLITE_ForeignKeys | SQLITE_ReverseOrder
+ db->flags &= ~(u64)(SQLITE_ForeignKeys | SQLITE_ReverseOrder
| SQLITE_Defensive | SQLITE_CountRows);
db->mTrace = 0;
@@ -189,19 +211,21 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db, int iDb){
** to write the journal header file.
*/
nDb = db->nDb;
- rc = execSql(db, pzErrMsg, "ATTACH''AS vacuum_db");
+ rc = execSqlF(db, pzErrMsg, "ATTACH %Q AS vacuum_db", zOut);
if( rc!=SQLITE_OK ) goto end_of_vacuum;
assert( (db->nDb-1)==nDb );
pDb = &db->aDb[nDb];
assert( strcmp(pDb->zDbSName,"vacuum_db")==0 );
pTemp = pDb->pBt;
-
- /* The call to execSql() to attach the temp database has left the file
- ** locked (as there was more than one active statement when the transaction
- ** to read the schema was concluded. Unlock it here so that this doesn't
- ** cause problems for the call to BtreeSetPageSize() below. */
- sqlite3BtreeCommit(pTemp);
-
+ if( pOut ){
+ sqlite3_file *id = sqlite3PagerFile(sqlite3BtreePager(pTemp));
+ i64 sz = 0;
+ if( id->pMethods!=0 && (sqlite3OsFileSize(id, &sz)!=SQLITE_OK || sz>0) ){
+ rc = SQLITE_ERROR;
+ sqlite3SetString(pzErrMsg, db, "output file already exists");
+ goto end_of_vacuum;
+ }
+ }
nRes = sqlite3BtreeGetOptimalReserve(pMain);
/* A VACUUM cannot change the pagesize of an encrypted database. */
@@ -225,7 +249,7 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db, int iDb){
*/
rc = execSql(db, pzErrMsg, "BEGIN");
if( rc!=SQLITE_OK ) goto end_of_vacuum;
- rc = sqlite3BtreeBeginTrans(pMain, 2, 0);
+ rc = sqlite3BtreeBeginTrans(pMain, pOut==0 ? 2 : 0, 0);
if( rc!=SQLITE_OK ) goto end_of_vacuum;
/* Do not attempt to change the page size for a WAL database */
@@ -320,7 +344,7 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db, int iDb){
};
assert( 1==sqlite3BtreeIsInTrans(pTemp) );
- assert( 1==sqlite3BtreeIsInTrans(pMain) );
+ assert( pOut!=0 || 1==sqlite3BtreeIsInTrans(pMain) );
/* Copy Btree meta values */
for(i=0; iflags */
diff --git a/src/vdbe.c b/src/vdbe.c
index fa543a50ef..d195acab72 100644
--- a/src/vdbe.c
+++ b/src/vdbe.c
@@ -6715,14 +6715,19 @@ case OP_JournalMode: { /* out2 */
#endif /* SQLITE_OMIT_PRAGMA */
#if !defined(SQLITE_OMIT_VACUUM) && !defined(SQLITE_OMIT_ATTACH)
-/* Opcode: Vacuum P1 * * * *
+/* Opcode: Vacuum P1 P2 * * *
**
** Vacuum the entire database P1. P1 is 0 for "main", and 2 or more
** for an attached database. The "temp" database may not be vacuumed.
+**
+** If P2 is not zero, then it is a register holding a string which is
+** the file into which the result of vacuum should be written. When
+** P2 is zero, the vacuum overwrites the original database.
*/
case OP_Vacuum: {
assert( p->readOnly==0 );
- rc = sqlite3RunVacuum(&p->zErrMsg, db, pOp->p1);
+ rc = sqlite3RunVacuum(&p->zErrMsg, db, pOp->p1,
+ pOp->p2 ? &aMem[pOp->p2] : 0);
if( rc ) goto abort_due_to_error;
break;
}
@@ -7125,7 +7130,7 @@ case OP_VRename: {
rc = sqlite3VdbeChangeEncoding(pName, SQLITE_UTF8);
if( rc ) goto abort_due_to_error;
rc = pVtab->pModule->xRename(pVtab, pName->z);
- if( isLegacy==0 ) db->flags &= ~SQLITE_LegacyAlter;
+ if( isLegacy==0 ) db->flags &= ~(u64)SQLITE_LegacyAlter;
sqlite3VtabImportErrmsg(p, pVtab);
p->expired = 0;
if( rc ) goto abort_due_to_error;
diff --git a/src/vdbe.h b/src/vdbe.h
index d42acc0cca..f4d360e49e 100644
--- a/src/vdbe.h
+++ b/src/vdbe.h
@@ -251,6 +251,10 @@ void sqlite3VdbeCountChanges(Vdbe*);
sqlite3 *sqlite3VdbeDb(Vdbe*);
u8 sqlite3VdbePrepareFlags(Vdbe*);
void sqlite3VdbeSetSql(Vdbe*, const char *z, int n, u8);
+#ifdef SQLITE_ENABLE_NORMALIZE
+void sqlite3VdbeAddDblquoteStr(sqlite3*,Vdbe*,const char*);
+int sqlite3VdbeUsesDoubleQuotedString(Vdbe*,const char*);
+#endif
void sqlite3VdbeSwap(Vdbe*,Vdbe*);
VdbeOp *sqlite3VdbeTakeOpArray(Vdbe*, int*, int*);
sqlite3_value *sqlite3VdbeGetBoundValue(Vdbe*, int, u8);
diff --git a/src/vdbeInt.h b/src/vdbeInt.h
index 5c719923d7..70543526c1 100644
--- a/src/vdbeInt.h
+++ b/src/vdbeInt.h
@@ -335,6 +335,9 @@ struct sqlite3_context {
*/
typedef unsigned bft; /* Bit Field Type */
+/* The ScanStatus object holds a single value for the
+** sqlite3_stmt_scanstatus() interface.
+*/
typedef struct ScanStatus ScanStatus;
struct ScanStatus {
int addrExplain; /* OP_Explain for loop */
@@ -345,6 +348,19 @@ struct ScanStatus {
char *zName; /* Name of table or index */
};
+/* The DblquoteStr object holds the text of a double-quoted
+** string for a prepared statement. A linked list of these objects
+** is constructed during statement parsing and is held on Vdbe.pDblStr.
+** When computing a normalized SQL statement for an SQL statement, that
+** list is consulted for each double-quoted identifier to see if the
+** identifier should really be a string literal.
+*/
+typedef struct DblquoteStr DblquoteStr;
+struct DblquoteStr {
+ DblquoteStr *pNextStr; /* Next string literal in the list */
+ char z[8]; /* Dequoted value for the string */
+};
+
/*
** An instance of the virtual machine. This structure contains the complete
** state of the virtual machine.
@@ -364,7 +380,7 @@ struct Vdbe {
int pc; /* The program counter */
int rc; /* Value to return */
int nChange; /* Number of db changes made since last reset */
- int iStatement; /* Statement number (or 0 if has not opened stmt) */
+ int iStatement; /* Statement number (or 0 if has no opened stmt) */
i64 iCurrentTime; /* Value of julianday('now') for this statement */
i64 nFkConstraint; /* Number of imm. FK constraints this VM */
i64 nStmtDefCons; /* Number of def. constraints when stmt started */
@@ -408,6 +424,7 @@ struct Vdbe {
char *zSql; /* Text of the SQL statement that generated this */
#ifdef SQLITE_ENABLE_NORMALIZE
char *zNormSql; /* Normalization of the associated SQL statement */
+ DblquoteStr *pDblStr; /* List of double-quoted string literals */
#endif
void *pFree; /* Free this when deleting the vdbe */
VdbeFrame *pFrame; /* Parent frame */
diff --git a/src/vdbeapi.c b/src/vdbeapi.c
index d8a463ae3b..23b19273b6 100644
--- a/src/vdbeapi.c
+++ b/src/vdbeapi.c
@@ -585,7 +585,7 @@ static int sqlite3Step(Vdbe *p){
return SQLITE_NOMEM_BKPT;
}
- if( p->pc<=0 && p->expired ){
+ if( p->pc<0 && p->expired ){
p->rc = SQLITE_SCHEMA;
rc = SQLITE_ERROR;
goto end_of_step;
@@ -662,9 +662,9 @@ end_of_step:
|| (rc&0xff)==SQLITE_BUSY || rc==SQLITE_MISUSE
);
assert( (p->rc!=SQLITE_ROW && p->rc!=SQLITE_DONE) || p->rc==p->rcApp );
- if( (p->prepFlags & SQLITE_PREPARE_SAVESQL)!=0
- && rc!=SQLITE_ROW
- && rc!=SQLITE_DONE
+ if( rc!=SQLITE_ROW
+ && rc!=SQLITE_DONE
+ && (p->prepFlags & SQLITE_PREPARE_SAVESQL)!=0
){
/* If this statement was prepared using saved SQL and an
** error has occurred, then return the error code in p->rc to the
@@ -1286,7 +1286,7 @@ static int vdbeUnbind(Vdbe *p, int i){
pVar = &p->aVar[i];
sqlite3VdbeMemRelease(pVar);
pVar->flags = MEM_Null;
- sqlite3Error(p->db, SQLITE_OK);
+ p->db->errCode = SQLITE_OK;
/* If the bit corresponding to this variable in Vdbe.expmask is set, then
** binding a new value to this variable invalidates the current query plan.
@@ -1713,9 +1713,9 @@ char *sqlite3_expanded_sql(sqlite3_stmt *pStmt){
const char *sqlite3_normalized_sql(sqlite3_stmt *pStmt){
Vdbe *p = (Vdbe *)pStmt;
if( p==0 ) return 0;
- if( p->zNormSql==0 && p->zSql!=0 ){
+ if( p->zNormSql==0 && ALWAYS(p->zSql!=0) ){
sqlite3_mutex_enter(p->db->mutex);
- p->zNormSql = sqlite3Normalize(p, p->zSql, sqlite3Strlen30(p->zSql));
+ p->zNormSql = sqlite3Normalize(p, p->zSql);
sqlite3_mutex_leave(p->db->mutex);
}
return p->zNormSql;
diff --git a/src/vdbeaux.c b/src/vdbeaux.c
index ba8d2b11c2..05fa0f623c 100644
--- a/src/vdbeaux.c
+++ b/src/vdbeaux.c
@@ -64,15 +64,45 @@ void sqlite3VdbeSetSql(Vdbe *p, const char *z, int n, u8 prepFlags){
}
assert( p->zSql==0 );
p->zSql = sqlite3DbStrNDup(p->db, z, n);
-#ifdef SQLITE_ENABLE_NORMALIZE
- assert( p->zNormSql==0 );
- if( p->zSql && (prepFlags & SQLITE_PREPARE_NORMALIZE)!=0 ){
- p->zNormSql = sqlite3Normalize(p, p->zSql, n);
- assert( p->zNormSql!=0 || p->db->mallocFailed );
- }
-#endif
}
+#ifdef SQLITE_ENABLE_NORMALIZE
+/*
+** Add a new element to the Vdbe->pDblStr list.
+*/
+void sqlite3VdbeAddDblquoteStr(sqlite3 *db, Vdbe *p, const char *z){
+ if( p ){
+ int n = sqlite3Strlen30(z);
+ DblquoteStr *pStr = sqlite3DbMallocRawNN(db,
+ sizeof(*pStr)+n+1-sizeof(pStr->z));
+ if( pStr ){
+ pStr->pNextStr = p->pDblStr;
+ p->pDblStr = pStr;
+ memcpy(pStr->z, z, n+1);
+ }
+ }
+}
+#endif
+
+#ifdef SQLITE_ENABLE_NORMALIZE
+/*
+** zId of length nId is a double-quoted identifier. Check to see if
+** that identifier is really used as a string literal.
+*/
+int sqlite3VdbeUsesDoubleQuotedString(
+ Vdbe *pVdbe, /* The prepared statement */
+ const char *zId /* The double-quoted identifier, already dequoted */
+){
+ DblquoteStr *pStr;
+ assert( zId!=0 );
+ if( pVdbe->pDblStr==0 ) return 0;
+ for(pStr=pVdbe->pDblStr; pStr; pStr=pStr->pNextStr){
+ if( strcmp(zId, pStr->z)==0 ) return 1;
+ }
+ return 0;
+}
+#endif
+
/*
** Swap all content between two VDBE structures.
*/
@@ -92,7 +122,7 @@ void sqlite3VdbeSwap(Vdbe *pA, Vdbe *pB){
zTmp = pA->zSql;
pA->zSql = pB->zSql;
pB->zSql = zTmp;
-#ifdef SQLITE_ENABLE_NORMALIZE
+#if 0
zTmp = pA->zNormSql;
pA->zNormSql = pB->zNormSql;
pB->zNormSql = zTmp;
@@ -2873,7 +2903,7 @@ int sqlite3VdbeHalt(Vdbe *p){
}else{
db->nDeferredCons = 0;
db->nDeferredImmCons = 0;
- db->flags &= ~SQLITE_DeferFKs;
+ db->flags &= ~(u64)SQLITE_DeferFKs;
sqlite3CommitInternalChanges(db);
}
}else{
@@ -3190,6 +3220,13 @@ void sqlite3VdbeClearObject(sqlite3 *db, Vdbe *p){
sqlite3DbFree(db, p->zSql);
#ifdef SQLITE_ENABLE_NORMALIZE
sqlite3DbFree(db, p->zNormSql);
+ {
+ DblquoteStr *pThis, *pNext;
+ for(pThis=p->pDblStr; pThis; pThis=pNext){
+ pNext = pThis->pNextStr;
+ sqlite3DbFree(db, pThis);
+ }
+ }
#endif
#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
{
diff --git a/src/whereexpr.c b/src/whereexpr.c
index dbb7f0d08e..db0a38d622 100644
--- a/src/whereexpr.c
+++ b/src/whereexpr.c
@@ -777,6 +777,7 @@ static void exprAnalyzeOrTerm(
** and column is found but leave okToChngToIN false if not found.
*/
for(j=0; j<2 && !okToChngToIN; j++){
+ Expr *pLeft = 0;
pOrTerm = pOrWc->a;
for(i=pOrWc->nTerm-1; i>=0; i--, pOrTerm++){
assert( pOrTerm->eOperator & WO_EQ );
@@ -800,6 +801,7 @@ static void exprAnalyzeOrTerm(
}
iColumn = pOrTerm->u.leftColumn;
iCursor = pOrTerm->leftCursor;
+ pLeft = pOrTerm->pExpr->pLeft;
break;
}
if( i<0 ){
@@ -819,7 +821,9 @@ static void exprAnalyzeOrTerm(
assert( pOrTerm->eOperator & WO_EQ );
if( pOrTerm->leftCursor!=iCursor ){
pOrTerm->wtFlags &= ~TERM_OR_OK;
- }else if( pOrTerm->u.leftColumn!=iColumn ){
+ }else if( pOrTerm->u.leftColumn!=iColumn || (iColumn==XN_EXPR
+ && sqlite3ExprCompare(pParse, pOrTerm->pExpr->pLeft, pLeft, -1)
+ )){
okToChngToIN = 0;
}else{
int affLeft, affRight;
diff --git a/src/window.c b/src/window.c
index f5deae9a6e..f3e274d6e3 100644
--- a/src/window.c
+++ b/src/window.c
@@ -2133,6 +2133,7 @@ Window *sqlite3WindowDup(sqlite3 *db, Expr *pOwner, Window *p){
if( pNew ){
pNew->zName = sqlite3DbStrDup(db, p->zName);
pNew->pFilter = sqlite3ExprDup(db, p->pFilter, 0);
+ pNew->pFunc = p->pFunc;
pNew->pPartition = sqlite3ExprListDup(db, p->pPartition, 0);
pNew->pOrderBy = sqlite3ExprListDup(db, p->pOrderBy, 0);
pNew->eType = p->eType;
diff --git a/test/concurrent2.test b/test/concurrent2.test
index 65f0022ab2..b7a8318930 100644
--- a/test/concurrent2.test
+++ b/test/concurrent2.test
@@ -343,18 +343,21 @@ do_execsql_test 7.3.2 {
# of corruption.
#
reset_db
-do_execsql_test 8.1 {
- PRAGMA journal_mode = wal;
- CREATE TABLE kv(k INTEGER PRIMARY KEY, v UNIQUE);
- INSERT INTO kv VALUES(NULL, randomblob(750));
- INSERT INTO kv SELECT NULL, randomblob(750) FROM kv;
- INSERT INTO kv SELECT NULL, randomblob(750) FROM kv;
- INSERT INTO kv SELECT NULL, randomblob(750) FROM kv;
- INSERT INTO kv SELECT NULL, randomblob(750) FROM kv;
- INSERT INTO kv SELECT NULL, randomblob(750) FROM kv;
- DELETE FROM kv WHERE rowid%2;
- PRAGMA freelist_count;
-} {wal 34}
+do_test 8.1 {
+ execsql {
+ PRAGMA journal_mode = wal;
+ CREATE TABLE kv(k INTEGER PRIMARY KEY, v UNIQUE);
+ INSERT INTO kv VALUES(NULL, randomblob(750));
+ INSERT INTO kv SELECT NULL, randomblob(750) FROM kv;
+ INSERT INTO kv SELECT NULL, randomblob(750) FROM kv;
+ INSERT INTO kv SELECT NULL, randomblob(750) FROM kv;
+ INSERT INTO kv SELECT NULL, randomblob(750) FROM kv;
+ INSERT INTO kv SELECT NULL, randomblob(750) FROM kv;
+ DELETE FROM kv WHERE rowid%2;
+ }
+ set v [db one {PRAGMA freelist_count}]
+ expr $v==33 || $v==34
+} {1}
do_execsql_test 8.2 { PRAGMA integrity_check } ok
do_execsql_test 8.3 {
BEGIN CONCURRENT;
diff --git a/test/dbfuzz001.test b/test/dbfuzz001.test
new file mode 100644
index 0000000000..0c19b06180
--- /dev/null
+++ b/test/dbfuzz001.test
@@ -0,0 +1,355 @@
+# 2012-12-13
+#
+# The author disclaims copyright to this source code. In place of
+# a legal notice, here is a blessing:
+#
+# May you do good and not evil.
+# May you find forgiveness for yourself and forgive others.
+# May you share freely, never taking more than you give.
+#
+#***********************************************************************
+#
+# Test cases for corrupt database files.
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+
+ifcapable !deserialize {
+ finish_test
+ return
+}
+database_may_be_corrupt
+
+# In the following database file, there is 384 bytes of free space
+# on page 8 that does not appear on the freeblock list.
+#
+do_test dbfuzz001-100 {
+ sqlite3 db {}
+ db deserialize [decode_hexdb {
+ | size 5632 pagesize 512 filename c4.db
+ | page 1 offset 0
+ | 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3.
+ | 16: 02 00 01 01 00 40 20 20 00 00 00 02 00 00 00 0b .....@ ........
+ | 32: 00 00 00 06 00 00 00 01 00 00 00 28 00 00 00 04 ...........(....
+ | 48: 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 ................
+ | 80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 ................
+ | 96: 00 2e 30 38 0d 00 00 00 06 01 06 00 01 da 01 b0 ..08............
+ | 112: 01 56 01 86 01 2a 01 06 00 00 00 00 00 00 00 00 .V...*..........
+ | 256: 00 00 00 00 00 00 22 07 06 17 11 11 01 31 74 61 ......"......1ta
+ | 272: 62 6c 65 74 34 74 34 07 43 52 45 41 54 45 20 54 blet4t4.CREATE T
+ | 288: 41 42 4c 45 20 74 34 28 78 29 2a 06 06 17 13 11 ABLE t4(x)*.....
+ | 304: 01 3f 69 6e 64 65 78 00 00 00 00 00 00 00 00 00 .?index.........
+ | 336: 20 74 33 28 78 29 2e 04 06 17 15 11 01 45 69 6e t3(x).......Ein
+ | 352: 64 65 78 74 32 63 64 74 32 05 43 52 45 41 54 45 dext2cdt2.CREATE
+ | 368: 20 49 4e 44 45 58 20 74 32 63 64 20 4f 4e 20 74 INDEX t2cd ON t
+ | 384: 32 28 63 2c 64 29 28 05 06 17 11 11 01 3d 74 61 2(c,d)(......=ta
+ | 400: 62 6c 65 74 33 74 33 04 43 52 45 41 54 45 20 54 blet3t3.CREATE T
+ | 416: 41 42 4c 45 20 74 33 28 63 2c 78 2c 65 2c 66 29 ABLE t3(c,x,e,f)
+ | 432: 28 02 06 17 11 11 01 3d 74 61 62 6c 65 74 32 74 (......=tablet2t
+ | 448: 32 03 43 52 45 41 54 45 20 54 41 42 4c 45 20 74 2.CREATE TABLE t
+ | 464: 32 28 63 2c 64 2c 65 2c 66 29 24 01 06 17 11 11 2(c,d,e,f)$.....
+ | 480: 01 35 74 61 62 6c 65 74 31 74 31 02 43 52 45 41 .5tablet1t1.CREA
+ | 496: 54 45 20 54 41 42 4c 45 20 74 31 28 61 2c 62 29 TE TABLE t1(a,b)
+ | page 2 offset 512
+ | 0: 0d 00 00 00 00 02 00 00 00 00 00 00 00 00 00 00 ................
+ | page 3 offset 1024
+ | 0: 0d 00 00 00 00 02 00 00 00 00 00 00 00 00 00 00 ................
+ | page 4 offset 1536
+ | 0: 05 00 00 00 03 01 f1 00 00 00 00 0b 01 fb 01 f6 ................
+ | 16: 01 f1 00 16 00 00 09 06 05 01 01 01 01 04 04 03 ................
+ | 32: 03 07 05 05 01 01 09 09 02 02 19 04 05 17 17 17 ................
+ | 48: 17 73 65 76 65 6e 65 69 67 68 74 65 69 67 68 74 .seveneighteight
+ | 64: 73 65 76 65 6e 25 03 05 07 07 07 07 40 14 00 00 seven%......@...
+ | 80: 00 00 00 00 40 18 00 00 00 00 00 00 40 18 00 00 ....@.......@...
+ | 96: 00 00 00 00 40 14 00 00 00 00 00 00 09 02 05 01 ....@...........
+ | 112: 01 01 01 03 04 04 03 07 01 05 09 01 01 09 02 02 ................
+ | 352: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 1a ................
+ | 496: 00 00 00 00 0a 3e 00 00 00 09 21 00 00 00 08 06 .....>....!.....
+ | page 5 offset 2048
+ | 0: 0a 00 00 00 00 02 00 00 00 00 00 00 00 00 00 00 ................
+ | page 7 offset 3072
+ | 0: 0d 00 00 00 08 01 c2 00 01 fb 01 f6 01 f1 01 ec ................
+ | 16: 01 e0 01 d4 01 cb 01 c2 00 00 00 00 00 00 00 00 ................
+ | 96: 00 00 00 00 13 00 00 00 00 00 00 00 00 00 00 00 ................
+ | 224: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 ................
+ | 288: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 03 ................
+ | 448: 00 00 07 08 02 17 65 69 67 68 74 07 07 02 17 65 ......eight....e
+ | 464: 69 67 68 74 0a 06 02 07 40 18 00 00 00 00 00 00 ight....@.......
+ | 480: 0a 05 02 07 40 18 00 00 00 00 00 00 03 04 02 01 ....@...........
+ | 496: 04 03 03 02 01 04 03 02 02 01 02 03 01 02 01 02 ................
+ | page 8 offset 3584
+ | 0: 0d 00 21 00 01 00 16 00 00 16 00 16 00 16 00 16 ..!.............
+ | 16: 00 16 00 16 00 00 09 06 05 01 01 01 01 04 04 03 ................
+ | 32: 03 00 00 00 5f 01 09 09 02 02 00 00 00 56 17 17 ...._........V..
+ | 48: 17 73 65 76 65 6e 65 69 67 68 74 65 69 67 68 74 .seveneighteight
+ | 64: 73 65 76 65 6e 00 00 00 3b 07 07 07 40 14 00 00 seven...;...@...
+ | 80: 00 00 00 00 40 18 00 00 00 00 00 00 40 18 00 00 ....@.......@...
+ | 96: 00 00 00 00 40 14 00 00 00 00 00 00 00 00 00 14 ....@...........
+ | 112: 01 01 01 03 04 04 03 00 00 00 09 01 01 09 02 02 ................
+ | 352: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 1a ................
+ | page 9 offset 4096
+ | 0: 0d 00 00 00 1b 00 47 00 01 d9 01 be 01 af 01 a0 ......G.........
+ | 16: 01 91 01 82 01 73 01 64 01 55 01 46 01 37 01 28 .....s.d.U.F.7.(
+ | 32: 01 19 01 0a 00 fb 00 ec 00 dd 00 ce 00 bf 00 b0 ................
+ | 48: 00 a1 00 92 00 83 00 74 00 65 00 56 00 47 00 00 .......t.e.V.G..
+ | 64: 00 00 00 00 00 00 00 0d 21 00 00 48 01 54 00 01 ........!..H.T..
+ | 80: f7 01 ec 01 c5 01 0d 20 00 00 48 01 54 00 01 f7 ....... ..H.T...
+ | 96: 01 ec 01 c5 01 0d 1f 00 00 48 01 54 00 01 f7 01 .........H.T....
+ | 112: ec 01 c5 01 0d 1e 00 00 48 01 54 00 01 f7 01 ec ........H.T.....
+ | 128: 01 c5 01 0d 1d 00 00 48 01 54 00 01 f7 01 ec 01 .......H.T......
+ | 144: c5 01 0d 1c 00 00 48 01 54 00 01 f7 01 ec 01 c5 ......H.T.......
+ | 160: 01 0d 1b 00 00 48 01 54 00 01 f7 01 ec 01 c5 01 .....H.T........
+ | 176: 0d 1a 00 00 48 01 54 00 01 f7 01 ec 01 c5 01 0d ....H.T.........
+ | 192: 19 00 00 48 01 54 00 01 f7 01 ec 01 c5 01 0d 18 ...H.T..........
+ | 208: 00 00 48 01 54 00 01 f7 01 ec 01 c5 01 0d 17 00 ..H.T...........
+ | 224: 00 48 01 54 00 01 f7 01 ec 01 c5 01 0d 16 00 00 .H.T............
+ | 240: 48 01 54 00 01 f7 01 ec 01 c5 01 0d 15 00 00 48 H.T............H
+ | 256: 01 54 00 01 f7 01 ec 01 c5 01 0d 14 00 00 48 01 .T............H.
+ | 272: 54 00 01 f7 01 ec 01 c5 01 0d 13 00 00 48 01 54 T............H.T
+ | 288: 00 01 f7 01 ec 01 c5 01 0d 12 00 00 48 01 54 00 ............H.T.
+ | 304: 01 f7 01 ec 01 c5 01 0d 11 00 00 48 01 54 00 01 ...........H.T..
+ | 320: f7 01 ec 01 c5 01 0d 10 00 00 48 01 54 00 01 f7 ..........H.T...
+ | 336: 01 ec 01 c5 01 0d 0f 00 00 48 01 54 00 01 f7 01 .........H.T....
+ | 352: ec 01 c5 01 0d 0e 00 00 48 01 54 00 01 f7 01 ec ........H.T.....
+ | 368: 01 c5 01 0d 0d 00 00 48 01 54 00 01 f7 01 ec 01 .......H.T......
+ | 384: c5 01 0d 0c 00 00 48 01 54 00 01 f7 01 ec 01 c5 ......H.T.......
+ | 400: 01 0d 0b 00 00 48 01 54 00 01 f7 01 ec 01 c5 01 .....H.T........
+ | 416: 0d 0a 00 00 48 01 54 00 01 f7 01 ec 01 c5 01 0d ....H.T.........
+ | 432: 09 00 00 48 01 54 00 01 f7 01 ec 01 c5 01 19 08 ...H.T..........
+ | 448: 05 17 17 17 17 65 69 67 68 74 65 69 67 68 74 73 .....eighteights
+ | 464: 65 76 65 6e 73 65 76 65 6e 25 07 05 07 07 07 07 evenseven%......
+ | 480: 40 18 00 00 00 00 00 00 40 18 00 00 00 00 00 00 @.......@.......
+ | 496: 40 14 00 00 00 00 00 00 40 14 00 00 00 00 00 00 @.......@.......
+ | page 10 offset 4608
+ | 0: 0d 00 00 00 1d 00 4d 00 01 f1 01 e2 01 d3 01 c4 ......M.........
+ | 16: 01 b5 01 a6 01 97 01 88 01 79 01 6a 01 5b 01 4c .........y.j.[.L
+ | 32: 01 3d 01 2e 01 1f 01 10 01 01 00 f2 00 e3 00 d4 .=..............
+ | 48: 00 c5 00 b6 00 a7 00 98 00 89 00 7a 00 6b 00 5c ...........z.k.\
+ | 64: 00 4d 00 00 00 00 00 00 00 00 00 00 00 0d 3e 00 .M............>.
+ | 80: 00 48 01 54 00 01 f7 01 ec 01 c5 01 0d 3d 00 00 .H.T.........=..
+ | 96: 48 01 54 00 01 f7 01 ec 01 c5 01 0d 3c 00 00 48 H.T.........<..H
+ | 112: 01 54 00 01 f7 01 ec 01 c5 01 0d 3b 00 00 48 01 .T.........;..H.
+ | 128: 54 00 01 f7 01 ec 01 c5 01 0d 3a 00 00 48 01 54 T.........:..H.T
+ | 144: 00 01 f7 01 ec 01 c5 01 0d 39 00 00 48 01 54 00 .........9..H.T.
+ | 160: 01 f7 01 ec 01 c5 01 0d 38 00 00 48 01 54 00 01 ........8..H.T..
+ | 176: f7 01 ec 01 c5 01 0d 37 00 00 48 01 54 00 01 f7 .......7..H.T...
+ | 192: 01 ec 01 c5 01 0d 36 00 00 48 01 54 00 01 f7 01 ......6..H.T....
+ | 208: ec 01 c5 01 0d 35 00 00 48 01 54 00 01 f7 01 ec .....5..H.T.....
+ | 224: 01 c5 01 0d 34 00 00 48 01 54 00 01 f7 01 ec 01 ....4..H.T......
+ | 240: c5 01 0d 33 00 00 48 01 54 00 01 f7 01 ec 01 c5 ...3..H.T.......
+ | 256: 01 0d 32 00 00 48 01 54 00 01 f7 01 ec 01 c5 01 ..2..H.T........
+ | 272: 0d 31 00 00 48 01 54 00 01 f7 01 ec 01 c5 01 0d .1..H.T.........
+ | 288: 30 00 00 48 01 54 00 01 f7 01 ec 01 c5 01 0d 2f 0..H.T........./
+ | 304: 00 00 48 01 54 00 01 f7 01 ec 01 c5 01 0d 2e 00 ..H.T...........
+ | 320: 00 48 01 54 00 01 f7 01 ec 01 c5 01 0d 2d 00 00 .H.T.........-..
+ | 336: 48 01 54 00 01 f7 01 ec 01 c5 01 0d 2c 00 00 48 H.T.........,..H
+ | 352: 01 54 00 01 f7 01 ec 01 c5 01 0d 2b 00 00 48 01 .T.........+..H.
+ | 368: 54 00 01 f7 01 ec 01 c5 01 0d 2a 00 00 48 01 54 T.........*..H.T
+ | 384: 00 01 f7 01 ec 01 c5 01 0d 29 00 00 48 01 54 00 .........)..H.T.
+ | 400: 01 f7 01 ec 01 c5 01 0d 28 00 00 48 01 54 00 01 ........(..H.T..
+ | 416: f7 01 ec 01 c5 01 0d 27 00 00 48 01 54 00 01 f7 .......'..H.T...
+ | 432: 01 ec 01 c5 01 0d 26 00 00 48 01 54 00 01 f7 01 ......&..H.T....
+ | 448: ec 01 c5 01 0d 25 00 00 48 01 54 00 01 f7 01 ec .....%..H.T.....
+ | 464: 01 c5 01 0d 24 00 00 48 01 54 00 01 f7 01 ec 01 ....$..H.T......
+ | 480: c5 01 0d 23 00 00 48 01 54 00 01 f7 01 ec 01 c5 ...#..H.T.......
+ | 496: 01 0d 22 00 00 48 01 54 00 01 f7 01 ec 01 c5 01 .."..H.T........
+ | page 11 offset 5120
+ | 0: 0d 00 00 00 0a 01 6a 00 01 f1 01 e2 01 d3 01 c4 ......j.........
+ | 16: 01 b5 01 a6 01 97 01 88 01 79 01 6a 00 00 00 00 .........y.j....
+ | 352: 00 00 00 00 00 00 00 00 00 00 0d 48 00 00 48 01 ...........H..H.
+ | 368: 54 00 01 f7 01 ec 01 c5 01 0d 47 00 00 48 01 54 T.........G..H.T
+ | 384: 00 01 f7 01 ec 01 c5 01 0d 46 00 00 48 01 54 00 .........F..H.T.
+ | 400: 01 f7 01 ec 01 c5 01 0d 45 00 00 48 01 54 00 01 ........E..H.T..
+ | 416: f7 01 ec 01 c5 01 0d 44 00 00 48 01 54 00 01 f7 .......D..H.T...
+ | 432: 01 ec 01 c5 01 0d 43 00 00 48 01 54 00 01 f7 01 ......C..H.T....
+ | 448: ec 01 c5 01 0d 42 00 00 48 01 54 00 01 f7 01 ec .....B..H.T.....
+ | 464: 01 c5 01 0d 41 00 00 48 01 54 00 01 f7 01 ec 01 ....A..H.T......
+ | 480: c5 01 0d 40 00 00 48 01 54 00 01 f7 01 ec 01 c5 ...@..H.T.......
+ | 496: 01 0d 3f 00 00 48 01 54 00 01 f7 01 ec 01 c5 01 ..?..H.T........
+ | end c4.db
+ }]
+ db eval {PRAGMA integrity_check}
+} {/Fragmentation of 384 bytes reported as 0 on page 8/}
+
+# The DELETE query below deletes the very last cell from page 8.
+# Prior to a certain fix to sqlite3BtreeDelete() and because of the
+# corruption to the freeblock list on page 8, this would fail to
+# cause a rebalance operation, which would leave the btree in a weird
+# state that would lead to segfaults and or assertion faults.
+#
+do_execsql_test dbfuzz001-110 {
+ DELETE FROM t3 WHERE x IS NOT NULL AND +rowid=6;
+} {}
+
+# This is a dbfuzz2-generate test case that can cause a page with
+# pPage->nCell==0 to enter the balancer.
+#
+do_test dbfuzz001-200 {
+ db deserialize [decode_hexdb {
+ | size 3076 pagesize 512 filename c03.db
+ | page 1 offset 0
+ | 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3.
+ | 16: 02 00 01 01 00 40 20 20 00 00 00 0c 00 00 00 07 .....@ ........
+ | 32: 00 00 00 00 00 00 00 00 00 00 00 08 00 00 00 04 ................
+ | 48: 00 00 00 00 00 00 00 03 e8 00 00 01 00 00 00 00 ................
+ | 80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0c ................
+ | 96: 00 2e 2c 50 0d 00 00 00 06 01 06 00 01 da 01 b0 ..,P............
+ | 112: 01 56 01 86 01 2a 01 06 00 00 00 00 00 00 00 00 .V...*..........
+ | 128: 00 00 00 00 00 00 00 00 ef 00 00 00 00 00 00 00 ................
+ | 192: 00 7f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ | 224: 00 00 00 00 00 00 00 00 00 00 00 00 00 ff e9 00 ................
+ | 256: 00 00 00 00 00 00 22 07 06 17 11 11 01 31 74 61 ......"......1ta
+ | 272: 62 6c 65 74 34 74 34 07 43 52 45 41 54 45 20 54 blet4t4.CREATE T
+ | 288: 41 42 4c 45 20 74 34 28 78 29 2a 06 06 17 13 11 ABLE t4(x)*.....
+ | 304: 01 3f 69 6e 64 65 78 74 33 78 74 33 06 43 52 45 .?indext3xt3.CRE
+ | 320: 41 54 45 20 49 4e 44 45 58 20 74 33 64 20 4f 4e ATE INDEX t3d ON
+ | 336: 20 74 33 28 78 29 2e 04 06 17 15 11 01 45 69 6e t3(x).......Ein
+ | 352: 64 65 78 74 32 63 64 74 32 05 43 52 45 41 54 45 dext2cdt2.CREATE
+ | 368: 20 49 4e 44 45 58 20 74 32 63 64 20 4f 4e 20 74 INDEX t2cd ON t
+ | 384: 32 28 63 2c 64 29 28 05 06 17 11 11 01 3d 74 61 2(c,d)(......=ta
+ | 400: 62 6c 65 74 33 74 33 04 43 52 45 41 54 45 20 54 blet3t3.CREATE T
+ | 416: 41 42 4c 45 20 74 33 28 63 2c 78 2c 65 2c 66 29 ABLE t3(c,x,e,f)
+ | 432: 28 02 06 17 11 11 01 3d 74 61 62 6c 65 74 32 74 (......=tablet2t
+ | 448: 32 03 43 52 45 41 54 45 20 54 41 42 4c 45 20 74 2.CREATE TABLE t
+ | 464: 32 28 63 2c 64 2c 65 2c 66 29 24 01 06 17 11 11 2(c,d,e,f)$.....
+ | 480: 01 35 74 61 62 6c 65 74 31 74 31 02 43 52 45 41 .5tablet1t1.CREA
+ | 496: 54 45 20 54 41 42 4c 45 20 74 31 28 61 2c 62 29 TE TABLE t1(a,b)
+ | page 2 offset 512
+ | 0: 0d 00 00 00 04 01 cf 00 01 fa 01 f3 01 de 01 cf ................
+ | 176: 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ | 256: 00 00 14 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ | 368: 00 00 00 00 00 00 00 00 00 00 00 00 1e 00 00 00 ................
+ | 416: 00 00 00 1b 00 00 00 00 04 00 00 00 00 00 00 00 ................
+ | 448: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0d ................
+ | 464: 04 03 17 17 73 65 76 65 6e 65 69 67 68 74 13 03 ....seveneight..
+ | 480: 03 07 07 40 14 00 00 00 00 00 00 40 18 00 00 00 ...@.......@....
+ | 496: 00 00 00 05 02 03 01 01 03 04 04 01 03 09 01 02 ................
+ | page 3 offset 1024
+ | 0: 0d 00 00 00 08 01 54 00 01 f7 01 ec 01 c5 01 aa ......T.........
+ | 16: 01 a1 01 96 01 6f 01 54 00 00 00 00 00 00 00 00 .....o.T........
+ | 32: 00 00 00 00 00 00 00 03 e8 00 00 00 00 00 00 00 ................
+ | 336: 00 00 00 00 19 08 05 16 17 17 17 65 69 67 68 74 ...........eight
+ | 352: 65 69 67 68 74 73 65 76 65 6e 73 65 76 ff ff ff eightsevensev...
+ | 368: 0e 05 07 07 07 07 40 18 00 00 00 00 00 00 40 18 ......@.......@.
+ | 384: 00 00 00 00 00 00 40 14 00 00 00 00 00 00 40 14 ......@.......@.
+ | 400: 00 00 00 00 00 00 09 06 05 01 01 01 01 04 04 03 ................
+ | 416: 03 07 05 05 01 01 09 09 02 02 19 04 05 17 17 17 ................
+ | 432: 17 73 65 6f 65 6e 65 69 67 68 74 65 69 67 68 74 .seoeneighteight
+ | 448: 73 65 76 65 6e 25 03 05 07 07 07 07 40 14 00 00 seven%......@...
+ | 464: 00 00 00 00 40 18 00 00 00 00 00 00 40 18 00 00 ....@.......@...
+ | 480: 00 00 00 00 40 14 00 00 00 00 00 00 09 02 05 01 ....@...........
+ | 496: 01 01 01 03 04 04 03 07 01 05 09 01 01 09 02 02 ................
+ | page 4 offset 1536
+ | 0: 0d 00 00 00 00 00 10 00 00 00 00 00 00 00 00 00 ................
+ | 160: 00 00 00 ea 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ | 336: 00 00 00 00 00 00 00 00 00 00 00 00 20 00 00 00 ............ ...
+ | page 5 offset 2048
+ | 0: 0a 00 00 00 08 01 96 00 01 fa 01 c4 01 f2 01 bc ................
+ | 16: 01 dc 01 a6 01 96 01 cc 00 00 00 00 00 00 00 00 ................
+ | 48: 00 00 00 00 00 00 00 00 00 00 10 00 00 00 00 00 ................
+ | 288: 00 00 00 00 00 00 00 00 00 64 00 00 00 2b 00 00 .........d...+..
+ | 400: 00 00 00 00 00 00 0f 04 17 17 01 65 69 67 68 74 ...........eight
+ | 416: 65 69 6f 68 74 08 15 04 07 07 01 40 18 00 00 00 eioht......@....
+ | 432: 00 00 00 40 18 00 00 00 00 00 00 07 07 04 01 01 ...@............
+ | 448: 01 04 04 06 07 04 01 01 01 02 02 05 0f 04 17 17 ................
+ | 464: 01 73 65 76 65 6e 65 69 67 68 74 04 15 04 07 07 .seveneight.....
+ | 480: 01 40 14 00 00 00 00 00 00 40 18 00 00 00 00 00 .@.......@......
+ | 496: 00 03 07 04 01 01 01 03 04 02 05 04 09 01 09 02 ................
+ | page 6 offset 2560
+ | 0: 0a 00 00 00 00 02 00 00 00 00 00 00 00 0d 00 00 ................
+ | 16: 00 08 01 c2 00 01 fb 01 f6 01 f1 01 ec 01 e0 01 ................
+ | 32: d4 01 cb 01 c2 00 00 00 00 00 00 00 00 00 00 00 ................
+ | 160: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 04 00 ................
+ | 448: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 07 ................
+ | 464: 08 02 17 65 69 67 68 74 07 07 02 17 65 69 67 68 ...eight....eigh
+ | 480: 74 0a 06 02 07 40 18 00 00 00 00 00 00 0a 05 02 t....@..........
+ | 496: 07 40 18 00 04 02 01 04 03 03 02 01 04 03 02 02 .@..............
+ | end x/c03.db
+ }]
+ catchsql {INSERT INTO t3 SELECT * FROM t2;}
+} {1 {database disk image is malformed}}
+
+
+do_test dbfuzz001-110 {
+ sqlite3 db {}
+ db deserialize [decode_hexdb {
+| size 3584 pagesize 512 filename x/c02.db
+| page 1 offset 0
+| 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3.
+| 16: 02 00 01 01 00 40 20 20 00 00 00 0c 00 00 00 07 .....@ ........
+| 32: 00 00 00 00 00 00 00 00 00 00 00 08 00 00 00 04 ................
+| 48: 00 00 00 00 00 00 00 04 00 00 00 01 00 00 00 00 ................
+| 80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0c ................
+| 96: 00 2e 2c 50 0d 00 00 00 06 01 06 00 01 da 01 b0 ..,P............
+| 112: 01 56 01 86 01 2a 01 06 00 00 00 00 00 00 00 00 .V...*..........
+| 256: 00 00 00 00 00 00 22 07 06 17 11 11 01 31 74 61 ......"......1ta
+| 272: 62 6c 65 74 34 74 34 07 43 52 45 41 54 45 20 54 blet4t4.CREATE T
+| 288: 41 42 4c 45 20 74 34 28 78 29 2a 06 06 17 13 11 ABLE t4(x)*.....
+| 304: 01 3f 69 6e 64 65 78 74 33 78 74 33 05 43 52 45 .?indext3xt3.CRE
+| 320: 41 54 45 20 49 4e 44 45 58 20 74 33 78 20 4f 4e ATE INDEX t3x ON
+| 336: 20 74 33 28 78 29 2e 04 06 17 15 11 01 45 69 6e t3(x).......Ein
+| 352: 64 65 78 74 32 63 64 74 32 05 43 52 45 41 54 45 dext2cdt2.CREATE
+| 368: 20 49 4e 44 45 58 20 74 32 63 64 20 4f 4e 20 74 INDEX t2cd ON t
+| 384: 32 28 63 2c 64 29 28 05 06 17 11 11 01 3d 74 61 2(c,d)(......=ta
+| 400: 62 6c 65 74 33 74 33 07 43 52 45 41 54 45 20 54 blet3t3.CREATE T
+| 416: 41 42 4c 45 20 74 33 28 63 2c 78 2c 65 2c 66 29 ABLE t3(c,x,e,f)
+| 432: 28 02 06 17 11 11 01 3d 74 61 74 65 6c 03 62 74 (......=tatel.bt
+| 448: 32 32 43 52 45 41 54 45 20 54 41 42 4c 45 20 74 22CREATE TABLE t
+| 464: 32 28 63 2c 64 2c 65 2c 66 29 24 01 06 17 11 11 2(c,d,e,f)$.....
+| 480: 01 35 74 61 62 6c 65 74 31 74 31 02 43 52 45 41 .5tablet1t1.CREA
+| 496: 54 45 20 54 41 42 4c 45 20 74 31 28 61 2c 62 29 TE TABLE t1(a,b)
+| page 2 offset 512
+| 0: 0d 00 00 00 04 01 cf 00 01 fa 01 f3 01 de 01 cf ................
+| 160: 00 00 20 00 00 00 00 00 00 00 00 00 00 00 00 00 .. .............
+| 448: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0d ................
+| 464: 04 03 17 17 73 65 76 65 6e 65 69 67 68 74 13 03 ....seveneight..
+| 480: 03 07 07 40 14 00 00 00 00 00 00 40 18 00 00 00 ...@.......@....
+| 496: 00 00 00 05 02 03 01 01 03 04 04 01 03 09 01 02 ................
+| page 3 offset 1024
+| 0: 0d 00 00 00 08 01 54 00 01 f7 01 ec 01 c5 01 aa ......T.........
+| 16: 01 a1 01 96 01 6f 01 54 00 00 00 00 00 00 00 00 .....o.T........
+| 112: 00 00 dd 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+| 336: 00 00 00 00 19 08 05 17 17 17 17 65 69 67 68 74 ...........eight
+| 352: 65 69 67 68 74 73 65 76 65 6e 73 65 76 65 6e 25 eightsevenseven%
+| 368: 07 05 07 07 07 07 40 18 00 00 00 00 00 00 40 18 ......@.......@.
+| 384: 00 00 00 00 00 00 40 14 00 00 00 00 00 00 40 14 ......@.......@.
+| 400: 00 00 00 00 00 00 09 06 05 01 01 01 01 04 04 03 ................
+| 416: 03 07 05 05 01 01 09 09 02 02 19 04 05 17 17 17 ................
+| 432: 17 73 65 76 65 6e 65 69 67 68 74 65 69 67 68 74 .seveneighteight
+| 448: 73 65 76 65 6e 25 03 05 07 07 07 07 40 14 00 00 seven%......@...
+| 464: 00 00 00 00 40 18 00 00 00 00 00 00 40 18 00 00 ....@.......@...
+| 480: 00 00 00 00 40 14 00 00 00 00 00 00 09 02 05 01 ....@...........
+| 496: 01 01 01 03 04 04 03 07 01 05 09 01 01 09 02 02 ................
+| page 4 offset 1536
+| 0: 0d 00 00 00 00 02 00 00 00 00 00 00 00 00 00 00 ................
+| 192: 00 00 00 00 00 00 7f 00 00 00 00 00 00 00 00 00 ................
+| 208: 00 e5 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+| page 5 offset 2048
+| 0: 0a 00 00 00 08 01 96 00 01 fa 01 c4 01 f2 01 bc ................
+| 16: 01 dc 01 a6 01 96 01 cc 00 00 00 00 00 00 00 00 ................
+| 240: 00 00 00 00 00 00 00 00 00 00 00 00 00 0e 00 00 ................
+| 400: 00 00 00 00 00 00 0f 04 17 07 01 65 69 67 68 74 ...........eight
+| 416: 65 69 67 68 74 08 15 04 07 07 01 40 18 00 00 00 eight......@....
+| 432: 00 00 00 40 18 00 00 00 00 00 00 07 07 04 01 01 ...@............
+| 448: 01 04 04 06 07 04 01 01 01 02 02 05 0f 04 17 17 ................
+| 464: 01 73 65 76 65 6e 65 69 67 68 74 04 15 04 07 07 .seveneight.....
+| 480: 01 40 14 00 00 00 00 00 00 40 18 00 00 00 00 00 .@.......@......
+| 496: 00 03 07 04 01 01 01 03 04 02 05 04 09 01 09 02 ................
+| page 6 offset 2560
+| 0: 0a 00 00 00 00 02 00 00 00 00 00 00 00 00 00 00 ................
+| 464: 00 00 00 00 00 00 00 00 00 00 7f 00 00 00 00 00 ................
+| page 7 offset 3072
+| 0: 0d 00 00 00 08 01 c2 00 01 fb 01 f6 01 f1 01 ec ................
+| 16: 01 e0 01 d4 01 cb 01 c2 00 00 00 00 00 00 00 00 ................
+| 448: 00 00 07 08 02 17 65 69 67 68 74 07 07 02 17 65 ......eight....e
+| 464: 69 67 68 74 0a 06 02 07 40 18 00 00 00 00 00 00 ight....@.......
+| 480: 0a 05 02 07 40 18 00 00 00 00 00 00 03 04 02 01 ....@...........
+| 496: 04 03 03 02 01 04 03 02 02 01 02 03 01 02 01 02 ................
+| end x/c02.db
+ }]
+ execsql {
+ DELETE FROM t3 WHERE x IN (SELECT x FROM t4);
+ }
+} {}
+
+finish_test
diff --git a/test/dbfuzz2.c b/test/dbfuzz2.c
index 0833f03868..9e3aca2527 100644
--- a/test/dbfuzz2.c
+++ b/test/dbfuzz2.c
@@ -78,6 +78,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *aData, size_t nByte){
printf("************** nByte=%d ***************\n", (int)nByte);
fflush(stdout);
}
+ if( sqlite3_initialize() ) return 0;
rc = sqlite3_open(0, &db);
if( rc ) return 1;
a = sqlite3_malloc64(nByte+1);
diff --git a/test/fuzz4.test b/test/fuzz4.test
new file mode 100644
index 0000000000..821cd16555
--- /dev/null
+++ b/test/fuzz4.test
@@ -0,0 +1,82 @@
+# 2018-12-12
+#
+# 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.
+#
+#***********************************************************************
+#
+# Test cases found by Matthew Denton's fuzzer at Chrome.
+#
+
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+
+do_execsql_test fuzz4-100 {
+ CREATE TABLE Table0 (Col0 NOT NULL DEFAULT (CURRENT_TIME IS 1 > 1));
+ INSERT OR REPLACE INTO Table0 DEFAULT VALUES ;
+ SELECT * FROM Table0;
+} {0}
+
+do_execsql_test fuzz4-110 {
+ CREATE TABLE Table1(
+ Col0 TEXT DEFAULT (CASE WHEN 1 IS 3530822107858468864
+ THEN 1 ELSE quote(1) IS 3530822107858468864 END)
+ );
+ INSERT INTO Table1 DEFAULT VALUES;
+ SELECT * FROM Table1;
+} {0}
+
+do_execsql_test fuzz4-200 {
+ CREATE TABLE Table2a(
+ Col0 NOT NULL DEFAULT (CURRENT_TIME IS 1 IS NOT 1 > 1)
+ );
+ INSERT OR REPLACE INTO Table2a DEFAULT VALUES;
+ SELECT * FROM Table2a;
+} {0}
+
+do_execsql_test fuzz4-210 {
+ CREATE TABLE Table2b (Col0 NOT NULL DEFAULT (CURRENT_TIME IS NOT FALSE)) ;
+ INSERT OR REPLACE INTO Table2b DEFAULT VALUES ;
+ SELECT * FROM Table2b;
+} {1}
+
+do_execsql_test fuzz4-300 {
+ CREATE TABLE Table3 (Col0 DEFAULT (CURRENT_TIMESTAMP BETWEEN 1 AND 1));
+ INSERT INTO Table3 DEFAULT VALUES;
+ SELECT * FROM Table3;
+} {0}
+
+do_execsql_test fuzz4-400 {
+ CREATE TABLE Table4 (Col0 DEFAULT (1 BETWEEN CURRENT_TIMESTAMP AND 1));
+ INSERT INTO Table4 DEFAULT VALUES;
+ SELECT * FROM Table4;
+} {0}
+
+do_execsql_test fuzz4-500 {
+ CREATE TABLE Table5 (Col0 DEFAULT (1 BETWEEN 1 AND CURRENT_TIMESTAMP));
+ INSERT INTO Table5 DEFAULT VALUES;
+ SELECT * FROM Table5;
+} {1}
+
+do_execsql_test fuzz4-600 {
+ CREATE TEMPORARY TABLE Table6(
+ Col0 DEFAULT (CASE x'5d' WHEN 1 THEN
+ CASE CURRENT_TIMESTAMP WHEN 1 THEN 1 ELSE 1 END
+ ELSE CASE WHEN 1 THEN FALSE END END )
+ );
+ INSERT INTO temp.Table6 DEFAULT VALUES ;
+ SELECT * FROM Table6;
+} {0}
+do_execsql_test fuzz4-610 {
+ WITH TableX AS (SELECT DISTINCT * ORDER BY 1 , 1 COLLATE RTRIM)
+ DELETE FROM Table6 WHERE Col0 || +8388608 ;
+ SELECT * FROM Table6;
+} {}
+
+
+finish_test
diff --git a/test/fuzzcheck.c b/test/fuzzcheck.c
index 005f59b3d8..0db4167445 100644
--- a/test/fuzzcheck.c
+++ b/test/fuzzcheck.c
@@ -447,7 +447,7 @@ static int inmemRead(
if( iOfst+iAmt>pVFile->sz ){
memset(pData, 0, iAmt);
iAmt = (int)(pVFile->sz - iOfst);
- memcpy(pData, pVFile->a, iAmt);
+ memcpy(pData, pVFile->a + iOfst, iAmt);
return SQLITE_IOERR_SHORT_READ;
}
memcpy(pData, pVFile->a + iOfst, iAmt);
diff --git a/test/fuzzdata7.db b/test/fuzzdata7.db
index 69469f9fcd..01c825ce4f 100644
Binary files a/test/fuzzdata7.db and b/test/fuzzdata7.db differ
diff --git a/test/index6.test b/test/index6.test
index 4ddce453fd..29b73f72d4 100644
--- a/test/index6.test
+++ b/test/index6.test
@@ -389,6 +389,25 @@ do_execsql_test index6-11.1 {
do_execsql_test index6-11.2 {
EXPLAIN QUERY PLAN SELECT a FROM t11 WHERE b<>99 AND c<>98;
} {/USING INDEX t11x/}
-
+# 2018-12-08
+# Ticket https://www.sqlite.org/src/info/1d958d90596593a7
+# NOT IN operator fails when using a partial index.
+#
+do_execsql_test index6-12.1 {
+ DROP TABLE IF EXISTS t1;
+ DROP TABLE IF EXISTS t2;
+ CREATE TABLE t1(a,b);
+ INSERT INTO t1 VALUES(1,1);
+ INSERT INTO t1 VALUES(2,2);
+ CREATE TABLE t2(x);
+ INSERT INTO t2 VALUES(1);
+ INSERT INTO t2 VALUES(2);
+ SELECT 'one', * FROM t2 WHERE x NOT IN (SELECT a FROM t1);
+ CREATE INDEX t1a ON t1(a) WHERE b=1;
+ SELECT 'two', * FROM t2 WHERE x NOT IN (SELECT a FROM t1);
+} {}
+do_execsql_test index6-12.2 {
+ SELECT x FROM t2 WHERE x IN (SELECT a FROM t1) ORDER BY +x;
+} {1 2}
finish_test
diff --git a/test/indexexpr2.test b/test/indexexpr2.test
index 79a6456e9a..368237f23e 100644
--- a/test/indexexpr2.test
+++ b/test/indexexpr2.test
@@ -231,5 +231,24 @@ ifcapable vtab {
} {t2 t2abc t2cd t2def}
}
+#-------------------------------------------------------------------------
+# Test that ticket [d96eba87] has been fixed.
+#
+do_execsql_test 5.0 {
+ CREATE TABLE t5(a INTEGER, b INTEGER);
+ INSERT INTO t5 VALUES(2, 4), (3, 9);
+}
+do_execsql_test 5.1 {
+ SELECT * FROM t5 WHERE abs(a)=2 or abs(b)=9;
+} {2 4 3 9}
+do_execsql_test 5.2 {
+ CREATE INDEX t5a ON t5( abs(a) );
+ CREATE INDEX t5b ON t5( abs(b) );
+}
+do_execsql_test 5.4 {
+ SELECT * FROM t5 WHERE abs(a)=2 or abs(b)=9;
+} {2 4 3 9}
+
+
finish_test
diff --git a/test/normalize.test b/test/normalize.test
index c5b69336e9..8b0c7ed8db 100644
--- a/test/normalize.test
+++ b/test/normalize.test
@@ -207,7 +207,7 @@ foreach {tnum sql flags norm} {
430
{SELECT "a" FROM t1 WHERE "x" IN ("1","2",'3');}
0x2
- {0 {SELECT"a"FROM t1 WHERE"x"IN("1","2",?);}}
+ {0 {SELECT a FROM t1 WHERE x IN(?,?,?);}}
440
{SELECT 'a' FROM t1 WHERE 'x';}
@@ -217,7 +217,7 @@ foreach {tnum sql flags norm} {
450
{SELECT [a] FROM t1 WHERE [x];}
0x2
- {0 {SELECT"a"FROM t1 WHERE"x";}}
+ {0 {SELECT a FROM t1 WHERE x;}}
460
{SELECT * FROM t1 WHERE x IN (x);}
@@ -232,12 +232,12 @@ foreach {tnum sql flags norm} {
480
{SELECT * FROM t1 WHERE x IN ([x],"a");}
0x2
- {0 {SELECT*FROM t1 WHERE x IN("x","a");}}
+ {0 {SELECT*FROM t1 WHERE x IN(x,a);}}
500
{SELECT * FROM t1 WHERE x IN ([x],"a",'b',sqlite_version());}
0x2
- {0 {SELECT*FROM t1 WHERE x IN("x","a",?,sqlite_version());}}
+ {0 {SELECT*FROM t1 WHERE x IN(x,a,?,sqlite_version());}}
520
{SELECT * FROM t1 WHERE x IN (SELECT x FROM t1);}
@@ -247,12 +247,12 @@ foreach {tnum sql flags norm} {
540
{SELECT * FROM t1 WHERE x IN ((SELECT x FROM t1));}
0x2
- {0 {SELECT*FROM t1 WHERE x IN(?,?,?);}}
+ {0 {SELECT*FROM t1 WHERE x IN((SELECT x FROM t1));}}
550
{SELECT a, a+1, a||'b', a+"b" FROM t1;}
0x2
- {0 {SELECT a,a+?,a||?,a+"b"FROM t1;}}
+ {0 {SELECT a,a+?,a||?,a+b FROM t1;}}
570
{SELECT * FROM t1 WHERE x IN (1);}
@@ -316,7 +316,7 @@ foreach {tnum sql flags norm} {
680
{SELECT a, "col f" FROM t1 LEFT OUTER JOIN t2 ON [t1].[col f] == [t2].[col y];}
0x2
- {0 {SELECT a,"col f"FROM t1 LEFT OUTER JOIN t2 ON"t1"."col f"=="t2"."col y";}}
+ {0 {SELECT a,"col f"FROM t1 LEFT OUTER JOIN t2 ON t1."col f"==t2."col y";}}
690
{SELECT * FROM ( WITH x AS ( SELECT * FROM t1 WHERE x IN ( 1)) SELECT 10);}
@@ -346,7 +346,7 @@ foreach {tnum sql flags norm} {
760
{SELECT x FROM t1 WHERE x IN ([x] IS NOT NULL, NULL, 1, 'a', "b", x'00');}
0x2
- {0 {SELECT x FROM t1 WHERE x IN("x"IS NOT NULL,?,?,?,"b",?);}}
+ {0 {SELECT x FROM t1 WHERE x IN(x IS NOT NULL,?,?,?,b,?);}}
} {
do_test $tnum {
set code [catch {
diff --git a/test/shell1.test b/test/shell1.test
index aaf7addf5c..f105bac5b7 100644
--- a/test/shell1.test
+++ b/test/shell1.test
@@ -256,7 +256,7 @@ do_test shell1-3.1.3 {
do_test shell1-3.1.4 {
# too many arguments
catchcmd "test.db" ".backup FOO BAR BAD"
-} {1 {Usage: .backup ?DB? ?--append? FILENAME}}
+} {1 {Usage: .backup ?DB? ?OPTIONS? FILENAME}}
# .bail ON|OFF Stop after hitting an error. Default OFF
do_test shell1-3.2.1 {
diff --git a/test/vacuum-into.test b/test/vacuum-into.test
new file mode 100644
index 0000000000..cb91abc5d9
--- /dev/null
+++ b/test/vacuum-into.test
@@ -0,0 +1,69 @@
+# 2018-12-07
+#
+# The author disclaims copyright to this source code. In place of
+# a legal notice, here is a blessing:
+#
+# May you do good and not evil.
+# May you find forgiveness for yourself and forgive others.
+# May you share freely, never taking more than you give.
+#
+#***********************************************************************
+# This file implements regression tests for SQLite library. The
+# focus of this file is testing the VACUUM INTO statement.
+#
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+
+# If the VACUUM statement is disabled in the current build, skip all
+# the tests in this file.
+#
+ifcapable {!vacuum} {
+ omit_test vacuum.test {Compiled with SQLITE_OMIT_VACUUM}
+ finish_test
+ return
+}
+
+forcedelete out.db
+do_execsql_test vacuum-into-100 {
+ CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
+ WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<100)
+ INSERT INTO t1(a,b) SELECT x, randomblob(600) FROM c;
+ CREATE INDEX t1b ON t1(b);
+ DELETE FROM t1 WHERE a%2;
+ SELECT count(*), sum(a), sum(length(b)) FROM t1;
+} {50 2550 30000}
+do_execsql_test vacuum-into-110 {
+ VACUUM main INTO 'out.db';
+} {}
+sqlite3 db2 out.db
+do_test vacuum-into-120 {
+ db2 eval {SELECT count(*), sum(a), sum(length(b)) FROM t1}
+} {50 2550 30000}
+do_catchsql_test vacuum-into-130 {
+ VACUUM INTO 'out.db';
+} {1 {output file already exists}}
+forcedelete out2.db
+do_catchsql_test vacuum-into-140 {
+ VACUUM INTO 'out2.db';
+} {0 {}}
+do_catchsql_test vacuum-into-150 {
+ VACUUM INTO 'out2.db';
+} {1 {output file already exists}}
+
+do_catchsql_test vacuum-into-200 {
+ VACUUM main INTO ':memory:';
+} {0 {}}
+
+# The INTO argument can be an arbitrary expression.
+#
+do_execsql_test vacuum-into-300 {
+ CREATE TABLE t2(name TEXT);
+ INSERT INTO t2 VALUES(':memory:');
+ VACUUM main INTO (SELECT name FROM t2);
+} {}
+do_catchsql_test vacuum-into-310 {
+ VACUUM INTO null;
+} {1 {non-text filename}}
+
+finish_test
diff --git a/test/window1.test b/test/window1.test
index a8399a8606..5f9b5dbb75 100644
--- a/test/window1.test
+++ b/test/window1.test
@@ -594,4 +594,31 @@ do_execsql_test 13.5 {
} {
}
+# 2018-12-06
+# https://www.sqlite.org/src/info/f09fcd17810f65f7
+# Assertion fault when window functions are used.
+#
+# Root cause is the query flattener invoking sqlite3ExprDup() on
+# expressions that contain subqueries with window functions. The
+# sqlite3ExprDup() routine is not making correctly initializing
+# Select.pWin field of the subqueries.
+#
+sqlite3 db :memory:
+do_execsql_test 14.0 {
+ SELECT * FROM(
+ SELECT * FROM (SELECT 1 AS c) WHERE c IN (
+ SELECT (row_number() OVER()) FROM (VALUES (0))
+ )
+ );
+} {1}
+do_execsql_test 14.1 {
+ CREATE TABLE t1(x); INSERT INTO t1(x) VALUES(12345);
+ CREATE TABLE t2(c); INSERT INTO t2(c) VALUES(1);
+ SELECT y, y+1, y+2 FROM (
+ SELECT c IN (
+ SELECT (row_number() OVER()) FROM t1
+ ) AS y FROM t2
+ );
+} {1 2 3}
+
finish_test
diff --git a/tool/dbtotxt.c b/tool/dbtotxt.c
new file mode 100644
index 0000000000..f28e209ce2
--- /dev/null
+++ b/tool/dbtotxt.c
@@ -0,0 +1,140 @@
+/*
+** Copyright 2008 D. Richard Hipp and Hipp, Wyrick & Company, Inc.
+** All Rights Reserved
+**
+******************************************************************************
+**
+** This file implements a stand-alone utility program that converts
+** a binary file (usually an SQLite database) into a text format that
+** is compact and friendly to human-readers.
+**
+** Usage:
+**
+** dbtotxt [--pagesize N] FILENAME
+**
+** The translation of the database appears on standard output. If the
+** --pagesize command-line option is omitted, then the page size is taken
+** from the database header.
+**
+** Compactness is achieved by suppressing lines of all zero bytes. This
+** works well at compressing test databases that are mostly empty. But
+** the output will probably be lengthy for a real database containing lots
+** of real content. For maximum compactness, it is suggested that test
+** databases be constructed with "zeroblob()" rather than "randomblob()"
+** used for filler content and with "PRAGMA secure_delete=ON" selected to
+** zero-out deleted content.
+*/
+#include
+#include
+#include
+
+/* Return true if the line is all zeros */
+static int allZero(unsigned char *aLine){
+ int i;
+ for(i=0; i<16 && aLine[i]==0; i++){}
+ return i==16;
+}
+
+int main(int argc, char **argv){
+ int pgsz = 0; /* page size */
+ long szFile; /* Size of the input file in bytes */
+ FILE *in; /* Input file */
+ int i, j; /* Loop counters */
+ int nErr = 0; /* Number of errors */
+ const char *zInputFile = 0; /* Name of the input file */
+ const char *zBaseName = 0; /* Base name of the file */
+ int lastPage = 0; /* Last page number shown */
+ int iPage; /* Current page number */
+ unsigned char aLine[16]; /* A single line of the file */
+ unsigned char aHdr[100]; /* File header */
+ for(i=1; i65536 || (pgsz&(pgsz-1))!=0 ){
+ fprintf(stderr, "Page size must be a power of two between"
+ " 512 and 65536.\n");
+ nErr++;
+ }
+ continue;
+ }
+ fprintf(stderr, "Unknown option: %s\n", argv[i]);
+ nErr++;
+ }else if( zInputFile ){
+ fprintf(stderr, "Already using a different input file: [%s]\n", argv[i]);
+ nErr++;
+ }else{
+ zInputFile = argv[i];
+ }
+ }
+ if( zInputFile==0 ){
+ fprintf(stderr, "No input file specified.\n");
+ nErr++;
+ }
+ if( nErr ){
+ fprintf(stderr, "Usage: %s [--pagesize N] FILENAME\n", argv[0]);
+ exit(1);
+ }
+ in = fopen(zInputFile, "rb");
+ if( in==0 ){
+ fprintf(stderr, "Cannot open input file [%s]\n", zInputFile);
+ exit(1);
+ }
+ fseek(in, 0, SEEK_END);
+ szFile = ftell(in);
+ rewind(in);
+ if( szFile<512 ){
+ fprintf(stderr, "File too short. Minimum size is 512 bytes.\n");
+ exit(1);
+ }
+ if( fread(aHdr, 100, 1, in)!=1 ){
+ fprintf(stderr, "Cannot read file header\n");
+ exit(1);
+ }
+ rewind(in);
+ if( pgsz==0 ){
+ pgsz = (aHdr[16]<<8) | aHdr[17];
+ if( pgsz==1 ) pgsz = 65536;
+ if( pgsz<512 || (pgsz&(pgsz-1))!=0 ){
+ fprintf(stderr, "Invalid page size in header: %d\n", pgsz);
+ exit(1);
+ }
+ }
+ zBaseName = zInputFile;
+ for(i=0; zInputFile[i]; i++){
+ if( zInputFile[i]=='/' && zInputFile[i+1]!=0 ) zBaseName = zInputFile+1;
+ }
+ printf("| size %d pagesize %d filename %s\n",(int)szFile,pgsz,zBaseName);
+ for(i=0; i=0x20 && c<=0x7e ? c : '.', stdout);
+ }
+ fputc('\n', stdout);
+ }
+ fclose(in);
+ printf("| end %s\n", zBaseName);
+ return 0;
+}
diff --git a/tool/dbtotxt.md b/tool/dbtotxt.md
new file mode 100644
index 0000000000..f2bd7c9c25
--- /dev/null
+++ b/tool/dbtotxt.md
@@ -0,0 +1,56 @@
+The dbtotxt Tool
+
+The dbtotxt utility program reads an SQLite database file and writes its
+raw binary content to screen as a hex dump for testing and debugging
+purposes.
+
+The hex-dump output is formatted in such a way as to be easily readable
+both by humans and by software. The dbtotxt utility has long been a part
+of the TH3 test suite. The output of dbtotxt can be embedded in TH3 test
+scripts and used to generate very specific database files, perhaps with
+deliberately introduced corruption. The cov1/corrupt*.test modules in
+TH3 make extensive use of dbtotxt.
+
+More recently (2018-12-13) the dbtotxt utility has been added to the SQLite
+core and the command-line shell (CLI) has been augmented to be able to read
+dbtotxt output. The CLI dot-command is:
+
+> .open --hexdb ?OPTIONAL-FILENAME?
+
+If the OPTIONAL-FILENAME is included, then content is read from that file.
+If OPTIONAL-FILENAME is omitted, then the text is taken from the input stream,
+terminated by the "| end" line of the dbtotxt text. This allows small test
+databases to be embedded directly in scripts. Consider this example:
+
+>
+ .open --hexdb
+ | size 8192 pagesize 4096 filename x9.db
+ | page 1 offset 0
+ | 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3.
+ | 16: 10 00 01 01 00 40 20 20 00 00 00 04 00 00 00 02 .....@ ........
+ | 32: 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 04 ................
+ | 48: 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 ................
+ | 80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 04 ................
+ | 96: 00 2e 30 38 0d 00 00 00 01 0f c0 00 0f c0 00 00 ..08............
+ | 4032: 3e 01 06 17 11 11 01 69 74 61 62 6c 65 74 31 74 >......itablet1t
+ | 4048: 31 02 43 52 45 41 54 45 20 54 41 42 4c 45 20 74 1.CREATE TABLE t
+ | 4064: 31 28 78 2c 79 20 44 45 46 41 55 4c 54 20 78 27 1(x,y DEFAULT x'
+ | 4080: 66 66 27 2c 7a 20 44 45 46 41 55 4c 54 20 30 29 ff',z DEFAULT 0)
+ | page 2 offset 4096
+ | 0: 0d 08 14 00 04 00 10 00 0e 05 0a 0f 04 15 00 10 ................
+ | 16: 88 02 03 05 90 04 0e 08 00 00 00 00 00 00 00 00 ................
+ | 1040: 00 00 00 00 ff 87 7c 02 05 8f 78 0e 08 00 00 00 ......|...x.....
+ | 2064: 00 00 00 ff 0c 0a 01 fb 00 00 00 00 00 00 00 00 ................
+ | 2560: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 83 ................
+ | 2576: 78 01 05 87 70 0e 08 00 00 00 00 00 00 00 00 00 x...p...........
+ | 3072: 00 00 00 00 00 00 00 00 00 ff 00 00 01 fb 00 00 ................
+ | 3584: 00 00 00 00 00 83 78 00 05 87 70 0e 08 00 00 00 ......x...p.....
+ | 4080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ff ................
+ | end x9.db
+ SELECT rowid FROM t1;
+ PRAGMA integrity_check;
+
+You can run this script to see that the database file is correctly decoded
+and loaded. Furthermore, you can make subtle corruptions to the input
+database simply by editing the hexadecimal description, then rerun the
+script to verify that SQLite correctly handles the corruption.