mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-05 15:55:57 +03:00
Merge latest trunk changes with this branch. Add tests for columnsize=0.
FossilOrigin-Name: ef44c71a22518727030dd90c0139af8973b05841
This commit is contained in:
50
Makefile.in
50
Makefile.in
@@ -181,10 +181,11 @@ LIBOBJS0 = alter.lo analyze.lo attach.lo auth.lo \
|
||||
notify.lo opcodes.lo os.lo os_unix.lo os_win.lo \
|
||||
pager.lo parse.lo pcache.lo pcache1.lo pragma.lo prepare.lo printf.lo \
|
||||
random.lo resolve.lo rowset.lo rtree.lo select.lo status.lo \
|
||||
table.lo threads.lo tokenize.lo trigger.lo \
|
||||
table.lo threads.lo tokenize.lo treeview.lo trigger.lo \
|
||||
update.lo util.lo vacuum.lo \
|
||||
vdbe.lo vdbeapi.lo vdbeaux.lo vdbeblob.lo vdbemem.lo vdbesort.lo \
|
||||
vdbetrace.lo wal.lo walker.lo where.lo utf.lo vtab.lo
|
||||
vdbetrace.lo wal.lo walker.lo where.lo wherecode.lo whereexpr.lo \
|
||||
utf.lo vtab.lo
|
||||
|
||||
# Object files for the amalgamation.
|
||||
#
|
||||
@@ -273,6 +274,7 @@ SRC = \
|
||||
$(TOP)/src/threads.c \
|
||||
$(TOP)/src/tclsqlite.c \
|
||||
$(TOP)/src/tokenize.c \
|
||||
$(TOP)/src/treeview.c \
|
||||
$(TOP)/src/trigger.c \
|
||||
$(TOP)/src/utf.c \
|
||||
$(TOP)/src/update.c \
|
||||
@@ -293,6 +295,8 @@ SRC = \
|
||||
$(TOP)/src/wal.h \
|
||||
$(TOP)/src/walker.c \
|
||||
$(TOP)/src/where.c \
|
||||
$(TOP)/src/wherecode.c \
|
||||
$(TOP)/src/whereexpr.c \
|
||||
$(TOP)/src/whereInt.h
|
||||
|
||||
# Source code for extensions
|
||||
@@ -470,6 +474,8 @@ TESTSRC2 = \
|
||||
$(TOP)/src/vdbemem.c \
|
||||
$(TOP)/src/vdbetrace.c \
|
||||
$(TOP)/src/where.c \
|
||||
$(TOP)/src/wherecode.c \
|
||||
$(TOP)/src/whereexpr.c \
|
||||
parse.c \
|
||||
$(TOP)/ext/fts3/fts3.c \
|
||||
$(TOP)/ext/fts3/fts3_aux.c \
|
||||
@@ -545,6 +551,10 @@ FUZZDATA = \
|
||||
$(TOP)/test/fuzzdata2.db \
|
||||
$(TOP)/test/fuzzdata3.db
|
||||
|
||||
# Standard options to testfixture
|
||||
#
|
||||
TESTOPTS = --verbose=file --output=test-out.txt
|
||||
|
||||
# This is the default Makefile target. The objects listed here
|
||||
# are what get build when you type just "make" with no arguments.
|
||||
#
|
||||
@@ -817,6 +827,9 @@ threads.lo: $(TOP)/src/threads.c $(HDR)
|
||||
tokenize.lo: $(TOP)/src/tokenize.c keywordhash.h $(HDR)
|
||||
$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/tokenize.c
|
||||
|
||||
treeview.lo: $(TOP)/src/treeview.c $(HDR)
|
||||
$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/treeview.c
|
||||
|
||||
trigger.lo: $(TOP)/src/trigger.c $(HDR)
|
||||
$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/trigger.c
|
||||
|
||||
@@ -865,6 +878,12 @@ walker.lo: $(TOP)/src/walker.c $(HDR)
|
||||
where.lo: $(TOP)/src/where.c $(HDR)
|
||||
$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/where.c
|
||||
|
||||
wherecode.lo: $(TOP)/src/wherecode.c $(HDR)
|
||||
$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/wherecode.c
|
||||
|
||||
whereexpr.lo: $(TOP)/src/whereexpr.c $(HDR)
|
||||
$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/whereexpr.c
|
||||
|
||||
tclsqlite.lo: $(TOP)/src/tclsqlite.c $(HDR)
|
||||
$(LTCOMPILE) -DUSE_TCL_STUBS=1 -c $(TOP)/src/tclsqlite.c
|
||||
|
||||
@@ -1006,39 +1025,46 @@ testfixture$(TEXE): $(TESTFIXTURE_SRC)
|
||||
|
||||
# A very detailed test running most or all test cases
|
||||
fulltest: $(TESTPROGS) fuzztest
|
||||
./testfixture$(TEXE) $(TOP)/test/all.test
|
||||
./testfixture$(TEXE) $(TOP)/test/all.test $(TESTOPTS)
|
||||
|
||||
# Really really long testing
|
||||
soaktest: $(TESTPROGS)
|
||||
./testfixture$(TEXE) $(TOP)/test/all.test -soak=1
|
||||
./testfixture$(TEXE) $(TOP)/test/all.test -soak=1 $(TESTOPTS)
|
||||
|
||||
# Do extra testing but not everything.
|
||||
fulltestonly: $(TESTPROGS)
|
||||
./testfixture$(TEXE) $(TOP)/test/full.test
|
||||
|
||||
# Fuzz testing
|
||||
fuzztest: fuzzcheck$(TEXE)
|
||||
fuzztest: fuzzcheck$(TEXE) $(FUZZDATA)
|
||||
./fuzzcheck$(TEXE) $(FUZZDATA)
|
||||
|
||||
# This is the common case. Run many tests but not those that take
|
||||
# a really long time.
|
||||
valgrindfuzz: fuzzcheck$(TEXT) $(FUZZDATA)
|
||||
valgrind ./fuzzcheck$(TEXE) --cell-size-check --quiet $(FUZZDATA)
|
||||
|
||||
# Minimal testing that runs in less than 3 minutes
|
||||
#
|
||||
quicktest: ./testfixture$(TEXE)
|
||||
./testfixture$(TEXE) $(TOP)/test/extraquick.test $(TESTOPTS)
|
||||
|
||||
# This is the common case. Run many tests that do not take too long,
|
||||
# including fuzzcheck, sqlite3_analyzer, and sqldiff tests.
|
||||
#
|
||||
test: $(TESTPROGS) fuzztest
|
||||
./testfixture$(TEXE) $(TOP)/test/veryquick.test
|
||||
./testfixture$(TEXE) $(TOP)/test/veryquick.test $(TESTOPTS)
|
||||
|
||||
# Run a test using valgrind. This can take a really long time
|
||||
# because valgrind is so much slower than a native machine.
|
||||
#
|
||||
valgrindtest: $(TESTPROGS) fuzzcheck$(TEXE)
|
||||
valgrind -v ./fuzzcheck$(TEXE) --cell-size-check --quiet $(FUZZDATA)
|
||||
OMIT_MISUSE=1 valgrind -v ./testfixture$(TEXE) $(TOP)/test/permutations.test valgrind
|
||||
valgrindtest: $(TESTPROGS) valgrindfuzz
|
||||
OMIT_MISUSE=1 valgrind -v ./testfixture$(TEXE) $(TOP)/test/permutations.test valgrind $(TESTOPTS)
|
||||
|
||||
# A very fast test that checks basic sanity. The name comes from
|
||||
# the 60s-era electronics testing: "Turn it on and see if smoke
|
||||
# comes out."
|
||||
#
|
||||
smoketest: $(TESTPROGS) fuzzcheck$(TEXE)
|
||||
./testfixture$(TEXE) $(TOP)/test/main.test
|
||||
./testfixture$(TEXE) $(TOP)/test/main.test $(TESTOPTS)
|
||||
|
||||
sqlite3_analyzer.c: sqlite3.c $(TOP)/src/tclsqlite.c $(TOP)/tool/spaceanal.tcl
|
||||
echo "#define TCLSH 2" > $@
|
||||
|
42
Makefile.msc
42
Makefile.msc
@@ -835,10 +835,11 @@ LIBOBJS0 = vdbe.lo parse.lo alter.lo analyze.lo attach.lo auth.lo \
|
||||
notify.lo opcodes.lo os.lo os_unix.lo os_win.lo \
|
||||
pager.lo pcache.lo pcache1.lo pragma.lo prepare.lo printf.lo \
|
||||
random.lo resolve.lo rowset.lo rtree.lo select.lo status.lo \
|
||||
table.lo threads.lo tokenize.lo trigger.lo \
|
||||
table.lo threads.lo tokenize.lo treeview.lo trigger.lo \
|
||||
update.lo util.lo vacuum.lo \
|
||||
vdbeapi.lo vdbeaux.lo vdbeblob.lo vdbemem.lo vdbesort.lo \
|
||||
vdbetrace.lo wal.lo walker.lo where.lo utf.lo vtab.lo
|
||||
vdbetrace.lo wal.lo walker.lo where.lo wherecode.lo whereexpr.lo \
|
||||
utf.lo vtab.lo
|
||||
|
||||
# Object files for the amalgamation.
|
||||
#
|
||||
@@ -939,6 +940,7 @@ SRC2 = \
|
||||
$(TOP)\src\threads.c \
|
||||
$(TOP)\src\tclsqlite.c \
|
||||
$(TOP)\src\tokenize.c \
|
||||
$(TOP)\src\treeview.c \
|
||||
$(TOP)\src\trigger.c \
|
||||
$(TOP)\src\utf.c \
|
||||
$(TOP)\src\update.c \
|
||||
@@ -959,6 +961,8 @@ SRC2 = \
|
||||
$(TOP)\src\wal.h \
|
||||
$(TOP)\src\walker.c \
|
||||
$(TOP)\src\where.c \
|
||||
$(TOP)\src\wherecode.c \
|
||||
$(TOP)\src\whereexpr.c \
|
||||
$(TOP)\src\whereInt.h
|
||||
|
||||
# Source code for extensions
|
||||
@@ -1121,6 +1125,8 @@ TESTSRC2 = \
|
||||
$(TOP)\src\vdbesort.c \
|
||||
$(TOP)\src\vdbetrace.c \
|
||||
$(TOP)\src\where.c \
|
||||
$(TOP)\src\wherecode.c \
|
||||
$(TOP)\src\whereexpr.c \
|
||||
parse.c \
|
||||
$(TOP)\ext\fts3\fts3.c \
|
||||
$(TOP)\ext\fts3\fts3_aux.c \
|
||||
@@ -1197,6 +1203,9 @@ FUZZDATA = \
|
||||
$(TOP)\test\fuzzdata2.db \
|
||||
$(TOP)\test\fuzzdata3.db
|
||||
|
||||
# Standard options to testfixture
|
||||
#
|
||||
TESTOPTS = --verbose=file --output=test-out.txt
|
||||
|
||||
# This is the default Makefile target. The objects listed here
|
||||
# are what get build when you type just "make" with no arguments.
|
||||
@@ -1482,6 +1491,9 @@ threads.lo: $(TOP)\src\threads.c $(HDR)
|
||||
tokenize.lo: $(TOP)\src\tokenize.c keywordhash.h $(HDR)
|
||||
$(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\tokenize.c
|
||||
|
||||
treeview.lo: $(TOP)\src\treeview.c $(HDR)
|
||||
$(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\treeview.c
|
||||
|
||||
trigger.lo: $(TOP)\src\trigger.c $(HDR)
|
||||
$(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\trigger.c
|
||||
|
||||
@@ -1530,6 +1542,12 @@ walker.lo: $(TOP)\src\walker.c $(HDR)
|
||||
where.lo: $(TOP)\src\where.c $(HDR)
|
||||
$(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\where.c
|
||||
|
||||
wherecode.lo: $(TOP)\src\wherecode.c $(HDR)
|
||||
$(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\wherecode.c
|
||||
|
||||
whereexpr.lo: $(TOP)\src\whereexpr.c $(HDR)
|
||||
$(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\whereexpr.c
|
||||
|
||||
tclsqlite.lo: $(TOP)\src\tclsqlite.c $(HDR)
|
||||
$(LTCOMPILE) $(NO_WARN) -DUSE_TCL_STUBS=1 -DBUILD_sqlite -I$(TCLINCDIR) -c $(TOP)\src\tclsqlite.c
|
||||
|
||||
@@ -1662,28 +1680,36 @@ testfixture.exe: $(TESTFIXTURE_SRC) $(LIBRESOBJS) $(HDR)
|
||||
/link $(LTLINKOPTS) $(LTLIBPATHS) $(LIBRESOBJS) $(LTLIBS) $(TLIBS)
|
||||
|
||||
extensiontest: testfixture.exe testloadext.dll
|
||||
.\testfixture.exe $(TOP)\test\loadext.test
|
||||
.\testfixture.exe $(TOP)\test\loadext.test $(TESTOPTS)
|
||||
|
||||
fulltest: $(TESTPROGS) fuzztest
|
||||
.\testfixture.exe $(TOP)\test\all.test
|
||||
.\testfixture.exe $(TOP)\test\all.test $(TESTOPTS)
|
||||
|
||||
soaktest: $(TESTPROGS)
|
||||
.\testfixture.exe $(TOP)\test\all.test -soak=1
|
||||
.\testfixture.exe $(TOP)\test\all.test -soak=1 $(TESTOPTS)
|
||||
|
||||
fulltestonly: $(TESTPROGS) fuzztest
|
||||
.\testfixture.exe $(TOP)\test\full.test
|
||||
|
||||
queryplantest: testfixture.exe sqlite3.exe
|
||||
.\testfixture.exe $(TOP)\test\permutations.test queryplanner
|
||||
.\testfixture.exe $(TOP)\test\permutations.test queryplanner $(TESTOPTS)
|
||||
|
||||
fuzztest: fuzzcheck.exe
|
||||
.\fuzzcheck.exe $(FUZZDATA)
|
||||
|
||||
# Minimal testing that runs in less than 3 minutes (on a fast machine)
|
||||
#
|
||||
quicktest: testfixture.exe
|
||||
.\testfixture.exe $(TOP)\test\extraquick.test $(TESTOPTS)
|
||||
|
||||
# This is the common case. Run many tests that do not take too long,
|
||||
# including fuzzcheck, sqlite3_analyzer, and sqldiff tests.
|
||||
#
|
||||
test: $(TESTPROGS) fuzztest
|
||||
.\testfixture.exe $(TOP)\test\veryquick.test
|
||||
.\testfixture.exe $(TOP)\test\veryquick.test $(TESTOPTS)
|
||||
|
||||
smoketest: $(TESTPROGS)
|
||||
.\testfixture.exe $(TOP)\test\main.test
|
||||
.\testfixture.exe $(TOP)\test\main.test $(TESTOPTS)
|
||||
|
||||
sqlite3_analyzer.c: $(SQLITE3C) $(TOP)\src\tclsqlite.c $(TOP)\tool\spaceanal.tcl
|
||||
echo #define TCLSH 2 > $@
|
||||
|
@@ -240,12 +240,13 @@ static int icuNext(
|
||||
** The set of routines that implement the simple tokenizer
|
||||
*/
|
||||
static const sqlite3_tokenizer_module icuTokenizerModule = {
|
||||
0, /* iVersion */
|
||||
icuCreate, /* xCreate */
|
||||
icuDestroy, /* xCreate */
|
||||
icuOpen, /* xOpen */
|
||||
icuClose, /* xClose */
|
||||
icuNext, /* xNext */
|
||||
0, /* iVersion */
|
||||
icuCreate, /* xCreate */
|
||||
icuDestroy, /* xCreate */
|
||||
icuOpen, /* xOpen */
|
||||
icuClose, /* xClose */
|
||||
icuNext, /* xNext */
|
||||
0, /* xLanguageid */
|
||||
};
|
||||
|
||||
/*
|
||||
|
@@ -512,11 +512,11 @@ int sqlite3Fts5StorageDelete(Fts5Storage *p, i64 iDel){
|
||||
/* Delete the %_docsize record */
|
||||
if( rc==SQLITE_OK && pConfig->bColumnsize ){
|
||||
rc = fts5StorageGetStmt(p, FTS5_STMT_DELETE_DOCSIZE, &pDel, 0);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
sqlite3_bind_int64(pDel, 1, iDel);
|
||||
sqlite3_step(pDel);
|
||||
rc = sqlite3_reset(pDel);
|
||||
if( rc==SQLITE_OK ){
|
||||
sqlite3_bind_int64(pDel, 1, iDel);
|
||||
sqlite3_step(pDel);
|
||||
rc = sqlite3_reset(pDel);
|
||||
}
|
||||
}
|
||||
|
||||
/* Delete the %_content record */
|
||||
|
@@ -108,5 +108,12 @@ do_execsql_test 3.1 {
|
||||
} {
|
||||
1 {2 0 1} 2 {3 0 0}
|
||||
}
|
||||
do_execsql_test 3.1 {
|
||||
INSERT INTO t3 VALUES(NULL, NULL, 'a a a a');
|
||||
DELETE FROM t3 WHERE rowid = 1;
|
||||
SELECT rowid, fts5_test_columnsize(t3) FROM t3 WHERE t3 MATCH 'a'
|
||||
} {
|
||||
2 {3 0 0} 3 {0 0 4}
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
@@ -398,6 +398,22 @@ do_faultsim_test 13.1 -faults oom-t* -prep {
|
||||
faultsim_test_result {0 {1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16}}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# OOM in an "ALTER TABLE RENAME TO"
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 14.0 {
|
||||
CREATE VIRTUAL TABLE "tbl one" USING fts5(x, y, z);
|
||||
}
|
||||
faultsim_save_and_close
|
||||
do_faultsim_test 14.1 -faults oom-t* -prep {
|
||||
faultsim_restore_and_reopen
|
||||
db eval { SELECT * FROM "tbl one" }
|
||||
} -body {
|
||||
db eval { ALTER TABLE "tbl one" RENAME TO "tbl two" }
|
||||
} -test {
|
||||
faultsim_test_result {0 {}}
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
|
@@ -83,7 +83,6 @@ static int icuLikeCompare(
|
||||
/* Read (and consume) the next character from the input pattern. */
|
||||
UChar32 uPattern;
|
||||
U8_NEXT_UNSAFE(zPattern, iPattern, uPattern);
|
||||
assert(uPattern!=0);
|
||||
|
||||
/* There are now 4 possibilities:
|
||||
**
|
||||
@@ -422,6 +421,7 @@ static void icuLoadCollation(
|
||||
int rc; /* Return code from sqlite3_create_collation_x() */
|
||||
|
||||
assert(nArg==2);
|
||||
(void)nArg; /* Unused parameter */
|
||||
zLocale = (const char *)sqlite3_value_text(apArg[0]);
|
||||
zName = (const char *)sqlite3_value_text(apArg[1]);
|
||||
|
||||
|
@@ -269,5 +269,88 @@ ifcapable rtree {
|
||||
db close
|
||||
}
|
||||
|
||||
#--------------------------------------------------------------------
|
||||
# Test that queries featuring LEFT or CROSS JOINS are handled correctly.
|
||||
# Handled correctly in this case means:
|
||||
#
|
||||
# * Terms with prereqs that appear to the left of a LEFT JOIN against
|
||||
# the virtual table are always available to xBestIndex.
|
||||
#
|
||||
# * Terms with prereqs that appear to the right of a LEFT JOIN against
|
||||
# the virtual table are never available to xBestIndex.
|
||||
#
|
||||
# And the same behaviour for CROSS joins.
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 7.0 {
|
||||
CREATE TABLE xdir(x1);
|
||||
CREATE TABLE ydir(y1);
|
||||
CREATE VIRTUAL TABLE rt USING rtree_i32(id, xmin, xmax, ymin, ymax);
|
||||
|
||||
INSERT INTO xdir VALUES(5);
|
||||
INSERT INTO ydir VALUES(10);
|
||||
|
||||
INSERT INTO rt VALUES(1, 2, 7, 12, 14); -- Not a hit
|
||||
INSERT INTO rt VALUES(2, 2, 7, 8, 12); -- A hit!
|
||||
INSERT INTO rt VALUES(3, 7, 11, 8, 12); -- Not a hit!
|
||||
INSERT INTO rt VALUES(4, 5, 5, 10, 10); -- A hit!
|
||||
|
||||
}
|
||||
|
||||
proc do_eqp_execsql_test {tn sql res} {
|
||||
set query "EXPLAIN QUERY PLAN $sql ; $sql "
|
||||
uplevel [list do_execsql_test $tn $query $res]
|
||||
}
|
||||
|
||||
do_eqp_execsql_test 7.1 {
|
||||
SELECT id FROM xdir, rt, ydir
|
||||
ON (y1 BETWEEN ymin AND ymax)
|
||||
WHERE (x1 BETWEEN xmin AND xmax);
|
||||
} {
|
||||
0 0 0 {SCAN TABLE xdir}
|
||||
0 1 2 {SCAN TABLE ydir}
|
||||
0 2 1 {SCAN TABLE rt VIRTUAL TABLE INDEX 2:B2D3B0D1}
|
||||
2 4
|
||||
}
|
||||
|
||||
do_eqp_execsql_test 7.2 {
|
||||
SELECT * FROM xdir, rt LEFT JOIN ydir
|
||||
ON (y1 BETWEEN ymin AND ymax)
|
||||
WHERE (x1 BETWEEN xmin AND xmax);
|
||||
} {
|
||||
0 0 0 {SCAN TABLE xdir}
|
||||
0 1 1 {SCAN TABLE rt VIRTUAL TABLE INDEX 2:B0D1}
|
||||
0 2 2 {SCAN TABLE ydir}
|
||||
|
||||
5 1 2 7 12 14 {}
|
||||
5 2 2 7 8 12 10
|
||||
5 4 5 5 10 10 10
|
||||
}
|
||||
|
||||
do_eqp_execsql_test 7.3 {
|
||||
SELECT id FROM xdir, rt CROSS JOIN ydir
|
||||
ON (y1 BETWEEN ymin AND ymax)
|
||||
WHERE (x1 BETWEEN xmin AND xmax);
|
||||
} {
|
||||
0 0 0 {SCAN TABLE xdir}
|
||||
0 1 1 {SCAN TABLE rt VIRTUAL TABLE INDEX 2:B0D1}
|
||||
0 2 2 {SCAN TABLE ydir}
|
||||
2 4
|
||||
}
|
||||
|
||||
do_eqp_execsql_test 7.4 {
|
||||
SELECT id FROM rt, xdir CROSS JOIN ydir
|
||||
ON (y1 BETWEEN ymin AND ymax)
|
||||
WHERE (x1 BETWEEN xmin AND xmax);
|
||||
} {
|
||||
0 0 1 {SCAN TABLE xdir}
|
||||
0 1 0 {SCAN TABLE rt VIRTUAL TABLE INDEX 2:B0D1}
|
||||
0 2 2 {SCAN TABLE ydir}
|
||||
2 4
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
|
||||
finish_test
|
||||
|
44
main.mk
44
main.mk
@@ -67,10 +67,11 @@ LIBOBJ+= vdbe.o parse.o \
|
||||
notify.o opcodes.o os.o os_unix.o os_win.o \
|
||||
pager.o pcache.o pcache1.o pragma.o prepare.o printf.o \
|
||||
random.o resolve.o rowset.o rtree.o select.o sqlite3ota.o status.o \
|
||||
table.o threads.o tokenize.o trigger.o \
|
||||
table.o threads.o tokenize.o treeview.o trigger.o \
|
||||
update.o userauth.o util.o vacuum.o \
|
||||
vdbeapi.o vdbeaux.o vdbeblob.o vdbemem.o vdbesort.o \
|
||||
vdbetrace.o wal.o walker.o where.o utf.o vtab.o
|
||||
vdbetrace.o wal.o walker.o where.o wherecode.o whereexpr.o \
|
||||
utf.o vtab.o
|
||||
|
||||
LIBOBJ += fts5.o
|
||||
LIBOBJ += fts5_aux.o
|
||||
@@ -166,6 +167,7 @@ SRC = \
|
||||
$(TOP)/src/tclsqlite.c \
|
||||
$(TOP)/src/threads.c \
|
||||
$(TOP)/src/tokenize.c \
|
||||
$(TOP)/src/treeview.c \
|
||||
$(TOP)/src/trigger.c \
|
||||
$(TOP)/src/utf.c \
|
||||
$(TOP)/src/update.c \
|
||||
@@ -186,6 +188,8 @@ SRC = \
|
||||
$(TOP)/src/wal.h \
|
||||
$(TOP)/src/walker.c \
|
||||
$(TOP)/src/where.c \
|
||||
$(TOP)/src/wherecode.c \
|
||||
$(TOP)/src/whereexpr.c \
|
||||
$(TOP)/src/whereInt.h
|
||||
|
||||
# Source code for extensions
|
||||
@@ -369,6 +373,8 @@ TESTSRC2 = \
|
||||
$(TOP)/src/vdbe.c \
|
||||
$(TOP)/src/vdbemem.c \
|
||||
$(TOP)/src/where.c \
|
||||
$(TOP)/src/wherecode.c \
|
||||
$(TOP)/src/whereexpr.c \
|
||||
parse.c \
|
||||
$(TOP)/ext/fts3/fts3.c \
|
||||
$(TOP)/ext/fts3/fts3_aux.c \
|
||||
@@ -446,6 +452,10 @@ FUZZDATA = \
|
||||
$(TOP)/test/fuzzdata2.db \
|
||||
$(TOP)/test/fuzzdata3.db
|
||||
|
||||
# Standard options to testfixture
|
||||
#
|
||||
TESTOPTS = --verbose=file --output=test-out.txt
|
||||
|
||||
# This is the default Makefile target. The objects listed here
|
||||
# are what get build when you type just "make" with no arguments.
|
||||
#
|
||||
@@ -749,36 +759,48 @@ fts3-testfixture$(EXE): sqlite3.c fts3amal.c $(TESTSRC) $(TOP)/src/tclsqlite.c
|
||||
-o testfixture$(EXE) $(LIBTCL) $(THREADLIB)
|
||||
|
||||
fulltest: $(TESTPROGS) fuzztest
|
||||
./testfixture$(EXE) $(TOP)/test/all.test
|
||||
./testfixture$(EXE) $(TOP)/test/all.test $(TESTOPTS)
|
||||
|
||||
soaktest: $(TESTPROGS)
|
||||
./testfixture$(EXE) $(TOP)/test/all.test -soak=1
|
||||
./testfixture$(EXE) $(TOP)/test/all.test -soak=1 $(TESTOPTS)
|
||||
|
||||
fulltestonly: $(TESTPROGS) fuzztest
|
||||
./testfixture$(EXE) $(TOP)/test/full.test
|
||||
./testfixture$(EXE) $(TOP)/test/full.test $(TESTOPTS)
|
||||
|
||||
queryplantest: testfixture$(EXE) sqlite3$(EXE)
|
||||
./testfixture$(EXE) $(TOP)/test/permutations.test queryplanner
|
||||
./testfixture$(EXE) $(TOP)/test/permutations.test queryplanner $(TESTOPTS)
|
||||
|
||||
fuzztest: fuzzcheck$(EXE) $(FUZZDATA)
|
||||
./fuzzcheck$(EXE) $(FUZZDATA)
|
||||
|
||||
valgrindfuzz: fuzzcheck$(EXE) $(FUZZDATA)
|
||||
valgrind ./fuzzcheck$(EXE) --cell-size-check --quiet $(FUZZDATA)
|
||||
|
||||
# A very quick test using only testfixture and omitting all the slower
|
||||
# tests. Designed to run in under 3 minutes on a workstation.
|
||||
#
|
||||
quicktest: ./testfixture$(EXE)
|
||||
./testfixture$(EXE) $(TOP)/test/extraquick.test $(TESTOPTS)
|
||||
|
||||
# The default test case. Runs most of the faster standard TCL tests,
|
||||
# and fuzz tests, and sqlite3_analyzer and sqldiff tests.
|
||||
#
|
||||
test: $(TESTPROGS) fuzztest
|
||||
./testfixture$(EXE) $(TOP)/test/veryquick.test
|
||||
./testfixture$(EXE) $(TOP)/test/veryquick.test $(TESTOPTS)
|
||||
|
||||
# Run a test using valgrind. This can take a really long time
|
||||
# because valgrind is so much slower than a native machine.
|
||||
#
|
||||
valgrindtest: $(TESTPROGS) fuzzcheck$(EXE) $(FUZZDATA)
|
||||
valgrind -v ./fuzzcheck$(EXE) --cell-size-check --quiet $(FUZZDATA)
|
||||
OMIT_MISUSE=1 valgrind -v ./testfixture$(EXE) $(TOP)/test/permutations.test valgrind
|
||||
valgrindtest: $(TESTPROGS) valgrindfuzz
|
||||
OMIT_MISUSE=1 valgrind -v \
|
||||
./testfixture$(EXE) $(TOP)/test/permutations.test valgrind $(TESTOPTS)
|
||||
|
||||
# A very fast test that checks basic sanity. The name comes from
|
||||
# the 60s-era electronics testing: "Turn it on and see if smoke
|
||||
# comes out."
|
||||
#
|
||||
smoketest: $(TESTPROGS) fuzzcheck$(EXE)
|
||||
./testfixture$(EXE) $(TOP)/test/main.test
|
||||
./testfixture$(EXE) $(TOP)/test/main.test $(TESTOPTS)
|
||||
|
||||
# The next two rules are used to support the "threadtest" target. Building
|
||||
# threadtest runs a few thread-safety tests that are implemented in C. This
|
||||
|
140
manifest
140
manifest
@@ -1,9 +1,9 @@
|
||||
C Fix\sthe\sfts5\sxRename()\smethod.
|
||||
D 2015-06-10T10:45:34.820
|
||||
C Merge\slatest\strunk\schanges\swith\sthis\sbranch.\sAdd\stests\sfor\scolumnsize=0.
|
||||
D 2015-06-23T15:06:13.029
|
||||
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
||||
F Makefile.in d272f8755b464f20e02dd7799bfe16794c9574c4
|
||||
F Makefile.in 6fa5a3c6f1f558bb443429e33806e2e494823e44
|
||||
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
||||
F Makefile.msc d37d2c2323df3acae6e24c71a478889421c17264
|
||||
F Makefile.msc b7db9ccbbad1c495b98e5326a06cac03aa206127
|
||||
F Makefile.vxworks e1b65dea203f054e71653415bd8f96dcaed47858
|
||||
F README.md 8ecc12493ff9f820cdea6520a9016001cb2e59b7
|
||||
F VERSION ce0ae95abd7121c534f6917c1c8f2b70d9acd4db
|
||||
@@ -85,7 +85,7 @@ F ext/fts3/fts3_aux.c 9edc3655fcb287f0467d0a4b886a01c6185fe9f1
|
||||
F ext/fts3/fts3_expr.c 71c063da9c2a4167fb54aec089dd5ef33a58c9cb
|
||||
F ext/fts3/fts3_hash.c 29b986e43f4e9dd40110eafa377dc0d63c422c60
|
||||
F ext/fts3/fts3_hash.h 39cf6874dc239d6b4e30479b1975fe5b22a3caaf
|
||||
F ext/fts3/fts3_icu.c e319e108661147bcca8dd511cd562f33a1ba81b5
|
||||
F ext/fts3/fts3_icu.c deb46f7020d87ea7a14a433fb7a7f4bef42a9652
|
||||
F ext/fts3/fts3_porter.c 3565faf04b626cddf85f03825e86056a4562c009
|
||||
F ext/fts3/fts3_snippet.c 68ae118b0f834ea53d2b89e4087fc0f0b8c4ee4e
|
||||
F ext/fts3/fts3_term.c 88c55a6fa1a51ab494e33dced0401a6c28791fd7
|
||||
@@ -114,7 +114,7 @@ F ext/fts5/fts5_config.c 6ae691e36f90185896f4db0a819ae2394f880ca1
|
||||
F ext/fts5/fts5_expr.c 549bda1f7edcf10365fbfbc002bdea1be3c287bb
|
||||
F ext/fts5/fts5_hash.c c1cfdb2cae0fad00b06fae38a40eaf9261563ccc
|
||||
F ext/fts5/fts5_index.c 7cea402924cd3d8cd5943a7f9514c9153696571b
|
||||
F ext/fts5/fts5_storage.c 7e77d1b2da424283d1d58a77e9a98067dc96f2c7
|
||||
F ext/fts5/fts5_storage.c b2fa301fce865d582d367a5e1bb438fe60c03cb5
|
||||
F ext/fts5/fts5_tcl.c 7ea165878e4ae3598e89acd470a0ee1b5a00e33c
|
||||
F ext/fts5/fts5_tokenize.c 97251d68d7a6a9415bde1203f9382864dfc1f989
|
||||
F ext/fts5/fts5_unicode2.c da3cf712f05cd8347c8c5bc00964cc0361c88da9
|
||||
@@ -140,7 +140,7 @@ F ext/fts5/test/fts5auto.test caa5bcf917db11944655a2a9bd38c67c520376ca
|
||||
F ext/fts5/test/fts5aux.test e5631607bbc05ac1c38cf7d691000509aca71ef3
|
||||
F ext/fts5/test/fts5auxdata.test c69b86092bf1a157172de5f9169731af3403179b
|
||||
F ext/fts5/test/fts5bigpl.test b1cfd00561350ab04994ba7dd9d48468e5e0ec3b
|
||||
F ext/fts5/test/fts5columnsize.test c7333cf079022c1ad25d04538b8f279fad4c2f8d
|
||||
F ext/fts5/test/fts5columnsize.test bd07a42a80a6805e84afa7daf54ecd4563f752d0
|
||||
F ext/fts5/test/fts5config.test c9cc535f3b36cde1e5a32bf579f3f5962a9e82b2
|
||||
F ext/fts5/test/fts5content.test e46904decd896e38c848ad4f38fa4e80251a028b
|
||||
F ext/fts5/test/fts5corrupt.test 35bfdbbb3cdcea46ae7385f6432e9b5c574e70a1
|
||||
@@ -153,7 +153,7 @@ F ext/fts5/test/fts5eb.test 728a1f23f263548f5c29b29dfb851b5f2dbe723e
|
||||
F ext/fts5/test/fts5fault1.test b42d3296be8a75f557cf2cbce0d8b483fc9db45b
|
||||
F ext/fts5/test/fts5fault2.test 28c36c843bb39ae855ba79827417ecc37f114341
|
||||
F ext/fts5/test/fts5fault3.test d6e9577d4312e331a913c72931bf131704efc8f3
|
||||
F ext/fts5/test/fts5fault4.test 8671f534136aa1c80a102e8fd25b4921885e6667
|
||||
F ext/fts5/test/fts5fault4.test 762991d526ee67c2b374351a17248097ea38bee7
|
||||
F ext/fts5/test/fts5fault5.test 54da9fd4c3434a1d4f6abdcb6469299d91cf5875
|
||||
F ext/fts5/test/fts5fault6.test 234dc6355f8d3f8b5be2763f30699d770247c215
|
||||
F ext/fts5/test/fts5full.test 0924bdca5416a242103239ace79c6f5aa34bab8d
|
||||
@@ -180,7 +180,7 @@ F ext/fts5/test/fts5vocab.test 389e5fe4928eae5fddcf26bcc5a6890b0791aa75
|
||||
F ext/fts5/tool/loadfts5.tcl 7ef3e62131f0434a78e4f5c5b056b09d221710a8
|
||||
F ext/fts5/tool/showfts5.tcl 921f33b30c3189deefd2b2cc81f951638544aaf1
|
||||
F ext/icu/README.txt d9fbbad0c2f647c3fdf715fc9fd64af53aedfc43
|
||||
F ext/icu/icu.c d415ccf984defeb9df2c0e1afcfaa2f6dc05eacb
|
||||
F ext/icu/icu.c b2732aef0b076e4276d9b39b5a33cec7a05e1413
|
||||
F ext/icu/sqliteicu.h 728867a802baa5a96de7495e9689a8e01715ef37
|
||||
F ext/misc/amatch.c 27b9b601fb1453084e18a3432ea0240d7af8decb
|
||||
F ext/misc/closure.c 636024302cde41b2bf0c542f81c40c624cfb7012
|
||||
@@ -232,7 +232,7 @@ F ext/rtree/rtree8.test db79c812f9e4a11f9b1f3f9934007884610a713a
|
||||
F ext/rtree/rtree9.test b5eb13849545dfd271a54ff16784cb00d8792aea
|
||||
F ext/rtree/rtreeA.test ace05e729a36e342d40cf94e9efc7b4723d9dcdf
|
||||
F ext/rtree/rtreeB.test c85f9ce78766c4e68b8b89fbf2979ee9cfa82b4e
|
||||
F ext/rtree/rtreeC.test df158dcc81f1a43ce7eef361af03c48ec91f1e06
|
||||
F ext/rtree/rtreeC.test 90aaaffe2fd4f0dcd12289cad5515f6d41f45ffd
|
||||
F ext/rtree/rtreeD.test 636630357638f5983701550b37f0f5867130d2ca
|
||||
F ext/rtree/rtreeE.test 45a147a64a76306172819562309681d8e90f94bb
|
||||
F ext/rtree/rtreeF.test 66deb9fd1611c7ca2e374adba63debdc2dbb12b4
|
||||
@@ -247,7 +247,7 @@ F ext/userauth/userauth.c 5fa3bdb492f481bbc1709fc83c91ebd13460c69e
|
||||
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
|
||||
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
|
||||
F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60
|
||||
F main.mk dc2b1bf580712422d5a8bb774d8d940940563fb8
|
||||
F main.mk 080c85fad8bf6532b7aeb782452b78e4440de346
|
||||
F mkopcodec.awk c2ff431854d702cdd2d779c9c0d1f58fa16fa4ea
|
||||
F mkopcodeh.awk d5e22023b5238985bb54a72d33e0ac71fe4f8a32
|
||||
F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83
|
||||
@@ -268,30 +268,30 @@ F src/auth.c b56c78ebe40a2110fd361379f7e8162d23f92240
|
||||
F src/backup.c ff743689c4d6c5cb55ad42ed9d174b2b3e71f1e3
|
||||
F src/bitvec.c 5eb7958c3bf65210211cbcfc44eff86d0ded7c9d
|
||||
F src/btmutex.c 45a968cc85afed9b5e6cf55bf1f42f8d18107f79
|
||||
F src/btree.c c73a170115df068764126a85288cdec092ec180c
|
||||
F src/btree.c 173c2ba1b8cf941971683f584965369791125f12
|
||||
F src/btree.h 969adc948e89e449220ff0ff724c94bb2a52e9f1
|
||||
F src/btreeInt.h 973a22a6fd61350b454ad614832b1f0a5e25a1e4
|
||||
F src/build.c 73da2b9e9311abc4fcb4e36f76c7800c2d2504a4
|
||||
F src/btreeInt.h 6ece2dd9c8e2eac05f0a8ded8772a44e96486c65
|
||||
F src/build.c b3f15255d5b16e42dafeaa638fd4f8a47c94ed70
|
||||
F src/callback.c 7b44ce59674338ad48b0e84e7b72f935ea4f68b0
|
||||
F src/complete.c a5cf5b4b56390cfb7b8636e8f7ddef90258dd575
|
||||
F src/ctime.c 5a0b735dc95604766f5dac73973658eef782ee8b
|
||||
F src/date.c e4d50b3283696836ec1036b695ead9a19e37a5ac
|
||||
F src/dbstat.c f402e77e25089c6003d0c60b3233b9b3947d599a
|
||||
F src/delete.c 37964e6c1d73ff49cbea9ff690c9605fb15f600e
|
||||
F src/expr.c 52f5c1c2c16bf47234dc276d9f72b5ea85ae14af
|
||||
F src/delete.c 8857a6f27560718f65d43bdbec86c967ae1f8dfa
|
||||
F src/expr.c 32c836d9fa22c25371039febf074849dcefb3de9
|
||||
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
|
||||
F src/fkey.c c9b63a217d86582c22121699a47f22f524608869
|
||||
F src/func.c 5b8b8e77a0fb644eaf8947d413804622e32692b6
|
||||
F src/func.c a98ea5880dc50e9ca6dd6f57079a37b9cfcdecf1
|
||||
F src/global.c 4f77cadbc5427d00139ba43d0f3979804cbb700e
|
||||
F src/hash.c 4263fbc955f26c2e8cdc0cf214bc42435aa4e4f5
|
||||
F src/hash.h c8f3c31722cf3277d03713909761e152a5b81094
|
||||
F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08
|
||||
F src/insert.c d6e1623a97ce33e9af2f1a0c1f0085a2f63327ef
|
||||
F src/insert.c b5f8b35a1b7924020e48cade5b2b5017bca7906b
|
||||
F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d
|
||||
F src/legacy.c ba1863ea58c4c840335a84ec276fc2b25e22bc4e
|
||||
F src/lempar.c 7274c97d24bb46631e504332ccd3bd1b37841770
|
||||
F src/loadext.c 29255bbe1cfb2ce9bbff2526a5ecfddcb49b9271
|
||||
F src/main.c 33562894d96cb65f4926cd5317725427cdb22770
|
||||
F src/loadext.c e722f4b832f923744788365df5fb8515c0bc8a47
|
||||
F src/main.c fb40edfcda10062e4d1adab7f41635002e9b7e9d
|
||||
F src/malloc.c 908c780fdddd472163c2d1b1820ae4081f01ad20
|
||||
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
|
||||
F src/mem1.c abe6ee469b6c5a35c7f22bfeb9c9bac664a1c987
|
||||
@@ -300,7 +300,7 @@ F src/mem3.c 61c9d47b792908c532ca3a62b999cf21795c6534
|
||||
F src/mem5.c 61eeb90134f9a5be6c2e68d8daae7628b25953fb
|
||||
F src/memjournal.c 3eb2c0b51adbd869cb6a44780323f05fa904dc85
|
||||
F src/msvc.h d9ba56c6851227ab44b3f228a35f3f5772296495
|
||||
F src/mutex.c 19bf9acba69ca2f367c3761080f8a9f0cf4670a8
|
||||
F src/mutex.c 529e95739f815300a33c73fd8a7d6bdf0c24bd18
|
||||
F src/mutex.h 779d588e3b7756ec3ecf7d78cde1d84aba414f85
|
||||
F src/mutex_noop.c 529bab0743c3321c940f32c3464de494fd38cfa9
|
||||
F src/mutex_unix.c 5cf676464bd19e0a866297515d146e8bf1669dfb
|
||||
@@ -318,20 +318,20 @@ F src/pager.h c3476e7c89cdf1c6914e50a11f3714e30b4e0a77
|
||||
F src/parse.y 6d60dda8f8d418b6dc034f1fbccd816c459983a8
|
||||
F src/pcache.c 10539fb959849ad6efff80050541cab3d25089d4
|
||||
F src/pcache.h b44658c9c932d203510279439d891a2a83e12ba8
|
||||
F src/pcache1.c 69d137620a305f814398bd29a0c998038c0695e9
|
||||
F src/pcache1.c 8e3799b33c41d517d86444d4abefc80d4f02adca
|
||||
F src/pragma.c c1f4d012ea9f6b1ce52d341b2cd0ad72d560afd7
|
||||
F src/pragma.h b8632d7cdda7b25323fa580e3e558a4f0d4502cc
|
||||
F src/prepare.c 82e5db1013846a819f198336fed72c44c974e7b1
|
||||
F src/printf.c 13ce37e5574f9b0682fa86dbcf9faf76b9d82a15
|
||||
F src/printf.c db11b5960105ee661dcac690f2ae6276e49bf251
|
||||
F src/random.c ba2679f80ec82c4190062d756f22d0c358180696
|
||||
F src/resolve.c 84c571794e3ee5806274d95158a4c0177c6c4708
|
||||
F src/resolve.c 2d47554370de8de6dd5be060cef9559eec315005
|
||||
F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e
|
||||
F src/select.c 7bb5c6334128877a30d4644fb948098a3ec41bbc
|
||||
F src/shell.c 07dda7cd692911d2f22269953418d049f2e2c0ee
|
||||
F src/sqlite.h.in d165beeceb6b40af60f352a4d4e37e02d9af7df0
|
||||
F src/select.c 09865f89997db6ec617a78440cc18d84855e3053
|
||||
F src/shell.c 8af3cced094aebb5f57a8ad739b9dafc7867eed7
|
||||
F src/sqlite.h.in 76d2f5637eb795b6300d9dd3c3ec3632ffafd721
|
||||
F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad
|
||||
F src/sqlite3ext.h 2ebeb634e751a61a6f0eebfa0f4669f46a42f6cd
|
||||
F src/sqliteInt.h bcf51f6ec3ad67dbdf1acf78fcb94884af93c183
|
||||
F src/sqlite3ext.h be1a718b7d2ce40ceba725ae92c8eb5f18003066
|
||||
F src/sqliteInt.h d5df694bc33870e77fb08f389d12309597fe3059
|
||||
F src/sqliteLimit.h 216557999cb45f2e3578ed53ebefe228d779cb46
|
||||
F src/status.c f266ad8a2892d659b74f0f50cb6a88b6e7c12179
|
||||
F src/table.c 51b46b2a62d1b3a959633d593b89bab5e2c9155e
|
||||
@@ -382,19 +382,20 @@ F src/test_vfs.c 3b65d42e18b262805716bd96178c81da8f2d9283
|
||||
F src/test_vfstrace.c bab9594adc976cbe696ff3970728830b4c5ed698
|
||||
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
|
||||
F src/threads.c 6bbcc9fe50c917864d48287b4792d46d6e873481
|
||||
F src/tokenize.c baa0e550dfa76a8d781732a7bfb1f0aa094942f2
|
||||
F src/tokenize.c 57cb3720f53f84d811def2069c2b169b6be539a5
|
||||
F src/treeview.c c84b1a8ebc7f1d00cd76ce4958eeb3ae1021beed
|
||||
F src/trigger.c 322f23aad694e8f31d384dcfa386d52a48d3c52f
|
||||
F src/update.c 487747b328b7216bb7f6af0695d6937d5c9e605f
|
||||
F src/utf.c fc6b889ba0779b7722634cdeaa25f1930d93820c
|
||||
F src/util.c a6431c92803b975b7322724a7b433e538d243539
|
||||
F src/vacuum.c 2ddd5cad2a7b9cef7f9e431b8c7771634c6b1701
|
||||
F src/vdbe.c 0a6a1df5c31415a0e974e74e7bd412616889453d
|
||||
F src/vdbe.h 7e538ecf47dccb307ea2d087c3ddc2dd8d70e79d
|
||||
F src/vdbeInt.h f0ccddac48583d5f762dc554a9f79e85ea8807e0
|
||||
F src/vdbe.c c9b8985dfc5df9bd512342ea2e56af4be30cb31a
|
||||
F src/vdbe.h 90048aea1910f9df93e6044592bd4a466dc9c5e7
|
||||
F src/vdbeInt.h 20295e482121d13437f69985f77db211cdc8bac1
|
||||
F src/vdbeapi.c 6a0d7757987018ff6b1b81bc5293219cd26bb299
|
||||
F src/vdbeaux.c 46f9bc4b32866082eb87a36b461e487a0bbdbe8e
|
||||
F src/vdbeaux.c 4c82d6f686f72ea7d266d26d528a171b728626f7
|
||||
F src/vdbeblob.c 4f2e8e075d238392df98c5e03a64342465b03f90
|
||||
F src/vdbemem.c 67b302dc6df64b4d6785881c5d22bd4f9b17739d
|
||||
F src/vdbemem.c 4e947cd322bb531e3f7f6f58f0f536d182b38ef8
|
||||
F src/vdbesort.c f5009e7a35e3065635d8918b9a31f498a499976b
|
||||
F src/vdbetrace.c 8befe829faff6d9e6f6e4dee5a7d3f85cc85f1a0
|
||||
F src/vtab.c 082b35a25a26e3d36f365ca8cd73c1922532f05e
|
||||
@@ -402,8 +403,10 @@ F src/vxworks.h c18586c8edc1bddbc15c004fa16aeb1e1342b4fb
|
||||
F src/wal.c ce2cb2d06faab54d1bce3e739bec79e063dd9113
|
||||
F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4
|
||||
F src/walker.c c253b95b4ee44b21c406e2a1052636c31ea27804
|
||||
F src/where.c dcdfee81d35ae9261a4c5bda6289ed5fa6d7e1ae
|
||||
F src/whereInt.h a6f5a762bc1b4b1c76e1cea79976b437ac35a435
|
||||
F src/where.c 909eba3b6db984eb2adfbca9de2c237ee7056adb
|
||||
F src/whereInt.h 5f87e3c4b0551747d119730dfebddd3c54f04047
|
||||
F src/wherecode.c 0669481cabaf5caf934b6bb825df15bc57f60d40
|
||||
F src/whereexpr.c 9ce1c9cfedbf80c93c7d899497025ec8256ce652
|
||||
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
|
||||
F test/affinity2.test a6d901b436328bd67a79b41bb0ac2663918fe3bd
|
||||
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
|
||||
@@ -430,7 +433,7 @@ F test/analyzeC.test 555a6cc388b9818b6eda6df816f01ce0a75d3a93
|
||||
F test/analyzeD.test 08f9d0bee4e118a66fff3a32d02dbe0ee0a2b594
|
||||
F test/analyzeE.test 8684e8ac5722fb97c251887ad97e5d496a98af1d
|
||||
F test/analyzeF.test 7ccd7a04f7d3061bde1a8a4dacc4792edccf6bf2
|
||||
F test/analyzer1.test e3bccac3be49382050464952998a631bf51e3ce1
|
||||
F test/analyzer1.test 498e2ff4b62740c2751c3a2f8b744fe26689fae9
|
||||
F test/async.test 1d0e056ba1bb9729283a0f22718d3a25e82c277b
|
||||
F test/async2.test c0a9bd20816d7d6a2ceca7b8c03d3d69c28ffb8b
|
||||
F test/async3.test d73a062002376d7edc1fe3edff493edbec1fc2f7
|
||||
@@ -530,7 +533,7 @@ F test/corruptE.test 193b4ca4e927e77c1d5f4f56203ddc998432a7ee
|
||||
F test/corruptF.test be9fde98e4c93648f1ba52b74e5318edc8f59fe4
|
||||
F test/corruptG.test 1ab3bf97ee7bdba70e0ff3ba2320657df55d1804
|
||||
F test/corruptH.test 5dd4fa98c6c1ed33b178f9e8a48c4fdd3cfc9067
|
||||
F test/corruptI.test ddf8c7146db0bc6080eedced67453b4cc69b5340
|
||||
F test/corruptI.test f2b10e4fec2a4315bca2b936ffa52ccbffac3422
|
||||
F test/corruptJ.test 9e29e7a81ee3b6ac50f77ea7a9e2f3fa03f32d91
|
||||
F test/cost.test 19d314526616ce4473eb4e4e450fcb94499ce318
|
||||
F test/count.test cb2e0f934c6eb33670044520748d2ecccd46259c
|
||||
@@ -583,7 +586,7 @@ F test/e_update.test 312cb8f5ccfe41515a6bb092f8ea562a9bd54d52
|
||||
F test/e_uri.test 5ae33760fb2039c61aa2d90886f1664664173585
|
||||
F test/e_vacuum.test 5bfbdc21b65c0abf24398d0ba31dc88d93ca77a9
|
||||
F test/e_wal.test ae9a593207a77d711443ee69ffe081fda9243625
|
||||
F test/e_walauto.test 6544af03423abc61b53cfb976839385ddc2a0a70
|
||||
F test/e_walauto.test 280714ddf14e1a47dcbc59d515cd0b026dfd5567
|
||||
F test/e_walckpt.test 65e29b6631e51f210f83e4ff11571e647ba93608
|
||||
F test/e_walhook.test da3ea8b3483d1af72190337bda50155a91a4b664
|
||||
F test/enc.test e54531cd6bf941ee6760be041dff19a104c7acea
|
||||
@@ -599,8 +602,9 @@ F test/exec.test e949714dc127eaa5ecc7d723efec1ec27118fdd7
|
||||
F test/exists.test 8f7b27b61c2fbe5822f0a1f899c715d14e416e30
|
||||
F test/expr.test 79c3e7502d9e571553b85f0ecc8ff2ac7d0e4931
|
||||
F test/extension01.test 00d13cec817f331a687a243e0e5a2d87b0e358c9
|
||||
F test/extraquick.test cb254400bd42bfb777ff675356aabf3287978f79
|
||||
F test/fallocate.test 3e979af17dfa7e5e9dda5eba1a696c04fa9d47f7
|
||||
F test/filectrl.test 14fa712e42c4cb791e09dfd58a6a03efb47ef13a
|
||||
F test/filectrl.test 7c13f96457435238da99aff7343ad6a3a4885787
|
||||
F test/filefmt.test cb34663f126cbc2d358af552dcaf5c72769b0146
|
||||
F test/fkey1.test de5b287f6a480b36bd51e8debcf48168e26e4ed2
|
||||
F test/fkey2.test f3d27ecba480a348c328965d154214719bb158a9
|
||||
@@ -675,7 +679,7 @@ F test/fts3conf.test ee8500c86dd58ec075e8831a1e216a79989436de
|
||||
F test/fts3corrupt.test 2710b77983cc7789295ddbffea52c1d3b7506dbb
|
||||
F test/fts3corrupt2.test 6d96efae2f8a6af3eeaf283aba437e6d0e5447ba
|
||||
F test/fts3cov.test e0fb00d8b715ddae4a94c305992dfc3ef70353d7
|
||||
F test/fts3d.test 95c17d1b67b33a5eac0bf5a0d11116a0c0ac7a3a
|
||||
F test/fts3d.test d3e9c8fb75135ada06bf3bab4f9666224965d708
|
||||
F test/fts3defer.test 0be4440b73a2e651fc1e472066686d6ada4b9963
|
||||
F test/fts3defer2.test c540f5f5c2840f70c68fd9b597df817ec7170468
|
||||
F test/fts3defer3.test dd53fc13223c6d8264a98244e9b19abd35ed71cd
|
||||
@@ -709,14 +713,14 @@ F test/fts4content.test abb0c77bc3da3df64fec72e00844d2257a90025d
|
||||
F test/fts4docid.test e33c383cfbdff0284685604d256f347a18fdbf01
|
||||
F test/fts4growth.test df10fde9f47cf5c71861e63fd8efcd573c4f7e53
|
||||
F test/fts4growth2.test 2f063be1902a73cd087355837c52fed42ac11a5d
|
||||
F test/fts4incr.test 361960ed3550e781f3f313e17e2182ef9cefc0e9
|
||||
F test/fts4incr.test 4e353a0bd886ea984e56fce9e77724fc923b8d0d
|
||||
F test/fts4langid.test 24a6e41063b416bbdf371ff6b4476fa41c194aa7
|
||||
F test/fts4merge.test c424309743fdd203f8e56a1f1cd7872cd66cc0ee
|
||||
F test/fts4merge2.test 5faa558d1b672f82b847d2a337465fa745e46891
|
||||
F test/fts4merge3.test aab02a09f50fe6baaddc2e159c3eabc116d45fc7
|
||||
F test/fts4merge4.test d895b1057a7798b67e03455d0fa50e9ea836c47b
|
||||
F test/fts4noti.test 524807f0c36d49deea7920cdd4cd687408b58849
|
||||
F test/fts4unicode.test 01ec3fe2a7c3cfff3b4c0581b83caa11b33efa36
|
||||
F test/fts4unicode.test 27378af76394542cf490cf001d8d1505fe55f6a9
|
||||
F test/full.test 6b3c8fb43c6beab6b95438c1675374b95fab245d
|
||||
F test/func.test ae97561957aba6ca9e3a7b8a13aac41830d701ef
|
||||
F test/func2.test 772d66227e4e6684b86053302e2d74a2500e1e0f
|
||||
@@ -729,10 +733,10 @@ F test/fuzz2.test 76dc35b32b6d6f965259508508abce75a6c4d7e1
|
||||
F test/fuzz3.test efd384b896c647b61a2c1848ba70d42aad60a7b3
|
||||
F test/fuzz_common.tcl a87dfbb88c2a6b08a38e9a070dabd129e617b45b
|
||||
F test/fuzz_malloc.test 328f70aaca63adf29b4c6f06505ed0cf57ca7c26
|
||||
F test/fuzzcheck.c a60f926e3fa86c8d33908406d75eec868c22b9ca
|
||||
F test/fuzzdata1.db b60254eeb6bc11474071b883059662a73c48da7f
|
||||
F test/fuzzcheck.c 5805b2236292f8643d56e727a3a6e4d88e0856a5
|
||||
F test/fuzzdata1.db 7ee3227bad0e7ccdeb08a9e6822916777073c664
|
||||
F test/fuzzdata2.db f03a420d3b822cc82e4f894ca957618fbe9c4973
|
||||
F test/fuzzdata3.db 3632e598ff8574228aadf09897bd040d3c5f5ffb
|
||||
F test/fuzzdata3.db 77bed4fc8c4945124ed5616daf2dc4f4c3bf762a
|
||||
F test/fuzzer1.test d4c52aaf3ef923da293a2653cfab33d02f718a36
|
||||
F test/fuzzerfault.test 8792cd77fd5bce765b05d0c8e01b9edcf8af8536
|
||||
F test/genesis.tcl 1e2e2e8e5cc4058549a154ff1892fe5c9de19f98
|
||||
@@ -740,7 +744,7 @@ F test/hexlit.test 1d312fa816dfd3650a3bb488093bc09a0c927f67
|
||||
F test/hook.test 162d7cef7a2d2b04839fe14402934e6a1b79442f
|
||||
F test/icu.test 70df4faca133254c042d02ae342c0a141f2663f4
|
||||
F test/imposter1.test c3f1db2d3db2c24611a6596a3fc0ffc14f1466c8
|
||||
F test/in.test b52fa96bcf6cebc5c8829c822315d0f87af9c6c2
|
||||
F test/in.test 61a24ae38d4b64ec69f06ccdf022992f68a98176
|
||||
F test/in2.test 5d4c61d17493c832f7d2d32bef785119e87bde75
|
||||
F test/in3.test 3cbf58c87f4052cee3a58b37b6389777505aa0c0
|
||||
F test/in4.test d2b38cba404bc4320f4fe1b595b3d163f212c068
|
||||
@@ -760,8 +764,8 @@ F test/index.test 4d990005a67a36984e4f1a5f1bdccea8d08da4ee
|
||||
F test/index2.test ee83c6b5e3173a3d7137140d945d9a5d4fdfb9d6
|
||||
F test/index3.test b6ec456cf3b81d9a32123fe7e449bde434db338b
|
||||
F test/index4.test ab92e736d5946840236cd61ac3191f91a7856bf6
|
||||
F test/index5.test 25b0b451aceed4ac5f7d49f856f6de7257470b3e
|
||||
F test/index6.test 3ae54e53c53f2adcacda269237d8e52bdb05a481
|
||||
F test/index5.test 8621491915800ec274609e42e02a97d67e9b13e7
|
||||
F test/index6.test fbf45ceb39eb8a01b837d22623b93b208e6509ef
|
||||
F test/index7.test 9c6765a74fc3fcde7aebc5b3bd40d98df14a527c
|
||||
F test/indexedby.test 5f527a78bae74c61b8046ae3037f9dfb0bf0c353
|
||||
F test/indexfault.test 31d4ab9a7d2f6e9616933eb079722362a883eb1d
|
||||
@@ -782,7 +786,7 @@ F test/ioerr3.test d3cec5e1a11ad6d27527d0d38573fbff14c71bdd
|
||||
F test/ioerr4.test f130fe9e71008577b342b8874d52984bd04ede2c
|
||||
F test/ioerr5.test 2edfa4fb0f896f733071303b42224df8bedd9da4
|
||||
F test/ioerr6.test a395a6ab144b26a9e3e21059a1ab6a7149cca65b
|
||||
F test/join.test 52d4d49f86d0cf46926672878c4eaf0da399104a
|
||||
F test/join.test f9d4a28dec81c6e9dc21b73518e024d73b5ebf57
|
||||
F test/join2.test f2171c265e57ee298a27e57e7051d22962f9f324
|
||||
F test/join3.test 6f0c774ff1ba0489e6c88a3e77b9d3528fb4fda0
|
||||
F test/join4.test 1a352e4e267114444c29266ce79e941af5885916
|
||||
@@ -897,13 +901,13 @@ F test/pagesize.test 5769fc62d8c890a83a503f67d47508dfdc543305
|
||||
F test/pcache.test b09104b03160aca0d968d99e8cd2c5b1921a993d
|
||||
F test/pcache2.test a83efe2dec0d392f814bfc998def1d1833942025
|
||||
F test/percentile.test 4243af26b8f3f4555abe166f723715a1f74c77ff
|
||||
F test/permutations.test a54a4c5e66dc158cb2c05579bbb4f7d1a4fdb6c1
|
||||
F test/permutations.test 6a88fd9ca15b804e9c20990773262ca67494058f
|
||||
F test/pragma.test be7195f0aa72bdb8a512133e9640ac40f15b57a2
|
||||
F test/pragma2.test f624a496a95ee878e81e59961eade66d5c00c028
|
||||
F test/pragma3.test 6f849ccffeee7e496d2f2b5e74152306c0b8757c
|
||||
F test/printf.test b3ff34e73d59124140eaf89f7672e21bc2ca5fcc
|
||||
F test/printf2.test 0b61566dd1c0f0b802f59dffa228c5dc5aa6b054
|
||||
F test/progress.test a282973d1d17f08071bc58a77d6b80f2a81c354d
|
||||
F test/progress.test ebab27f670bd0d4eb9d20d49cef96e68141d92fb
|
||||
F test/ptrchng.test ef1aa72d6cf35a2bbd0869a649b744e9d84977fc
|
||||
F test/queryonly.test 5f653159e0f552f0552d43259890c1089391dcca
|
||||
F test/quick.test 1681febc928d686362d50057c642f77a02c62e57
|
||||
@@ -916,7 +920,7 @@ F test/randexpr1.test eda062a97e60f9c38ae8d806b03b0ddf23d796df
|
||||
F test/rdonly.test 64e2696c322e3538df0b1ed624e21f9a23ed9ff8
|
||||
F test/regexp1.test 497ea812f264d12b6198d6e50a76be4a1973a9d8
|
||||
F test/reindex.test 44edd3966b474468b823d481eafef0c305022254
|
||||
F test/releasetest.tcl 3e906a8bbd047b8e1f035984fbdc96df4caaea47
|
||||
F test/releasetest.tcl 2aaffa548a8f8d10053b20bcf68a1b5a01081e51
|
||||
F test/resolver01.test f4022acafda7f4d40eca94dbf16bc5fc4ac30ceb
|
||||
F test/rollback.test 458fe73eb3ffdfdf9f6ba3e9b7350a6220414dea
|
||||
F test/rollback2.test fc14cf6d1a2b250d2735ef16124b971bce152f14
|
||||
@@ -947,8 +951,8 @@ F test/select3.test 2ce595f8fb8e2ac10071d3b4e424cadd4634a054
|
||||
F test/select4.test 6d5bc6d178a367e8b48fa1c1d3ea12cae9c2d650
|
||||
F test/select5.test e758b8ef94f69b111df4cb819008856655dcd535
|
||||
F test/select6.test 39eac4a5c03650b2b473c532882273283ee8b7a0
|
||||
F test/select7.test 7fd2ef598cfabb6b9ff6ac13973b91d0527df49d
|
||||
F test/select8.test 391de11bdd52339c30580dabbbbe97e3e9a3c79d
|
||||
F test/select7.test 71f06cd37cb6f65bb08ba1ccf8e2f5818c09329f
|
||||
F test/select8.test 8c8f5ae43894c891efc5755ed905467d1d67ad5d
|
||||
F test/select9.test aebc2bb0c3bc44606125033cbcaac2c8d1f33a95
|
||||
F test/selectA.test e452bdb975f488ea46d091382a9185b5853ed2c7
|
||||
F test/selectB.test 954e4e49cf1f896d61794e440669e03a27ceea25
|
||||
@@ -961,7 +965,7 @@ F test/server1.test 46803bd3fe8b99b30dbc5ff38ffc756f5c13a118
|
||||
F test/shared.test 1da9dbad400cee0d93f252ccf76e1ae007a63746
|
||||
F test/shared2.test 03eb4a8d372e290107d34b6ce1809919a698e879
|
||||
F test/shared3.test fcd65cb11d189eff5f5c85cc4fad246fb0933108
|
||||
F test/shared4.test 72d90821e8d2fc918a08f16d32880868d8ee8e9d
|
||||
F test/shared4.test c75f476804e76e26bf6fa0e7b421fb0ca7d07558
|
||||
F test/shared6.test 866bb4982c45ce216c61ded5e8fde4e7e2f3ffa9
|
||||
F test/shared7.test a81e99f83e6c51b02ac99c96fb3a2a7b5978c956
|
||||
F test/shared8.test 00a07bf5e1337ecf72e94542bdefdc330d7a2538
|
||||
@@ -1000,9 +1004,9 @@ F test/speed3.test d32043614c08c53eafdc80f33191d5bd9b920523
|
||||
F test/speed4.test abc0ad3399dcf9703abed2fff8705e4f8e416715
|
||||
F test/speed4p.explain 6b5f104ebeb34a038b2f714150f51d01143e59aa
|
||||
F test/speed4p.test 0e51908951677de5a969b723e03a27a1c45db38b
|
||||
F test/speedtest1.c 9f1b745c24886cced3f70ffc666300152a39013c
|
||||
F test/speedtest1.c f42fd04a34a0c1dc289cbe536ef62d706227a736
|
||||
F test/spellfix.test 24f676831acddd2f4056a598fd731a72c6311f49
|
||||
F test/sqldiff1.test e5ecfe95b3a2ff6380f0db6ea8bec246b675e122
|
||||
F test/sqldiff1.test 8f6bc7c6a5b3585d350d779c6078869ba402f8f5
|
||||
F test/sqllimits1.test e05786eaed7950ff6a2d00031d001d8a26131e68
|
||||
F test/stat.test 8de91498c99f5298b303f70f1d1f3b9557af91bf
|
||||
F test/statfault.test f525a7bf633e50afd027700e9a486090684b1ac1
|
||||
@@ -1015,14 +1019,14 @@ F test/superlock.test 1cde669f68d2dd37d6c9bd35eee1d95491ae3fc2
|
||||
F test/sync.test a34cd43e98b7fb84eabbf38f7ed8f7349b3f3d85
|
||||
F test/syscall.test d2fdaad713f103ac611fe7ef9b724c7b69f8149c
|
||||
F test/sysfault.test fa776e60bf46bdd3ae69f0b73e46ee3977a58ae6
|
||||
F test/table.test bd841e8df69b99172ce9c7d53587463913d711ca
|
||||
F test/table.test 33bf0d1fd07f304582695184b8e6feb017303816
|
||||
F test/tableapi.test 2674633fa95d80da917571ebdd759a14d9819126
|
||||
F test/tableopts.test dba698ba97251017b7c80d738c198d39ab747930
|
||||
F test/tclsqlite.test 7fb866443c7deceed22b63948ccd6f76b52ad054
|
||||
F test/tempdb.test 19d0f66e2e3eeffd68661a11c83ba5e6ace9128c
|
||||
F test/temptable.test d2c9b87a54147161bcd1822e30c1d1cd891e5b30
|
||||
F test/temptrigger.test 8ec228b0db5d7ebc4ee9b458fc28cb9e7873f5e1
|
||||
F test/tester.tcl c18dbf42f4b0c1fb889b0efeb8a59d5143dd9828
|
||||
F test/tester.tcl b3a41e20f98a029a76e930b33d0711c5854267bb
|
||||
F test/thread001.test 9f22fd3525a307ff42a326b6bc7b0465be1745a5
|
||||
F test/thread002.test e630504f8a06c00bf8bbe68528774dd96aeb2e58
|
||||
F test/thread003.test ee4c9efc3b86a6a2767516a37bd64251272560a7
|
||||
@@ -1220,7 +1224,7 @@ F test/vacuum4.test d3f8ecff345f166911568f397d2432c16d2867d9
|
||||
F test/varint.test ab7b110089a08b9926ed7390e7e97bdefeb74102
|
||||
F test/veryquick.test 57ab846bacf7b90cf4e9a672721ea5c5b669b661
|
||||
F test/view.test f311691d696a5cc27e3c1b875cec1b0866b4ccd9
|
||||
F test/vtab1.test dbe0e9e121102d0ba365f20d126a72676aa2343f
|
||||
F test/vtab1.test 6210e076997f176bedc300a87ad6404651b601dd
|
||||
F test/vtab2.test f8cd1bb9aba7143eba97812d9617880a36d247ad
|
||||
F test/vtab3.test b45f47d20f225ccc9c28dc915d92740c2dee311e
|
||||
F test/vtab4.test 942f8b8280b3ea8a41dae20e7822d065ca1cb275
|
||||
@@ -1281,7 +1285,7 @@ F test/whereC.test cae295158703cb3fc23bf1a108a9ab730efff0f6
|
||||
F test/whereD.test 9eba1f9b18e5b19a0b0bcaae5e8c037260195f2b
|
||||
F test/whereE.test b3a055eef928c992b0a33198a7b8dc10eea5ad2f
|
||||
F test/whereF.test 5b2ba0dbe8074aa13e416b37c753991f0a2492d7
|
||||
F test/whereG.test 69f5ec4b15760a8c860f80e2d55525669390aab3
|
||||
F test/whereG.test dde4c52a97385a55be6a7cd46be8373f0cf35501
|
||||
F test/whereH.test e4b07f7a3c2f5d31195cd33710054c78667573b2
|
||||
F test/whereI.test 1d89199697919d4930be05a71e7fe620f114e622
|
||||
F test/whereJ.test 55a3221706a7ab706293f17cc8f96da563bf0767
|
||||
@@ -1324,7 +1328,7 @@ F tool/mkopts.tcl 66ac10d240cc6e86abd37dc908d50382f84ff46e
|
||||
F tool/mkpragmatab.tcl 40c287d3f929ece67da6e9e7c49885789960accf
|
||||
F tool/mkspeedsql.tcl a1a334d288f7adfe6e996f2e712becf076745c97
|
||||
F tool/mksqlite3c-noext.tcl 69bae8ce4aa52d2ff82d4a8a856bf283ec035b2e
|
||||
F tool/mksqlite3c.tcl ccee8fe53dabbeb00d55fe0a4a24005f69eccec9
|
||||
F tool/mksqlite3c.tcl b601b174d783094edd926d913a8f545709e89f8a
|
||||
F tool/mksqlite3h.tcl 44730d586c9031638cdd2eb443b801c0d2dbd9f8
|
||||
F tool/mksqlite3internalh.tcl eb994013e833359137eb53a55acdad0b5ae1049b
|
||||
F tool/mkvsix.tcl 3b58b9398f91c7dbf18d49eb87cefeee9efdbce1
|
||||
@@ -1357,9 +1361,9 @@ F tool/varint.c 5d94cb5003db9dbbcbcc5df08d66f16071aee003
|
||||
F tool/vdbe-compress.tcl 5926c71f9c12d2ab73ef35c29376e756eb68361c
|
||||
F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1
|
||||
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
|
||||
F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32
|
||||
F tool/warnings.sh 48bd54594752d5be3337f12c72f28d2080cb630b
|
||||
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
|
||||
P aa12f9d9b79c2f523fd6b00e47bcb66dba09ce0c
|
||||
R 92d332093f5da6f2c10bbd12aba6b7b5
|
||||
P 0f7fd51325875fbf0f1eaca3bbbd170ef99c4208 4df852ce26c95d5d23c83dbe9c59d2c3435acddf
|
||||
R 3ac475f744e56c1ad80818d65ed40944
|
||||
U dan
|
||||
Z 4c307463292fc937d885d935d5d6ac74
|
||||
Z b74a37a10556c5365b257dc3f6c234f4
|
||||
|
@@ -1 +1 @@
|
||||
0f7fd51325875fbf0f1eaca3bbbd170ef99c4208
|
||||
ef44c71a22518727030dd90c0139af8973b05841
|
339
src/btree.c
339
src/btree.c
@@ -980,11 +980,73 @@ static u8 *findOverflowCell(MemPage *pPage, int iCell){
|
||||
}
|
||||
|
||||
/*
|
||||
** Parse a cell content block and fill in the CellInfo structure. There
|
||||
** are two versions of this function. btreeParseCell() takes a
|
||||
** cell index as the second argument and btreeParseCellPtr()
|
||||
** takes a pointer to the body of the cell as its second argument.
|
||||
** This is common tail processing for btreeParseCellPtr() and
|
||||
** btreeParseCellPtrIndex() for the case when the cell does not fit entirely
|
||||
** on a single B-tree page. Make necessary adjustments to the CellInfo
|
||||
** structure.
|
||||
*/
|
||||
static SQLITE_NOINLINE void btreeParseCellAdjustSizeForOverflow(
|
||||
MemPage *pPage, /* Page containing the cell */
|
||||
u8 *pCell, /* Pointer to the cell text. */
|
||||
CellInfo *pInfo /* Fill in this structure */
|
||||
){
|
||||
/* If the payload will not fit completely on the local page, we have
|
||||
** to decide how much to store locally and how much to spill onto
|
||||
** overflow pages. The strategy is to minimize the amount of unused
|
||||
** space on overflow pages while keeping the amount of local storage
|
||||
** in between minLocal and maxLocal.
|
||||
**
|
||||
** Warning: changing the way overflow payload is distributed in any
|
||||
** way will result in an incompatible file format.
|
||||
*/
|
||||
int minLocal; /* Minimum amount of payload held locally */
|
||||
int maxLocal; /* Maximum amount of payload held locally */
|
||||
int surplus; /* Overflow payload available for local storage */
|
||||
|
||||
minLocal = pPage->minLocal;
|
||||
maxLocal = pPage->maxLocal;
|
||||
surplus = minLocal + (pInfo->nPayload - minLocal)%(pPage->pBt->usableSize-4);
|
||||
testcase( surplus==maxLocal );
|
||||
testcase( surplus==maxLocal+1 );
|
||||
if( surplus <= maxLocal ){
|
||||
pInfo->nLocal = (u16)surplus;
|
||||
}else{
|
||||
pInfo->nLocal = (u16)minLocal;
|
||||
}
|
||||
pInfo->iOverflow = (u16)(&pInfo->pPayload[pInfo->nLocal] - pCell);
|
||||
pInfo->nSize = pInfo->iOverflow + 4;
|
||||
}
|
||||
|
||||
/*
|
||||
** The following routines are implementations of the MemPage.xParseCell()
|
||||
** method.
|
||||
**
|
||||
** Parse a cell content block and fill in the CellInfo structure.
|
||||
**
|
||||
** btreeParseCellPtr() => table btree leaf nodes
|
||||
** btreeParseCellNoPayload() => table btree internal nodes
|
||||
** btreeParseCellPtrIndex() => index btree nodes
|
||||
**
|
||||
** There is also a wrapper function btreeParseCell() that works for
|
||||
** all MemPage types and that references the cell by index rather than
|
||||
** by pointer.
|
||||
*/
|
||||
static void btreeParseCellPtrNoPayload(
|
||||
MemPage *pPage, /* Page containing the cell */
|
||||
u8 *pCell, /* Pointer to the cell text. */
|
||||
CellInfo *pInfo /* Fill in this structure */
|
||||
){
|
||||
assert( sqlite3_mutex_held(pPage->pBt->mutex) );
|
||||
assert( pPage->leaf==0 );
|
||||
assert( pPage->noPayload );
|
||||
assert( pPage->childPtrSize==4 );
|
||||
pInfo->nSize = 4 + getVarint(&pCell[4], (u64*)&pInfo->nKey);
|
||||
pInfo->nPayload = 0;
|
||||
pInfo->nLocal = 0;
|
||||
pInfo->iOverflow = 0;
|
||||
pInfo->pPayload = 0;
|
||||
return;
|
||||
}
|
||||
static void btreeParseCellPtr(
|
||||
MemPage *pPage, /* Page containing the cell */
|
||||
u8 *pCell, /* Pointer to the cell text. */
|
||||
@@ -992,26 +1054,54 @@ static void btreeParseCellPtr(
|
||||
){
|
||||
u8 *pIter; /* For scanning through pCell */
|
||||
u32 nPayload; /* Number of bytes of cell payload */
|
||||
u64 iKey; /* Extracted Key value */
|
||||
|
||||
assert( sqlite3_mutex_held(pPage->pBt->mutex) );
|
||||
assert( pPage->leaf==0 || pPage->leaf==1 );
|
||||
if( pPage->intKeyLeaf ){
|
||||
assert( pPage->childPtrSize==0 );
|
||||
pIter = pCell + getVarint32(pCell, nPayload);
|
||||
pIter += getVarint(pIter, (u64*)&pInfo->nKey);
|
||||
}else if( pPage->noPayload ){
|
||||
assert( pPage->childPtrSize==4 );
|
||||
pInfo->nSize = 4 + getVarint(&pCell[4], (u64*)&pInfo->nKey);
|
||||
pInfo->nPayload = 0;
|
||||
pInfo->nLocal = 0;
|
||||
pInfo->iOverflow = 0;
|
||||
pInfo->pPayload = 0;
|
||||
return;
|
||||
}else{
|
||||
pIter = pCell + pPage->childPtrSize;
|
||||
pIter += getVarint32(pIter, nPayload);
|
||||
pInfo->nKey = nPayload;
|
||||
assert( pPage->intKeyLeaf || pPage->noPayload );
|
||||
assert( pPage->noPayload==0 );
|
||||
assert( pPage->intKeyLeaf );
|
||||
assert( pPage->childPtrSize==0 );
|
||||
pIter = pCell;
|
||||
|
||||
/* The next block of code is equivalent to:
|
||||
**
|
||||
** pIter += getVarint32(pIter, nPayload);
|
||||
**
|
||||
** The code is inlined to avoid a function call.
|
||||
*/
|
||||
nPayload = *pIter;
|
||||
if( nPayload>=0x80 ){
|
||||
u8 *pEnd = &pIter[8];
|
||||
nPayload &= 0x7f;
|
||||
do{
|
||||
nPayload = (nPayload<<7) | (*++pIter & 0x7f);
|
||||
}while( (*pIter)>=0x80 && pIter<pEnd );
|
||||
}
|
||||
pIter++;
|
||||
|
||||
/* The next block of code is equivalent to:
|
||||
**
|
||||
** pIter += getVarint(pIter, (u64*)&pInfo->nKey);
|
||||
**
|
||||
** The code is inlined to avoid a function call.
|
||||
*/
|
||||
iKey = *pIter;
|
||||
if( iKey>=0x80 ){
|
||||
u8 *pEnd = &pIter[7];
|
||||
iKey &= 0x7f;
|
||||
while(1){
|
||||
iKey = (iKey<<7) | (*++pIter & 0x7f);
|
||||
if( (*pIter)<0x80 ) break;
|
||||
if( pIter>=pEnd ){
|
||||
iKey = (iKey<<8) | *++pIter;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
pIter++;
|
||||
|
||||
pInfo->nKey = *(i64*)&iKey;
|
||||
pInfo->nPayload = nPayload;
|
||||
pInfo->pPayload = pIter;
|
||||
testcase( nPayload==pPage->maxLocal );
|
||||
@@ -1025,31 +1115,46 @@ static void btreeParseCellPtr(
|
||||
pInfo->nLocal = (u16)nPayload;
|
||||
pInfo->iOverflow = 0;
|
||||
}else{
|
||||
/* If the payload will not fit completely on the local page, we have
|
||||
** to decide how much to store locally and how much to spill onto
|
||||
** overflow pages. The strategy is to minimize the amount of unused
|
||||
** space on overflow pages while keeping the amount of local storage
|
||||
** in between minLocal and maxLocal.
|
||||
**
|
||||
** Warning: changing the way overflow payload is distributed in any
|
||||
** way will result in an incompatible file format.
|
||||
*/
|
||||
int minLocal; /* Minimum amount of payload held locally */
|
||||
int maxLocal; /* Maximum amount of payload held locally */
|
||||
int surplus; /* Overflow payload available for local storage */
|
||||
btreeParseCellAdjustSizeForOverflow(pPage, pCell, pInfo);
|
||||
}
|
||||
}
|
||||
static void btreeParseCellPtrIndex(
|
||||
MemPage *pPage, /* Page containing the cell */
|
||||
u8 *pCell, /* Pointer to the cell text. */
|
||||
CellInfo *pInfo /* Fill in this structure */
|
||||
){
|
||||
u8 *pIter; /* For scanning through pCell */
|
||||
u32 nPayload; /* Number of bytes of cell payload */
|
||||
|
||||
minLocal = pPage->minLocal;
|
||||
maxLocal = pPage->maxLocal;
|
||||
surplus = minLocal + (nPayload - minLocal)%(pPage->pBt->usableSize - 4);
|
||||
testcase( surplus==maxLocal );
|
||||
testcase( surplus==maxLocal+1 );
|
||||
if( surplus <= maxLocal ){
|
||||
pInfo->nLocal = (u16)surplus;
|
||||
}else{
|
||||
pInfo->nLocal = (u16)minLocal;
|
||||
}
|
||||
pInfo->iOverflow = (u16)(&pInfo->pPayload[pInfo->nLocal] - pCell);
|
||||
pInfo->nSize = pInfo->iOverflow + 4;
|
||||
assert( sqlite3_mutex_held(pPage->pBt->mutex) );
|
||||
assert( pPage->leaf==0 || pPage->leaf==1 );
|
||||
assert( pPage->intKeyLeaf==0 );
|
||||
assert( pPage->noPayload==0 );
|
||||
pIter = pCell + pPage->childPtrSize;
|
||||
nPayload = *pIter;
|
||||
if( nPayload>=0x80 ){
|
||||
u8 *pEnd = &pIter[8];
|
||||
nPayload &= 0x7f;
|
||||
do{
|
||||
nPayload = (nPayload<<7) | (*++pIter & 0x7f);
|
||||
}while( *(pIter)>=0x80 && pIter<pEnd );
|
||||
}
|
||||
pIter++;
|
||||
pInfo->nKey = nPayload;
|
||||
pInfo->nPayload = nPayload;
|
||||
pInfo->pPayload = pIter;
|
||||
testcase( nPayload==pPage->maxLocal );
|
||||
testcase( nPayload==pPage->maxLocal+1 );
|
||||
if( nPayload<=pPage->maxLocal ){
|
||||
/* This is the (easy) common case where the entire payload fits
|
||||
** on the local page. No overflow is required.
|
||||
*/
|
||||
pInfo->nSize = nPayload + (u16)(pIter - pCell);
|
||||
if( pInfo->nSize<4 ) pInfo->nSize = 4;
|
||||
pInfo->nLocal = (u16)nPayload;
|
||||
pInfo->iOverflow = 0;
|
||||
}else{
|
||||
btreeParseCellAdjustSizeForOverflow(pPage, pCell, pInfo);
|
||||
}
|
||||
}
|
||||
static void btreeParseCell(
|
||||
@@ -1057,14 +1162,20 @@ static void btreeParseCell(
|
||||
int iCell, /* The cell index. First cell is 0 */
|
||||
CellInfo *pInfo /* Fill in this structure */
|
||||
){
|
||||
btreeParseCellPtr(pPage, findCell(pPage, iCell), pInfo);
|
||||
pPage->xParseCell(pPage, findCell(pPage, iCell), pInfo);
|
||||
}
|
||||
|
||||
/*
|
||||
** The following routines are implementations of the MemPage.xCellSize
|
||||
** method.
|
||||
**
|
||||
** Compute the total number of bytes that a Cell needs in the cell
|
||||
** data area of the btree-page. The return number includes the cell
|
||||
** data header and the local payload, but not any overflow page or
|
||||
** the space used by the cell pointer.
|
||||
**
|
||||
** cellSizePtrNoPayload() => table internal nodes
|
||||
** cellSizePtr() => all index nodes & table leaf nodes
|
||||
*/
|
||||
static u16 cellSizePtr(MemPage *pPage, u8 *pCell){
|
||||
u8 *pIter = pCell + pPage->childPtrSize; /* For looping over bytes of pCell */
|
||||
@@ -1077,18 +1188,13 @@ static u16 cellSizePtr(MemPage *pPage, u8 *pCell){
|
||||
** cell. If SQLITE_DEBUG is defined, an assert() at the bottom of
|
||||
** this function verifies that this invariant is not violated. */
|
||||
CellInfo debuginfo;
|
||||
btreeParseCellPtr(pPage, pCell, &debuginfo);
|
||||
pPage->xParseCell(pPage, pCell, &debuginfo);
|
||||
#endif
|
||||
|
||||
if( pPage->noPayload ){
|
||||
pEnd = &pIter[9];
|
||||
while( (*pIter++)&0x80 && pIter<pEnd );
|
||||
assert( pPage->childPtrSize==4 );
|
||||
return (u16)(pIter - pCell);
|
||||
}
|
||||
assert( pPage->noPayload==0 );
|
||||
nSize = *pIter;
|
||||
if( nSize>=0x80 ){
|
||||
pEnd = &pIter[9];
|
||||
pEnd = &pIter[8];
|
||||
nSize &= 0x7f;
|
||||
do{
|
||||
nSize = (nSize<<7) | (*++pIter & 0x7f);
|
||||
@@ -1120,12 +1226,32 @@ static u16 cellSizePtr(MemPage *pPage, u8 *pCell){
|
||||
assert( nSize==debuginfo.nSize || CORRUPT_DB );
|
||||
return (u16)nSize;
|
||||
}
|
||||
static u16 cellSizePtrNoPayload(MemPage *pPage, u8 *pCell){
|
||||
u8 *pIter = pCell + 4; /* For looping over bytes of pCell */
|
||||
u8 *pEnd; /* End mark for a varint */
|
||||
|
||||
#ifdef SQLITE_DEBUG
|
||||
/* The value returned by this function should always be the same as
|
||||
** the (CellInfo.nSize) value found by doing a full parse of the
|
||||
** cell. If SQLITE_DEBUG is defined, an assert() at the bottom of
|
||||
** this function verifies that this invariant is not violated. */
|
||||
CellInfo debuginfo;
|
||||
pPage->xParseCell(pPage, pCell, &debuginfo);
|
||||
#endif
|
||||
|
||||
assert( pPage->childPtrSize==4 );
|
||||
pEnd = pIter + 9;
|
||||
while( (*pIter++)&0x80 && pIter<pEnd );
|
||||
assert( debuginfo.nSize==(u16)(pIter - pCell) || CORRUPT_DB );
|
||||
return (u16)(pIter - pCell);
|
||||
}
|
||||
|
||||
|
||||
#ifdef SQLITE_DEBUG
|
||||
/* This variation on cellSizePtr() is used inside of assert() statements
|
||||
** only. */
|
||||
static u16 cellSize(MemPage *pPage, int iCell){
|
||||
return cellSizePtr(pPage, findCell(pPage, iCell));
|
||||
return pPage->xCellSize(pPage, findCell(pPage, iCell));
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1139,7 +1265,7 @@ static void ptrmapPutOvflPtr(MemPage *pPage, u8 *pCell, int *pRC){
|
||||
CellInfo info;
|
||||
if( *pRC ) return;
|
||||
assert( pCell!=0 );
|
||||
btreeParseCellPtr(pPage, pCell, &info);
|
||||
pPage->xParseCell(pPage, pCell, &info);
|
||||
if( info.iOverflow ){
|
||||
Pgno ovfl = get4byte(&pCell[info.iOverflow]);
|
||||
ptrmapPut(pPage->pBt, ovfl, PTRMAP_OVERFLOW1, pPage->pgno, pRC);
|
||||
@@ -1203,7 +1329,7 @@ static int defragmentPage(MemPage *pPage){
|
||||
return SQLITE_CORRUPT_BKPT;
|
||||
}
|
||||
assert( pc>=iCellFirst && pc<=iCellLast );
|
||||
size = cellSizePtr(pPage, &src[pc]);
|
||||
size = pPage->xCellSize(pPage, &src[pc]);
|
||||
cbrk -= size;
|
||||
if( cbrk<iCellFirst || pc+size>usableSize ){
|
||||
return SQLITE_CORRUPT_BKPT;
|
||||
@@ -1272,7 +1398,10 @@ static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc, int *pbDefrag){
|
||||
int x = size - nByte;
|
||||
testcase( x==4 );
|
||||
testcase( x==3 );
|
||||
if( x<4 ){
|
||||
if( pc < pPg->cellOffset+2*pPg->nCell || size+pc > usableSize ){
|
||||
*pRc = SQLITE_CORRUPT_BKPT;
|
||||
return 0;
|
||||
}else if( x<4 ){
|
||||
/* EVIDENCE-OF: R-11498-58022 In a well-formed b-tree page, the total
|
||||
** number of bytes in fragments may not exceed 60. */
|
||||
if( aData[hdr+7]>=60 ){
|
||||
@@ -1283,9 +1412,6 @@ static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc, int *pbDefrag){
|
||||
** fragmented bytes within the page. */
|
||||
memcpy(&aData[iAddr], &aData[pc], 2);
|
||||
aData[hdr+7] += (u8)x;
|
||||
}else if( pc < pPg->cellOffset+2*pPg->nCell || size+pc > usableSize ){
|
||||
*pRc = SQLITE_CORRUPT_BKPT;
|
||||
return 0;
|
||||
}else{
|
||||
/* The slot remains on the free-list. Reduce its size to account
|
||||
** for the portion used by the new allocation. */
|
||||
@@ -1441,7 +1567,7 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
|
||||
|
||||
/* At this point:
|
||||
** iFreeBlk: First freeblock after iStart, or zero if none
|
||||
** iPtr: The address of a pointer iFreeBlk
|
||||
** iPtr: The address of a pointer to iFreeBlk
|
||||
**
|
||||
** Check to see if iFreeBlk should be coalesced onto the end of iStart.
|
||||
*/
|
||||
@@ -1449,6 +1575,7 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
|
||||
nFrag = iFreeBlk - iEnd;
|
||||
if( iEnd>iFreeBlk ) return SQLITE_CORRUPT_BKPT;
|
||||
iEnd = iFreeBlk + get2byte(&data[iFreeBlk+2]);
|
||||
if( iEnd > pPage->pBt->usableSize ) return SQLITE_CORRUPT_BKPT;
|
||||
iSize = iEnd - iStart;
|
||||
iFreeBlk = get2byte(&data[iFreeBlk]);
|
||||
}
|
||||
@@ -1506,6 +1633,7 @@ static int decodeFlags(MemPage *pPage, int flagByte){
|
||||
pPage->leaf = (u8)(flagByte>>3); assert( PTF_LEAF == 1<<3 );
|
||||
flagByte &= ~PTF_LEAF;
|
||||
pPage->childPtrSize = 4-4*pPage->leaf;
|
||||
pPage->xCellSize = cellSizePtr;
|
||||
pBt = pPage->pBt;
|
||||
if( flagByte==(PTF_LEAFDATA | PTF_INTKEY) ){
|
||||
/* EVIDENCE-OF: R-03640-13415 A value of 5 means the page is an interior
|
||||
@@ -1515,8 +1643,16 @@ static int decodeFlags(MemPage *pPage, int flagByte){
|
||||
** table b-tree page. */
|
||||
assert( (PTF_LEAFDATA|PTF_INTKEY|PTF_LEAF)==13 );
|
||||
pPage->intKey = 1;
|
||||
pPage->intKeyLeaf = pPage->leaf;
|
||||
pPage->noPayload = !pPage->leaf;
|
||||
if( pPage->leaf ){
|
||||
pPage->intKeyLeaf = 1;
|
||||
pPage->noPayload = 0;
|
||||
pPage->xParseCell = btreeParseCellPtr;
|
||||
}else{
|
||||
pPage->intKeyLeaf = 0;
|
||||
pPage->noPayload = 1;
|
||||
pPage->xCellSize = cellSizePtrNoPayload;
|
||||
pPage->xParseCell = btreeParseCellPtrNoPayload;
|
||||
}
|
||||
pPage->maxLocal = pBt->maxLeaf;
|
||||
pPage->minLocal = pBt->minLeaf;
|
||||
}else if( flagByte==PTF_ZERODATA ){
|
||||
@@ -1529,6 +1665,7 @@ static int decodeFlags(MemPage *pPage, int flagByte){
|
||||
pPage->intKey = 0;
|
||||
pPage->intKeyLeaf = 0;
|
||||
pPage->noPayload = 0;
|
||||
pPage->xParseCell = btreeParseCellPtrIndex;
|
||||
pPage->maxLocal = pBt->maxLocal;
|
||||
pPage->minLocal = pBt->minLocal;
|
||||
}else{
|
||||
@@ -1623,7 +1760,7 @@ static int btreeInitPage(MemPage *pPage){
|
||||
if( pc<iCellFirst || pc>iCellLast ){
|
||||
return SQLITE_CORRUPT_BKPT;
|
||||
}
|
||||
sz = cellSizePtr(pPage, &data[pc]);
|
||||
sz = pPage->xCellSize(pPage, &data[pc]);
|
||||
testcase( pc+sz==usableSize );
|
||||
if( pc+sz>usableSize ){
|
||||
return SQLITE_CORRUPT_BKPT;
|
||||
@@ -3119,7 +3256,7 @@ static int modifyPagePointer(MemPage *pPage, Pgno iFrom, Pgno iTo, u8 eType){
|
||||
u8 *pCell = findCell(pPage, i);
|
||||
if( eType==PTRMAP_OVERFLOW1 ){
|
||||
CellInfo info;
|
||||
btreeParseCellPtr(pPage, pCell, &info);
|
||||
pPage->xParseCell(pPage, pCell, &info);
|
||||
if( info.iOverflow
|
||||
&& pCell+info.iOverflow+3<=pPage->aData+pPage->maskPage
|
||||
&& iFrom==get4byte(&pCell[info.iOverflow])
|
||||
@@ -3984,13 +4121,6 @@ int sqlite3BtreeCloseCursor(BtCursor *pCur){
|
||||
**
|
||||
** BtCursor.info is a cache of the information in the current cell.
|
||||
** Using this cache reduces the number of calls to btreeParseCell().
|
||||
**
|
||||
** 2007-06-25: There is a bug in some versions of MSVC that cause the
|
||||
** compiler to crash when getCellInfo() is implemented as a macro.
|
||||
** But there is a measureable speed advantage to using the macro on gcc
|
||||
** (when less compiler optimizations like -Os or -O0 are used and the
|
||||
** compiler is not doing aggressive inlining.) So we use a real function
|
||||
** for MSVC and a macro for everything else. Ticket #2457.
|
||||
*/
|
||||
#ifndef NDEBUG
|
||||
static void assertCellInfo(BtCursor *pCur){
|
||||
@@ -4003,28 +4133,15 @@ int sqlite3BtreeCloseCursor(BtCursor *pCur){
|
||||
#else
|
||||
#define assertCellInfo(x)
|
||||
#endif
|
||||
#ifdef _MSC_VER
|
||||
/* Use a real function in MSVC to work around bugs in that compiler. */
|
||||
static void getCellInfo(BtCursor *pCur){
|
||||
if( pCur->info.nSize==0 ){
|
||||
int iPage = pCur->iPage;
|
||||
btreeParseCell(pCur->apPage[iPage],pCur->aiIdx[iPage],&pCur->info);
|
||||
pCur->curFlags |= BTCF_ValidNKey;
|
||||
}else{
|
||||
assertCellInfo(pCur);
|
||||
}
|
||||
static SQLITE_NOINLINE void getCellInfo(BtCursor *pCur){
|
||||
if( pCur->info.nSize==0 ){
|
||||
int iPage = pCur->iPage;
|
||||
pCur->curFlags |= BTCF_ValidNKey;
|
||||
btreeParseCell(pCur->apPage[iPage],pCur->aiIdx[iPage],&pCur->info);
|
||||
}else{
|
||||
assertCellInfo(pCur);
|
||||
}
|
||||
#else /* if not _MSC_VER */
|
||||
/* Use a macro in all other compilers so that the function is inlined */
|
||||
#define getCellInfo(pCur) \
|
||||
if( pCur->info.nSize==0 ){ \
|
||||
int iPage = pCur->iPage; \
|
||||
btreeParseCell(pCur->apPage[iPage],pCur->aiIdx[iPage],&pCur->info); \
|
||||
pCur->curFlags |= BTCF_ValidNKey; \
|
||||
}else{ \
|
||||
assertCellInfo(pCur); \
|
||||
}
|
||||
#endif /* _MSC_VER */
|
||||
}
|
||||
|
||||
#ifndef NDEBUG /* The next routine used only within assert() statements */
|
||||
/*
|
||||
@@ -4984,7 +5101,7 @@ int sqlite3BtreeMovetoUnpacked(
|
||||
** case this happens. */
|
||||
void *pCellKey;
|
||||
u8 * const pCellBody = pCell - pPage->childPtrSize;
|
||||
btreeParseCellPtr(pPage, pCellBody, &pCur->info);
|
||||
pPage->xParseCell(pPage, pCellBody, &pCur->info);
|
||||
nCell = (int)pCur->info.nKey;
|
||||
testcase( nCell<0 ); /* True if key size is 2^32 or more */
|
||||
testcase( nCell==0 ); /* Invalid key size: 0x80 0x80 0x00 */
|
||||
@@ -5773,7 +5890,7 @@ static int clearCell(
|
||||
u32 ovflPageSize;
|
||||
|
||||
assert( sqlite3_mutex_held(pPage->pBt->mutex) );
|
||||
btreeParseCellPtr(pPage, pCell, &info);
|
||||
pPage->xParseCell(pPage, pCell, &info);
|
||||
*pnSize = info.nSize;
|
||||
if( info.iOverflow==0 ){
|
||||
return SQLITE_OK; /* No overflow pages. Return without doing anything */
|
||||
@@ -5927,7 +6044,7 @@ static int fillInCell(
|
||||
#if SQLITE_DEBUG
|
||||
{
|
||||
CellInfo info;
|
||||
btreeParseCellPtr(pPage, pCell, &info);
|
||||
pPage->xParseCell(pPage, pCell, &info);
|
||||
assert( nHeader=(int)(info.pPayload - pCell) );
|
||||
assert( info.nKey==nKey );
|
||||
assert( *pnSize == info.nSize );
|
||||
@@ -6115,7 +6232,7 @@ static void insertCell(
|
||||
** wanted to be less than 4 but got rounded up to 4 on the leaf, then size
|
||||
** might be less than 8 (leaf-size + pointer) on the interior node. Hence
|
||||
** the term after the || in the following assert(). */
|
||||
assert( sz==cellSizePtr(pPage, pCell) || (sz==8 && iChild>0) );
|
||||
assert( sz==pPage->xCellSize(pPage, pCell) || (sz==8 && iChild>0) );
|
||||
if( pPage->nOverflow || sz+2>pPage->nFree ){
|
||||
if( pTemp ){
|
||||
memcpy(pTemp, pCell, sz);
|
||||
@@ -6206,8 +6323,8 @@ static void rebuildPage(
|
||||
memcpy(pData, pCell, szCell[i]);
|
||||
put2byte(pCellptr, (pData - aData));
|
||||
pCellptr += 2;
|
||||
assert( szCell[i]==cellSizePtr(pPg, pCell) || CORRUPT_DB );
|
||||
testcase( szCell[i]==cellSizePtr(pPg,pCell) );
|
||||
assert( szCell[i]==pPg->xCellSize(pPg, pCell) || CORRUPT_DB );
|
||||
testcase( szCell[i]==pPg->xCellSize(pPg,pCell) );
|
||||
}
|
||||
|
||||
/* The pPg->nFree field is now set incorrectly. The caller will fix it. */
|
||||
@@ -6497,7 +6614,7 @@ static int balance_quick(MemPage *pParent, MemPage *pPage, u8 *pSpace){
|
||||
|
||||
u8 *pOut = &pSpace[4];
|
||||
u8 *pCell = pPage->apOvfl[0];
|
||||
u16 szCell = cellSizePtr(pPage, pCell);
|
||||
u16 szCell = pPage->xCellSize(pPage, pCell);
|
||||
u8 *pStop;
|
||||
|
||||
assert( sqlite3PagerIswriteable(pNew->pDbPage) );
|
||||
@@ -6576,7 +6693,7 @@ static int ptrmapCheckPages(MemPage **apPage, int nPage){
|
||||
u8 *z;
|
||||
|
||||
z = findCell(pPage, j);
|
||||
btreeParseCellPtr(pPage, z, &info);
|
||||
pPage->xParseCell(pPage, z, &info);
|
||||
if( info.iOverflow ){
|
||||
Pgno ovfl = get4byte(&z[info.iOverflow]);
|
||||
ptrmapGet(pBt, ovfl, &e, &n);
|
||||
@@ -6803,12 +6920,12 @@ static int balance_nonroot(
|
||||
if( i+nxDiv==pParent->aiOvfl[0] && pParent->nOverflow ){
|
||||
apDiv[i] = pParent->apOvfl[0];
|
||||
pgno = get4byte(apDiv[i]);
|
||||
szNew[i] = cellSizePtr(pParent, apDiv[i]);
|
||||
szNew[i] = pParent->xCellSize(pParent, apDiv[i]);
|
||||
pParent->nOverflow = 0;
|
||||
}else{
|
||||
apDiv[i] = findCell(pParent, i+nxDiv-pParent->nOverflow);
|
||||
pgno = get4byte(apDiv[i]);
|
||||
szNew[i] = cellSizePtr(pParent, apDiv[i]);
|
||||
szNew[i] = pParent->xCellSize(pParent, apDiv[i]);
|
||||
|
||||
/* Drop the cell from the parent page. apDiv[i] still points to
|
||||
** the cell within the parent, even though it has been dropped.
|
||||
@@ -6898,7 +7015,7 @@ static int balance_nonroot(
|
||||
for(j=0; j<limit; j++){
|
||||
assert( nCell<nMaxCells );
|
||||
apCell[nCell] = findOverflowCell(pOld, j);
|
||||
szCell[nCell] = cellSizePtr(pOld, apCell[nCell]);
|
||||
szCell[nCell] = pOld->xCellSize(pOld, apCell[nCell]);
|
||||
nCell++;
|
||||
}
|
||||
}else{
|
||||
@@ -6908,7 +7025,7 @@ static int balance_nonroot(
|
||||
for(j=0; j<limit; j++){
|
||||
assert( nCell<nMaxCells );
|
||||
apCell[nCell] = findCellv2(aData, maskPage, cellOffset, j);
|
||||
szCell[nCell] = cellSizePtr(pOld, apCell[nCell]);
|
||||
szCell[nCell] = pOld->xCellSize(pOld, apCell[nCell]);
|
||||
nCell++;
|
||||
}
|
||||
}
|
||||
@@ -7207,7 +7324,7 @@ static int balance_nonroot(
|
||||
*/
|
||||
CellInfo info;
|
||||
j--;
|
||||
btreeParseCellPtr(pNew, apCell[j], &info);
|
||||
pNew->xParseCell(pNew, apCell[j], &info);
|
||||
pCell = pTemp;
|
||||
sz = 4 + putVarint(&pCell[4], info.nKey);
|
||||
pTemp = 0;
|
||||
@@ -7226,7 +7343,7 @@ static int balance_nonroot(
|
||||
*/
|
||||
if( szCell[j]==4 ){
|
||||
assert(leafCorrection==4);
|
||||
sz = cellSizePtr(pParent, pCell);
|
||||
sz = pParent->xCellSize(pParent, pCell);
|
||||
}
|
||||
}
|
||||
iOvflSpace += sz;
|
||||
@@ -7671,7 +7788,7 @@ int sqlite3BtreeInsert(
|
||||
assert( newCell!=0 );
|
||||
rc = fillInCell(pPage, newCell, pKey, nKey, pData, nData, nZero, &szNew);
|
||||
if( rc ) goto end_insert;
|
||||
assert( szNew==cellSizePtr(pPage, newCell) );
|
||||
assert( szNew==pPage->xCellSize(pPage, newCell) );
|
||||
assert( szNew <= MX_CELL_SIZE(pBt) );
|
||||
idx = pCur->aiIdx[pCur->iPage];
|
||||
if( loc==0 ){
|
||||
@@ -7813,7 +7930,7 @@ int sqlite3BtreeDelete(BtCursor *pCur){
|
||||
|
||||
pCell = findCell(pLeaf, pLeaf->nCell-1);
|
||||
if( pCell<&pLeaf->aData[4] ) return SQLITE_CORRUPT_BKPT;
|
||||
nCell = cellSizePtr(pLeaf, pCell);
|
||||
nCell = pLeaf->xCellSize(pLeaf, pCell);
|
||||
assert( MX_CELL_SIZE(pBt) >= nCell );
|
||||
pTmp = pBt->pTmpSpace;
|
||||
assert( pTmp!=0 );
|
||||
@@ -8707,7 +8824,7 @@ static int checkTreePage(
|
||||
pCheck->v1 = iPage;
|
||||
pCheck->v2 = i;
|
||||
pCell = findCell(pPage,i);
|
||||
btreeParseCellPtr(pPage, pCell, &info);
|
||||
pPage->xParseCell(pPage, pCell, &info);
|
||||
sz = info.nPayload;
|
||||
/* For intKey pages, check that the keys are in order.
|
||||
*/
|
||||
@@ -8825,7 +8942,7 @@ static int checkTreePage(
|
||||
int pc = get2byte(&data[cellStart+i*2]);
|
||||
u32 size = 65536;
|
||||
if( pc<=usableSize-4 ){
|
||||
size = cellSizePtr(pPage, &data[pc]);
|
||||
size = pPage->xCellSize(pPage, &data[pc]);
|
||||
}
|
||||
if( (int)(pc+size-1)>=usableSize ){
|
||||
pCheck->zPfx = 0;
|
||||
|
@@ -231,6 +231,7 @@
|
||||
/* Forward declarations */
|
||||
typedef struct MemPage MemPage;
|
||||
typedef struct BtLock BtLock;
|
||||
typedef struct CellInfo CellInfo;
|
||||
|
||||
/*
|
||||
** This is a magic string that appears at the beginning of every
|
||||
@@ -295,6 +296,8 @@ struct MemPage {
|
||||
u8 *aDataEnd; /* One byte past the end of usable data */
|
||||
u8 *aCellIdx; /* The cell index area */
|
||||
DbPage *pDbPage; /* Pager page handle */
|
||||
u16 (*xCellSize)(MemPage*,u8*); /* cellSizePtr method */
|
||||
void (*xParseCell)(MemPage*,u8*,CellInfo*); /* btreeParseCell method */
|
||||
Pgno pgno; /* Page number for this page */
|
||||
};
|
||||
|
||||
@@ -460,7 +463,6 @@ struct BtShared {
|
||||
** about a cell. The parseCellPtr() function fills in this structure
|
||||
** based on information extract from the raw disk page.
|
||||
*/
|
||||
typedef struct CellInfo CellInfo;
|
||||
struct CellInfo {
|
||||
i64 nKey; /* The key for INTKEY tables, or nPayload otherwise */
|
||||
u8 *pPayload; /* Pointer to the start of payload */
|
||||
|
@@ -976,7 +976,7 @@ void sqlite3StartTable(
|
||||
int j1;
|
||||
int fileFormat;
|
||||
int reg1, reg2, reg3;
|
||||
sqlite3BeginWriteOperation(pParse, 0, iDb);
|
||||
sqlite3BeginWriteOperation(pParse, 1, iDb);
|
||||
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
if( isVirtual ){
|
||||
@@ -1924,6 +1924,7 @@ void sqlite3EndTable(
|
||||
regRec = ++pParse->nMem;
|
||||
regRowid = ++pParse->nMem;
|
||||
assert(pParse->nTab==1);
|
||||
sqlite3MayAbort(pParse);
|
||||
sqlite3VdbeAddOp3(v, OP_OpenWrite, 1, pParse->regRoot, iDb);
|
||||
sqlite3VdbeChangeP5(v, OPFLAG_P2ISREG);
|
||||
pParse->nTab = 2;
|
||||
@@ -3701,7 +3702,7 @@ void sqlite3SrcListDelete(sqlite3 *db, SrcList *pList){
|
||||
sqlite3DbFree(db, pItem->zDatabase);
|
||||
sqlite3DbFree(db, pItem->zName);
|
||||
sqlite3DbFree(db, pItem->zAlias);
|
||||
sqlite3DbFree(db, pItem->zIndex);
|
||||
sqlite3DbFree(db, pItem->zIndexedBy);
|
||||
sqlite3DeleteTable(db, pItem->pTab);
|
||||
sqlite3SelectDelete(db, pItem->pSelect);
|
||||
sqlite3ExprDelete(db, pItem->pOn);
|
||||
@@ -3774,13 +3775,13 @@ void sqlite3SrcListIndexedBy(Parse *pParse, SrcList *p, Token *pIndexedBy){
|
||||
assert( pIndexedBy!=0 );
|
||||
if( p && ALWAYS(p->nSrc>0) ){
|
||||
struct SrcList_item *pItem = &p->a[p->nSrc-1];
|
||||
assert( pItem->notIndexed==0 && pItem->zIndex==0 );
|
||||
assert( pItem->notIndexed==0 && pItem->zIndexedBy==0 );
|
||||
if( pIndexedBy->n==1 && !pIndexedBy->z ){
|
||||
/* A "NOT INDEXED" clause was supplied. See parse.y
|
||||
** construct "indexed_opt" for details. */
|
||||
pItem->notIndexed = 1;
|
||||
}else{
|
||||
pItem->zIndex = sqlite3NameFromToken(pParse->db, pIndexedBy);
|
||||
pItem->zIndexedBy = sqlite3NameFromToken(pParse->db, pIndexedBy);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -798,8 +798,8 @@ int sqlite3GenerateIndexKey(
|
||||
*piPartIdxLabel = sqlite3VdbeMakeLabel(v);
|
||||
pParse->iPartIdxTab = iDataCur;
|
||||
sqlite3ExprCachePush(pParse);
|
||||
sqlite3ExprIfFalse(pParse, pIdx->pPartIdxWhere, *piPartIdxLabel,
|
||||
SQLITE_JUMPIFNULL);
|
||||
sqlite3ExprIfFalseDup(pParse, pIdx->pPartIdxWhere, *piPartIdxLabel,
|
||||
SQLITE_JUMPIFNULL);
|
||||
}else{
|
||||
*piPartIdxLabel = 0;
|
||||
}
|
||||
|
300
src/expr.c
300
src/expr.c
@@ -1041,7 +1041,7 @@ SrcList *sqlite3SrcListDup(sqlite3 *db, SrcList *p, int flags){
|
||||
pNewItem->isCorrelated = pOldItem->isCorrelated;
|
||||
pNewItem->viaCoroutine = pOldItem->viaCoroutine;
|
||||
pNewItem->isRecursive = pOldItem->isRecursive;
|
||||
pNewItem->zIndex = sqlite3DbStrDup(db, pOldItem->zIndex);
|
||||
pNewItem->zIndexedBy = sqlite3DbStrDup(db, pOldItem->zIndexedBy);
|
||||
pNewItem->notIndexed = pOldItem->notIndexed;
|
||||
pNewItem->pIndex = pOldItem->pIndex;
|
||||
pTab = pNewItem->pTab = pOldItem->pTab;
|
||||
@@ -2208,17 +2208,6 @@ static void sqlite3ExprCodeIN(
|
||||
}
|
||||
#endif /* SQLITE_OMIT_SUBQUERY */
|
||||
|
||||
/*
|
||||
** Duplicate an 8-byte value
|
||||
*/
|
||||
static char *dup8bytes(Vdbe *v, const char *in){
|
||||
char *out = sqlite3DbMallocRaw(sqlite3VdbeDb(v), 8);
|
||||
if( out ){
|
||||
memcpy(out, in, 8);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_FLOATING_POINT
|
||||
/*
|
||||
** Generate an instruction that will put the floating point
|
||||
@@ -2231,12 +2220,10 @@ static char *dup8bytes(Vdbe *v, const char *in){
|
||||
static void codeReal(Vdbe *v, const char *z, int negateFlag, int iMem){
|
||||
if( ALWAYS(z!=0) ){
|
||||
double value;
|
||||
char *zV;
|
||||
sqlite3AtoF(z, &value, sqlite3Strlen30(z), SQLITE_UTF8);
|
||||
assert( !sqlite3IsNaN(value) ); /* The new AtoF never returns NaN */
|
||||
if( negateFlag ) value = -value;
|
||||
zV = dup8bytes(v, (char*)&value);
|
||||
sqlite3VdbeAddOp4(v, OP_Real, 0, iMem, 0, zV, P4_REAL);
|
||||
sqlite3VdbeAddOp4Dup8(v, OP_Real, 0, iMem, 0, (u8*)&value, P4_REAL);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -2262,10 +2249,8 @@ static void codeInteger(Parse *pParse, Expr *pExpr, int negFlag, int iMem){
|
||||
assert( z!=0 );
|
||||
c = sqlite3DecOrHexToI64(z, &value);
|
||||
if( c==0 || (c==2 && negFlag) ){
|
||||
char *zV;
|
||||
if( negFlag ){ value = c==2 ? SMALLEST_INT64 : -value; }
|
||||
zV = dup8bytes(v, (char*)&value);
|
||||
sqlite3VdbeAddOp4(v, OP_Int64, 0, iMem, 0, zV, P4_INT64);
|
||||
sqlite3VdbeAddOp4Dup8(v, OP_Int64, 0, iMem, 0, (u8*)&value, P4_INT64);
|
||||
}else{
|
||||
#ifdef SQLITE_OMIT_FLOATING_POINT
|
||||
sqlite3ErrorMsg(pParse, "oversized integer: %s%s", negFlag ? "-" : "", z);
|
||||
@@ -2870,7 +2855,7 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
|
||||
*/
|
||||
if( pDef->funcFlags & SQLITE_FUNC_UNLIKELY ){
|
||||
assert( nFarg>=1 );
|
||||
sqlite3ExprCode(pParse, pFarg->a[0].pExpr, target);
|
||||
inReg = sqlite3ExprCodeTarget(pParse, pFarg->a[0].pExpr, target);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -3311,268 +3296,6 @@ void sqlite3ExprCodeAndCache(Parse *pParse, Expr *pExpr, int target){
|
||||
exprToRegister(pExpr, iMem);
|
||||
}
|
||||
|
||||
#ifdef SQLITE_DEBUG
|
||||
/*
|
||||
** Generate a human-readable explanation of an expression tree.
|
||||
*/
|
||||
void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){
|
||||
const char *zBinOp = 0; /* Binary operator */
|
||||
const char *zUniOp = 0; /* Unary operator */
|
||||
pView = sqlite3TreeViewPush(pView, moreToFollow);
|
||||
if( pExpr==0 ){
|
||||
sqlite3TreeViewLine(pView, "nil");
|
||||
sqlite3TreeViewPop(pView);
|
||||
return;
|
||||
}
|
||||
switch( pExpr->op ){
|
||||
case TK_AGG_COLUMN: {
|
||||
sqlite3TreeViewLine(pView, "AGG{%d:%d}",
|
||||
pExpr->iTable, pExpr->iColumn);
|
||||
break;
|
||||
}
|
||||
case TK_COLUMN: {
|
||||
if( pExpr->iTable<0 ){
|
||||
/* This only happens when coding check constraints */
|
||||
sqlite3TreeViewLine(pView, "COLUMN(%d)", pExpr->iColumn);
|
||||
}else{
|
||||
sqlite3TreeViewLine(pView, "{%d:%d}",
|
||||
pExpr->iTable, pExpr->iColumn);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TK_INTEGER: {
|
||||
if( pExpr->flags & EP_IntValue ){
|
||||
sqlite3TreeViewLine(pView, "%d", pExpr->u.iValue);
|
||||
}else{
|
||||
sqlite3TreeViewLine(pView, "%s", pExpr->u.zToken);
|
||||
}
|
||||
break;
|
||||
}
|
||||
#ifndef SQLITE_OMIT_FLOATING_POINT
|
||||
case TK_FLOAT: {
|
||||
sqlite3TreeViewLine(pView,"%s", pExpr->u.zToken);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
case TK_STRING: {
|
||||
sqlite3TreeViewLine(pView,"%Q", pExpr->u.zToken);
|
||||
break;
|
||||
}
|
||||
case TK_NULL: {
|
||||
sqlite3TreeViewLine(pView,"NULL");
|
||||
break;
|
||||
}
|
||||
#ifndef SQLITE_OMIT_BLOB_LITERAL
|
||||
case TK_BLOB: {
|
||||
sqlite3TreeViewLine(pView,"%s", pExpr->u.zToken);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
case TK_VARIABLE: {
|
||||
sqlite3TreeViewLine(pView,"VARIABLE(%s,%d)",
|
||||
pExpr->u.zToken, pExpr->iColumn);
|
||||
break;
|
||||
}
|
||||
case TK_REGISTER: {
|
||||
sqlite3TreeViewLine(pView,"REGISTER(%d)", pExpr->iTable);
|
||||
break;
|
||||
}
|
||||
case TK_AS: {
|
||||
sqlite3TreeViewLine(pView,"AS %Q", pExpr->u.zToken);
|
||||
sqlite3TreeViewExpr(pView, pExpr->pLeft, 0);
|
||||
break;
|
||||
}
|
||||
case TK_ID: {
|
||||
sqlite3TreeViewLine(pView,"ID \"%w\"", pExpr->u.zToken);
|
||||
break;
|
||||
}
|
||||
#ifndef SQLITE_OMIT_CAST
|
||||
case TK_CAST: {
|
||||
/* Expressions of the form: CAST(pLeft AS token) */
|
||||
sqlite3TreeViewLine(pView,"CAST %Q", pExpr->u.zToken);
|
||||
sqlite3TreeViewExpr(pView, pExpr->pLeft, 0);
|
||||
break;
|
||||
}
|
||||
#endif /* SQLITE_OMIT_CAST */
|
||||
case TK_LT: zBinOp = "LT"; break;
|
||||
case TK_LE: zBinOp = "LE"; break;
|
||||
case TK_GT: zBinOp = "GT"; break;
|
||||
case TK_GE: zBinOp = "GE"; break;
|
||||
case TK_NE: zBinOp = "NE"; break;
|
||||
case TK_EQ: zBinOp = "EQ"; break;
|
||||
case TK_IS: zBinOp = "IS"; break;
|
||||
case TK_ISNOT: zBinOp = "ISNOT"; break;
|
||||
case TK_AND: zBinOp = "AND"; break;
|
||||
case TK_OR: zBinOp = "OR"; break;
|
||||
case TK_PLUS: zBinOp = "ADD"; break;
|
||||
case TK_STAR: zBinOp = "MUL"; break;
|
||||
case TK_MINUS: zBinOp = "SUB"; break;
|
||||
case TK_REM: zBinOp = "REM"; break;
|
||||
case TK_BITAND: zBinOp = "BITAND"; break;
|
||||
case TK_BITOR: zBinOp = "BITOR"; break;
|
||||
case TK_SLASH: zBinOp = "DIV"; break;
|
||||
case TK_LSHIFT: zBinOp = "LSHIFT"; break;
|
||||
case TK_RSHIFT: zBinOp = "RSHIFT"; break;
|
||||
case TK_CONCAT: zBinOp = "CONCAT"; break;
|
||||
case TK_DOT: zBinOp = "DOT"; break;
|
||||
|
||||
case TK_UMINUS: zUniOp = "UMINUS"; break;
|
||||
case TK_UPLUS: zUniOp = "UPLUS"; break;
|
||||
case TK_BITNOT: zUniOp = "BITNOT"; break;
|
||||
case TK_NOT: zUniOp = "NOT"; break;
|
||||
case TK_ISNULL: zUniOp = "ISNULL"; break;
|
||||
case TK_NOTNULL: zUniOp = "NOTNULL"; break;
|
||||
|
||||
case TK_COLLATE: {
|
||||
sqlite3TreeViewLine(pView, "COLLATE %Q", pExpr->u.zToken);
|
||||
sqlite3TreeViewExpr(pView, pExpr->pLeft, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
case TK_AGG_FUNCTION:
|
||||
case TK_FUNCTION: {
|
||||
ExprList *pFarg; /* List of function arguments */
|
||||
if( ExprHasProperty(pExpr, EP_TokenOnly) ){
|
||||
pFarg = 0;
|
||||
}else{
|
||||
pFarg = pExpr->x.pList;
|
||||
}
|
||||
if( pExpr->op==TK_AGG_FUNCTION ){
|
||||
sqlite3TreeViewLine(pView, "AGG_FUNCTION%d %Q",
|
||||
pExpr->op2, pExpr->u.zToken);
|
||||
}else{
|
||||
sqlite3TreeViewLine(pView, "FUNCTION %Q", pExpr->u.zToken);
|
||||
}
|
||||
if( pFarg ){
|
||||
sqlite3TreeViewExprList(pView, pFarg, 0, 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
#ifndef SQLITE_OMIT_SUBQUERY
|
||||
case TK_EXISTS: {
|
||||
sqlite3TreeViewLine(pView, "EXISTS-expr");
|
||||
sqlite3TreeViewSelect(pView, pExpr->x.pSelect, 0);
|
||||
break;
|
||||
}
|
||||
case TK_SELECT: {
|
||||
sqlite3TreeViewLine(pView, "SELECT-expr");
|
||||
sqlite3TreeViewSelect(pView, pExpr->x.pSelect, 0);
|
||||
break;
|
||||
}
|
||||
case TK_IN: {
|
||||
sqlite3TreeViewLine(pView, "IN");
|
||||
sqlite3TreeViewExpr(pView, pExpr->pLeft, 1);
|
||||
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
|
||||
sqlite3TreeViewSelect(pView, pExpr->x.pSelect, 0);
|
||||
}else{
|
||||
sqlite3TreeViewExprList(pView, pExpr->x.pList, 0, 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif /* SQLITE_OMIT_SUBQUERY */
|
||||
|
||||
/*
|
||||
** x BETWEEN y AND z
|
||||
**
|
||||
** This is equivalent to
|
||||
**
|
||||
** x>=y AND x<=z
|
||||
**
|
||||
** X is stored in pExpr->pLeft.
|
||||
** Y is stored in pExpr->pList->a[0].pExpr.
|
||||
** Z is stored in pExpr->pList->a[1].pExpr.
|
||||
*/
|
||||
case TK_BETWEEN: {
|
||||
Expr *pX = pExpr->pLeft;
|
||||
Expr *pY = pExpr->x.pList->a[0].pExpr;
|
||||
Expr *pZ = pExpr->x.pList->a[1].pExpr;
|
||||
sqlite3TreeViewLine(pView, "BETWEEN");
|
||||
sqlite3TreeViewExpr(pView, pX, 1);
|
||||
sqlite3TreeViewExpr(pView, pY, 1);
|
||||
sqlite3TreeViewExpr(pView, pZ, 0);
|
||||
break;
|
||||
}
|
||||
case TK_TRIGGER: {
|
||||
/* If the opcode is TK_TRIGGER, then the expression is a reference
|
||||
** to a column in the new.* or old.* pseudo-tables available to
|
||||
** trigger programs. In this case Expr.iTable is set to 1 for the
|
||||
** new.* pseudo-table, or 0 for the old.* pseudo-table. Expr.iColumn
|
||||
** is set to the column of the pseudo-table to read, or to -1 to
|
||||
** read the rowid field.
|
||||
*/
|
||||
sqlite3TreeViewLine(pView, "%s(%d)",
|
||||
pExpr->iTable ? "NEW" : "OLD", pExpr->iColumn);
|
||||
break;
|
||||
}
|
||||
case TK_CASE: {
|
||||
sqlite3TreeViewLine(pView, "CASE");
|
||||
sqlite3TreeViewExpr(pView, pExpr->pLeft, 1);
|
||||
sqlite3TreeViewExprList(pView, pExpr->x.pList, 0, 0);
|
||||
break;
|
||||
}
|
||||
#ifndef SQLITE_OMIT_TRIGGER
|
||||
case TK_RAISE: {
|
||||
const char *zType = "unk";
|
||||
switch( pExpr->affinity ){
|
||||
case OE_Rollback: zType = "rollback"; break;
|
||||
case OE_Abort: zType = "abort"; break;
|
||||
case OE_Fail: zType = "fail"; break;
|
||||
case OE_Ignore: zType = "ignore"; break;
|
||||
}
|
||||
sqlite3TreeViewLine(pView, "RAISE %s(%Q)", zType, pExpr->u.zToken);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
default: {
|
||||
sqlite3TreeViewLine(pView, "op=%d", pExpr->op);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( zBinOp ){
|
||||
sqlite3TreeViewLine(pView, "%s", zBinOp);
|
||||
sqlite3TreeViewExpr(pView, pExpr->pLeft, 1);
|
||||
sqlite3TreeViewExpr(pView, pExpr->pRight, 0);
|
||||
}else if( zUniOp ){
|
||||
sqlite3TreeViewLine(pView, "%s", zUniOp);
|
||||
sqlite3TreeViewExpr(pView, pExpr->pLeft, 0);
|
||||
}
|
||||
sqlite3TreeViewPop(pView);
|
||||
}
|
||||
#endif /* SQLITE_DEBUG */
|
||||
|
||||
#ifdef SQLITE_DEBUG
|
||||
/*
|
||||
** Generate a human-readable explanation of an expression list.
|
||||
*/
|
||||
void sqlite3TreeViewExprList(
|
||||
TreeView *pView,
|
||||
const ExprList *pList,
|
||||
u8 moreToFollow,
|
||||
const char *zLabel
|
||||
){
|
||||
int i;
|
||||
pView = sqlite3TreeViewPush(pView, moreToFollow);
|
||||
if( zLabel==0 || zLabel[0]==0 ) zLabel = "LIST";
|
||||
if( pList==0 ){
|
||||
sqlite3TreeViewLine(pView, "%s (empty)", zLabel);
|
||||
}else{
|
||||
sqlite3TreeViewLine(pView, "%s", zLabel);
|
||||
for(i=0; i<pList->nExpr; i++){
|
||||
sqlite3TreeViewExpr(pView, pList->a[i].pExpr, i<pList->nExpr-1);
|
||||
#if 0
|
||||
if( pList->a[i].zName ){
|
||||
sqlite3ExplainPrintf(pOut, " AS %s", pList->a[i].zName);
|
||||
}
|
||||
if( pList->a[i].bSpanIsTab ){
|
||||
sqlite3ExplainPrintf(pOut, " (%s)", pList->a[i].zSpan);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
sqlite3TreeViewPop(pView);
|
||||
}
|
||||
#endif /* SQLITE_DEBUG */
|
||||
|
||||
/*
|
||||
** Generate code that pushes the value of every element of the given
|
||||
** expression list into a sequence of registers beginning at target.
|
||||
@@ -3964,6 +3687,21 @@ void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
|
||||
sqlite3ReleaseTempReg(pParse, regFree2);
|
||||
}
|
||||
|
||||
/*
|
||||
** Like sqlite3ExprIfFalse() except that a copy is made of pExpr before
|
||||
** code generation, and that copy is deleted after code generation. This
|
||||
** ensures that the original pExpr is unchanged.
|
||||
*/
|
||||
void sqlite3ExprIfFalseDup(Parse *pParse, Expr *pExpr, int dest,int jumpIfNull){
|
||||
sqlite3 *db = pParse->db;
|
||||
Expr *pCopy = sqlite3ExprDup(db, pExpr, 0);
|
||||
if( db->mallocFailed==0 ){
|
||||
sqlite3ExprIfFalse(pParse, pCopy, dest, jumpIfNull);
|
||||
}
|
||||
sqlite3ExprDelete(db, pCopy);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Do a deep comparison of two expression trees. Return 0 if the two
|
||||
** expressions are completely identical. Return 1 if they differ only
|
||||
|
23
src/func.c
23
src/func.c
@@ -575,17 +575,15 @@ struct compareInfo {
|
||||
|
||||
/*
|
||||
** For LIKE and GLOB matching on EBCDIC machines, assume that every
|
||||
** character is exactly one byte in size. Also, all characters are
|
||||
** able to participate in upper-case-to-lower-case mappings in EBCDIC
|
||||
** whereas only characters less than 0x80 do in ASCII.
|
||||
** character is exactly one byte in size. Also, provde the Utf8Read()
|
||||
** macro for fast reading of the next character in the common case where
|
||||
** the next character is ASCII.
|
||||
*/
|
||||
#if defined(SQLITE_EBCDIC)
|
||||
# define sqlite3Utf8Read(A) (*((*A)++))
|
||||
# define GlobUpperToLower(A) A = sqlite3UpperToLower[A]
|
||||
# define GlobUpperToLowerAscii(A) A = sqlite3UpperToLower[A]
|
||||
# define Utf8Read(A) (*(A++))
|
||||
#else
|
||||
# define GlobUpperToLower(A) if( A<=0x7f ){ A = sqlite3UpperToLower[A]; }
|
||||
# define GlobUpperToLowerAscii(A) A = sqlite3UpperToLower[A]
|
||||
# define Utf8Read(A) (A[0]<0x80?*(A++):sqlite3Utf8Read(&A))
|
||||
#endif
|
||||
|
||||
static const struct compareInfo globInfo = { '*', '?', '[', 0 };
|
||||
@@ -627,7 +625,7 @@ static const struct compareInfo likeInfoAlt = { '%', '_', 0, 0 };
|
||||
** Ec Where E is the "esc" character and c is any other
|
||||
** character, including '%', '_', and esc, match exactly c.
|
||||
**
|
||||
** The comments through this routine usually assume glob matching.
|
||||
** The comments within this routine usually assume glob matching.
|
||||
**
|
||||
** This routine is usually quick, but can be N**2 in the worst case.
|
||||
*/
|
||||
@@ -651,13 +649,12 @@ static int patternCompare(
|
||||
*/
|
||||
matchOther = esc ? esc : pInfo->matchSet;
|
||||
|
||||
while( (c = sqlite3Utf8Read(&zPattern))!=0 ){
|
||||
while( (c = Utf8Read(zPattern))!=0 ){
|
||||
if( c==matchAll ){ /* Match "*" */
|
||||
/* Skip over multiple "*" characters in the pattern. If there
|
||||
** are also "?" characters, skip those as well, but consume a
|
||||
** single character of the input string for each "?" skipped */
|
||||
while( (c=sqlite3Utf8Read(&zPattern)) == matchAll
|
||||
|| c == matchOne ){
|
||||
while( (c=Utf8Read(zPattern)) == matchAll || c == matchOne ){
|
||||
if( c==matchOne && sqlite3Utf8Read(&zString)==0 ){
|
||||
return 0;
|
||||
}
|
||||
@@ -702,7 +699,7 @@ static int patternCompare(
|
||||
if( patternCompare(zPattern,zString,pInfo,esc) ) return 1;
|
||||
}
|
||||
}else{
|
||||
while( (c2 = sqlite3Utf8Read(&zString))!=0 ){
|
||||
while( (c2 = Utf8Read(zString))!=0 ){
|
||||
if( c2!=c ) continue;
|
||||
if( patternCompare(zPattern,zString,pInfo,esc) ) return 1;
|
||||
}
|
||||
@@ -748,7 +745,7 @@ static int patternCompare(
|
||||
continue;
|
||||
}
|
||||
}
|
||||
c2 = sqlite3Utf8Read(&zString);
|
||||
c2 = Utf8Read(zString);
|
||||
if( c==c2 ) continue;
|
||||
if( noCase && c<0x80 && c2<0x80 && sqlite3Tolower(c)==sqlite3Tolower(c2) ){
|
||||
continue;
|
||||
|
@@ -1381,8 +1381,8 @@ void sqlite3GenerateConstraintChecks(
|
||||
if( pIdx->pPartIdxWhere ){
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, aRegIdx[ix]);
|
||||
pParse->ckBase = regNewData+1;
|
||||
sqlite3ExprIfFalse(pParse, pIdx->pPartIdxWhere, addrUniqueOk,
|
||||
SQLITE_JUMPIFNULL);
|
||||
sqlite3ExprIfFalseDup(pParse, pIdx->pPartIdxWhere, addrUniqueOk,
|
||||
SQLITE_JUMPIFNULL);
|
||||
pParse->ckBase = 0;
|
||||
}
|
||||
|
||||
|
@@ -402,7 +402,10 @@ static const sqlite3_api_routines sqlite3Apis = {
|
||||
sqlite3_reset_auto_extension,
|
||||
sqlite3_result_blob64,
|
||||
sqlite3_result_text64,
|
||||
sqlite3_strglob
|
||||
sqlite3_strglob,
|
||||
/* Version 3.8.11 and later */
|
||||
(sqlite3_value*(*)(const sqlite3_value*))sqlite3_value_dup,
|
||||
sqlite3_value_free
|
||||
};
|
||||
|
||||
/*
|
||||
|
@@ -2085,9 +2085,11 @@ int sqlite3TempInMemory(const sqlite3 *db){
|
||||
return ( db->temp_store!=1 );
|
||||
#endif
|
||||
#if SQLITE_TEMP_STORE==3
|
||||
UNUSED_PARAMETER(db);
|
||||
return 1;
|
||||
#endif
|
||||
#if SQLITE_TEMP_STORE<1 || SQLITE_TEMP_STORE>3
|
||||
UNUSED_PARAMETER(db);
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
@@ -3365,7 +3367,9 @@ int sqlite3_file_control(sqlite3 *db, const char *zDbName, int op, void *pArg){
|
||||
*/
|
||||
int sqlite3_test_control(int op, ...){
|
||||
int rc = 0;
|
||||
#ifndef SQLITE_OMIT_BUILTIN_TEST
|
||||
#ifdef SQLITE_OMIT_BUILTIN_TEST
|
||||
UNUSED_PARAMETER(op);
|
||||
#else
|
||||
va_list ap;
|
||||
va_start(ap, op);
|
||||
switch( op ){
|
||||
|
11
src/mutex.c
11
src/mutex.c
@@ -45,9 +45,14 @@ int sqlite3MutexInit(void){
|
||||
}else{
|
||||
pFrom = sqlite3NoopMutex();
|
||||
}
|
||||
memcpy(pTo, pFrom, offsetof(sqlite3_mutex_methods, xMutexAlloc));
|
||||
memcpy(&pTo->xMutexFree, &pFrom->xMutexFree,
|
||||
sizeof(*pTo) - offsetof(sqlite3_mutex_methods, xMutexFree));
|
||||
pTo->xMutexInit = pFrom->xMutexInit;
|
||||
pTo->xMutexEnd = pFrom->xMutexEnd;
|
||||
pTo->xMutexFree = pFrom->xMutexFree;
|
||||
pTo->xMutexEnter = pFrom->xMutexEnter;
|
||||
pTo->xMutexTry = pFrom->xMutexTry;
|
||||
pTo->xMutexLeave = pFrom->xMutexLeave;
|
||||
pTo->xMutexHeld = pFrom->xMutexHeld;
|
||||
pTo->xMutexNotheld = pFrom->xMutexNotheld;
|
||||
pTo->xMutexAlloc = pFrom->xMutexAlloc;
|
||||
}
|
||||
rc = sqlite3GlobalConfig.mutex.xMutexInit();
|
||||
|
@@ -148,8 +148,15 @@ static SQLITE_WSD struct PCacheGlobal {
|
||||
/*
|
||||
** Macros to enter and leave the PCache LRU mutex.
|
||||
*/
|
||||
#define pcache1EnterMutex(X) sqlite3_mutex_enter((X)->mutex)
|
||||
#define pcache1LeaveMutex(X) sqlite3_mutex_leave((X)->mutex)
|
||||
#if !defined(SQLITE_ENABLE_MEMORY_MANAGEMENT) || SQLITE_THREADSAFE==0
|
||||
# define pcache1EnterMutex(X) assert((X)->mutex==0)
|
||||
# define pcache1LeaveMutex(X) assert((X)->mutex==0)
|
||||
# define PCACHE1_MIGHT_USE_GROUP_MUTEX 0
|
||||
#else
|
||||
# define pcache1EnterMutex(X) sqlite3_mutex_enter((X)->mutex)
|
||||
# define pcache1LeaveMutex(X) sqlite3_mutex_leave((X)->mutex)
|
||||
# define PCACHE1_MIGHT_USE_GROUP_MUTEX 1
|
||||
#endif
|
||||
|
||||
/******************************************************************************/
|
||||
/******** Page Allocation/SQLITE_CONFIG_PCACHE Related Functions **************/
|
||||
@@ -425,31 +432,30 @@ static void pcache1ResizeHash(PCache1 *p){
|
||||
**
|
||||
** The PGroup mutex must be held when this function is called.
|
||||
*/
|
||||
static void pcache1PinPage(PgHdr1 *pPage){
|
||||
static PgHdr1 *pcache1PinPage(PgHdr1 *pPage){
|
||||
PCache1 *pCache;
|
||||
PGroup *pGroup;
|
||||
|
||||
assert( pPage!=0 );
|
||||
assert( pPage->isPinned==0 );
|
||||
pCache = pPage->pCache;
|
||||
pGroup = pCache->pGroup;
|
||||
assert( pPage->pLruNext || pPage==pGroup->pLruTail );
|
||||
assert( pPage->pLruPrev || pPage==pGroup->pLruHead );
|
||||
assert( sqlite3_mutex_held(pGroup->mutex) );
|
||||
assert( pPage->pLruNext || pPage==pCache->pGroup->pLruTail );
|
||||
assert( pPage->pLruPrev || pPage==pCache->pGroup->pLruHead );
|
||||
assert( sqlite3_mutex_held(pCache->pGroup->mutex) );
|
||||
if( pPage->pLruPrev ){
|
||||
pPage->pLruPrev->pLruNext = pPage->pLruNext;
|
||||
}else{
|
||||
pGroup->pLruHead = pPage->pLruNext;
|
||||
pCache->pGroup->pLruHead = pPage->pLruNext;
|
||||
}
|
||||
if( pPage->pLruNext ){
|
||||
pPage->pLruNext->pLruPrev = pPage->pLruPrev;
|
||||
}else{
|
||||
pGroup->pLruTail = pPage->pLruPrev;
|
||||
pCache->pGroup->pLruTail = pPage->pLruPrev;
|
||||
}
|
||||
pPage->pLruNext = 0;
|
||||
pPage->pLruPrev = 0;
|
||||
pPage->isPinned = 1;
|
||||
pCache->nRecyclable--;
|
||||
return pPage;
|
||||
}
|
||||
|
||||
|
||||
@@ -530,10 +536,12 @@ static int pcache1Init(void *NotUsed){
|
||||
UNUSED_PARAMETER(NotUsed);
|
||||
assert( pcache1.isInit==0 );
|
||||
memset(&pcache1, 0, sizeof(pcache1));
|
||||
#if SQLITE_THREADSAFE
|
||||
if( sqlite3GlobalConfig.bCoreMutex ){
|
||||
pcache1.grp.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_LRU);
|
||||
pcache1.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_PMEM);
|
||||
}
|
||||
#endif
|
||||
pcache1.grp.mxPinned = 10;
|
||||
pcache1.isInit = 1;
|
||||
return SQLITE_OK;
|
||||
@@ -729,9 +737,9 @@ static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2(
|
||||
** attempt to allocate a new one.
|
||||
*/
|
||||
if( !pPage ){
|
||||
if( createFlag==1 ) sqlite3BeginBenignMalloc();
|
||||
if( createFlag==1 ){ sqlite3BeginBenignMalloc(); }
|
||||
pPage = pcache1AllocPage(pCache);
|
||||
if( createFlag==1 ) sqlite3EndBenignMalloc();
|
||||
if( createFlag==1 ){ sqlite3EndBenignMalloc(); }
|
||||
}
|
||||
|
||||
if( pPage ){
|
||||
@@ -805,8 +813,13 @@ static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2(
|
||||
** proceed to step 5.
|
||||
**
|
||||
** 5. Otherwise, allocate and return a new page buffer.
|
||||
**
|
||||
** There are two versions of this routine. pcache1FetchWithMutex() is
|
||||
** the general case. pcache1FetchNoMutex() is a faster implementation for
|
||||
** the common case where pGroup->mutex is NULL. The pcache1Fetch() wrapper
|
||||
** invokes the appropriate routine.
|
||||
*/
|
||||
static sqlite3_pcache_page *pcache1Fetch(
|
||||
static PgHdr1 *pcache1FetchNoMutex(
|
||||
sqlite3_pcache *p,
|
||||
unsigned int iKey,
|
||||
int createFlag
|
||||
@@ -814,28 +827,63 @@ static sqlite3_pcache_page *pcache1Fetch(
|
||||
PCache1 *pCache = (PCache1 *)p;
|
||||
PgHdr1 *pPage = 0;
|
||||
|
||||
assert( offsetof(PgHdr1,page)==0 );
|
||||
assert( pCache->bPurgeable || createFlag!=1 );
|
||||
assert( pCache->bPurgeable || pCache->nMin==0 );
|
||||
assert( pCache->bPurgeable==0 || pCache->nMin==10 );
|
||||
assert( pCache->nMin==0 || pCache->bPurgeable );
|
||||
assert( pCache->nHash>0 );
|
||||
pcache1EnterMutex(pCache->pGroup);
|
||||
|
||||
/* Step 1: Search the hash table for an existing entry. */
|
||||
pPage = pCache->apHash[iKey % pCache->nHash];
|
||||
while( pPage && pPage->iKey!=iKey ){ pPage = pPage->pNext; }
|
||||
|
||||
/* Step 2: Abort if no existing page is found and createFlag is 0 */
|
||||
if( pPage ){
|
||||
if( !pPage->isPinned ) pcache1PinPage(pPage);
|
||||
if( !pPage->isPinned ){
|
||||
return pcache1PinPage(pPage);
|
||||
}else{
|
||||
return pPage;
|
||||
}
|
||||
}else if( createFlag ){
|
||||
/* Steps 3, 4, and 5 implemented by this subroutine */
|
||||
pPage = pcache1FetchStage2(pCache, iKey, createFlag);
|
||||
return pcache1FetchStage2(pCache, iKey, createFlag);
|
||||
}else{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#if PCACHE1_MIGHT_USE_GROUP_MUTEX
|
||||
static PgHdr1 *pcache1FetchWithMutex(
|
||||
sqlite3_pcache *p,
|
||||
unsigned int iKey,
|
||||
int createFlag
|
||||
){
|
||||
PCache1 *pCache = (PCache1 *)p;
|
||||
PgHdr1 *pPage;
|
||||
|
||||
pcache1EnterMutex(pCache->pGroup);
|
||||
pPage = pcache1FetchNoMutex(p, iKey, createFlag);
|
||||
assert( pPage==0 || pCache->iMaxKey>=iKey );
|
||||
pcache1LeaveMutex(pCache->pGroup);
|
||||
return (sqlite3_pcache_page*)pPage;
|
||||
return pPage;
|
||||
}
|
||||
#endif
|
||||
static sqlite3_pcache_page *pcache1Fetch(
|
||||
sqlite3_pcache *p,
|
||||
unsigned int iKey,
|
||||
int createFlag
|
||||
){
|
||||
#if PCACHE1_MIGHT_USE_GROUP_MUTEX || defined(SQLITE_DEBUG)
|
||||
PCache1 *pCache = (PCache1 *)p;
|
||||
#endif
|
||||
|
||||
assert( offsetof(PgHdr1,page)==0 );
|
||||
assert( pCache->bPurgeable || createFlag!=1 );
|
||||
assert( pCache->bPurgeable || pCache->nMin==0 );
|
||||
assert( pCache->bPurgeable==0 || pCache->nMin==10 );
|
||||
assert( pCache->nMin==0 || pCache->bPurgeable );
|
||||
assert( pCache->nHash>0 );
|
||||
#if PCACHE1_MIGHT_USE_GROUP_MUTEX
|
||||
if( pCache->pGroup->mutex ){
|
||||
return (sqlite3_pcache_page*)pcache1FetchWithMutex(p, iKey, createFlag);
|
||||
}else
|
||||
#endif
|
||||
{
|
||||
return (sqlite3_pcache_page*)pcache1FetchNoMutex(p, iKey, createFlag);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
68
src/printf.c
68
src/printf.c
@@ -1,16 +1,13 @@
|
||||
/*
|
||||
** The "printf" code that follows dates from the 1980's. It is in
|
||||
** the public domain. The original comments are included here for
|
||||
** completeness. They are very out-of-date but might be useful as
|
||||
** an historical reference. Most of the "enhancements" have been backed
|
||||
** out so that the functionality is now the same as standard printf().
|
||||
** the public domain.
|
||||
**
|
||||
**************************************************************************
|
||||
**
|
||||
** This file contains code for a set of "printf"-like routines. These
|
||||
** routines format strings much like the printf() from the standard C
|
||||
** library, though the implementation here has enhancements to support
|
||||
** SQLlite.
|
||||
** SQLite.
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
@@ -1058,67 +1055,6 @@ void sqlite3DebugPrintf(const char *zFormat, ...){
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_DEBUG
|
||||
/*************************************************************************
|
||||
** Routines for implementing the "TreeView" display of hierarchical
|
||||
** data structures for debugging.
|
||||
**
|
||||
** The main entry points (coded elsewhere) are:
|
||||
** sqlite3TreeViewExpr(0, pExpr, 0);
|
||||
** sqlite3TreeViewExprList(0, pList, 0, 0);
|
||||
** sqlite3TreeViewSelect(0, pSelect, 0);
|
||||
** Insert calls to those routines while debugging in order to display
|
||||
** a diagram of Expr, ExprList, and Select objects.
|
||||
**
|
||||
*/
|
||||
/* Add a new subitem to the tree. The moreToFollow flag indicates that this
|
||||
** is not the last item in the tree. */
|
||||
TreeView *sqlite3TreeViewPush(TreeView *p, u8 moreToFollow){
|
||||
if( p==0 ){
|
||||
p = sqlite3_malloc64( sizeof(*p) );
|
||||
if( p==0 ) return 0;
|
||||
memset(p, 0, sizeof(*p));
|
||||
}else{
|
||||
p->iLevel++;
|
||||
}
|
||||
assert( moreToFollow==0 || moreToFollow==1 );
|
||||
if( p->iLevel<sizeof(p->bLine) ) p->bLine[p->iLevel] = moreToFollow;
|
||||
return p;
|
||||
}
|
||||
/* Finished with one layer of the tree */
|
||||
void sqlite3TreeViewPop(TreeView *p){
|
||||
if( p==0 ) return;
|
||||
p->iLevel--;
|
||||
if( p->iLevel<0 ) sqlite3_free(p);
|
||||
}
|
||||
/* Generate a single line of output for the tree, with a prefix that contains
|
||||
** all the appropriate tree lines */
|
||||
void sqlite3TreeViewLine(TreeView *p, const char *zFormat, ...){
|
||||
va_list ap;
|
||||
int i;
|
||||
StrAccum acc;
|
||||
char zBuf[500];
|
||||
sqlite3StrAccumInit(&acc, 0, zBuf, sizeof(zBuf), 0);
|
||||
if( p ){
|
||||
for(i=0; i<p->iLevel && i<sizeof(p->bLine)-1; i++){
|
||||
sqlite3StrAccumAppend(&acc, p->bLine[i] ? "| " : " ", 4);
|
||||
}
|
||||
sqlite3StrAccumAppend(&acc, p->bLine[i] ? "|-- " : "'-- ", 4);
|
||||
}
|
||||
va_start(ap, zFormat);
|
||||
sqlite3VXPrintf(&acc, 0, zFormat, ap);
|
||||
va_end(ap);
|
||||
if( zBuf[acc.nChar-1]!='\n' ) sqlite3StrAccumAppend(&acc, "\n", 1);
|
||||
sqlite3StrAccumFinish(&acc);
|
||||
fprintf(stdout,"%s", zBuf);
|
||||
fflush(stdout);
|
||||
}
|
||||
/* Shorthand for starting a new tree item that consists of a single label */
|
||||
void sqlite3TreeViewItem(TreeView *p, const char *zLabel, u8 moreToFollow){
|
||||
p = sqlite3TreeViewPush(p, moreToFollow);
|
||||
sqlite3TreeViewLine(p, "%s", zLabel);
|
||||
}
|
||||
#endif /* SQLITE_DEBUG */
|
||||
|
||||
/*
|
||||
** variable-argument wrapper around sqlite3VXPrintf().
|
||||
|
@@ -1331,6 +1331,13 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
|
||||
}
|
||||
}
|
||||
|
||||
/* If this is part of a compound SELECT, check that it has the right
|
||||
** number of expressions in the select list. */
|
||||
if( p->pNext && p->pEList->nExpr!=p->pNext->pEList->nExpr ){
|
||||
sqlite3SelectWrongNumTermsError(pParse, p->pNext);
|
||||
return WRC_Abort;
|
||||
}
|
||||
|
||||
/* Advance to the next term of the compound
|
||||
*/
|
||||
p = p->pPrior;
|
||||
|
379
src/select.c
379
src/select.c
@@ -21,7 +21,8 @@
|
||||
/***/ int sqlite3SelectTrace = 0;
|
||||
# define SELECTTRACE(K,P,S,X) \
|
||||
if(sqlite3SelectTrace&(K)) \
|
||||
sqlite3DebugPrintf("%*s%s.%p: ",(P)->nSelectIndent*2-2,"",(S)->zSelName,(S)),\
|
||||
sqlite3DebugPrintf("%*s%s.%p: ",(P)->nSelectIndent*2-2,"",\
|
||||
(S)->zSelName,(S)),\
|
||||
sqlite3DebugPrintf X
|
||||
#else
|
||||
# define SELECTTRACE(K,P,S,X)
|
||||
@@ -365,6 +366,12 @@ static void setJoinExpr(Expr *p, int iTable){
|
||||
assert( !ExprHasProperty(p, EP_TokenOnly|EP_Reduced) );
|
||||
ExprSetVVAProperty(p, EP_NoReduce);
|
||||
p->iRightJoinTable = (i16)iTable;
|
||||
if( p->op==TK_FUNCTION && p->x.pList ){
|
||||
int i;
|
||||
for(i=0; i<p->x.pList->nExpr; i++){
|
||||
setJoinExpr(p->x.pList->a[i].pExpr, iTable);
|
||||
}
|
||||
}
|
||||
setJoinExpr(p->pLeft, iTable);
|
||||
p = p->pRight;
|
||||
}
|
||||
@@ -774,7 +781,8 @@ static void selectInnerLoop(
|
||||
|
||||
default: {
|
||||
assert( pDistinct->eTnctType==WHERE_DISTINCT_UNORDERED );
|
||||
codeDistinct(pParse, pDistinct->tabTnct, iContinue, nResultCol, regResult);
|
||||
codeDistinct(pParse, pDistinct->tabTnct, iContinue, nResultCol,
|
||||
regResult);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -827,7 +835,8 @@ static void selectInnerLoop(
|
||||
** current row to the index and proceed with writing it to the
|
||||
** output table as well. */
|
||||
int addr = sqlite3VdbeCurrentAddr(v) + 4;
|
||||
sqlite3VdbeAddOp4Int(v, OP_Found, iParm+1, addr, r1, 0); VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp4Int(v, OP_Found, iParm+1, addr, r1, 0);
|
||||
VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm+1, r1);
|
||||
assert( pSort==0 );
|
||||
}
|
||||
@@ -1310,28 +1319,27 @@ static void generateSortTail(
|
||||
*/
|
||||
#ifdef SQLITE_ENABLE_COLUMN_METADATA
|
||||
# define columnType(A,B,C,D,E,F) columnTypeImpl(A,B,C,D,E,F)
|
||||
#else /* if !defined(SQLITE_ENABLE_COLUMN_METADATA) */
|
||||
# define columnType(A,B,C,D,E,F) columnTypeImpl(A,B,F)
|
||||
#endif
|
||||
static const char *columnTypeImpl(
|
||||
NameContext *pNC,
|
||||
Expr *pExpr,
|
||||
#ifdef SQLITE_ENABLE_COLUMN_METADATA
|
||||
const char **pzOrigDb,
|
||||
const char **pzOrigTab,
|
||||
const char **pzOrigCol,
|
||||
#endif
|
||||
u8 *pEstWidth
|
||||
){
|
||||
char const *zOrigDb = 0;
|
||||
char const *zOrigTab = 0;
|
||||
char const *zOrigCol = 0;
|
||||
#else /* if !defined(SQLITE_ENABLE_COLUMN_METADATA) */
|
||||
# define columnType(A,B,C,D,E,F) columnTypeImpl(A,B,F)
|
||||
static const char *columnTypeImpl(
|
||||
NameContext *pNC,
|
||||
Expr *pExpr,
|
||||
u8 *pEstWidth
|
||||
){
|
||||
#endif /* !defined(SQLITE_ENABLE_COLUMN_METADATA) */
|
||||
char const *zType = 0;
|
||||
int j;
|
||||
u8 estWidth = 1;
|
||||
#ifdef SQLITE_ENABLE_COLUMN_METADATA
|
||||
char const *zOrigDb = 0;
|
||||
char const *zOrigTab = 0;
|
||||
char const *zOrigCol = 0;
|
||||
#endif
|
||||
|
||||
if( NEVER(pExpr==0) || pNC->pSrcList==0 ) return 0;
|
||||
switch( pExpr->op ){
|
||||
@@ -1705,7 +1713,8 @@ static void selectAddColumnTypeAndCollation(
|
||||
for(i=0, pCol=pTab->aCol; i<pTab->nCol; i++, pCol++){
|
||||
p = a[i].pExpr;
|
||||
if( pCol->zType==0 ){
|
||||
pCol->zType = sqlite3DbStrDup(db, columnType(&sNC, p,0,0,0, &pCol->szEst));
|
||||
pCol->zType = sqlite3DbStrDup(db,
|
||||
columnType(&sNC, p,0,0,0, &pCol->szEst));
|
||||
}
|
||||
szAll += pCol->szEst;
|
||||
pCol->affinity = sqlite3ExprAffinity(p);
|
||||
@@ -2084,7 +2093,7 @@ static int multiSelectOrderBy(
|
||||
** Error message for when two or more terms of a compound select have different
|
||||
** size result sets.
|
||||
*/
|
||||
static void selectWrongNumTermsError(Parse *pParse, Select *p){
|
||||
void sqlite3SelectWrongNumTermsError(Parse *pParse, Select *p){
|
||||
if( p->selFlags & SF_Values ){
|
||||
sqlite3ErrorMsg(pParse, "all VALUES must have the same number of terms");
|
||||
}else{
|
||||
@@ -2110,7 +2119,6 @@ static int multiSelectValues(
|
||||
SelectDest *pDest /* What to do with query results */
|
||||
){
|
||||
Select *pPrior;
|
||||
int nExpr = p->pEList->nExpr;
|
||||
int nRow = 1;
|
||||
int rc = 0;
|
||||
assert( p->selFlags & SF_MultiValue );
|
||||
@@ -2119,10 +2127,7 @@ static int multiSelectValues(
|
||||
assert( p->op==TK_ALL || (p->op==TK_SELECT && p->pPrior==0) );
|
||||
assert( p->pLimit==0 );
|
||||
assert( p->pOffset==0 );
|
||||
if( p->pEList->nExpr!=nExpr ){
|
||||
selectWrongNumTermsError(pParse, p);
|
||||
return 1;
|
||||
}
|
||||
assert( p->pNext==0 || p->pEList->nExpr==p->pNext->pEList->nExpr );
|
||||
if( p->pPrior==0 ) break;
|
||||
assert( p->pPrior->pNext==p );
|
||||
p = p->pPrior;
|
||||
@@ -2231,11 +2236,7 @@ static int multiSelect(
|
||||
** in their result sets.
|
||||
*/
|
||||
assert( p->pEList && pPrior->pEList );
|
||||
if( p->pEList->nExpr!=pPrior->pEList->nExpr ){
|
||||
selectWrongNumTermsError(pParse, p);
|
||||
rc = 1;
|
||||
goto multi_select_end;
|
||||
}
|
||||
assert( p->pEList->nExpr==pPrior->pEList->nExpr );
|
||||
|
||||
#ifndef SQLITE_OMIT_CTE
|
||||
if( p->selFlags & SF_Recursive ){
|
||||
@@ -3215,8 +3216,8 @@ static void substSelect(
|
||||
**
|
||||
** (**) Restriction (10) was removed from the code on 2005-02-05 but we
|
||||
** accidently carried the comment forward until 2014-09-15. Original
|
||||
** text: "The subquery does not use aggregates or the outer query does not
|
||||
** use LIMIT."
|
||||
** text: "The subquery does not use aggregates or the outer query
|
||||
** does not use LIMIT."
|
||||
**
|
||||
** (11) The subquery and the outer query do not both have ORDER BY clauses.
|
||||
**
|
||||
@@ -3709,7 +3710,7 @@ static int flattenSubquery(
|
||||
|
||||
#if SELECTTRACE_ENABLED
|
||||
if( sqlite3SelectTrace & 0x100 ){
|
||||
sqlite3DebugPrintf("After flattening:\n");
|
||||
SELECTTRACE(0x100,pParse,p,("After flattening:\n"));
|
||||
sqlite3TreeViewSelect(0, p, 0);
|
||||
}
|
||||
#endif
|
||||
@@ -3718,6 +3719,73 @@ static int flattenSubquery(
|
||||
}
|
||||
#endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */
|
||||
|
||||
|
||||
|
||||
#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
|
||||
/*
|
||||
** Make copies of relevant WHERE clause terms of the outer query into
|
||||
** the WHERE clause of subquery. Example:
|
||||
**
|
||||
** SELECT * FROM (SELECT a AS x, c-d AS y FROM t1) WHERE x=5 AND y=10;
|
||||
**
|
||||
** Transformed into:
|
||||
**
|
||||
** SELECT * FROM (SELECT a AS x, c-d AS y FROM t1 WHERE a=5 AND c-d=10)
|
||||
** WHERE x=5 AND y=10;
|
||||
**
|
||||
** The hope is that the terms added to the inner query will make it more
|
||||
** efficient.
|
||||
**
|
||||
** Do not attempt this optimization if:
|
||||
**
|
||||
** (1) The inner query is an aggregate. (In that case, we'd really want
|
||||
** to copy the outer WHERE-clause terms onto the HAVING clause of the
|
||||
** inner query. But they probably won't help there so do not bother.)
|
||||
**
|
||||
** (2) The inner query is the recursive part of a common table expression.
|
||||
**
|
||||
** (3) The inner query has a LIMIT clause (since the changes to the WHERE
|
||||
** close would change the meaning of the LIMIT).
|
||||
**
|
||||
** (4) The inner query is the right operand of a LEFT JOIN. (The caller
|
||||
** enforces this restriction since this routine does not have enough
|
||||
** information to know.)
|
||||
**
|
||||
** Return 0 if no changes are made and non-zero if one or more WHERE clause
|
||||
** terms are duplicated into the subquery.
|
||||
*/
|
||||
static int pushDownWhereTerms(
|
||||
sqlite3 *db, /* The database connection (for malloc()) */
|
||||
Select *pSubq, /* The subquery whose WHERE clause is to be augmented */
|
||||
Expr *pWhere, /* The WHERE clause of the outer query */
|
||||
int iCursor /* Cursor number of the subquery */
|
||||
){
|
||||
Expr *pNew;
|
||||
int nChng = 0;
|
||||
if( pWhere==0 ) return 0;
|
||||
if( (pSubq->selFlags & (SF_Aggregate|SF_Recursive))!=0 ){
|
||||
return 0; /* restrictions (1) and (2) */
|
||||
}
|
||||
if( pSubq->pLimit!=0 ){
|
||||
return 0; /* restriction (3) */
|
||||
}
|
||||
while( pWhere->op==TK_AND ){
|
||||
nChng += pushDownWhereTerms(db, pSubq, pWhere->pRight, iCursor);
|
||||
pWhere = pWhere->pLeft;
|
||||
}
|
||||
if( sqlite3ExprIsTableConstant(pWhere, iCursor) ){
|
||||
nChng++;
|
||||
while( pSubq ){
|
||||
pNew = sqlite3ExprDup(db, pWhere, 0);
|
||||
pNew = substExpr(db, pNew, iCursor, pSubq->pEList);
|
||||
pSubq->pWhere = sqlite3ExprAnd(db, pSubq->pWhere, pNew);
|
||||
pSubq = pSubq->pPrior;
|
||||
}
|
||||
}
|
||||
return nChng;
|
||||
}
|
||||
#endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */
|
||||
|
||||
/*
|
||||
** Based on the contents of the AggInfo structure indicated by the first
|
||||
** argument, this function checks if the following are true:
|
||||
@@ -3801,16 +3869,16 @@ static Table *isSimpleCount(Select *p, AggInfo *pAggInfo){
|
||||
** pFrom->pIndex and return SQLITE_OK.
|
||||
*/
|
||||
int sqlite3IndexedByLookup(Parse *pParse, struct SrcList_item *pFrom){
|
||||
if( pFrom->pTab && pFrom->zIndex ){
|
||||
if( pFrom->pTab && pFrom->zIndexedBy ){
|
||||
Table *pTab = pFrom->pTab;
|
||||
char *zIndex = pFrom->zIndex;
|
||||
char *zIndexedBy = pFrom->zIndexedBy;
|
||||
Index *pIdx;
|
||||
for(pIdx=pTab->pIndex;
|
||||
pIdx && sqlite3StrICmp(pIdx->zName, zIndex);
|
||||
pIdx && sqlite3StrICmp(pIdx->zName, zIndexedBy);
|
||||
pIdx=pIdx->pNext
|
||||
);
|
||||
if( !pIdx ){
|
||||
sqlite3ErrorMsg(pParse, "no such index: %s", zIndex, 0);
|
||||
sqlite3ErrorMsg(pParse, "no such index: %s", zIndexedBy, 0);
|
||||
pParse->checkSchema = 1;
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
@@ -4747,12 +4815,11 @@ int sqlite3Select(
|
||||
memset(&sSort, 0, sizeof(sSort));
|
||||
sSort.pOrderBy = p->pOrderBy;
|
||||
pTabList = p->pSrc;
|
||||
pEList = p->pEList;
|
||||
if( pParse->nErr || db->mallocFailed ){
|
||||
goto select_end;
|
||||
}
|
||||
assert( p->pEList!=0 );
|
||||
isAgg = (p->selFlags & SF_Aggregate)!=0;
|
||||
assert( pEList!=0 );
|
||||
#if SELECTTRACE_ENABLED
|
||||
if( sqlite3SelectTrace & 0x100 ){
|
||||
SELECTTRACE(0x100,pParse,p, ("after name resolution:\n"));
|
||||
@@ -4761,29 +4828,67 @@ int sqlite3Select(
|
||||
#endif
|
||||
|
||||
|
||||
/* Begin generating code.
|
||||
*/
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
if( v==0 ) goto select_end;
|
||||
|
||||
/* If writing to memory or generating a set
|
||||
** only a single column may be output.
|
||||
*/
|
||||
#ifndef SQLITE_OMIT_SUBQUERY
|
||||
if( checkForMultiColumnSelectError(pParse, pDest, pEList->nExpr) ){
|
||||
if( checkForMultiColumnSelectError(pParse, pDest, p->pEList->nExpr) ){
|
||||
goto select_end;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Try to flatten subqueries in the FROM clause up into the main query
|
||||
*/
|
||||
#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
|
||||
for(i=0; !p->pPrior && i<pTabList->nSrc; i++){
|
||||
struct SrcList_item *pItem = &pTabList->a[i];
|
||||
Select *pSub = pItem->pSelect;
|
||||
int isAggSub;
|
||||
if( pSub==0 ) continue;
|
||||
isAggSub = (pSub->selFlags & SF_Aggregate)!=0;
|
||||
if( flattenSubquery(pParse, p, i, isAgg, isAggSub) ){
|
||||
/* This subquery can be absorbed into its parent. */
|
||||
if( isAggSub ){
|
||||
isAgg = 1;
|
||||
p->selFlags |= SF_Aggregate;
|
||||
}
|
||||
i = -1;
|
||||
}
|
||||
pTabList = p->pSrc;
|
||||
if( db->mallocFailed ) goto select_end;
|
||||
if( !IgnorableOrderby(pDest) ){
|
||||
sSort.pOrderBy = p->pOrderBy;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Get a pointer the VDBE under construction, allocating a new VDBE if one
|
||||
** does not already exist */
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
if( v==0 ) goto select_end;
|
||||
|
||||
#ifndef SQLITE_OMIT_COMPOUND_SELECT
|
||||
/* Handle compound SELECT statements using the separate multiSelect()
|
||||
** procedure.
|
||||
*/
|
||||
if( p->pPrior ){
|
||||
rc = multiSelect(pParse, p, pDest);
|
||||
explainSetInteger(pParse->iSelectId, iRestoreSelectId);
|
||||
#if SELECTTRACE_ENABLED
|
||||
SELECTTRACE(1,pParse,p,("end compound-select processing\n"));
|
||||
pParse->nSelectIndent--;
|
||||
#endif
|
||||
return rc;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Generate code for all sub-queries in the FROM clause
|
||||
*/
|
||||
#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
|
||||
for(i=0; !p->pPrior && i<pTabList->nSrc; i++){
|
||||
for(i=0; i<pTabList->nSrc; i++){
|
||||
struct SrcList_item *pItem = &pTabList->a[i];
|
||||
SelectDest dest;
|
||||
Select *pSub = pItem->pSelect;
|
||||
int isAggSub;
|
||||
|
||||
if( pSub==0 ) continue;
|
||||
|
||||
/* Sometimes the code for a subquery will be generated more than
|
||||
@@ -4808,17 +4913,25 @@ int sqlite3Select(
|
||||
*/
|
||||
pParse->nHeight += sqlite3SelectExprHeight(p);
|
||||
|
||||
isAggSub = (pSub->selFlags & SF_Aggregate)!=0;
|
||||
if( flattenSubquery(pParse, p, i, isAgg, isAggSub) ){
|
||||
/* This subquery can be absorbed into its parent. */
|
||||
if( isAggSub ){
|
||||
isAgg = 1;
|
||||
p->selFlags |= SF_Aggregate;
|
||||
/* Make copies of constant WHERE-clause terms in the outer query down
|
||||
** inside the subquery. This can help the subquery to run more efficiently.
|
||||
*/
|
||||
if( (pItem->jointype & JT_OUTER)==0
|
||||
&& pushDownWhereTerms(db, pSub, p->pWhere, pItem->iCursor)
|
||||
){
|
||||
#if SELECTTRACE_ENABLED
|
||||
if( sqlite3SelectTrace & 0x100 ){
|
||||
SELECTTRACE(0x100,pParse,p,("After WHERE-clause push-down:\n"));
|
||||
sqlite3TreeViewSelect(0, p, 0);
|
||||
}
|
||||
i = -1;
|
||||
}else if( pTabList->nSrc==1
|
||||
&& (p->selFlags & SF_All)==0
|
||||
&& OptimizationEnabled(db, SQLITE_SubqCoroutine)
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Generate code to implement the subquery
|
||||
*/
|
||||
if( pTabList->nSrc==1
|
||||
&& (p->selFlags & SF_All)==0
|
||||
&& OptimizationEnabled(db, SQLITE_SubqCoroutine)
|
||||
){
|
||||
/* Implement a co-routine that will return a single row of the result
|
||||
** set on each invocation.
|
||||
@@ -4869,33 +4982,23 @@ int sqlite3Select(
|
||||
sqlite3VdbeChangeP1(v, topAddr, retAddr);
|
||||
sqlite3ClearTempRegCache(pParse);
|
||||
}
|
||||
if( /*pParse->nErr ||*/ db->mallocFailed ){
|
||||
goto select_end;
|
||||
}
|
||||
if( db->mallocFailed ) goto select_end;
|
||||
pParse->nHeight -= sqlite3SelectExprHeight(p);
|
||||
pTabList = p->pSrc;
|
||||
if( !IgnorableOrderby(pDest) ){
|
||||
sSort.pOrderBy = p->pOrderBy;
|
||||
}
|
||||
}
|
||||
pEList = p->pEList;
|
||||
#endif
|
||||
|
||||
/* Various elements of the SELECT copied into local variables for
|
||||
** convenience */
|
||||
pEList = p->pEList;
|
||||
pWhere = p->pWhere;
|
||||
pGroupBy = p->pGroupBy;
|
||||
pHaving = p->pHaving;
|
||||
sDistinct.isTnct = (p->selFlags & SF_Distinct)!=0;
|
||||
|
||||
#ifndef SQLITE_OMIT_COMPOUND_SELECT
|
||||
/* If there is are a sequence of queries, do the earlier ones first.
|
||||
*/
|
||||
if( p->pPrior ){
|
||||
rc = multiSelect(pParse, p, pDest);
|
||||
explainSetInteger(pParse->iSelectId, iRestoreSelectId);
|
||||
#if SELECTTRACE_ENABLED
|
||||
SELECTTRACE(1,pParse,p,("end compound-select processing\n"));
|
||||
pParse->nSelectIndent--;
|
||||
#endif
|
||||
return rc;
|
||||
if( sqlite3SelectTrace & 0x400 ){
|
||||
SELECTTRACE(0x400,pParse,p,("After all FROM-clause analysis:\n"));
|
||||
sqlite3TreeViewSelect(0, p, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -4915,23 +5018,23 @@ int sqlite3Select(
|
||||
** BY and DISTINCT, and an index or separate temp-table for the other.
|
||||
*/
|
||||
if( (p->selFlags & (SF_Distinct|SF_Aggregate))==SF_Distinct
|
||||
&& sqlite3ExprListCompare(sSort.pOrderBy, p->pEList, -1)==0
|
||||
&& sqlite3ExprListCompare(sSort.pOrderBy, pEList, -1)==0
|
||||
){
|
||||
p->selFlags &= ~SF_Distinct;
|
||||
p->pGroupBy = sqlite3ExprListDup(db, p->pEList, 0);
|
||||
pGroupBy = p->pGroupBy;
|
||||
pGroupBy = p->pGroupBy = sqlite3ExprListDup(db, pEList, 0);
|
||||
/* Notice that even thought SF_Distinct has been cleared from p->selFlags,
|
||||
** the sDistinct.isTnct is still set. Hence, isTnct represents the
|
||||
** original setting of the SF_Distinct flag, not the current setting */
|
||||
assert( sDistinct.isTnct );
|
||||
}
|
||||
|
||||
/* If there is an ORDER BY clause, then this sorting
|
||||
** index might end up being unused if the data can be
|
||||
** extracted in pre-sorted order. If that is the case, then the
|
||||
** OP_OpenEphemeral instruction will be changed to an OP_Noop once
|
||||
** we figure out that the sorting index is not needed. The addrSortIndex
|
||||
** variable is used to facilitate that change.
|
||||
/* If there is an ORDER BY clause, then create an ephemeral index to
|
||||
** do the sorting. But this sorting ephemeral index might end up
|
||||
** being unused if the data can be extracted in pre-sorted order.
|
||||
** If that is the case, then the OP_OpenEphemeral instruction will be
|
||||
** changed to an OP_Noop once we figure out that the sorting index is
|
||||
** not needed. The sSort.addrSortIndex variable is used to facilitate
|
||||
** that change.
|
||||
*/
|
||||
if( sSort.pOrderBy ){
|
||||
KeyInfo *pKeyInfo;
|
||||
@@ -4962,14 +5065,14 @@ int sqlite3Select(
|
||||
sSort.sortFlags |= SORTFLAG_UseSorter;
|
||||
}
|
||||
|
||||
/* Open a virtual index to use for the distinct set.
|
||||
/* Open an ephemeral index to use for the distinct set.
|
||||
*/
|
||||
if( p->selFlags & SF_Distinct ){
|
||||
sDistinct.tabTnct = pParse->nTab++;
|
||||
sDistinct.addrTnct = sqlite3VdbeAddOp4(v, OP_OpenEphemeral,
|
||||
sDistinct.tabTnct, 0, 0,
|
||||
(char*)keyInfoFromExprList(pParse, p->pEList,0,0),
|
||||
P4_KEYINFO);
|
||||
sDistinct.tabTnct, 0, 0,
|
||||
(char*)keyInfoFromExprList(pParse, p->pEList,0,0),
|
||||
P4_KEYINFO);
|
||||
sqlite3VdbeChangeP5(v, BTREE_UNORDERED);
|
||||
sDistinct.eTnctType = WHERE_DISTINCT_UNORDERED;
|
||||
}else{
|
||||
@@ -5047,11 +5150,10 @@ int sqlite3Select(
|
||||
p->nSelectRow = 1;
|
||||
}
|
||||
|
||||
|
||||
/* If there is both a GROUP BY and an ORDER BY clause and they are
|
||||
** identical, then it may be possible to disable the ORDER BY clause
|
||||
** on the grounds that the GROUP BY will cause elements to come out
|
||||
** in the correct order. It also may not - the GROUP BY may use a
|
||||
** in the correct order. It also may not - the GROUP BY might use a
|
||||
** database index that causes rows to be grouped together as required
|
||||
** but not actually sorted. Either way, record the fact that the
|
||||
** ORDER BY and GROUP BY clauses are the same by setting the orderByGrp
|
||||
@@ -5229,7 +5331,8 @@ int sqlite3Select(
|
||||
addrTopOfLoop = sqlite3VdbeCurrentAddr(v);
|
||||
sqlite3ExprCacheClear(pParse);
|
||||
if( groupBySort ){
|
||||
sqlite3VdbeAddOp3(v, OP_SorterData, sAggInfo.sortingIdx, sortOut,sortPTab);
|
||||
sqlite3VdbeAddOp3(v, OP_SorterData, sAggInfo.sortingIdx,
|
||||
sortOut, sortPTab);
|
||||
}
|
||||
for(j=0; j<pGroupBy->nExpr; j++){
|
||||
if( groupBySort ){
|
||||
@@ -5301,7 +5404,8 @@ int sqlite3Select(
|
||||
sqlite3VdbeAddOp1(v, OP_Return, regOutputRow);
|
||||
sqlite3VdbeResolveLabel(v, addrOutputRow);
|
||||
addrOutputRow = sqlite3VdbeCurrentAddr(v);
|
||||
sqlite3VdbeAddOp2(v, OP_IfPos, iUseFlag, addrOutputRow+2); VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp2(v, OP_IfPos, iUseFlag, addrOutputRow+2);
|
||||
VdbeCoverage(v);
|
||||
VdbeComment((v, "Groupby result generator entry point"));
|
||||
sqlite3VdbeAddOp1(v, OP_Return, regOutputRow);
|
||||
finalizeAggFunctions(pParse, &sAggInfo);
|
||||
@@ -5465,7 +5569,8 @@ int sqlite3Select(
|
||||
** and send them to the callback one by one.
|
||||
*/
|
||||
if( sSort.pOrderBy ){
|
||||
explainTempTable(pParse, sSort.nOBSat>0 ? "RIGHT PART OF ORDER BY":"ORDER BY");
|
||||
explainTempTable(pParse,
|
||||
sSort.nOBSat>0 ? "RIGHT PART OF ORDER BY":"ORDER BY");
|
||||
generateSortTail(pParse, p, &sSort, pEList->nExpr, pDest);
|
||||
}
|
||||
|
||||
@@ -5497,97 +5602,3 @@ select_end:
|
||||
#endif
|
||||
return rc;
|
||||
}
|
||||
|
||||
#ifdef SQLITE_DEBUG
|
||||
/*
|
||||
** Generate a human-readable description of a the Select object.
|
||||
*/
|
||||
void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 moreToFollow){
|
||||
int n = 0;
|
||||
pView = sqlite3TreeViewPush(pView, moreToFollow);
|
||||
sqlite3TreeViewLine(pView, "SELECT%s%s (0x%p) selFlags=0x%x",
|
||||
((p->selFlags & SF_Distinct) ? " DISTINCT" : ""),
|
||||
((p->selFlags & SF_Aggregate) ? " agg_flag" : ""), p, p->selFlags
|
||||
);
|
||||
if( p->pSrc && p->pSrc->nSrc ) n++;
|
||||
if( p->pWhere ) n++;
|
||||
if( p->pGroupBy ) n++;
|
||||
if( p->pHaving ) n++;
|
||||
if( p->pOrderBy ) n++;
|
||||
if( p->pLimit ) n++;
|
||||
if( p->pOffset ) n++;
|
||||
if( p->pPrior ) n++;
|
||||
sqlite3TreeViewExprList(pView, p->pEList, (n--)>0, "result-set");
|
||||
if( p->pSrc && p->pSrc->nSrc ){
|
||||
int i;
|
||||
pView = sqlite3TreeViewPush(pView, (n--)>0);
|
||||
sqlite3TreeViewLine(pView, "FROM");
|
||||
for(i=0; i<p->pSrc->nSrc; i++){
|
||||
struct SrcList_item *pItem = &p->pSrc->a[i];
|
||||
StrAccum x;
|
||||
char zLine[100];
|
||||
sqlite3StrAccumInit(&x, 0, zLine, sizeof(zLine), 0);
|
||||
sqlite3XPrintf(&x, 0, "{%d,*}", pItem->iCursor);
|
||||
if( pItem->zDatabase ){
|
||||
sqlite3XPrintf(&x, 0, " %s.%s", pItem->zDatabase, pItem->zName);
|
||||
}else if( pItem->zName ){
|
||||
sqlite3XPrintf(&x, 0, " %s", pItem->zName);
|
||||
}
|
||||
if( pItem->pTab ){
|
||||
sqlite3XPrintf(&x, 0, " tabname=%Q", pItem->pTab->zName);
|
||||
}
|
||||
if( pItem->zAlias ){
|
||||
sqlite3XPrintf(&x, 0, " (AS %s)", pItem->zAlias);
|
||||
}
|
||||
if( pItem->jointype & JT_LEFT ){
|
||||
sqlite3XPrintf(&x, 0, " LEFT-JOIN");
|
||||
}
|
||||
sqlite3StrAccumFinish(&x);
|
||||
sqlite3TreeViewItem(pView, zLine, i<p->pSrc->nSrc-1);
|
||||
if( pItem->pSelect ){
|
||||
sqlite3TreeViewSelect(pView, pItem->pSelect, 0);
|
||||
}
|
||||
sqlite3TreeViewPop(pView);
|
||||
}
|
||||
sqlite3TreeViewPop(pView);
|
||||
}
|
||||
if( p->pWhere ){
|
||||
sqlite3TreeViewItem(pView, "WHERE", (n--)>0);
|
||||
sqlite3TreeViewExpr(pView, p->pWhere, 0);
|
||||
sqlite3TreeViewPop(pView);
|
||||
}
|
||||
if( p->pGroupBy ){
|
||||
sqlite3TreeViewExprList(pView, p->pGroupBy, (n--)>0, "GROUPBY");
|
||||
}
|
||||
if( p->pHaving ){
|
||||
sqlite3TreeViewItem(pView, "HAVING", (n--)>0);
|
||||
sqlite3TreeViewExpr(pView, p->pHaving, 0);
|
||||
sqlite3TreeViewPop(pView);
|
||||
}
|
||||
if( p->pOrderBy ){
|
||||
sqlite3TreeViewExprList(pView, p->pOrderBy, (n--)>0, "ORDERBY");
|
||||
}
|
||||
if( p->pLimit ){
|
||||
sqlite3TreeViewItem(pView, "LIMIT", (n--)>0);
|
||||
sqlite3TreeViewExpr(pView, p->pLimit, 0);
|
||||
sqlite3TreeViewPop(pView);
|
||||
}
|
||||
if( p->pOffset ){
|
||||
sqlite3TreeViewItem(pView, "OFFSET", (n--)>0);
|
||||
sqlite3TreeViewExpr(pView, p->pOffset, 0);
|
||||
sqlite3TreeViewPop(pView);
|
||||
}
|
||||
if( p->pPrior ){
|
||||
const char *zOp = "UNION";
|
||||
switch( p->op ){
|
||||
case TK_ALL: zOp = "UNION ALL"; break;
|
||||
case TK_INTERSECT: zOp = "INTERSECT"; break;
|
||||
case TK_EXCEPT: zOp = "EXCEPT"; break;
|
||||
}
|
||||
sqlite3TreeViewItem(pView, zOp, (n--)>0);
|
||||
sqlite3TreeViewSelect(pView, p->pPrior, 0);
|
||||
sqlite3TreeViewPop(pView);
|
||||
}
|
||||
sqlite3TreeViewPop(pView);
|
||||
}
|
||||
#endif /* SQLITE_DEBUG */
|
||||
|
62
src/shell.c
62
src/shell.c
@@ -101,28 +101,26 @@
|
||||
#if defined(_WIN32) || defined(WIN32)
|
||||
# include <io.h>
|
||||
# include <fcntl.h>
|
||||
#define isatty(h) _isatty(h)
|
||||
#ifndef access
|
||||
# define access(f,m) _access((f),(m))
|
||||
#endif
|
||||
#undef popen
|
||||
#define popen _popen
|
||||
#undef pclose
|
||||
#define pclose _pclose
|
||||
# define isatty(h) _isatty(h)
|
||||
# ifndef access
|
||||
# define access(f,m) _access((f),(m))
|
||||
# endif
|
||||
# undef popen
|
||||
# define popen _popen
|
||||
# undef pclose
|
||||
# define pclose _pclose
|
||||
#else
|
||||
/* Make sure isatty() has a prototype.
|
||||
*/
|
||||
extern int isatty(int);
|
||||
|
||||
#if !defined(__RTP__) && !defined(_WRS_KERNEL)
|
||||
/* popen and pclose are not C89 functions and so are sometimes omitted from
|
||||
** the <stdio.h> header */
|
||||
extern FILE *popen(const char*,const char*);
|
||||
extern int pclose(FILE*);
|
||||
#else
|
||||
# define SQLITE_OMIT_POPEN 1
|
||||
#endif
|
||||
/* Make sure isatty() has a prototype. */
|
||||
extern int isatty(int);
|
||||
|
||||
# if !defined(__RTP__) && !defined(_WRS_KERNEL)
|
||||
/* popen and pclose are not C89 functions and so are
|
||||
** sometimes omitted from the <stdio.h> header */
|
||||
extern FILE *popen(const char*,const char*);
|
||||
extern int pclose(FILE*);
|
||||
# else
|
||||
# define SQLITE_OMIT_POPEN 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32_WCE)
|
||||
@@ -1331,7 +1329,10 @@ static void display_scanstats(
|
||||
sqlite3 *db, /* Database to query */
|
||||
ShellState *pArg /* Pointer to ShellState */
|
||||
){
|
||||
#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
|
||||
#ifndef SQLITE_ENABLE_STMT_SCANSTATUS
|
||||
UNUSED_PARAMETER(db);
|
||||
UNUSED_PARAMETER(pArg);
|
||||
#else
|
||||
int i, k, n, mx;
|
||||
fprintf(pArg->out, "-------- scanstats --------\n");
|
||||
mx = 0;
|
||||
@@ -1866,6 +1867,7 @@ static void readfileFunc(
|
||||
long nIn;
|
||||
void *pBuf;
|
||||
|
||||
UNUSED_PARAMETER(argc);
|
||||
zName = (const char*)sqlite3_value_text(argv[0]);
|
||||
if( zName==0 ) return;
|
||||
in = fopen(zName, "rb");
|
||||
@@ -1898,6 +1900,7 @@ static void writefileFunc(
|
||||
sqlite3_int64 rc;
|
||||
const char *zFile;
|
||||
|
||||
UNUSED_PARAMETER(argc);
|
||||
zFile = (const char*)sqlite3_value_text(argv[0]);
|
||||
if( zFile==0 ) return;
|
||||
out = fopen(zFile, "wb");
|
||||
@@ -2577,7 +2580,7 @@ static int shell_dbinfo_command(ShellState *p, int nArg, char **azArg){
|
||||
fprintf(p->out, "%-20s %d\n", "write format:", aHdr[18]);
|
||||
fprintf(p->out, "%-20s %d\n", "read format:", aHdr[19]);
|
||||
fprintf(p->out, "%-20s %d\n", "reserved bytes:", aHdr[20]);
|
||||
for(i=0; i<sizeof(aField)/sizeof(aField[0]); i++){
|
||||
for(i=0; i<ArraySize(aField); i++){
|
||||
int ofst = aField[i].ofst;
|
||||
unsigned int val = get4byteInt(aHdr + ofst);
|
||||
fprintf(p->out, "%-20s %u", aField[i].zName, val);
|
||||
@@ -2597,7 +2600,7 @@ static int shell_dbinfo_command(ShellState *p, int nArg, char **azArg){
|
||||
}else{
|
||||
zSchemaTab = sqlite3_mprintf("\"%w\".sqlite_master", zDb);
|
||||
}
|
||||
for(i=0; i<sizeof(aQuery)/sizeof(aQuery[0]); i++){
|
||||
for(i=0; i<ArraySize(aQuery); i++){
|
||||
char *zSql = sqlite3_mprintf(aQuery[i].zSql, zSchemaTab);
|
||||
int val = db_int(p, zSql);
|
||||
sqlite3_free(zSql);
|
||||
@@ -3228,7 +3231,7 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
int i, n2;
|
||||
open_db(p, 0);
|
||||
if( nArg==1 ){
|
||||
for(i=0; i<sizeof(aLimit)/sizeof(aLimit[0]); i++){
|
||||
for(i=0; i<ArraySize(aLimit); i++){
|
||||
printf("%20s %d\n", aLimit[i].zLimitName,
|
||||
sqlite3_limit(p->db, aLimit[i].limitCode, -1));
|
||||
}
|
||||
@@ -3239,7 +3242,7 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
}else{
|
||||
int iLimit = -1;
|
||||
n2 = strlen30(azArg[1]);
|
||||
for(i=0; i<sizeof(aLimit)/sizeof(aLimit[0]); i++){
|
||||
for(i=0; i<ArraySize(aLimit); i++){
|
||||
if( sqlite3_strnicmp(aLimit[i].zLimitName, azArg[1], n2)==0 ){
|
||||
if( iLimit<0 ){
|
||||
iLimit = i;
|
||||
@@ -3349,9 +3352,8 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
const char *zSavedFilename = p->zDbFilename;
|
||||
char *zNewFilename = 0;
|
||||
p->db = 0;
|
||||
if( nArg>=2 ){
|
||||
p->zDbFilename = zNewFilename = sqlite3_mprintf("%s", azArg[1]);
|
||||
}
|
||||
if( nArg>=2 ) zNewFilename = sqlite3_mprintf("%s", azArg[1]);
|
||||
p->zDbFilename = zNewFilename;
|
||||
open_db(p, 1);
|
||||
if( p->db!=0 ){
|
||||
sqlite3_close(savedDb);
|
||||
@@ -3815,7 +3817,7 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
/* convert testctrl text option to value. allow any unique prefix
|
||||
** of the option name, or a numerical value. */
|
||||
n2 = strlen30(azArg[1]);
|
||||
for(i=0; i<(int)(sizeof(aCtrl)/sizeof(aCtrl[0])); i++){
|
||||
for(i=0; i<ArraySize(aCtrl); i++){
|
||||
if( strncmp(azArg[1], aCtrl[i].zCtrlName, n2)==0 ){
|
||||
if( testctrl<0 ){
|
||||
testctrl = aCtrl[i].ctrlCode;
|
||||
@@ -4792,7 +4794,7 @@ int SQLITE_CDECL main(int argc, char **argv){
|
||||
sqlite3_snprintf(nHistory, zHistory,"%s/.sqlite_history", zHome);
|
||||
}
|
||||
}
|
||||
if( zHistory ) shell_read_history(zHistory);
|
||||
if( zHistory ){ shell_read_history(zHistory); }
|
||||
rc = process_input(&data, 0);
|
||||
if( zHistory ){
|
||||
shell_stifle_history(100);
|
||||
|
@@ -23,7 +23,7 @@
|
||||
**
|
||||
** The official C-language API documentation for SQLite is derived
|
||||
** from comments in this file. This file is the authoritative source
|
||||
** on how SQLite interfaces are suppose to operate.
|
||||
** on how SQLite interfaces are supposed to operate.
|
||||
**
|
||||
** The name of this file under configuration management is "sqlite.h.in".
|
||||
** The makefile makes some minor changes to this file (such as inserting
|
||||
|
@@ -267,7 +267,8 @@ struct sqlite3_api_routines {
|
||||
void (*result_text64)(sqlite3_context*,const char*,sqlite3_uint64,
|
||||
void(*)(void*), unsigned char);
|
||||
int (*strglob)(const char*,const char*);
|
||||
sqlite3_value (*value_dup)(const sqlite3_value*);
|
||||
/* Version 3.8.11 and later */
|
||||
sqlite3_value *(*value_dup)(const sqlite3_value*);
|
||||
void (*value_free)(sqlite3_value*);
|
||||
};
|
||||
|
||||
|
@@ -2260,7 +2260,7 @@ struct SrcList {
|
||||
Expr *pOn; /* The ON clause of a join */
|
||||
IdList *pUsing; /* The USING clause of a join */
|
||||
Bitmask colUsed; /* Bit N (1<<N) set if column N of pTab is used */
|
||||
char *zIndex; /* Identifier from "INDEXED BY <zIndex>" clause */
|
||||
char *zIndexedBy; /* Identifier from "INDEXED BY <zIndex>" clause */
|
||||
Index *pIndex; /* Index structure corresponding to zIndex, if any */
|
||||
} a[1]; /* One entry for each identifier on the list */
|
||||
};
|
||||
@@ -3066,7 +3066,9 @@ int sqlite3CantopenError(int);
|
||||
# define sqlite3Isxdigit(x) isxdigit((unsigned char)(x))
|
||||
# define sqlite3Tolower(x) tolower((unsigned char)(x))
|
||||
#endif
|
||||
#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
|
||||
int sqlite3IsIdChar(u8);
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Internal function prototypes
|
||||
@@ -3094,7 +3096,9 @@ void sqlite3ScratchFree(void*);
|
||||
void *sqlite3PageMalloc(int);
|
||||
void sqlite3PageFree(void*);
|
||||
void sqlite3MemSetDefault(void);
|
||||
#ifndef SQLITE_OMIT_BUILTIN_TEST
|
||||
void sqlite3BenignMallocHooks(void (*)(void), void (*)(void));
|
||||
#endif
|
||||
int sqlite3HeapNearlyFull(void);
|
||||
|
||||
/*
|
||||
@@ -3170,10 +3174,6 @@ char *sqlite3VMPrintf(sqlite3*,const char*, va_list);
|
||||
#endif
|
||||
|
||||
#if defined(SQLITE_DEBUG)
|
||||
TreeView *sqlite3TreeViewPush(TreeView*,u8);
|
||||
void sqlite3TreeViewPop(TreeView*);
|
||||
void sqlite3TreeViewLine(TreeView*, const char*, ...);
|
||||
void sqlite3TreeViewItem(TreeView*, const char*, u8);
|
||||
void sqlite3TreeViewExpr(TreeView*, const Expr*, u8);
|
||||
void sqlite3TreeViewExprList(TreeView*, const ExprList*, u8, const char*);
|
||||
void sqlite3TreeViewSelect(TreeView*, const Select*, u8);
|
||||
@@ -3242,7 +3242,9 @@ int sqlite3BitvecSet(Bitvec*, u32);
|
||||
void sqlite3BitvecClear(Bitvec*, u32, void*);
|
||||
void sqlite3BitvecDestroy(Bitvec*);
|
||||
u32 sqlite3BitvecSize(Bitvec*);
|
||||
#ifndef SQLITE_OMIT_BUILTIN_TEST
|
||||
int sqlite3BitvecBuiltinTest(int,int*);
|
||||
#endif
|
||||
|
||||
RowSet *sqlite3RowSetInit(sqlite3*, void*, unsigned int);
|
||||
void sqlite3RowSetClear(RowSet*);
|
||||
@@ -3330,6 +3332,7 @@ int sqlite3ExprCodeExprList(Parse*, ExprList*, int, u8);
|
||||
#define SQLITE_ECEL_FACTOR 0x02 /* Factor out constant terms */
|
||||
void sqlite3ExprIfTrue(Parse*, Expr*, int, int);
|
||||
void sqlite3ExprIfFalse(Parse*, Expr*, int, int);
|
||||
void sqlite3ExprIfFalseDup(Parse*, Expr*, int, int);
|
||||
Table *sqlite3FindTable(sqlite3*,const char*, const char*);
|
||||
Table *sqlite3LocateTable(Parse*,int isView,const char*, const char*);
|
||||
Table *sqlite3LocateTableItem(Parse*,int isView,struct SrcList_item *);
|
||||
@@ -3346,8 +3349,10 @@ void sqlite3ExprAnalyzeAggregates(NameContext*, Expr*);
|
||||
void sqlite3ExprAnalyzeAggList(NameContext*,ExprList*);
|
||||
int sqlite3FunctionUsesThisSrc(Expr*, SrcList*);
|
||||
Vdbe *sqlite3GetVdbe(Parse*);
|
||||
#ifndef SQLITE_OMIT_BUILTIN_TEST
|
||||
void sqlite3PrngSaveState(void);
|
||||
void sqlite3PrngRestoreState(void);
|
||||
#endif
|
||||
void sqlite3RollbackAll(sqlite3*,int);
|
||||
void sqlite3CodeVerifySchema(Parse*, int);
|
||||
void sqlite3CodeVerifyNamedSchema(Parse*, const char *zDb);
|
||||
@@ -3565,6 +3570,7 @@ void sqlite3NestedParse(Parse*, const char*, ...);
|
||||
void sqlite3ExpirePreparedStatements(sqlite3*);
|
||||
int sqlite3CodeSubselect(Parse *, Expr *, int, int);
|
||||
void sqlite3SelectPrep(Parse*, Select*, NameContext*);
|
||||
void sqlite3SelectWrongNumTermsError(Parse *pParse, Select *p);
|
||||
int sqlite3MatchSpanName(const char*, const char*, const char*, const char*);
|
||||
int sqlite3ResolveExprNames(NameContext*, Expr*);
|
||||
void sqlite3ResolveSelectNames(Parse*, Select*, NameContext*);
|
||||
|
@@ -102,7 +102,11 @@ const char sqlite3IsEbcdicIdChar[] = {
|
||||
};
|
||||
#define IdChar(C) (((c=C)>=0x42 && sqlite3IsEbcdicIdChar[c-0x40]))
|
||||
#endif
|
||||
|
||||
/* Make the IdChar function accessible from ctime.c */
|
||||
#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
|
||||
int sqlite3IsIdChar(u8 c){ return IdChar(c); }
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
|
431
src/treeview.c
Normal file
431
src/treeview.c
Normal file
@@ -0,0 +1,431 @@
|
||||
/*
|
||||
** 2015-06-08
|
||||
**
|
||||
** 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 contains C code to implement the TreeView debugging routines.
|
||||
** These routines print a parse tree to standard output for debugging and
|
||||
** analysis.
|
||||
**
|
||||
** The interfaces in this file is only available when compiling
|
||||
** with SQLITE_DEBUG.
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#ifdef SQLITE_DEBUG
|
||||
|
||||
/*
|
||||
** Add a new subitem to the tree. The moreToFollow flag indicates that this
|
||||
** is not the last item in the tree.
|
||||
*/
|
||||
static TreeView *sqlite3TreeViewPush(TreeView *p, u8 moreToFollow){
|
||||
if( p==0 ){
|
||||
p = sqlite3_malloc64( sizeof(*p) );
|
||||
if( p==0 ) return 0;
|
||||
memset(p, 0, sizeof(*p));
|
||||
}else{
|
||||
p->iLevel++;
|
||||
}
|
||||
assert( moreToFollow==0 || moreToFollow==1 );
|
||||
if( p->iLevel<sizeof(p->bLine) ) p->bLine[p->iLevel] = moreToFollow;
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
** Finished with one layer of the tree
|
||||
*/
|
||||
static void sqlite3TreeViewPop(TreeView *p){
|
||||
if( p==0 ) return;
|
||||
p->iLevel--;
|
||||
if( p->iLevel<0 ) sqlite3_free(p);
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate a single line of output for the tree, with a prefix that contains
|
||||
** all the appropriate tree lines
|
||||
*/
|
||||
static void sqlite3TreeViewLine(TreeView *p, const char *zFormat, ...){
|
||||
va_list ap;
|
||||
int i;
|
||||
StrAccum acc;
|
||||
char zBuf[500];
|
||||
sqlite3StrAccumInit(&acc, 0, zBuf, sizeof(zBuf), 0);
|
||||
if( p ){
|
||||
for(i=0; i<p->iLevel && i<sizeof(p->bLine)-1; i++){
|
||||
sqlite3StrAccumAppend(&acc, p->bLine[i] ? "| " : " ", 4);
|
||||
}
|
||||
sqlite3StrAccumAppend(&acc, p->bLine[i] ? "|-- " : "'-- ", 4);
|
||||
}
|
||||
va_start(ap, zFormat);
|
||||
sqlite3VXPrintf(&acc, 0, zFormat, ap);
|
||||
va_end(ap);
|
||||
if( zBuf[acc.nChar-1]!='\n' ) sqlite3StrAccumAppend(&acc, "\n", 1);
|
||||
sqlite3StrAccumFinish(&acc);
|
||||
fprintf(stdout,"%s", zBuf);
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
/*
|
||||
** Shorthand for starting a new tree item that consists of a single label
|
||||
*/
|
||||
static void sqlite3TreeViewItem(TreeView *p, const char *zLabel,u8 moreFollows){
|
||||
p = sqlite3TreeViewPush(p, moreFollows);
|
||||
sqlite3TreeViewLine(p, "%s", zLabel);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Generate a human-readable description of a the Select object.
|
||||
*/
|
||||
void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 moreToFollow){
|
||||
int n = 0;
|
||||
pView = sqlite3TreeViewPush(pView, moreToFollow);
|
||||
sqlite3TreeViewLine(pView, "SELECT%s%s (0x%p) selFlags=0x%x",
|
||||
((p->selFlags & SF_Distinct) ? " DISTINCT" : ""),
|
||||
((p->selFlags & SF_Aggregate) ? " agg_flag" : ""), p, p->selFlags
|
||||
);
|
||||
if( p->pSrc && p->pSrc->nSrc ) n++;
|
||||
if( p->pWhere ) n++;
|
||||
if( p->pGroupBy ) n++;
|
||||
if( p->pHaving ) n++;
|
||||
if( p->pOrderBy ) n++;
|
||||
if( p->pLimit ) n++;
|
||||
if( p->pOffset ) n++;
|
||||
if( p->pPrior ) n++;
|
||||
sqlite3TreeViewExprList(pView, p->pEList, (n--)>0, "result-set");
|
||||
if( p->pSrc && p->pSrc->nSrc ){
|
||||
int i;
|
||||
pView = sqlite3TreeViewPush(pView, (n--)>0);
|
||||
sqlite3TreeViewLine(pView, "FROM");
|
||||
for(i=0; i<p->pSrc->nSrc; i++){
|
||||
struct SrcList_item *pItem = &p->pSrc->a[i];
|
||||
StrAccum x;
|
||||
char zLine[100];
|
||||
sqlite3StrAccumInit(&x, 0, zLine, sizeof(zLine), 0);
|
||||
sqlite3XPrintf(&x, 0, "{%d,*}", pItem->iCursor);
|
||||
if( pItem->zDatabase ){
|
||||
sqlite3XPrintf(&x, 0, " %s.%s", pItem->zDatabase, pItem->zName);
|
||||
}else if( pItem->zName ){
|
||||
sqlite3XPrintf(&x, 0, " %s", pItem->zName);
|
||||
}
|
||||
if( pItem->pTab ){
|
||||
sqlite3XPrintf(&x, 0, " tabname=%Q", pItem->pTab->zName);
|
||||
}
|
||||
if( pItem->zAlias ){
|
||||
sqlite3XPrintf(&x, 0, " (AS %s)", pItem->zAlias);
|
||||
}
|
||||
if( pItem->jointype & JT_LEFT ){
|
||||
sqlite3XPrintf(&x, 0, " LEFT-JOIN");
|
||||
}
|
||||
sqlite3StrAccumFinish(&x);
|
||||
sqlite3TreeViewItem(pView, zLine, i<p->pSrc->nSrc-1);
|
||||
if( pItem->pSelect ){
|
||||
sqlite3TreeViewSelect(pView, pItem->pSelect, 0);
|
||||
}
|
||||
sqlite3TreeViewPop(pView);
|
||||
}
|
||||
sqlite3TreeViewPop(pView);
|
||||
}
|
||||
if( p->pWhere ){
|
||||
sqlite3TreeViewItem(pView, "WHERE", (n--)>0);
|
||||
sqlite3TreeViewExpr(pView, p->pWhere, 0);
|
||||
sqlite3TreeViewPop(pView);
|
||||
}
|
||||
if( p->pGroupBy ){
|
||||
sqlite3TreeViewExprList(pView, p->pGroupBy, (n--)>0, "GROUPBY");
|
||||
}
|
||||
if( p->pHaving ){
|
||||
sqlite3TreeViewItem(pView, "HAVING", (n--)>0);
|
||||
sqlite3TreeViewExpr(pView, p->pHaving, 0);
|
||||
sqlite3TreeViewPop(pView);
|
||||
}
|
||||
if( p->pOrderBy ){
|
||||
sqlite3TreeViewExprList(pView, p->pOrderBy, (n--)>0, "ORDERBY");
|
||||
}
|
||||
if( p->pLimit ){
|
||||
sqlite3TreeViewItem(pView, "LIMIT", (n--)>0);
|
||||
sqlite3TreeViewExpr(pView, p->pLimit, 0);
|
||||
sqlite3TreeViewPop(pView);
|
||||
}
|
||||
if( p->pOffset ){
|
||||
sqlite3TreeViewItem(pView, "OFFSET", (n--)>0);
|
||||
sqlite3TreeViewExpr(pView, p->pOffset, 0);
|
||||
sqlite3TreeViewPop(pView);
|
||||
}
|
||||
if( p->pPrior ){
|
||||
const char *zOp = "UNION";
|
||||
switch( p->op ){
|
||||
case TK_ALL: zOp = "UNION ALL"; break;
|
||||
case TK_INTERSECT: zOp = "INTERSECT"; break;
|
||||
case TK_EXCEPT: zOp = "EXCEPT"; break;
|
||||
}
|
||||
sqlite3TreeViewItem(pView, zOp, (n--)>0);
|
||||
sqlite3TreeViewSelect(pView, p->pPrior, 0);
|
||||
sqlite3TreeViewPop(pView);
|
||||
}
|
||||
sqlite3TreeViewPop(pView);
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate a human-readable explanation of an expression tree.
|
||||
*/
|
||||
void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){
|
||||
const char *zBinOp = 0; /* Binary operator */
|
||||
const char *zUniOp = 0; /* Unary operator */
|
||||
char zFlgs[30];
|
||||
pView = sqlite3TreeViewPush(pView, moreToFollow);
|
||||
if( pExpr==0 ){
|
||||
sqlite3TreeViewLine(pView, "nil");
|
||||
sqlite3TreeViewPop(pView);
|
||||
return;
|
||||
}
|
||||
if( pExpr->flags ){
|
||||
sqlite3_snprintf(sizeof(zFlgs),zFlgs," flags=0x%x",pExpr->flags);
|
||||
}else{
|
||||
zFlgs[0] = 0;
|
||||
}
|
||||
switch( pExpr->op ){
|
||||
case TK_AGG_COLUMN: {
|
||||
sqlite3TreeViewLine(pView, "AGG{%d:%d}%s",
|
||||
pExpr->iTable, pExpr->iColumn, zFlgs);
|
||||
break;
|
||||
}
|
||||
case TK_COLUMN: {
|
||||
if( pExpr->iTable<0 ){
|
||||
/* This only happens when coding check constraints */
|
||||
sqlite3TreeViewLine(pView, "COLUMN(%d)%s", pExpr->iColumn, zFlgs);
|
||||
}else{
|
||||
sqlite3TreeViewLine(pView, "{%d:%d}%s",
|
||||
pExpr->iTable, pExpr->iColumn, zFlgs);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TK_INTEGER: {
|
||||
if( pExpr->flags & EP_IntValue ){
|
||||
sqlite3TreeViewLine(pView, "%d", pExpr->u.iValue);
|
||||
}else{
|
||||
sqlite3TreeViewLine(pView, "%s", pExpr->u.zToken);
|
||||
}
|
||||
break;
|
||||
}
|
||||
#ifndef SQLITE_OMIT_FLOATING_POINT
|
||||
case TK_FLOAT: {
|
||||
sqlite3TreeViewLine(pView,"%s", pExpr->u.zToken);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
case TK_STRING: {
|
||||
sqlite3TreeViewLine(pView,"%Q", pExpr->u.zToken);
|
||||
break;
|
||||
}
|
||||
case TK_NULL: {
|
||||
sqlite3TreeViewLine(pView,"NULL");
|
||||
break;
|
||||
}
|
||||
#ifndef SQLITE_OMIT_BLOB_LITERAL
|
||||
case TK_BLOB: {
|
||||
sqlite3TreeViewLine(pView,"%s", pExpr->u.zToken);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
case TK_VARIABLE: {
|
||||
sqlite3TreeViewLine(pView,"VARIABLE(%s,%d)",
|
||||
pExpr->u.zToken, pExpr->iColumn);
|
||||
break;
|
||||
}
|
||||
case TK_REGISTER: {
|
||||
sqlite3TreeViewLine(pView,"REGISTER(%d)", pExpr->iTable);
|
||||
break;
|
||||
}
|
||||
case TK_AS: {
|
||||
sqlite3TreeViewLine(pView,"AS %Q", pExpr->u.zToken);
|
||||
sqlite3TreeViewExpr(pView, pExpr->pLeft, 0);
|
||||
break;
|
||||
}
|
||||
case TK_ID: {
|
||||
sqlite3TreeViewLine(pView,"ID \"%w\"", pExpr->u.zToken);
|
||||
break;
|
||||
}
|
||||
#ifndef SQLITE_OMIT_CAST
|
||||
case TK_CAST: {
|
||||
/* Expressions of the form: CAST(pLeft AS token) */
|
||||
sqlite3TreeViewLine(pView,"CAST %Q", pExpr->u.zToken);
|
||||
sqlite3TreeViewExpr(pView, pExpr->pLeft, 0);
|
||||
break;
|
||||
}
|
||||
#endif /* SQLITE_OMIT_CAST */
|
||||
case TK_LT: zBinOp = "LT"; break;
|
||||
case TK_LE: zBinOp = "LE"; break;
|
||||
case TK_GT: zBinOp = "GT"; break;
|
||||
case TK_GE: zBinOp = "GE"; break;
|
||||
case TK_NE: zBinOp = "NE"; break;
|
||||
case TK_EQ: zBinOp = "EQ"; break;
|
||||
case TK_IS: zBinOp = "IS"; break;
|
||||
case TK_ISNOT: zBinOp = "ISNOT"; break;
|
||||
case TK_AND: zBinOp = "AND"; break;
|
||||
case TK_OR: zBinOp = "OR"; break;
|
||||
case TK_PLUS: zBinOp = "ADD"; break;
|
||||
case TK_STAR: zBinOp = "MUL"; break;
|
||||
case TK_MINUS: zBinOp = "SUB"; break;
|
||||
case TK_REM: zBinOp = "REM"; break;
|
||||
case TK_BITAND: zBinOp = "BITAND"; break;
|
||||
case TK_BITOR: zBinOp = "BITOR"; break;
|
||||
case TK_SLASH: zBinOp = "DIV"; break;
|
||||
case TK_LSHIFT: zBinOp = "LSHIFT"; break;
|
||||
case TK_RSHIFT: zBinOp = "RSHIFT"; break;
|
||||
case TK_CONCAT: zBinOp = "CONCAT"; break;
|
||||
case TK_DOT: zBinOp = "DOT"; break;
|
||||
|
||||
case TK_UMINUS: zUniOp = "UMINUS"; break;
|
||||
case TK_UPLUS: zUniOp = "UPLUS"; break;
|
||||
case TK_BITNOT: zUniOp = "BITNOT"; break;
|
||||
case TK_NOT: zUniOp = "NOT"; break;
|
||||
case TK_ISNULL: zUniOp = "ISNULL"; break;
|
||||
case TK_NOTNULL: zUniOp = "NOTNULL"; break;
|
||||
|
||||
case TK_COLLATE: {
|
||||
sqlite3TreeViewLine(pView, "COLLATE %Q", pExpr->u.zToken);
|
||||
sqlite3TreeViewExpr(pView, pExpr->pLeft, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
case TK_AGG_FUNCTION:
|
||||
case TK_FUNCTION: {
|
||||
ExprList *pFarg; /* List of function arguments */
|
||||
if( ExprHasProperty(pExpr, EP_TokenOnly) ){
|
||||
pFarg = 0;
|
||||
}else{
|
||||
pFarg = pExpr->x.pList;
|
||||
}
|
||||
if( pExpr->op==TK_AGG_FUNCTION ){
|
||||
sqlite3TreeViewLine(pView, "AGG_FUNCTION%d %Q",
|
||||
pExpr->op2, pExpr->u.zToken);
|
||||
}else{
|
||||
sqlite3TreeViewLine(pView, "FUNCTION %Q", pExpr->u.zToken);
|
||||
}
|
||||
if( pFarg ){
|
||||
sqlite3TreeViewExprList(pView, pFarg, 0, 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
#ifndef SQLITE_OMIT_SUBQUERY
|
||||
case TK_EXISTS: {
|
||||
sqlite3TreeViewLine(pView, "EXISTS-expr");
|
||||
sqlite3TreeViewSelect(pView, pExpr->x.pSelect, 0);
|
||||
break;
|
||||
}
|
||||
case TK_SELECT: {
|
||||
sqlite3TreeViewLine(pView, "SELECT-expr");
|
||||
sqlite3TreeViewSelect(pView, pExpr->x.pSelect, 0);
|
||||
break;
|
||||
}
|
||||
case TK_IN: {
|
||||
sqlite3TreeViewLine(pView, "IN");
|
||||
sqlite3TreeViewExpr(pView, pExpr->pLeft, 1);
|
||||
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
|
||||
sqlite3TreeViewSelect(pView, pExpr->x.pSelect, 0);
|
||||
}else{
|
||||
sqlite3TreeViewExprList(pView, pExpr->x.pList, 0, 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif /* SQLITE_OMIT_SUBQUERY */
|
||||
|
||||
/*
|
||||
** x BETWEEN y AND z
|
||||
**
|
||||
** This is equivalent to
|
||||
**
|
||||
** x>=y AND x<=z
|
||||
**
|
||||
** X is stored in pExpr->pLeft.
|
||||
** Y is stored in pExpr->pList->a[0].pExpr.
|
||||
** Z is stored in pExpr->pList->a[1].pExpr.
|
||||
*/
|
||||
case TK_BETWEEN: {
|
||||
Expr *pX = pExpr->pLeft;
|
||||
Expr *pY = pExpr->x.pList->a[0].pExpr;
|
||||
Expr *pZ = pExpr->x.pList->a[1].pExpr;
|
||||
sqlite3TreeViewLine(pView, "BETWEEN");
|
||||
sqlite3TreeViewExpr(pView, pX, 1);
|
||||
sqlite3TreeViewExpr(pView, pY, 1);
|
||||
sqlite3TreeViewExpr(pView, pZ, 0);
|
||||
break;
|
||||
}
|
||||
case TK_TRIGGER: {
|
||||
/* If the opcode is TK_TRIGGER, then the expression is a reference
|
||||
** to a column in the new.* or old.* pseudo-tables available to
|
||||
** trigger programs. In this case Expr.iTable is set to 1 for the
|
||||
** new.* pseudo-table, or 0 for the old.* pseudo-table. Expr.iColumn
|
||||
** is set to the column of the pseudo-table to read, or to -1 to
|
||||
** read the rowid field.
|
||||
*/
|
||||
sqlite3TreeViewLine(pView, "%s(%d)",
|
||||
pExpr->iTable ? "NEW" : "OLD", pExpr->iColumn);
|
||||
break;
|
||||
}
|
||||
case TK_CASE: {
|
||||
sqlite3TreeViewLine(pView, "CASE");
|
||||
sqlite3TreeViewExpr(pView, pExpr->pLeft, 1);
|
||||
sqlite3TreeViewExprList(pView, pExpr->x.pList, 0, 0);
|
||||
break;
|
||||
}
|
||||
#ifndef SQLITE_OMIT_TRIGGER
|
||||
case TK_RAISE: {
|
||||
const char *zType = "unk";
|
||||
switch( pExpr->affinity ){
|
||||
case OE_Rollback: zType = "rollback"; break;
|
||||
case OE_Abort: zType = "abort"; break;
|
||||
case OE_Fail: zType = "fail"; break;
|
||||
case OE_Ignore: zType = "ignore"; break;
|
||||
}
|
||||
sqlite3TreeViewLine(pView, "RAISE %s(%Q)", zType, pExpr->u.zToken);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
default: {
|
||||
sqlite3TreeViewLine(pView, "op=%d", pExpr->op);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( zBinOp ){
|
||||
sqlite3TreeViewLine(pView, "%s%s", zBinOp, zFlgs);
|
||||
sqlite3TreeViewExpr(pView, pExpr->pLeft, 1);
|
||||
sqlite3TreeViewExpr(pView, pExpr->pRight, 0);
|
||||
}else if( zUniOp ){
|
||||
sqlite3TreeViewLine(pView, "%s%s", zUniOp, zFlgs);
|
||||
sqlite3TreeViewExpr(pView, pExpr->pLeft, 0);
|
||||
}
|
||||
sqlite3TreeViewPop(pView);
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate a human-readable explanation of an expression list.
|
||||
*/
|
||||
void sqlite3TreeViewExprList(
|
||||
TreeView *pView,
|
||||
const ExprList *pList,
|
||||
u8 moreToFollow,
|
||||
const char *zLabel
|
||||
){
|
||||
int i;
|
||||
pView = sqlite3TreeViewPush(pView, moreToFollow);
|
||||
if( zLabel==0 || zLabel[0]==0 ) zLabel = "LIST";
|
||||
if( pList==0 ){
|
||||
sqlite3TreeViewLine(pView, "%s (empty)", zLabel);
|
||||
}else{
|
||||
sqlite3TreeViewLine(pView, "%s", zLabel);
|
||||
for(i=0; i<pList->nExpr; i++){
|
||||
sqlite3TreeViewExpr(pView, pList->a[i].pExpr, i<pList->nExpr-1);
|
||||
}
|
||||
}
|
||||
sqlite3TreeViewPop(pView);
|
||||
}
|
||||
|
||||
#endif /* SQLITE_DEBUG */
|
20
src/vdbe.c
20
src/vdbe.c
@@ -3511,6 +3511,26 @@ case OP_Close: {
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef SQLITE_ENABLE_COLUMN_USED_MASK
|
||||
/* Opcode: ColumnsUsed P1 * * P4 *
|
||||
**
|
||||
** This opcode (which only exists if SQLite was compiled with
|
||||
** SQLITE_ENABLE_COLUMN_USED_MASK) identifies which columns of the
|
||||
** table or index for cursor P1 are used. P4 is a 64-bit integer
|
||||
** (P4_INT64) in which the first 63 bits are one for each of the
|
||||
** first 63 columns of the table or index that are actually used
|
||||
** by the cursor. The high-order bit is set if any column after
|
||||
** the 64th is used.
|
||||
*/
|
||||
case OP_ColumnsUsed: {
|
||||
VdbeCursor *pC;
|
||||
pC = p->apCsr[pOp->p1];
|
||||
assert( pC->pCursor );
|
||||
pC->maskUsed = *(u64*)pOp->p4.pI64;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Opcode: SeekGE P1 P2 P3 P4 *
|
||||
** Synopsis: key=r[P3@P4]
|
||||
**
|
||||
|
@@ -169,6 +169,7 @@ int sqlite3VdbeAddOp1(Vdbe*,int,int);
|
||||
int sqlite3VdbeAddOp2(Vdbe*,int,int,int);
|
||||
int sqlite3VdbeAddOp3(Vdbe*,int,int,int,int);
|
||||
int sqlite3VdbeAddOp4(Vdbe*,int,int,int,int,const char *zP4,int);
|
||||
int sqlite3VdbeAddOp4Dup8(Vdbe*,int,int,int,int,const u8*,int);
|
||||
int sqlite3VdbeAddOp4Int(Vdbe*,int,int,int,int,int);
|
||||
int sqlite3VdbeAddOpList(Vdbe*, int nOp, VdbeOpList const *aOp, int iLineno);
|
||||
void sqlite3VdbeAddParseSchemaOp(Vdbe*,int,char*);
|
||||
|
@@ -83,6 +83,9 @@ struct VdbeCursor {
|
||||
i64 seqCount; /* Sequence counter */
|
||||
i64 movetoTarget; /* Argument to the deferred sqlite3BtreeMoveto() */
|
||||
VdbeSorter *pSorter; /* Sorter object for OP_SorterOpen cursors */
|
||||
#ifdef SQLITE_ENABLE_COLUMN_USED_MASK
|
||||
u64 maskUsed; /* Mask of columns used by this cursor */
|
||||
#endif
|
||||
|
||||
/* Cached information about the header for the data record that the
|
||||
** cursor is currently pointing to. Only valid if cacheStatus matches
|
||||
|
@@ -233,6 +233,23 @@ int sqlite3VdbeAddOp4(
|
||||
return addr;
|
||||
}
|
||||
|
||||
/*
|
||||
** Add an opcode that includes the p4 value with a P4_INT64 type.
|
||||
*/
|
||||
int sqlite3VdbeAddOp4Dup8(
|
||||
Vdbe *p, /* Add the opcode to this VM */
|
||||
int op, /* The new opcode */
|
||||
int p1, /* The P1 operand */
|
||||
int p2, /* The P2 operand */
|
||||
int p3, /* The P3 operand */
|
||||
const u8 *zP4, /* The P4 operand */
|
||||
int p4type /* P4 operand type */
|
||||
){
|
||||
char *p4copy = sqlite3DbMallocRaw(sqlite3VdbeDb(p), 8);
|
||||
if( p4copy ) memcpy(p4copy, zP4, 8);
|
||||
return sqlite3VdbeAddOp4(p, op, p1, p2, p3, p4copy, p4type);
|
||||
}
|
||||
|
||||
/*
|
||||
** Add an OP_ParseSchema opcode. This routine is broken out from
|
||||
** sqlite3VdbeAddOp4() since it needs to also needs to mark all btrees
|
||||
@@ -397,6 +414,7 @@ static Op *opIterNext(VdbeOpIter *p){
|
||||
** * OP_VUpdate
|
||||
** * OP_VRename
|
||||
** * OP_FkCounter with P2==0 (immediate foreign key constraint)
|
||||
** * OP_CreateTable and OP_InitCoroutine (for CREATE TABLE AS SELECT ...)
|
||||
**
|
||||
** Then check that the value of Parse.mayAbort is true if an
|
||||
** ABORT may be thrown, or false otherwise. Return true if it does
|
||||
@@ -408,6 +426,8 @@ static Op *opIterNext(VdbeOpIter *p){
|
||||
int sqlite3VdbeAssertMayAbort(Vdbe *v, int mayAbort){
|
||||
int hasAbort = 0;
|
||||
int hasFkCounter = 0;
|
||||
int hasCreateTable = 0;
|
||||
int hasInitCoroutine = 0;
|
||||
Op *pOp;
|
||||
VdbeOpIter sIter;
|
||||
memset(&sIter, 0, sizeof(sIter));
|
||||
@@ -422,6 +442,8 @@ int sqlite3VdbeAssertMayAbort(Vdbe *v, int mayAbort){
|
||||
hasAbort = 1;
|
||||
break;
|
||||
}
|
||||
if( opcode==OP_CreateTable ) hasCreateTable = 1;
|
||||
if( opcode==OP_InitCoroutine ) hasInitCoroutine = 1;
|
||||
#ifndef SQLITE_OMIT_FOREIGN_KEY
|
||||
if( opcode==OP_FkCounter && pOp->p1==0 && pOp->p2==1 ){
|
||||
hasFkCounter = 1;
|
||||
@@ -435,7 +457,8 @@ int sqlite3VdbeAssertMayAbort(Vdbe *v, int mayAbort){
|
||||
** through all opcodes and hasAbort may be set incorrectly. Return
|
||||
** true for this case to prevent the assert() in the callers frame
|
||||
** from failing. */
|
||||
return ( v->db->mallocFailed || hasAbort==mayAbort || hasFkCounter );
|
||||
return ( v->db->mallocFailed || hasAbort==mayAbort || hasFkCounter
|
||||
|| (hasCreateTable && hasInitCoroutine) );
|
||||
}
|
||||
#endif /* SQLITE_DEBUG - the sqlite3AssertMayAbort() function */
|
||||
|
||||
@@ -1218,12 +1241,11 @@ void sqlite3VdbeEnter(Vdbe *p){
|
||||
/*
|
||||
** Unlock all of the btrees previously locked by a call to sqlite3VdbeEnter().
|
||||
*/
|
||||
void sqlite3VdbeLeave(Vdbe *p){
|
||||
static SQLITE_NOINLINE void vdbeLeave(Vdbe *p){
|
||||
int i;
|
||||
sqlite3 *db;
|
||||
Db *aDb;
|
||||
int nDb;
|
||||
if( DbMaskAllZero(p->lockMask) ) return; /* The common case */
|
||||
db = p->db;
|
||||
aDb = db->aDb;
|
||||
nDb = db->nDb;
|
||||
@@ -1233,6 +1255,10 @@ void sqlite3VdbeLeave(Vdbe *p){
|
||||
}
|
||||
}
|
||||
}
|
||||
void sqlite3VdbeLeave(Vdbe *p){
|
||||
if( DbMaskAllZero(p->lockMask) ) return; /* The common case */
|
||||
vdbeLeave(p);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(VDBE_PROFILE) || defined(SQLITE_DEBUG)
|
||||
|
@@ -777,10 +777,15 @@ void sqlite3VdbeMemAboutToChange(Vdbe *pVdbe, Mem *pMem){
|
||||
** pFrom->z is used, then pTo->z points to the same thing as pFrom->z
|
||||
** and flags gets srcType (either MEM_Ephem or MEM_Static).
|
||||
*/
|
||||
static SQLITE_NOINLINE void vdbeClrCopy(Mem *pTo, const Mem *pFrom, int eType){
|
||||
vdbeMemClearExternAndSetNull(pTo);
|
||||
assert( !VdbeMemDynamic(pTo) );
|
||||
sqlite3VdbeMemShallowCopy(pTo, pFrom, eType);
|
||||
}
|
||||
void sqlite3VdbeMemShallowCopy(Mem *pTo, const Mem *pFrom, int srcType){
|
||||
assert( (pFrom->flags & MEM_RowSet)==0 );
|
||||
assert( pTo->db==pFrom->db );
|
||||
if( VdbeMemDynamic(pTo) ) vdbeMemClearExternAndSetNull(pTo);
|
||||
if( VdbeMemDynamic(pTo) ){ vdbeClrCopy(pTo,pFrom,srcType); return; }
|
||||
memcpy(pTo, pFrom, MEMCELLSIZE);
|
||||
if( (pFrom->flags&MEM_Static)==0 ){
|
||||
pTo->flags &= ~(MEM_Dyn|MEM_Static|MEM_Ephem);
|
||||
@@ -946,6 +951,32 @@ int sqlite3VdbeMemSetStr(
|
||||
** If this routine fails for any reason (malloc returns NULL or unable
|
||||
** to read from the disk) then the pMem is left in an inconsistent state.
|
||||
*/
|
||||
static SQLITE_NOINLINE int vdbeMemFromBtreeResize(
|
||||
BtCursor *pCur, /* Cursor pointing at record to retrieve. */
|
||||
u32 offset, /* Offset from the start of data to return bytes from. */
|
||||
u32 amt, /* Number of bytes to return. */
|
||||
int key, /* If true, retrieve from the btree key, not data. */
|
||||
Mem *pMem /* OUT: Return data in this Mem structure. */
|
||||
){
|
||||
int rc;
|
||||
pMem->flags = MEM_Null;
|
||||
if( SQLITE_OK==(rc = sqlite3VdbeMemClearAndResize(pMem, amt+2)) ){
|
||||
if( key ){
|
||||
rc = sqlite3BtreeKey(pCur, offset, amt, pMem->z);
|
||||
}else{
|
||||
rc = sqlite3BtreeData(pCur, offset, amt, pMem->z);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
pMem->z[amt] = 0;
|
||||
pMem->z[amt+1] = 0;
|
||||
pMem->flags = MEM_Blob|MEM_Term;
|
||||
pMem->n = (int)amt;
|
||||
}else{
|
||||
sqlite3VdbeMemRelease(pMem);
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
int sqlite3VdbeMemFromBtree(
|
||||
BtCursor *pCur, /* Cursor pointing at record to retrieve. */
|
||||
u32 offset, /* Offset from the start of data to return bytes from. */
|
||||
@@ -975,22 +1006,7 @@ int sqlite3VdbeMemFromBtree(
|
||||
pMem->flags = MEM_Blob|MEM_Ephem;
|
||||
pMem->n = (int)amt;
|
||||
}else{
|
||||
pMem->flags = MEM_Null;
|
||||
if( SQLITE_OK==(rc = sqlite3VdbeMemClearAndResize(pMem, amt+2)) ){
|
||||
if( key ){
|
||||
rc = sqlite3BtreeKey(pCur, offset, amt, pMem->z);
|
||||
}else{
|
||||
rc = sqlite3BtreeData(pCur, offset, amt, pMem->z);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
pMem->z[amt] = 0;
|
||||
pMem->z[amt+1] = 0;
|
||||
pMem->flags = MEM_Blob|MEM_Term;
|
||||
pMem->n = (int)amt;
|
||||
}else{
|
||||
sqlite3VdbeMemRelease(pMem);
|
||||
}
|
||||
}
|
||||
rc = vdbeMemFromBtreeResize(pCur, offset, amt, key, pMem);
|
||||
}
|
||||
|
||||
return rc;
|
||||
|
2870
src/where.c
2870
src/where.c
File diff suppressed because it is too large
Load Diff
@@ -19,7 +19,7 @@
|
||||
** Trace output macros
|
||||
*/
|
||||
#if defined(SQLITE_TEST) || defined(SQLITE_DEBUG)
|
||||
/***/ int sqlite3WhereTrace = 0;
|
||||
/***/ int sqlite3WhereTrace;
|
||||
#endif
|
||||
#if defined(SQLITE_DEBUG) \
|
||||
&& (defined(SQLITE_TEST) || defined(SQLITE_ENABLE_WHERETRACE))
|
||||
@@ -161,10 +161,6 @@ struct WhereOrSet {
|
||||
WhereOrCost a[N_OR_COST]; /* Set of best costs */
|
||||
};
|
||||
|
||||
|
||||
/* Forward declaration of methods */
|
||||
static int whereLoopResize(sqlite3*, WhereLoop*, int);
|
||||
|
||||
/*
|
||||
** Each instance of this object holds a sequence of WhereLoop objects
|
||||
** that implement some or all of a query plan.
|
||||
@@ -372,6 +368,11 @@ struct WhereMaskSet {
|
||||
int ix[BMS]; /* Cursor assigned to each bit */
|
||||
};
|
||||
|
||||
/*
|
||||
** Initialize a WhereMaskSet object
|
||||
*/
|
||||
#define initMaskSet(P) (P)->n=0
|
||||
|
||||
/*
|
||||
** This object is a convenience wrapper holding all information needed
|
||||
** to construct WhereLoop objects for a particular query.
|
||||
@@ -423,6 +424,62 @@ struct WhereInfo {
|
||||
WhereLevel a[1]; /* Information about each nest loop in WHERE */
|
||||
};
|
||||
|
||||
/*
|
||||
** Private interfaces - callable only by other where.c routines.
|
||||
**
|
||||
** where.c:
|
||||
*/
|
||||
Bitmask sqlite3WhereGetMask(WhereMaskSet*,int);
|
||||
WhereTerm *sqlite3WhereFindTerm(
|
||||
WhereClause *pWC, /* The WHERE clause to be searched */
|
||||
int iCur, /* Cursor number of LHS */
|
||||
int iColumn, /* Column number of LHS */
|
||||
Bitmask notReady, /* RHS must not overlap with this mask */
|
||||
u32 op, /* Mask of WO_xx values describing operator */
|
||||
Index *pIdx /* Must be compatible with this index, if not NULL */
|
||||
);
|
||||
|
||||
/* wherecode.c: */
|
||||
#ifndef SQLITE_OMIT_EXPLAIN
|
||||
int sqlite3WhereExplainOneScan(
|
||||
Parse *pParse, /* Parse context */
|
||||
SrcList *pTabList, /* Table list this loop refers to */
|
||||
WhereLevel *pLevel, /* Scan to write OP_Explain opcode for */
|
||||
int iLevel, /* Value for "level" column of output */
|
||||
int iFrom, /* Value for "from" column of output */
|
||||
u16 wctrlFlags /* Flags passed to sqlite3WhereBegin() */
|
||||
);
|
||||
#else
|
||||
# define sqlite3WhereExplainOneScan(u,v,w,x,y,z) 0
|
||||
#endif /* SQLITE_OMIT_EXPLAIN */
|
||||
#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
|
||||
void sqlite3WhereAddScanStatus(
|
||||
Vdbe *v, /* Vdbe to add scanstatus entry to */
|
||||
SrcList *pSrclist, /* FROM clause pLvl reads data from */
|
||||
WhereLevel *pLvl, /* Level to add scanstatus() entry for */
|
||||
int addrExplain /* Address of OP_Explain (or 0) */
|
||||
);
|
||||
#else
|
||||
# define sqlite3WhereAddScanStatus(a, b, c, d) ((void)d)
|
||||
#endif
|
||||
Bitmask sqlite3WhereCodeOneLoopStart(
|
||||
WhereInfo *pWInfo, /* Complete information about the WHERE clause */
|
||||
int iLevel, /* Which level of pWInfo->a[] should be coded */
|
||||
Bitmask notReady /* Which tables are currently available */
|
||||
);
|
||||
|
||||
/* whereexpr.c: */
|
||||
void sqlite3WhereClauseInit(WhereClause*,WhereInfo*);
|
||||
void sqlite3WhereClauseClear(WhereClause*);
|
||||
void sqlite3WhereSplit(WhereClause*,Expr*,u8);
|
||||
Bitmask sqlite3WhereExprUsage(WhereMaskSet*, Expr*);
|
||||
Bitmask sqlite3WhereExprListUsage(WhereMaskSet*, ExprList*);
|
||||
void sqlite3WhereExprAnalyze(SrcList*, WhereClause*);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
** Bitmasks for the operators on WhereTerm objects. These are all
|
||||
** operators that are of interest to the query planner. An
|
||||
|
1501
src/wherecode.c
Normal file
1501
src/wherecode.c
Normal file
File diff suppressed because it is too large
Load Diff
1249
src/whereexpr.c
Normal file
1249
src/whereexpr.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -24,6 +24,11 @@ if {$tcl_platform(platform)=="windows"} {
|
||||
} else {
|
||||
set PROG "./sqlite3_analyzer"
|
||||
}
|
||||
if {![file exe $PROG]} {
|
||||
puts "analyzer1 cannot run because $PROG is not available"
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
db close
|
||||
forcedelete test.db test.db-journal test.db-wal
|
||||
sqlite3 db test.db
|
||||
|
@@ -204,7 +204,7 @@ do_execsql_test 6.0 {
|
||||
} {}
|
||||
do_test 6.1 {
|
||||
db close
|
||||
hexio_write test.db 616 EAFFFFFF0202
|
||||
hexio_write test.db 616 8FFFFFFF7F02
|
||||
sqlite3 db test.db
|
||||
breakpoint
|
||||
execsql { DELETE FROM t1 WHERE rowid=2 }
|
||||
|
@@ -171,7 +171,6 @@ foreach {tn code} {
|
||||
#
|
||||
set ::busy_callback_count 0
|
||||
proc busy_callback {args} {
|
||||
puts Hello
|
||||
incr ::busy_callback_count
|
||||
return 0
|
||||
}
|
||||
|
16
test/extraquick.test
Normal file
16
test/extraquick.test
Normal file
@@ -0,0 +1,16 @@
|
||||
#
|
||||
# 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 runs most of the tests run by veryquick.test except for those
|
||||
# that take a long time.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/permutations.test
|
||||
|
||||
run_test_suite extraquick
|
||||
|
||||
finish_test
|
@@ -39,7 +39,6 @@ do_test filectrl-1.5 {
|
||||
do_test filectrl-1.6 {
|
||||
sqlite3 db test.db
|
||||
set fn [file_control_tempfilename db]
|
||||
puts -nonewline \[$fn\]
|
||||
set fn
|
||||
} {/etilqs_/}
|
||||
db close
|
||||
|
@@ -213,7 +213,7 @@ do_test fts3d-4.matches {
|
||||
{0 1 0 4 0 2 5 3 0 3 9 1 0 5 11 4} \
|
||||
{0 0 0 4 0 4 5 2 0 3 8 1 0 5 10 4}]
|
||||
|
||||
puts [db eval {SELECT c FROM t1 } ]
|
||||
db eval {SELECT c FROM t1 }
|
||||
check_terms_all fts3d-4.1 {a four is test that this was}
|
||||
check_doclist_all fts3d-4.1.1 a {[1 0[2]] [2 0[2]] [3 0[2]]}
|
||||
check_doclist_all fts3d-4.1.2 four {}
|
||||
|
@@ -47,7 +47,9 @@ foreach {tn q res} {
|
||||
do_execsql_test 2.$tn.$s $q $res
|
||||
set t($s) [lindex [time [list execsql $q] 100] 0]
|
||||
}
|
||||
puts "with optimization: $t(0) without: $t(1)"
|
||||
if {0} {
|
||||
puts "with optimization: $t(0) without: $t(1)"
|
||||
}
|
||||
}
|
||||
|
||||
do_test 2.1 {
|
||||
|
@@ -362,11 +362,17 @@ ifcapable icu { lappend tokenizers icu }
|
||||
# Some tests to check that the tokenizers can both identify white-space
|
||||
# codepoints. All codepoints tested below are of type "Zs" in the
|
||||
# UnicodeData.txt file.
|
||||
#
|
||||
# Note that codepoint 6158 has changed from Zs to Cf in recent versions
|
||||
# of UnicodeData.txt. So take that into account for the "icu" tests.
|
||||
#
|
||||
foreach T $tokenizers {
|
||||
do_isspace_test 6.$T.1 $T 32
|
||||
do_isspace_test 6.$T.2 $T 160
|
||||
do_isspace_test 6.$T.3 $T 5760
|
||||
do_isspace_test 6.$T.4 $T 6158
|
||||
if {$T!="icu"} {
|
||||
do_isspace_test 6.$T.4 $T 6158
|
||||
}
|
||||
do_isspace_test 6.$T.5 $T 8192
|
||||
do_isspace_test 6.$T.6 $T 8193
|
||||
do_isspace_test 6.$T.7 $T 8194
|
||||
@@ -382,7 +388,11 @@ foreach T $tokenizers {
|
||||
do_isspace_test 6.$T.17 $T 8287
|
||||
do_isspace_test 6.$T.18 $T 12288
|
||||
|
||||
do_isspace_test 6.$T.19 $T {32 160 5760 6158}
|
||||
if {$T!="icu"} {
|
||||
do_isspace_test 6.$T.19 $T {32 160 5760 6158}
|
||||
} else {
|
||||
do_isspace_test 6.$T.19 $T {32 160 5760 8192}
|
||||
}
|
||||
do_isspace_test 6.$T.20 $T {8192 8193 8194 8195}
|
||||
do_isspace_test 6.$T.21 $T {8196 8197 8198 8199}
|
||||
do_isspace_test 6.$T.22 $T {8200 8201 8202 8239}
|
||||
|
@@ -10,8 +10,8 @@
|
||||
**
|
||||
*************************************************************************
|
||||
**
|
||||
** This is a utility program designed to aid running regressions tests
|
||||
** on SQLite library using data from an external fuzzer, such as American
|
||||
** This is a utility program designed to aid running regressions tests on
|
||||
** the SQLite library using data from an external fuzzer, such as American
|
||||
** Fuzzy Lop (AFL) (http://lcamtuf.coredump.cx/afl/).
|
||||
**
|
||||
** This program reads content from an SQLite database file with the following
|
||||
@@ -25,16 +25,44 @@
|
||||
** sqlid INTEGER PRIMARY KEY, -- SQL script id
|
||||
** sqltext TEXT -- Text of SQL statements to run
|
||||
** );
|
||||
** CREATE TABLE IF NOT EXISTS readme(
|
||||
** msg TEXT -- Human-readable description of this test collection
|
||||
** );
|
||||
**
|
||||
** For each database file in the DB table, the SQL text in the XSQL table
|
||||
** is run against that database. This program is looking for crashes,
|
||||
** assertion faults, and/or memory leaks. No attempt is made to verify
|
||||
** the output. The assumption is that either all of the database files
|
||||
** or all of the SQL statements are malformed inputs, generated by a fuzzer,
|
||||
** that need to be checked to make sure they do not present a security risk.
|
||||
** is run against that database. All README.MSG values are printed prior
|
||||
** to the start of the test (unless the --quiet option is used). If the
|
||||
** DB table is empty, then all entries in XSQL are run against an empty
|
||||
** in-memory database.
|
||||
**
|
||||
** This program is looking for crashes, assertion faults, and/or memory leaks.
|
||||
** No attempt is made to verify the output. The assumption is that either all
|
||||
** of the database files or all of the SQL statements are malformed inputs,
|
||||
** generated by a fuzzer, that need to be checked to make sure they do not
|
||||
** present a security risk.
|
||||
**
|
||||
** This program also includes some command-line options to help with
|
||||
** creation and maintenance of the source content database.
|
||||
** creation and maintenance of the source content database. The command
|
||||
**
|
||||
** ./fuzzcheck database.db --load-sql FILE...
|
||||
**
|
||||
** Loads all FILE... arguments into the XSQL table. The --load-db option
|
||||
** works the same but loads the files into the DB table. The -m option can
|
||||
** be used to initialize the README table. The "database.db" file is created
|
||||
** if it does not previously exist. Example:
|
||||
**
|
||||
** ./fuzzcheck new.db --load-sql *.sql
|
||||
** ./fuzzcheck new.db --load-db *.db
|
||||
** ./fuzzcheck new.db -m 'New test cases'
|
||||
**
|
||||
** The three commands above will create the "new.db" file and initialize all
|
||||
** tables. Then do "./fuzzcheck new.db" to run the tests.
|
||||
**
|
||||
** DEBUGGING HINTS:
|
||||
**
|
||||
** If fuzzcheck does crash, it can be run in the debugger and the content
|
||||
** of the global variable g.zTextName[] will identify the specific XSQL and
|
||||
** DB values that were running when the crash occurred.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
Binary file not shown.
Binary file not shown.
20
test/in.test
20
test/in.test
@@ -450,28 +450,42 @@ do_test in-12.10 {
|
||||
SELECT a FROM t3 UNION ALL SELECT a, b FROM t2
|
||||
);
|
||||
}
|
||||
} {1 {only a single result allowed for a SELECT that is part of an expression}}
|
||||
} {1 {SELECTs to the left and right of UNION ALL do not have the same number of result columns}}
|
||||
do_test in-12.11 {
|
||||
catchsql {
|
||||
SELECT * FROM t2 WHERE a IN (
|
||||
SELECT a FROM t3 UNION SELECT a, b FROM t2
|
||||
);
|
||||
}
|
||||
} {1 {only a single result allowed for a SELECT that is part of an expression}}
|
||||
} {1 {SELECTs to the left and right of UNION do not have the same number of result columns}}
|
||||
do_test in-12.12 {
|
||||
catchsql {
|
||||
SELECT * FROM t2 WHERE a IN (
|
||||
SELECT a FROM t3 EXCEPT SELECT a, b FROM t2
|
||||
);
|
||||
}
|
||||
} {1 {only a single result allowed for a SELECT that is part of an expression}}
|
||||
} {1 {SELECTs to the left and right of EXCEPT do not have the same number of result columns}}
|
||||
do_test in-12.13 {
|
||||
catchsql {
|
||||
SELECT * FROM t2 WHERE a IN (
|
||||
SELECT a FROM t3 INTERSECT SELECT a, b FROM t2
|
||||
);
|
||||
}
|
||||
} {1 {SELECTs to the left and right of INTERSECT do not have the same number of result columns}}
|
||||
do_test in-12.14 {
|
||||
catchsql {
|
||||
SELECT * FROM t2 WHERE a IN (
|
||||
SELECT a, b FROM t3 UNION ALL SELECT a, b FROM t2
|
||||
);
|
||||
}
|
||||
} {1 {only a single result allowed for a SELECT that is part of an expression}}
|
||||
do_test in-12.15 {
|
||||
catchsql {
|
||||
SELECT * FROM t2 WHERE a IN (
|
||||
SELECT a, b FROM t3 UNION ALL SELECT a FROM t2
|
||||
);
|
||||
}
|
||||
} {1 {SELECTs to the left and right of UNION ALL do not have the same number of result columns}}
|
||||
}; #ifcapable compound
|
||||
|
||||
|
||||
|
@@ -67,8 +67,10 @@ do_test 1.3 {
|
||||
}
|
||||
set iPrev $iNext
|
||||
}
|
||||
puts -nonewline \
|
||||
" (forward=$nForward, back=$nBackward, noncontiguous=$nNoncont)"
|
||||
if {0} {
|
||||
puts -nonewline \
|
||||
" (forward=$nForward, back=$nBackward, noncontiguous=$nNoncont)"
|
||||
}
|
||||
|
||||
expr {$nForward > 2*($nBackward + $nNoncont)}
|
||||
} {1}
|
||||
|
@@ -327,4 +327,23 @@ do_execsql_test index6-8.2 {
|
||||
3 three value 3
|
||||
}
|
||||
|
||||
# 2015-06-11. Assertion fault found by AFL
|
||||
#
|
||||
do_execsql_test index6-9.1 {
|
||||
CREATE TABLE t9(a int, b int, c int);
|
||||
CREATE INDEX t9ca ON t9(c,a) WHERE a in (10,12,20);
|
||||
INSERT INTO t9 VALUES(1,1,9),(10,2,35),(11,15,82),(20,19,5),(NULL,7,3);
|
||||
UPDATE t9 SET b=c WHERE a in (10,12,20);
|
||||
SELECT a,b,c,'|' FROM t9 ORDER BY a;
|
||||
} {{} 7 3 | 1 1 9 | 10 35 35 | 11 15 82 | 20 5 5 |}
|
||||
do_execsql_test index6-9.2 {
|
||||
DROP TABLE t9;
|
||||
CREATE TABLE t9(a int, b int, c int, PRIMARY KEY(a)) WITHOUT ROWID;
|
||||
CREATE INDEX t9ca ON t9(c,a) WHERE a in (10,12,20);
|
||||
INSERT INTO t9 VALUES(1,1,9),(10,2,35),(11,15,82),(20,19,5);
|
||||
UPDATE t9 SET b=c WHERE a in (10,12,20);
|
||||
SELECT a,b,c,'|' FROM t9 ORDER BY a;
|
||||
} {1 1 9 | 10 35 35 | 11 15 82 | 20 5 5 |}
|
||||
|
||||
|
||||
finish_test
|
||||
|
@@ -687,4 +687,30 @@ ifcapable pragma&&compileoption_diags {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test a problem with reordering tables following a LEFT JOIN.
|
||||
#
|
||||
do_execsql_test join-13.0 {
|
||||
CREATE TABLE aa(a);
|
||||
CREATE TABLE bb(b);
|
||||
CREATE TABLE cc(c);
|
||||
|
||||
INSERT INTO aa VALUES(45);
|
||||
INSERT INTO cc VALUES(45);
|
||||
INSERT INTO cc VALUES(45);
|
||||
}
|
||||
|
||||
do_execsql_test join-13.1 {
|
||||
SELECT * FROM aa LEFT JOIN bb, cc WHERE cc.c=aa.a;
|
||||
} {45 {} 45 45 {} 45}
|
||||
|
||||
# In the following, the order of [cc] and [bb] must not be exchanged, even
|
||||
# though this would be helpful if the query used an inner join.
|
||||
do_execsql_test join-13.2 {
|
||||
CREATE INDEX ccc ON cc(c);
|
||||
SELECT * FROM aa LEFT JOIN bb, cc WHERE cc.c=aa.a;
|
||||
} {45 {} 45 45 {} 45}
|
||||
|
||||
|
||||
finish_test
|
||||
|
@@ -96,7 +96,7 @@ if {$::tcl_platform(platform)!="unix"} {
|
||||
set alltests [test_set $alltests -exclude {
|
||||
all.test async.test quick.test veryquick.test
|
||||
memleak.test permutations.test soak.test fts3.test
|
||||
mallocAll.test rtree.test full.test
|
||||
mallocAll.test rtree.test full.test extraquick.test
|
||||
}]
|
||||
|
||||
set allquicktests [test_set $alltests -exclude {
|
||||
@@ -146,11 +146,22 @@ if {[info exists ::env(TEST_FAILURE)]} {
|
||||
lappend ::testsuitelist xxx
|
||||
|
||||
test_suite "veryquick" -prefix "" -description {
|
||||
"Very" quick test suite. Runs in less than 5 minutes on a workstation.
|
||||
"Very" quick test suite. Runs in minutes on a workstation.
|
||||
This test suite is the same as the "quick" tests, except that some files
|
||||
that test malloc and IO errors are omitted.
|
||||
} -files [
|
||||
test_set $allquicktests -exclude *malloc* *ioerr* *fault*
|
||||
test_set $allquicktests -exclude *malloc* *ioerr* *fault* *bigfile*
|
||||
]
|
||||
|
||||
test_suite "extraquick" -prefix "" -description {
|
||||
"Extra" quick test suite. Runs in a few minutes on a workstation.
|
||||
This test suite is the same as the "veryquick" tests, except that
|
||||
slower tests are omitted.
|
||||
} -files [
|
||||
test_set $allquicktests -exclude *malloc* *ioerr* *fault* *bigfile* \
|
||||
wal3.test fts4merge* sort2.test mmap1.test walcrash* \
|
||||
percentile.test where8m.test walcksum.test savepoint3.test \
|
||||
fuzzer1.test fuzzer3.test fts3expr3.test
|
||||
]
|
||||
|
||||
test_suite "mmap" -prefix "mm-" -description {
|
||||
|
@@ -164,7 +164,6 @@ do_test progress-1.7 {
|
||||
}
|
||||
|
||||
set ::res [list]
|
||||
explain {SELECT a, b, c FROM abc}
|
||||
db eval {SELECT a, b, c FROM abc} {
|
||||
lappend ::res $a $b $c
|
||||
db progress 5 "expr 1"
|
||||
|
@@ -547,7 +547,10 @@ proc process_options {argv} {
|
||||
puts " --srcdir $::SRCDIR"
|
||||
puts " --platform [list $platform]"
|
||||
puts " --config [list $config]"
|
||||
if {$::QUICK} {puts " --quick"}
|
||||
if {$::QUICK} {
|
||||
if {$::QUICK==1} {puts " --quick"}
|
||||
if {$::QUICK==2} {puts " --veryquick"}
|
||||
}
|
||||
if {$::MSVC} {puts " --msvc"}
|
||||
if {$::BUILDONLY} {puts " --buildonly"}
|
||||
if {$::DRYRUN} {puts " --dryrun"}
|
||||
@@ -645,7 +648,7 @@ proc main {argv} {
|
||||
}
|
||||
if {$target ne "checksymbols"} {
|
||||
switch -- $::QUICK {
|
||||
1 {set target test}
|
||||
1 {set target quicktest}
|
||||
2 {set target smoketest}
|
||||
}
|
||||
if {$::BUILDONLY} {
|
||||
|
@@ -15,6 +15,7 @@
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix select7
|
||||
|
||||
ifcapable compound {
|
||||
|
||||
@@ -201,4 +202,23 @@ do_test select7-7.7 {
|
||||
}
|
||||
} {text 123}
|
||||
|
||||
do_execsql_test 8.0 {
|
||||
CREATE TABLE t01(x, y);
|
||||
CREATE TABLE t02(x, y);
|
||||
}
|
||||
|
||||
do_catchsql_test 8.1 {
|
||||
SELECT * FROM (
|
||||
SELECT * FROM t01 UNION SELECT x FROM t02
|
||||
) WHERE y=1
|
||||
} {1 {SELECTs to the left and right of UNION do not have the same number of result columns}}
|
||||
|
||||
do_catchsql_test 8.2 {
|
||||
CREATE VIEW v0 as SELECT x, y FROM t01 UNION SELECT x FROM t02;
|
||||
EXPLAIN QUERY PLAN SELECT * FROM v0 WHERE x='0' OR y;
|
||||
} {1 {SELECTs to the left and right of UNION do not have the same number of result columns}}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
|
@@ -32,7 +32,6 @@ set result [execsql {
|
||||
FROM songs
|
||||
GROUP BY LOWER(artist)
|
||||
}]
|
||||
puts result=$result
|
||||
do_test select8-1.1 {
|
||||
execsql {
|
||||
SELECT DISTINCT artist,sum(timesplayed) AS total
|
||||
|
@@ -16,7 +16,6 @@
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
db close
|
||||
puts hello
|
||||
|
||||
# This script is only valid if we are running shared-cache mode in a
|
||||
# threadsafe-capable database engine.
|
||||
|
@@ -43,6 +43,9 @@ static const char zHelp[] =
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#if SQLITE_VERSION_NUMBER<3005000
|
||||
# define sqlite3_int64 sqlite_int64
|
||||
#endif
|
||||
#ifdef SQLITE_ENABLE_OTA
|
||||
# include "sqlite3ota.h"
|
||||
#endif
|
||||
@@ -143,6 +146,9 @@ static int integerValue(const char *zArg){
|
||||
|
||||
/* Return the current wall-clock time, in milliseconds */
|
||||
sqlite3_int64 speedtest1_timestamp(void){
|
||||
#if SQLITE_VERSION_NUMBER<3005000
|
||||
return 0;
|
||||
#else
|
||||
static sqlite3_vfs *clockVfs = 0;
|
||||
sqlite3_int64 t;
|
||||
if( clockVfs==0 ) clockVfs = sqlite3_vfs_find(0);
|
||||
@@ -157,6 +163,7 @@ sqlite3_int64 speedtest1_timestamp(void){
|
||||
t = (sqlite3_int64)(r*86400000.0);
|
||||
}
|
||||
return t;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Return a pseudo-random unsigned integer */
|
||||
@@ -306,7 +313,7 @@ static void printSql(const char *zSql){
|
||||
if( g.bExplain ) printf("EXPLAIN ");
|
||||
printf("%.*s;\n", n, zSql);
|
||||
if( g.bExplain
|
||||
#if SQLITE_VERSION_NUMBER>=3007010
|
||||
#if SQLITE_VERSION_NUMBER>=3007017
|
||||
&& ( sqlite3_strglob("CREATE *", zSql)==0
|
||||
|| sqlite3_strglob("DROP *", zSql)==0
|
||||
|| sqlite3_strglob("ALTER *", zSql)==0
|
||||
@@ -374,12 +381,15 @@ void speedtest1_run(void){
|
||||
}
|
||||
}
|
||||
}
|
||||
#if SQLITE_VERSION_NUMBER>=3006001
|
||||
if( g.bReprepare ){
|
||||
sqlite3_stmt *pNew;
|
||||
sqlite3_prepare_v2(g.db, sqlite3_sql(g.pStmt), -1, &pNew, 0);
|
||||
sqlite3_finalize(g.pStmt);
|
||||
g.pStmt = pNew;
|
||||
}else{
|
||||
}else
|
||||
#endif
|
||||
{
|
||||
sqlite3_reset(g.pStmt);
|
||||
}
|
||||
}
|
||||
@@ -1273,6 +1283,7 @@ int main(int argc, char **argv){
|
||||
fatal_error(zHelp, argv[0]);
|
||||
}
|
||||
#endif
|
||||
#if SQLITE_VERSION_NUMBER>=3006001
|
||||
if( nHeap>0 ){
|
||||
pHeap = malloc( nHeap );
|
||||
if( pHeap==0 ) fatal_error("cannot allocate %d-byte heap\n", nHeap);
|
||||
@@ -1296,16 +1307,19 @@ int main(int argc, char **argv){
|
||||
if( nLook>0 ){
|
||||
sqlite3_config(SQLITE_CONFIG_LOOKASIDE, 0, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Open the database and the input file */
|
||||
if( sqlite3_open(zDbName, &g.db) ){
|
||||
fatal_error("Cannot open database file: %s\n", zDbName);
|
||||
}
|
||||
#if SQLITE_VERSION_NUMBER>=3006001
|
||||
if( nLook>0 && szLook>0 ){
|
||||
pLook = malloc( nLook*szLook );
|
||||
rc = sqlite3_db_config(g.db, SQLITE_DBCONFIG_LOOKASIDE, pLook, szLook,nLook);
|
||||
if( rc ) fatal_error("lookaside configuration failed: %d\n", rc);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Set database connection options */
|
||||
sqlite3_create_function(g.db, "random", 0, SQLITE_UTF8, 0, randomFunc, 0, 0);
|
||||
@@ -1387,6 +1401,7 @@ int main(int argc, char **argv){
|
||||
|
||||
sqlite3_close(g.db);
|
||||
|
||||
#if SQLITE_VERSION_NUMBER>=3006001
|
||||
/* Global memory usage statistics printed after the database connection
|
||||
** has closed. Memory usage should be zero at this point. */
|
||||
if( showStats ){
|
||||
@@ -1407,6 +1422,7 @@ int main(int argc, char **argv){
|
||||
sqlite3_status(SQLITE_STATUS_SCRATCH_SIZE, &iCur, &iHi, 0);
|
||||
printf("-- Largest Scratch Allocation: %d bytes\n", iHi);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Release memory */
|
||||
free( pLook );
|
||||
|
@@ -19,6 +19,11 @@ if {$tcl_platform(platform)=="windows"} {
|
||||
} else {
|
||||
set PROG "./sqldiff"
|
||||
}
|
||||
if {![file exe $PROG]} {
|
||||
puts "sqldiff cannot run because $PROG is not available"
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
db close
|
||||
forcedelete test.db test2.db
|
||||
sqlite3 db test.db
|
||||
|
@@ -808,4 +808,20 @@ do_execsql_test table-17.1 {
|
||||
SELECT p, q, '|' FROM t3 ORDER BY p;
|
||||
} {1 1 | 2 2 |}
|
||||
|
||||
# 2015-06-16
|
||||
# Ticket [https://www.sqlite.org/src/tktview/873cae2b6e25b1991ce5e9b782f9cd0409b96063]
|
||||
# Make sure a CREATE TABLE AS statement correctly rolls back partial changes to the
|
||||
# sqlite_master table when the SELECT on the right-hand side aborts.
|
||||
#
|
||||
do_catchsql_test table-18.1 {
|
||||
DROP TABLE IF EXISTS t1;
|
||||
BEGIN;
|
||||
CREATE TABLE t1 AS SELECT zeroblob(2e20);
|
||||
} {1 {string or blob too big}}
|
||||
do_execsql_test table-18.2 {
|
||||
COMMIT;
|
||||
PRAGMA integrity_check;
|
||||
} {ok}
|
||||
|
||||
|
||||
finish_test
|
||||
|
220
test/tester.tcl
220
test/tester.tcl
@@ -81,6 +81,12 @@
|
||||
# permutation
|
||||
# presql
|
||||
#
|
||||
# Command to test whether or not --verbose=1 was specified on the command
|
||||
# line (returns 0 for not-verbose, 1 for verbose and 2 for "verbose in the
|
||||
# output file only").
|
||||
#
|
||||
# verbose
|
||||
#
|
||||
|
||||
# Set the precision of FP arithmatic used by the interpreter. And
|
||||
# configure SQLite to take database file locks on the page that begins
|
||||
@@ -388,6 +394,9 @@ if {[info exists cmdlinearg]==0} {
|
||||
# --file-retry-delay=N
|
||||
# --start=[$permutation:]$testfile
|
||||
# --match=$pattern
|
||||
# --verbose=$val
|
||||
# --output=$filename
|
||||
# --help
|
||||
#
|
||||
set cmdlinearg(soft-heap-limit) 0
|
||||
set cmdlinearg(maxerror) 1000
|
||||
@@ -399,6 +408,8 @@ if {[info exists cmdlinearg]==0} {
|
||||
set cmdlinearg(file-retry-delay) 0
|
||||
set cmdlinearg(start) ""
|
||||
set cmdlinearg(match) ""
|
||||
set cmdlinearg(verbose) ""
|
||||
set cmdlinearg(output) ""
|
||||
|
||||
set leftover [list]
|
||||
foreach a $argv {
|
||||
@@ -457,6 +468,22 @@ if {[info exists cmdlinearg]==0} {
|
||||
set ::G(match) $cmdlinearg(match)
|
||||
if {$::G(match) == ""} {unset ::G(match)}
|
||||
}
|
||||
|
||||
{^-+output=.+$} {
|
||||
foreach {dummy cmdlinearg(output)} [split $a =] break
|
||||
if {$cmdlinearg(verbose)==""} {
|
||||
set cmdlinearg(verbose) 2
|
||||
}
|
||||
}
|
||||
{^-+verbose=.+$} {
|
||||
foreach {dummy cmdlinearg(verbose)} [split $a =] break
|
||||
if {$cmdlinearg(verbose)=="file"} {
|
||||
set cmdlinearg(verbose) 2
|
||||
} elseif {[string is boolean -strict $cmdlinearg(verbose)]==0} {
|
||||
error "option --verbose= must be set to a boolean or to \"file\""
|
||||
}
|
||||
}
|
||||
|
||||
default {
|
||||
lappend leftover $a
|
||||
}
|
||||
@@ -484,6 +511,16 @@ if {[info exists cmdlinearg]==0} {
|
||||
if {$cmdlinearg(malloctrace)} {
|
||||
sqlite3_memdebug_backtrace $cmdlinearg(backtrace)
|
||||
}
|
||||
|
||||
if {$cmdlinearg(output)!=""} {
|
||||
puts "Copying output to file $cmdlinearg(output)"
|
||||
set ::G(output_fd) [open $cmdlinearg(output) w]
|
||||
fconfigure $::G(output_fd) -buffering line
|
||||
}
|
||||
|
||||
if {$cmdlinearg(verbose)==""} {
|
||||
set cmdlinearg(verbose) 1
|
||||
}
|
||||
}
|
||||
|
||||
# Update the soft-heap-limit each time this script is run. In that
|
||||
@@ -554,7 +591,7 @@ proc fail_test {name} {
|
||||
|
||||
set nFail [set_test_counter errors]
|
||||
if {$nFail>=$::cmdlinearg(maxerror)} {
|
||||
puts "*** Giving up..."
|
||||
output2 "*** Giving up..."
|
||||
finalize_testing
|
||||
}
|
||||
}
|
||||
@@ -562,7 +599,7 @@ proc fail_test {name} {
|
||||
# Remember a warning message to be displayed at the conclusion of all testing
|
||||
#
|
||||
proc warning {msg {append 1}} {
|
||||
puts "Warning: $msg"
|
||||
output2 "Warning: $msg"
|
||||
set warnList [set_test_counter warn_list]
|
||||
if {$append} {
|
||||
lappend warnList $msg
|
||||
@@ -577,6 +614,61 @@ proc incr_ntest {} {
|
||||
set_test_counter count [expr [set_test_counter count] + 1]
|
||||
}
|
||||
|
||||
# Return true if --verbose=1 was specified on the command line. Otherwise,
|
||||
# return false.
|
||||
#
|
||||
proc verbose {} {
|
||||
return $::cmdlinearg(verbose)
|
||||
}
|
||||
|
||||
# Use the following commands instead of [puts] for test output within
|
||||
# this file. Test scripts can still use regular [puts], which is directed
|
||||
# to stdout and, if one is open, the --output file.
|
||||
#
|
||||
# output1: output that should be printed if --verbose=1 was specified.
|
||||
# output2: output that should be printed unconditionally.
|
||||
# output2_if_no_verbose: output that should be printed only if --verbose=0.
|
||||
#
|
||||
proc output1 {args} {
|
||||
set v [verbose]
|
||||
if {$v==1} {
|
||||
uplevel output2 $args
|
||||
} elseif {$v==2} {
|
||||
uplevel puts [lrange $args 0 end-1] $::G(output_fd) [lrange $args end end]
|
||||
}
|
||||
}
|
||||
proc output2 {args} {
|
||||
set nArg [llength $args]
|
||||
uplevel puts $args
|
||||
}
|
||||
proc output2_if_no_verbose {args} {
|
||||
set v [verbose]
|
||||
if {$v==0} {
|
||||
uplevel output2 $args
|
||||
} elseif {$v==2} {
|
||||
uplevel puts [lrange $args 0 end-1] stdout [lrange $args end end]
|
||||
}
|
||||
}
|
||||
|
||||
# Override the [puts] command so that if no channel is explicitly
|
||||
# specified the string is written to both stdout and to the file
|
||||
# specified by "--output=", if any.
|
||||
#
|
||||
proc puts_override {args} {
|
||||
set nArg [llength $args]
|
||||
if {$nArg==1 || ($nArg==2 && [string first [lindex $args 0] -nonewline]==0)} {
|
||||
uplevel puts_original $args
|
||||
if {[info exists ::G(output_fd)]} {
|
||||
uplevel puts [lrange $args 0 end-1] $::G(output_fd) [lrange $args end end]
|
||||
}
|
||||
} else {
|
||||
# A channel was explicitly specified.
|
||||
uplevel puts_original $args
|
||||
}
|
||||
}
|
||||
rename puts puts_original
|
||||
proc puts {args} { uplevel puts_override $args }
|
||||
|
||||
|
||||
# Invoke the do_test procedure to run a single test
|
||||
#
|
||||
@@ -604,12 +696,13 @@ proc do_test {name cmd expected} {
|
||||
}
|
||||
|
||||
incr_ntest
|
||||
puts -nonewline $name...
|
||||
output1 -nonewline $name...
|
||||
flush stdout
|
||||
|
||||
if {![info exists ::G(match)] || [string match $::G(match) $name]} {
|
||||
if {[catch {uplevel #0 "$cmd;\n"} result]} {
|
||||
puts "\nError: $result"
|
||||
output2_if_no_verbose -nonewline $name...
|
||||
output2 "\nError: $result"
|
||||
fail_test $name
|
||||
} else {
|
||||
if {[regexp {^~?/.*/$} $expected]} {
|
||||
@@ -653,14 +746,15 @@ proc do_test {name cmd expected} {
|
||||
# if {![info exists ::testprefix] || $::testprefix eq ""} {
|
||||
# error "no test prefix"
|
||||
# }
|
||||
puts "\nExpected: \[$expected\]\n Got: \[$result\]"
|
||||
output2_if_no_verbose -nonewline $name...
|
||||
output2 "\nExpected: \[$expected\]\n Got: \[$result\]"
|
||||
fail_test $name
|
||||
} else {
|
||||
puts " Ok"
|
||||
output1 " Ok"
|
||||
}
|
||||
}
|
||||
} else {
|
||||
puts " Omitted"
|
||||
output1 " Omitted"
|
||||
omit_test $name "pattern mismatch" 0
|
||||
}
|
||||
flush stdout
|
||||
@@ -837,7 +931,7 @@ proc delete_all_data {} {
|
||||
# Return the number of microseconds per statement.
|
||||
#
|
||||
proc speed_trial {name numstmt units sql} {
|
||||
puts -nonewline [format {%-21.21s } $name...]
|
||||
output2 -nonewline [format {%-21.21s } $name...]
|
||||
flush stdout
|
||||
set speed [time {sqlite3_exec_nr db $sql}]
|
||||
set tm [lindex $speed 0]
|
||||
@@ -847,13 +941,13 @@ proc speed_trial {name numstmt units sql} {
|
||||
set rate [format %20.5f [expr {1000000.0*$numstmt/$tm}]]
|
||||
}
|
||||
set u2 $units/s
|
||||
puts [format {%12d uS %s %s} $tm $rate $u2]
|
||||
output2 [format {%12d uS %s %s} $tm $rate $u2]
|
||||
global total_time
|
||||
set total_time [expr {$total_time+$tm}]
|
||||
lappend ::speed_trial_times $name $tm
|
||||
}
|
||||
proc speed_trial_tcl {name numstmt units script} {
|
||||
puts -nonewline [format {%-21.21s } $name...]
|
||||
output2 -nonewline [format {%-21.21s } $name...]
|
||||
flush stdout
|
||||
set speed [time {eval $script}]
|
||||
set tm [lindex $speed 0]
|
||||
@@ -863,7 +957,7 @@ proc speed_trial_tcl {name numstmt units script} {
|
||||
set rate [format %20.5f [expr {1000000.0*$numstmt/$tm}]]
|
||||
}
|
||||
set u2 $units/s
|
||||
puts [format {%12d uS %s %s} $tm $rate $u2]
|
||||
output2 [format {%12d uS %s %s} $tm $rate $u2]
|
||||
global total_time
|
||||
set total_time [expr {$total_time+$tm}]
|
||||
lappend ::speed_trial_times $name $tm
|
||||
@@ -875,19 +969,19 @@ proc speed_trial_init {name} {
|
||||
sqlite3 versdb :memory:
|
||||
set vers [versdb one {SELECT sqlite_source_id()}]
|
||||
versdb close
|
||||
puts "SQLite $vers"
|
||||
output2 "SQLite $vers"
|
||||
}
|
||||
proc speed_trial_summary {name} {
|
||||
global total_time
|
||||
puts [format {%-21.21s %12d uS TOTAL} $name $total_time]
|
||||
output2 [format {%-21.21s %12d uS TOTAL} $name $total_time]
|
||||
|
||||
if { 0 } {
|
||||
sqlite3 versdb :memory:
|
||||
set vers [lindex [versdb one {SELECT sqlite_source_id()}] 0]
|
||||
versdb close
|
||||
puts "CREATE TABLE IF NOT EXISTS time(version, script, test, us);"
|
||||
output2 "CREATE TABLE IF NOT EXISTS time(version, script, test, us);"
|
||||
foreach {test us} $::speed_trial_times {
|
||||
puts "INSERT INTO time VALUES('$vers', '$name', '$test', $us);"
|
||||
output2 "INSERT INTO time VALUES('$vers', '$name', '$test', $us);"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -931,75 +1025,75 @@ proc finalize_testing {} {
|
||||
}
|
||||
}
|
||||
if {$nKnown>0} {
|
||||
puts "[expr {$nErr-$nKnown}] new errors and $nKnown known errors\
|
||||
output2 "[expr {$nErr-$nKnown}] new errors and $nKnown known errors\
|
||||
out of $nTest tests"
|
||||
} else {
|
||||
puts "$nErr errors out of $nTest tests"
|
||||
output2 "$nErr errors out of $nTest tests"
|
||||
}
|
||||
if {$nErr>$nKnown} {
|
||||
puts -nonewline "Failures on these tests:"
|
||||
output2 -nonewline "Failures on these tests:"
|
||||
foreach x [set_test_counter fail_list] {
|
||||
if {![info exists known_error($x)]} {puts -nonewline " $x"}
|
||||
if {![info exists known_error($x)]} {output2 -nonewline " $x"}
|
||||
}
|
||||
puts ""
|
||||
output2 ""
|
||||
}
|
||||
foreach warning [set_test_counter warn_list] {
|
||||
puts "Warning: $warning"
|
||||
output2 "Warning: $warning"
|
||||
}
|
||||
run_thread_tests 1
|
||||
if {[llength $omitList]>0} {
|
||||
puts "Omitted test cases:"
|
||||
output2 "Omitted test cases:"
|
||||
set prec {}
|
||||
foreach {rec} [lsort $omitList] {
|
||||
if {$rec==$prec} continue
|
||||
set prec $rec
|
||||
puts [format { %-12s %s} [lindex $rec 0] [lindex $rec 1]]
|
||||
output2 [format { %-12s %s} [lindex $rec 0] [lindex $rec 1]]
|
||||
}
|
||||
}
|
||||
if {$nErr>0 && ![working_64bit_int]} {
|
||||
puts "******************************************************************"
|
||||
puts "N.B.: The version of TCL that you used to build this test harness"
|
||||
puts "is defective in that it does not support 64-bit integers. Some or"
|
||||
puts "all of the test failures above might be a result from this defect"
|
||||
puts "in your TCL build."
|
||||
puts "******************************************************************"
|
||||
output2 "******************************************************************"
|
||||
output2 "N.B.: The version of TCL that you used to build this test harness"
|
||||
output2 "is defective in that it does not support 64-bit integers. Some or"
|
||||
output2 "all of the test failures above might be a result from this defect"
|
||||
output2 "in your TCL build."
|
||||
output2 "******************************************************************"
|
||||
}
|
||||
if {$::cmdlinearg(binarylog)} {
|
||||
vfslog finalize binarylog
|
||||
}
|
||||
if {$sqlite_open_file_count} {
|
||||
puts "$sqlite_open_file_count files were left open"
|
||||
output2 "$sqlite_open_file_count files were left open"
|
||||
incr nErr
|
||||
}
|
||||
if {[lindex [sqlite3_status SQLITE_STATUS_MALLOC_COUNT 0] 1]>0 ||
|
||||
[sqlite3_memory_used]>0} {
|
||||
puts "Unfreed memory: [sqlite3_memory_used] bytes in\
|
||||
output2 "Unfreed memory: [sqlite3_memory_used] bytes in\
|
||||
[lindex [sqlite3_status SQLITE_STATUS_MALLOC_COUNT 0] 1] allocations"
|
||||
incr nErr
|
||||
ifcapable memdebug||mem5||(mem3&&debug) {
|
||||
puts "Writing unfreed memory log to \"./memleak.txt\""
|
||||
output2 "Writing unfreed memory log to \"./memleak.txt\""
|
||||
sqlite3_memdebug_dump ./memleak.txt
|
||||
}
|
||||
} else {
|
||||
puts "All memory allocations freed - no leaks"
|
||||
output2 "All memory allocations freed - no leaks"
|
||||
ifcapable memdebug||mem5 {
|
||||
sqlite3_memdebug_dump ./memusage.txt
|
||||
}
|
||||
}
|
||||
show_memstats
|
||||
puts "Maximum memory usage: [sqlite3_memory_highwater 1] bytes"
|
||||
puts "Current memory usage: [sqlite3_memory_highwater] bytes"
|
||||
output2 "Maximum memory usage: [sqlite3_memory_highwater 1] bytes"
|
||||
output2 "Current memory usage: [sqlite3_memory_highwater] bytes"
|
||||
if {[info commands sqlite3_memdebug_malloc_count] ne ""} {
|
||||
puts "Number of malloc() : [sqlite3_memdebug_malloc_count] calls"
|
||||
output2 "Number of malloc() : [sqlite3_memdebug_malloc_count] calls"
|
||||
}
|
||||
if {$::cmdlinearg(malloctrace)} {
|
||||
puts "Writing mallocs.sql..."
|
||||
output2 "Writing mallocs.sql..."
|
||||
memdebug_log_sql
|
||||
sqlite3_memdebug_log stop
|
||||
sqlite3_memdebug_log clear
|
||||
|
||||
if {[sqlite3_memory_used]>0} {
|
||||
puts "Writing leaks.sql..."
|
||||
output2 "Writing leaks.sql..."
|
||||
sqlite3_memdebug_log sync
|
||||
memdebug_log_sql leaks.sql
|
||||
}
|
||||
@@ -1020,30 +1114,30 @@ proc show_memstats {} {
|
||||
set y [sqlite3_status SQLITE_STATUS_MALLOC_SIZE 0]
|
||||
set val [format {now %10d max %10d max-size %10d} \
|
||||
[lindex $x 1] [lindex $x 2] [lindex $y 2]]
|
||||
puts "Memory used: $val"
|
||||
output1 "Memory used: $val"
|
||||
set x [sqlite3_status SQLITE_STATUS_MALLOC_COUNT 0]
|
||||
set val [format {now %10d max %10d} [lindex $x 1] [lindex $x 2]]
|
||||
puts "Allocation count: $val"
|
||||
output1 "Allocation count: $val"
|
||||
set x [sqlite3_status SQLITE_STATUS_PAGECACHE_USED 0]
|
||||
set y [sqlite3_status SQLITE_STATUS_PAGECACHE_SIZE 0]
|
||||
set val [format {now %10d max %10d max-size %10d} \
|
||||
[lindex $x 1] [lindex $x 2] [lindex $y 2]]
|
||||
puts "Page-cache used: $val"
|
||||
output1 "Page-cache used: $val"
|
||||
set x [sqlite3_status SQLITE_STATUS_PAGECACHE_OVERFLOW 0]
|
||||
set val [format {now %10d max %10d} [lindex $x 1] [lindex $x 2]]
|
||||
puts "Page-cache overflow: $val"
|
||||
output1 "Page-cache overflow: $val"
|
||||
set x [sqlite3_status SQLITE_STATUS_SCRATCH_USED 0]
|
||||
set val [format {now %10d max %10d} [lindex $x 1] [lindex $x 2]]
|
||||
puts "Scratch memory used: $val"
|
||||
output1 "Scratch memory used: $val"
|
||||
set x [sqlite3_status SQLITE_STATUS_SCRATCH_OVERFLOW 0]
|
||||
set y [sqlite3_status SQLITE_STATUS_SCRATCH_SIZE 0]
|
||||
set val [format {now %10d max %10d max-size %10d} \
|
||||
[lindex $x 1] [lindex $x 2] [lindex $y 2]]
|
||||
puts "Scratch overflow: $val"
|
||||
output1 "Scratch overflow: $val"
|
||||
ifcapable yytrackmaxstackdepth {
|
||||
set x [sqlite3_status SQLITE_STATUS_PARSER_STACK 0]
|
||||
set val [format { max %10d} [lindex $x 2]]
|
||||
puts "Parser stack depth: $val"
|
||||
output2 "Parser stack depth: $val"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1058,7 +1152,7 @@ proc execsql_timed {sql {db db}} {
|
||||
set x [uplevel [list $db eval $sql]]
|
||||
} 1]
|
||||
set tm [lindex $tm 0]
|
||||
puts -nonewline " ([expr {$tm*0.001}]ms) "
|
||||
output1 -nonewline " ([expr {$tm*0.001}]ms) "
|
||||
set x
|
||||
}
|
||||
|
||||
@@ -1074,20 +1168,20 @@ proc catchsql {sql {db db}} {
|
||||
# Do an VDBE code dump on the SQL given
|
||||
#
|
||||
proc explain {sql {db db}} {
|
||||
puts ""
|
||||
puts "addr opcode p1 p2 p3 p4 p5 #"
|
||||
puts "---- ------------ ------ ------ ------ --------------- -- -"
|
||||
output2 ""
|
||||
output2 "addr opcode p1 p2 p3 p4 p5 #"
|
||||
output2 "---- ------------ ------ ------ ------ --------------- -- -"
|
||||
$db eval "explain $sql" {} {
|
||||
puts [format {%-4d %-12.12s %-6d %-6d %-6d % -17s %s %s} \
|
||||
output2 [format {%-4d %-12.12s %-6d %-6d %-6d % -17s %s %s} \
|
||||
$addr $opcode $p1 $p2 $p3 $p4 $p5 $comment
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
proc explain_i {sql {db db}} {
|
||||
puts ""
|
||||
puts "addr opcode p1 p2 p3 p4 p5 #"
|
||||
puts "---- ------------ ------ ------ ------ ---------------- -- -"
|
||||
output2 ""
|
||||
output2 "addr opcode p1 p2 p3 p4 p5 #"
|
||||
output2 "---- ------------ ------ ------ ------ ---------------- -- -"
|
||||
|
||||
|
||||
# Set up colors for the different opcodes. Scheme is as follows:
|
||||
@@ -1153,18 +1247,18 @@ proc explain_i {sql {db db}} {
|
||||
|
||||
$db eval "explain $sql" {} {
|
||||
if {[info exists linebreak($addr)]} {
|
||||
puts ""
|
||||
output2 ""
|
||||
}
|
||||
set I [string repeat " " $x($addr)]
|
||||
|
||||
set col ""
|
||||
catch { set col $color($opcode) }
|
||||
|
||||
puts [format {%-4d %s%s%-12.12s%s %-6d %-6d %-6d % -17s %s %s} \
|
||||
output2 [format {%-4d %s%s%-12.12s%s %-6d %-6d %-6d % -17s %s %s} \
|
||||
$addr $I $col $opcode $D $p1 $p2 $p3 $p4 $p5 $comment
|
||||
]
|
||||
}
|
||||
puts "---- ------------ ------ ------ ------ ---------------- -- -"
|
||||
output2 "---- ------------ ------ ------ ------ ---------------- -- -"
|
||||
}
|
||||
|
||||
# Show the VDBE program for an SQL statement but omit the Trace
|
||||
@@ -1595,9 +1689,9 @@ proc do_ioerr_test {testname args} {
|
||||
set nowcksum [cksum]
|
||||
set res [expr {$nowcksum==$::checksum || $nowcksum==$::goodcksum}]
|
||||
if {$res==0} {
|
||||
puts "now=$nowcksum"
|
||||
puts "the=$::checksum"
|
||||
puts "fwd=$::goodcksum"
|
||||
output2 "now=$nowcksum"
|
||||
output2 "the=$::checksum"
|
||||
output2 "fwd=$::goodcksum"
|
||||
}
|
||||
set res
|
||||
} 1
|
||||
@@ -1821,6 +1915,12 @@ proc slave_test_script {script} {
|
||||
interp eval tinterp [list set $var $value]
|
||||
}
|
||||
|
||||
# If output is being copied into a file, share the file-descriptor with
|
||||
# the interpreter.
|
||||
if {[info exists ::G(output_fd)]} {
|
||||
interp share {} $::G(output_fd) tinterp
|
||||
}
|
||||
|
||||
# The alias used to access the global test counters.
|
||||
tinterp alias set_test_counter set_test_counter
|
||||
|
||||
@@ -1889,7 +1989,7 @@ proc slave_test_file {zFile} {
|
||||
|
||||
# Add some info to the output.
|
||||
#
|
||||
puts "Time: $tail $ms ms"
|
||||
output2 "Time: $tail $ms ms"
|
||||
show_memstats
|
||||
}
|
||||
|
||||
|
@@ -56,9 +56,6 @@ ifcapable !vtab||!schema_pragmas {
|
||||
# We cannot create a virtual table if the module has not been registered.
|
||||
#
|
||||
do_test vtab1-1.1.1 {
|
||||
explain {
|
||||
CREATE VIRTUAL TABLE t1 USING echo;
|
||||
}
|
||||
catchsql {
|
||||
CREATE VIRTUAL TABLE t1 USING echo;
|
||||
}
|
||||
|
@@ -230,4 +230,41 @@ do_eqp_test 5.3.3 {
|
||||
SELECT * FROM t1 WHERE likely(a=?)
|
||||
} {0 0 0 {SCAN TABLE t1}}
|
||||
|
||||
# 2015-06-18
|
||||
# Ticket [https://www.sqlite.org/see/tktview/472f0742a1868fb58862bc588ed70]
|
||||
#
|
||||
do_execsql_test 6.0 {
|
||||
DROP TABLE IF EXISTS t1;
|
||||
CREATE TABLE t1(i int, x, y, z);
|
||||
INSERT INTO t1 VALUES (1,1,1,1), (2,2,2,2), (3,3,3,3), (4,4,4,4);
|
||||
DROP TABLE IF EXISTS t2;
|
||||
CREATE TABLE t2(i int, bool char);
|
||||
INSERT INTO t2 VALUES(1,'T'), (2,'F');
|
||||
SELECT count(*) FROM t1 LEFT JOIN t2 ON t1.i=t2.i AND bool='T';
|
||||
SELECT count(*) FROM t1 LEFT JOIN t2 ON likely(t1.i=t2.i) AND bool='T';
|
||||
} {4 4}
|
||||
|
||||
# 2015-06-20
|
||||
# Crash discovered by AFL
|
||||
#
|
||||
do_execsql_test 7.0 {
|
||||
DROP TABLE IF EXISTS t1;
|
||||
CREATE TABLE t1(a, b, PRIMARY KEY(a,b));
|
||||
INSERT INTO t1 VALUES(9,1),(1,2);
|
||||
DROP TABLE IF EXISTS t2;
|
||||
CREATE TABLE t2(x, y, PRIMARY KEY(x,y));
|
||||
INSERT INTO t2 VALUES(3,3),(4,4);
|
||||
SELECT likely(a), x FROM t1, t2 ORDER BY 1, 2;
|
||||
} {1 3 1 4 9 3 9 4}
|
||||
do_execsql_test 7.1 {
|
||||
SELECT unlikely(a), x FROM t1, t2 ORDER BY 1, 2;
|
||||
} {1 3 1 4 9 3 9 4}
|
||||
do_execsql_test 7.2 {
|
||||
SELECT likelihood(a,0.5), x FROM t1, t2 ORDER BY 1, 2;
|
||||
} {1 3 1 4 9 3 9 4}
|
||||
do_execsql_test 7.3 {
|
||||
SELECT coalesce(a,a), x FROM t1, t2 ORDER BY 1, 2;
|
||||
} {1 3 1 4 9 3 9 4}
|
||||
|
||||
|
||||
finish_test
|
||||
|
@@ -292,6 +292,7 @@ foreach file {
|
||||
mutex_w32.c
|
||||
malloc.c
|
||||
printf.c
|
||||
treeview.c
|
||||
random.c
|
||||
threads.c
|
||||
utf.c
|
||||
@@ -346,6 +347,8 @@ foreach file {
|
||||
update.c
|
||||
vacuum.c
|
||||
vtab.c
|
||||
wherecode.c
|
||||
whereexpr.c
|
||||
where.c
|
||||
|
||||
parse.c
|
||||
|
@@ -9,6 +9,28 @@ echo '********** No optimizations. Includes FTS4 and RTREE *********'
|
||||
gcc -c -Wshadow -Wall -Wextra -pedantic-errors -Wno-long-long -std=c89 \
|
||||
-ansi -DHAVE_STDINT_H -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_RTREE \
|
||||
sqlite3.c
|
||||
echo '********** Android configuration ******************************'
|
||||
gcc -c \
|
||||
-DHAVE_USLEEP=1 \
|
||||
-DSQLITE_HAVE_ISNAN \
|
||||
-DSQLITE_DEFAULT_JOURNAL_SIZE_LIMIT=1048576 \
|
||||
-DSQLITE_THREADSAFE=2 \
|
||||
-DSQLITE_TEMP_STORE=3 \
|
||||
-DSQLITE_POWERSAFE_OVERWRITE=1 \
|
||||
-DSQLITE_DEFAULT_FILE_FORMAT=4 \
|
||||
-DSQLITE_DEFAULT_AUTOVACUUM=1 \
|
||||
-DSQLITE_ENABLE_MEMORY_MANAGEMENT=1 \
|
||||
-DSQLITE_ENABLE_FTS3 \
|
||||
-DSQLITE_ENABLE_FTS3_BACKWARDS \
|
||||
-DSQLITE_ENABLE_FTS4 \
|
||||
-DSQLITE_OMIT_BUILTIN_TEST \
|
||||
-DSQLITE_OMIT_COMPILEOPTION_DIAGS \
|
||||
-DSQLITE_OMIT_LOAD_EXTENSION \
|
||||
-DSQLITE_DEFAULT_FILE_PERMISSIONS=0600 \
|
||||
-DSQLITE_ENABLE_ICU \
|
||||
-DUSE_PREAD64 \
|
||||
-Wshadow -Wall -Wextra \
|
||||
-Os sqlite3.c shell.c
|
||||
echo '********** No optimizations. ENABLE_STAT4. THREADSAFE=0 *******'
|
||||
gcc -c -Wshadow -Wall -Wextra -pedantic-errors -Wno-long-long -std=c89 \
|
||||
-ansi -DSQLITE_ENABLE_STAT4 -DSQLITE_THREADSAFE=0 \
|
||||
|
Reference in New Issue
Block a user