1
0
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:
dan
2015-06-23 15:06:13 +00:00
69 changed files with 4793 additions and 3715 deletions

View File

@@ -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 \ 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 \ 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 \ 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 \ update.lo util.lo vacuum.lo \
vdbe.lo vdbeapi.lo vdbeaux.lo vdbeblob.lo vdbemem.lo vdbesort.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. # Object files for the amalgamation.
# #
@@ -273,6 +274,7 @@ SRC = \
$(TOP)/src/threads.c \ $(TOP)/src/threads.c \
$(TOP)/src/tclsqlite.c \ $(TOP)/src/tclsqlite.c \
$(TOP)/src/tokenize.c \ $(TOP)/src/tokenize.c \
$(TOP)/src/treeview.c \
$(TOP)/src/trigger.c \ $(TOP)/src/trigger.c \
$(TOP)/src/utf.c \ $(TOP)/src/utf.c \
$(TOP)/src/update.c \ $(TOP)/src/update.c \
@@ -293,6 +295,8 @@ SRC = \
$(TOP)/src/wal.h \ $(TOP)/src/wal.h \
$(TOP)/src/walker.c \ $(TOP)/src/walker.c \
$(TOP)/src/where.c \ $(TOP)/src/where.c \
$(TOP)/src/wherecode.c \
$(TOP)/src/whereexpr.c \
$(TOP)/src/whereInt.h $(TOP)/src/whereInt.h
# Source code for extensions # Source code for extensions
@@ -470,6 +474,8 @@ TESTSRC2 = \
$(TOP)/src/vdbemem.c \ $(TOP)/src/vdbemem.c \
$(TOP)/src/vdbetrace.c \ $(TOP)/src/vdbetrace.c \
$(TOP)/src/where.c \ $(TOP)/src/where.c \
$(TOP)/src/wherecode.c \
$(TOP)/src/whereexpr.c \
parse.c \ parse.c \
$(TOP)/ext/fts3/fts3.c \ $(TOP)/ext/fts3/fts3.c \
$(TOP)/ext/fts3/fts3_aux.c \ $(TOP)/ext/fts3/fts3_aux.c \
@@ -545,6 +551,10 @@ FUZZDATA = \
$(TOP)/test/fuzzdata2.db \ $(TOP)/test/fuzzdata2.db \
$(TOP)/test/fuzzdata3.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 # This is the default Makefile target. The objects listed here
# are what get build when you type just "make" with no arguments. # 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) tokenize.lo: $(TOP)/src/tokenize.c keywordhash.h $(HDR)
$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/tokenize.c $(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) trigger.lo: $(TOP)/src/trigger.c $(HDR)
$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/trigger.c $(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) where.lo: $(TOP)/src/where.c $(HDR)
$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/where.c $(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) tclsqlite.lo: $(TOP)/src/tclsqlite.c $(HDR)
$(LTCOMPILE) -DUSE_TCL_STUBS=1 -c $(TOP)/src/tclsqlite.c $(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 # A very detailed test running most or all test cases
fulltest: $(TESTPROGS) fuzztest fulltest: $(TESTPROGS) fuzztest
./testfixture$(TEXE) $(TOP)/test/all.test ./testfixture$(TEXE) $(TOP)/test/all.test $(TESTOPTS)
# Really really long testing # Really really long testing
soaktest: $(TESTPROGS) 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. # Do extra testing but not everything.
fulltestonly: $(TESTPROGS) fulltestonly: $(TESTPROGS)
./testfixture$(TEXE) $(TOP)/test/full.test ./testfixture$(TEXE) $(TOP)/test/full.test
# Fuzz testing # Fuzz testing
fuzztest: fuzzcheck$(TEXE) fuzztest: fuzzcheck$(TEXE) $(FUZZDATA)
./fuzzcheck$(TEXE) $(FUZZDATA) ./fuzzcheck$(TEXE) $(FUZZDATA)
# This is the common case. Run many tests but not those that take valgrindfuzz: fuzzcheck$(TEXT) $(FUZZDATA)
# a really long time. 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 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 # Run a test using valgrind. This can take a really long time
# because valgrind is so much slower than a native machine. # because valgrind is so much slower than a native machine.
# #
valgrindtest: $(TESTPROGS) fuzzcheck$(TEXE) valgrindtest: $(TESTPROGS) valgrindfuzz
valgrind -v ./fuzzcheck$(TEXE) --cell-size-check --quiet $(FUZZDATA) OMIT_MISUSE=1 valgrind -v ./testfixture$(TEXE) $(TOP)/test/permutations.test valgrind $(TESTOPTS)
OMIT_MISUSE=1 valgrind -v ./testfixture$(TEXE) $(TOP)/test/permutations.test valgrind
# A very fast test that checks basic sanity. The name comes from # A very fast test that checks basic sanity. The name comes from
# the 60s-era electronics testing: "Turn it on and see if smoke # the 60s-era electronics testing: "Turn it on and see if smoke
# comes out." # comes out."
# #
smoketest: $(TESTPROGS) fuzzcheck$(TEXE) 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 sqlite3_analyzer.c: sqlite3.c $(TOP)/src/tclsqlite.c $(TOP)/tool/spaceanal.tcl
echo "#define TCLSH 2" > $@ echo "#define TCLSH 2" > $@

View File

@@ -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 \ notify.lo opcodes.lo os.lo os_unix.lo os_win.lo \
pager.lo pcache.lo pcache1.lo pragma.lo prepare.lo printf.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 \ 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 \ update.lo util.lo vacuum.lo \
vdbeapi.lo vdbeaux.lo vdbeblob.lo vdbemem.lo vdbesort.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. # Object files for the amalgamation.
# #
@@ -939,6 +940,7 @@ SRC2 = \
$(TOP)\src\threads.c \ $(TOP)\src\threads.c \
$(TOP)\src\tclsqlite.c \ $(TOP)\src\tclsqlite.c \
$(TOP)\src\tokenize.c \ $(TOP)\src\tokenize.c \
$(TOP)\src\treeview.c \
$(TOP)\src\trigger.c \ $(TOP)\src\trigger.c \
$(TOP)\src\utf.c \ $(TOP)\src\utf.c \
$(TOP)\src\update.c \ $(TOP)\src\update.c \
@@ -959,6 +961,8 @@ SRC2 = \
$(TOP)\src\wal.h \ $(TOP)\src\wal.h \
$(TOP)\src\walker.c \ $(TOP)\src\walker.c \
$(TOP)\src\where.c \ $(TOP)\src\where.c \
$(TOP)\src\wherecode.c \
$(TOP)\src\whereexpr.c \
$(TOP)\src\whereInt.h $(TOP)\src\whereInt.h
# Source code for extensions # Source code for extensions
@@ -1121,6 +1125,8 @@ TESTSRC2 = \
$(TOP)\src\vdbesort.c \ $(TOP)\src\vdbesort.c \
$(TOP)\src\vdbetrace.c \ $(TOP)\src\vdbetrace.c \
$(TOP)\src\where.c \ $(TOP)\src\where.c \
$(TOP)\src\wherecode.c \
$(TOP)\src\whereexpr.c \
parse.c \ parse.c \
$(TOP)\ext\fts3\fts3.c \ $(TOP)\ext\fts3\fts3.c \
$(TOP)\ext\fts3\fts3_aux.c \ $(TOP)\ext\fts3\fts3_aux.c \
@@ -1197,6 +1203,9 @@ FUZZDATA = \
$(TOP)\test\fuzzdata2.db \ $(TOP)\test\fuzzdata2.db \
$(TOP)\test\fuzzdata3.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 # This is the default Makefile target. The objects listed here
# are what get build when you type just "make" with no arguments. # 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) tokenize.lo: $(TOP)\src\tokenize.c keywordhash.h $(HDR)
$(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\tokenize.c $(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) trigger.lo: $(TOP)\src\trigger.c $(HDR)
$(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\trigger.c $(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) where.lo: $(TOP)\src\where.c $(HDR)
$(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\where.c $(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) tclsqlite.lo: $(TOP)\src\tclsqlite.c $(HDR)
$(LTCOMPILE) $(NO_WARN) -DUSE_TCL_STUBS=1 -DBUILD_sqlite -I$(TCLINCDIR) -c $(TOP)\src\tclsqlite.c $(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) /link $(LTLINKOPTS) $(LTLIBPATHS) $(LIBRESOBJS) $(LTLIBS) $(TLIBS)
extensiontest: testfixture.exe testloadext.dll extensiontest: testfixture.exe testloadext.dll
.\testfixture.exe $(TOP)\test\loadext.test .\testfixture.exe $(TOP)\test\loadext.test $(TESTOPTS)
fulltest: $(TESTPROGS) fuzztest fulltest: $(TESTPROGS) fuzztest
.\testfixture.exe $(TOP)\test\all.test .\testfixture.exe $(TOP)\test\all.test $(TESTOPTS)
soaktest: $(TESTPROGS) soaktest: $(TESTPROGS)
.\testfixture.exe $(TOP)\test\all.test -soak=1 .\testfixture.exe $(TOP)\test\all.test -soak=1 $(TESTOPTS)
fulltestonly: $(TESTPROGS) fuzztest fulltestonly: $(TESTPROGS) fuzztest
.\testfixture.exe $(TOP)\test\full.test .\testfixture.exe $(TOP)\test\full.test
queryplantest: testfixture.exe sqlite3.exe queryplantest: testfixture.exe sqlite3.exe
.\testfixture.exe $(TOP)\test\permutations.test queryplanner .\testfixture.exe $(TOP)\test\permutations.test queryplanner $(TESTOPTS)
fuzztest: fuzzcheck.exe fuzztest: fuzzcheck.exe
.\fuzzcheck.exe $(FUZZDATA) .\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 test: $(TESTPROGS) fuzztest
.\testfixture.exe $(TOP)\test\veryquick.test .\testfixture.exe $(TOP)\test\veryquick.test $(TESTOPTS)
smoketest: $(TESTPROGS) 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 sqlite3_analyzer.c: $(SQLITE3C) $(TOP)\src\tclsqlite.c $(TOP)\tool\spaceanal.tcl
echo #define TCLSH 2 > $@ echo #define TCLSH 2 > $@

View File

@@ -240,12 +240,13 @@ static int icuNext(
** The set of routines that implement the simple tokenizer ** The set of routines that implement the simple tokenizer
*/ */
static const sqlite3_tokenizer_module icuTokenizerModule = { static const sqlite3_tokenizer_module icuTokenizerModule = {
0, /* iVersion */ 0, /* iVersion */
icuCreate, /* xCreate */ icuCreate, /* xCreate */
icuDestroy, /* xCreate */ icuDestroy, /* xCreate */
icuOpen, /* xOpen */ icuOpen, /* xOpen */
icuClose, /* xClose */ icuClose, /* xClose */
icuNext, /* xNext */ icuNext, /* xNext */
0, /* xLanguageid */
}; };
/* /*

View File

@@ -512,11 +512,11 @@ int sqlite3Fts5StorageDelete(Fts5Storage *p, i64 iDel){
/* Delete the %_docsize record */ /* Delete the %_docsize record */
if( rc==SQLITE_OK && pConfig->bColumnsize ){ if( rc==SQLITE_OK && pConfig->bColumnsize ){
rc = fts5StorageGetStmt(p, FTS5_STMT_DELETE_DOCSIZE, &pDel, 0); rc = fts5StorageGetStmt(p, FTS5_STMT_DELETE_DOCSIZE, &pDel, 0);
} if( rc==SQLITE_OK ){
if( rc==SQLITE_OK ){ sqlite3_bind_int64(pDel, 1, iDel);
sqlite3_bind_int64(pDel, 1, iDel); sqlite3_step(pDel);
sqlite3_step(pDel); rc = sqlite3_reset(pDel);
rc = sqlite3_reset(pDel); }
} }
/* Delete the %_content record */ /* Delete the %_content record */

View File

@@ -108,5 +108,12 @@ do_execsql_test 3.1 {
} { } {
1 {2 0 1} 2 {3 0 0} 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 finish_test

View File

@@ -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}} 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 finish_test

View File

@@ -83,7 +83,6 @@ static int icuLikeCompare(
/* Read (and consume) the next character from the input pattern. */ /* Read (and consume) the next character from the input pattern. */
UChar32 uPattern; UChar32 uPattern;
U8_NEXT_UNSAFE(zPattern, iPattern, uPattern); U8_NEXT_UNSAFE(zPattern, iPattern, uPattern);
assert(uPattern!=0);
/* There are now 4 possibilities: /* There are now 4 possibilities:
** **
@@ -422,6 +421,7 @@ static void icuLoadCollation(
int rc; /* Return code from sqlite3_create_collation_x() */ int rc; /* Return code from sqlite3_create_collation_x() */
assert(nArg==2); assert(nArg==2);
(void)nArg; /* Unused parameter */
zLocale = (const char *)sqlite3_value_text(apArg[0]); zLocale = (const char *)sqlite3_value_text(apArg[0]);
zName = (const char *)sqlite3_value_text(apArg[1]); zName = (const char *)sqlite3_value_text(apArg[1]);

View File

@@ -269,5 +269,88 @@ ifcapable rtree {
db close 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 finish_test

44
main.mk
View File

@@ -67,10 +67,11 @@ LIBOBJ+= vdbe.o parse.o \
notify.o opcodes.o os.o os_unix.o os_win.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 \ 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 \ 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 \ update.o userauth.o util.o vacuum.o \
vdbeapi.o vdbeaux.o vdbeblob.o vdbemem.o vdbesort.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.o
LIBOBJ += fts5_aux.o LIBOBJ += fts5_aux.o
@@ -166,6 +167,7 @@ SRC = \
$(TOP)/src/tclsqlite.c \ $(TOP)/src/tclsqlite.c \
$(TOP)/src/threads.c \ $(TOP)/src/threads.c \
$(TOP)/src/tokenize.c \ $(TOP)/src/tokenize.c \
$(TOP)/src/treeview.c \
$(TOP)/src/trigger.c \ $(TOP)/src/trigger.c \
$(TOP)/src/utf.c \ $(TOP)/src/utf.c \
$(TOP)/src/update.c \ $(TOP)/src/update.c \
@@ -186,6 +188,8 @@ SRC = \
$(TOP)/src/wal.h \ $(TOP)/src/wal.h \
$(TOP)/src/walker.c \ $(TOP)/src/walker.c \
$(TOP)/src/where.c \ $(TOP)/src/where.c \
$(TOP)/src/wherecode.c \
$(TOP)/src/whereexpr.c \
$(TOP)/src/whereInt.h $(TOP)/src/whereInt.h
# Source code for extensions # Source code for extensions
@@ -369,6 +373,8 @@ TESTSRC2 = \
$(TOP)/src/vdbe.c \ $(TOP)/src/vdbe.c \
$(TOP)/src/vdbemem.c \ $(TOP)/src/vdbemem.c \
$(TOP)/src/where.c \ $(TOP)/src/where.c \
$(TOP)/src/wherecode.c \
$(TOP)/src/whereexpr.c \
parse.c \ parse.c \
$(TOP)/ext/fts3/fts3.c \ $(TOP)/ext/fts3/fts3.c \
$(TOP)/ext/fts3/fts3_aux.c \ $(TOP)/ext/fts3/fts3_aux.c \
@@ -446,6 +452,10 @@ FUZZDATA = \
$(TOP)/test/fuzzdata2.db \ $(TOP)/test/fuzzdata2.db \
$(TOP)/test/fuzzdata3.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 # This is the default Makefile target. The objects listed here
# are what get build when you type just "make" with no arguments. # 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) -o testfixture$(EXE) $(LIBTCL) $(THREADLIB)
fulltest: $(TESTPROGS) fuzztest fulltest: $(TESTPROGS) fuzztest
./testfixture$(EXE) $(TOP)/test/all.test ./testfixture$(EXE) $(TOP)/test/all.test $(TESTOPTS)
soaktest: $(TESTPROGS) soaktest: $(TESTPROGS)
./testfixture$(EXE) $(TOP)/test/all.test -soak=1 ./testfixture$(EXE) $(TOP)/test/all.test -soak=1 $(TESTOPTS)
fulltestonly: $(TESTPROGS) fuzztest fulltestonly: $(TESTPROGS) fuzztest
./testfixture$(EXE) $(TOP)/test/full.test ./testfixture$(EXE) $(TOP)/test/full.test $(TESTOPTS)
queryplantest: testfixture$(EXE) sqlite3$(EXE) queryplantest: testfixture$(EXE) sqlite3$(EXE)
./testfixture$(EXE) $(TOP)/test/permutations.test queryplanner ./testfixture$(EXE) $(TOP)/test/permutations.test queryplanner $(TESTOPTS)
fuzztest: fuzzcheck$(EXE) $(FUZZDATA) fuzztest: fuzzcheck$(EXE) $(FUZZDATA)
./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 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 # Run a test using valgrind. This can take a really long time
# because valgrind is so much slower than a native machine. # because valgrind is so much slower than a native machine.
# #
valgrindtest: $(TESTPROGS) fuzzcheck$(EXE) $(FUZZDATA) valgrindtest: $(TESTPROGS) valgrindfuzz
valgrind -v ./fuzzcheck$(EXE) --cell-size-check --quiet $(FUZZDATA) OMIT_MISUSE=1 valgrind -v \
OMIT_MISUSE=1 valgrind -v ./testfixture$(EXE) $(TOP)/test/permutations.test valgrind ./testfixture$(EXE) $(TOP)/test/permutations.test valgrind $(TESTOPTS)
# A very fast test that checks basic sanity. The name comes from # A very fast test that checks basic sanity. The name comes from
# the 60s-era electronics testing: "Turn it on and see if smoke # the 60s-era electronics testing: "Turn it on and see if smoke
# comes out." # comes out."
# #
smoketest: $(TESTPROGS) fuzzcheck$(EXE) 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 # 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 # threadtest runs a few thread-safety tests that are implemented in C. This

140
manifest
View File

@@ -1,9 +1,9 @@
C Fix\sthe\sfts5\sxRename()\smethod. C Merge\slatest\strunk\schanges\swith\sthis\sbranch.\sAdd\stests\sfor\scolumnsize=0.
D 2015-06-10T10:45:34.820 D 2015-06-23T15:06:13.029
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in d272f8755b464f20e02dd7799bfe16794c9574c4 F Makefile.in 6fa5a3c6f1f558bb443429e33806e2e494823e44
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
F Makefile.msc d37d2c2323df3acae6e24c71a478889421c17264 F Makefile.msc b7db9ccbbad1c495b98e5326a06cac03aa206127
F Makefile.vxworks e1b65dea203f054e71653415bd8f96dcaed47858 F Makefile.vxworks e1b65dea203f054e71653415bd8f96dcaed47858
F README.md 8ecc12493ff9f820cdea6520a9016001cb2e59b7 F README.md 8ecc12493ff9f820cdea6520a9016001cb2e59b7
F VERSION ce0ae95abd7121c534f6917c1c8f2b70d9acd4db 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_expr.c 71c063da9c2a4167fb54aec089dd5ef33a58c9cb
F ext/fts3/fts3_hash.c 29b986e43f4e9dd40110eafa377dc0d63c422c60 F ext/fts3/fts3_hash.c 29b986e43f4e9dd40110eafa377dc0d63c422c60
F ext/fts3/fts3_hash.h 39cf6874dc239d6b4e30479b1975fe5b22a3caaf 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_porter.c 3565faf04b626cddf85f03825e86056a4562c009
F ext/fts3/fts3_snippet.c 68ae118b0f834ea53d2b89e4087fc0f0b8c4ee4e F ext/fts3/fts3_snippet.c 68ae118b0f834ea53d2b89e4087fc0f0b8c4ee4e
F ext/fts3/fts3_term.c 88c55a6fa1a51ab494e33dced0401a6c28791fd7 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_expr.c 549bda1f7edcf10365fbfbc002bdea1be3c287bb
F ext/fts5/fts5_hash.c c1cfdb2cae0fad00b06fae38a40eaf9261563ccc F ext/fts5/fts5_hash.c c1cfdb2cae0fad00b06fae38a40eaf9261563ccc
F ext/fts5/fts5_index.c 7cea402924cd3d8cd5943a7f9514c9153696571b 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_tcl.c 7ea165878e4ae3598e89acd470a0ee1b5a00e33c
F ext/fts5/fts5_tokenize.c 97251d68d7a6a9415bde1203f9382864dfc1f989 F ext/fts5/fts5_tokenize.c 97251d68d7a6a9415bde1203f9382864dfc1f989
F ext/fts5/fts5_unicode2.c da3cf712f05cd8347c8c5bc00964cc0361c88da9 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/fts5aux.test e5631607bbc05ac1c38cf7d691000509aca71ef3
F ext/fts5/test/fts5auxdata.test c69b86092bf1a157172de5f9169731af3403179b F ext/fts5/test/fts5auxdata.test c69b86092bf1a157172de5f9169731af3403179b
F ext/fts5/test/fts5bigpl.test b1cfd00561350ab04994ba7dd9d48468e5e0ec3b 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/fts5config.test c9cc535f3b36cde1e5a32bf579f3f5962a9e82b2
F ext/fts5/test/fts5content.test e46904decd896e38c848ad4f38fa4e80251a028b F ext/fts5/test/fts5content.test e46904decd896e38c848ad4f38fa4e80251a028b
F ext/fts5/test/fts5corrupt.test 35bfdbbb3cdcea46ae7385f6432e9b5c574e70a1 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/fts5fault1.test b42d3296be8a75f557cf2cbce0d8b483fc9db45b
F ext/fts5/test/fts5fault2.test 28c36c843bb39ae855ba79827417ecc37f114341 F ext/fts5/test/fts5fault2.test 28c36c843bb39ae855ba79827417ecc37f114341
F ext/fts5/test/fts5fault3.test d6e9577d4312e331a913c72931bf131704efc8f3 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/fts5fault5.test 54da9fd4c3434a1d4f6abdcb6469299d91cf5875
F ext/fts5/test/fts5fault6.test 234dc6355f8d3f8b5be2763f30699d770247c215 F ext/fts5/test/fts5fault6.test 234dc6355f8d3f8b5be2763f30699d770247c215
F ext/fts5/test/fts5full.test 0924bdca5416a242103239ace79c6f5aa34bab8d 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/loadfts5.tcl 7ef3e62131f0434a78e4f5c5b056b09d221710a8
F ext/fts5/tool/showfts5.tcl 921f33b30c3189deefd2b2cc81f951638544aaf1 F ext/fts5/tool/showfts5.tcl 921f33b30c3189deefd2b2cc81f951638544aaf1
F ext/icu/README.txt d9fbbad0c2f647c3fdf715fc9fd64af53aedfc43 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/icu/sqliteicu.h 728867a802baa5a96de7495e9689a8e01715ef37
F ext/misc/amatch.c 27b9b601fb1453084e18a3432ea0240d7af8decb F ext/misc/amatch.c 27b9b601fb1453084e18a3432ea0240d7af8decb
F ext/misc/closure.c 636024302cde41b2bf0c542f81c40c624cfb7012 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/rtree9.test b5eb13849545dfd271a54ff16784cb00d8792aea
F ext/rtree/rtreeA.test ace05e729a36e342d40cf94e9efc7b4723d9dcdf F ext/rtree/rtreeA.test ace05e729a36e342d40cf94e9efc7b4723d9dcdf
F ext/rtree/rtreeB.test c85f9ce78766c4e68b8b89fbf2979ee9cfa82b4e 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/rtreeD.test 636630357638f5983701550b37f0f5867130d2ca
F ext/rtree/rtreeE.test 45a147a64a76306172819562309681d8e90f94bb F ext/rtree/rtreeE.test 45a147a64a76306172819562309681d8e90f94bb
F ext/rtree/rtreeF.test 66deb9fd1611c7ca2e374adba63debdc2dbb12b4 F ext/rtree/rtreeF.test 66deb9fd1611c7ca2e374adba63debdc2dbb12b4
@@ -247,7 +247,7 @@ F ext/userauth/userauth.c 5fa3bdb492f481bbc1709fc83c91ebd13460c69e
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8 F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60 F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60
F main.mk dc2b1bf580712422d5a8bb774d8d940940563fb8 F main.mk 080c85fad8bf6532b7aeb782452b78e4440de346
F mkopcodec.awk c2ff431854d702cdd2d779c9c0d1f58fa16fa4ea F mkopcodec.awk c2ff431854d702cdd2d779c9c0d1f58fa16fa4ea
F mkopcodeh.awk d5e22023b5238985bb54a72d33e0ac71fe4f8a32 F mkopcodeh.awk d5e22023b5238985bb54a72d33e0ac71fe4f8a32
F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83 F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83
@@ -268,30 +268,30 @@ F src/auth.c b56c78ebe40a2110fd361379f7e8162d23f92240
F src/backup.c ff743689c4d6c5cb55ad42ed9d174b2b3e71f1e3 F src/backup.c ff743689c4d6c5cb55ad42ed9d174b2b3e71f1e3
F src/bitvec.c 5eb7958c3bf65210211cbcfc44eff86d0ded7c9d F src/bitvec.c 5eb7958c3bf65210211cbcfc44eff86d0ded7c9d
F src/btmutex.c 45a968cc85afed9b5e6cf55bf1f42f8d18107f79 F src/btmutex.c 45a968cc85afed9b5e6cf55bf1f42f8d18107f79
F src/btree.c c73a170115df068764126a85288cdec092ec180c F src/btree.c 173c2ba1b8cf941971683f584965369791125f12
F src/btree.h 969adc948e89e449220ff0ff724c94bb2a52e9f1 F src/btree.h 969adc948e89e449220ff0ff724c94bb2a52e9f1
F src/btreeInt.h 973a22a6fd61350b454ad614832b1f0a5e25a1e4 F src/btreeInt.h 6ece2dd9c8e2eac05f0a8ded8772a44e96486c65
F src/build.c 73da2b9e9311abc4fcb4e36f76c7800c2d2504a4 F src/build.c b3f15255d5b16e42dafeaa638fd4f8a47c94ed70
F src/callback.c 7b44ce59674338ad48b0e84e7b72f935ea4f68b0 F src/callback.c 7b44ce59674338ad48b0e84e7b72f935ea4f68b0
F src/complete.c a5cf5b4b56390cfb7b8636e8f7ddef90258dd575 F src/complete.c a5cf5b4b56390cfb7b8636e8f7ddef90258dd575
F src/ctime.c 5a0b735dc95604766f5dac73973658eef782ee8b F src/ctime.c 5a0b735dc95604766f5dac73973658eef782ee8b
F src/date.c e4d50b3283696836ec1036b695ead9a19e37a5ac F src/date.c e4d50b3283696836ec1036b695ead9a19e37a5ac
F src/dbstat.c f402e77e25089c6003d0c60b3233b9b3947d599a F src/dbstat.c f402e77e25089c6003d0c60b3233b9b3947d599a
F src/delete.c 37964e6c1d73ff49cbea9ff690c9605fb15f600e F src/delete.c 8857a6f27560718f65d43bdbec86c967ae1f8dfa
F src/expr.c 52f5c1c2c16bf47234dc276d9f72b5ea85ae14af F src/expr.c 32c836d9fa22c25371039febf074849dcefb3de9
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
F src/fkey.c c9b63a217d86582c22121699a47f22f524608869 F src/fkey.c c9b63a217d86582c22121699a47f22f524608869
F src/func.c 5b8b8e77a0fb644eaf8947d413804622e32692b6 F src/func.c a98ea5880dc50e9ca6dd6f57079a37b9cfcdecf1
F src/global.c 4f77cadbc5427d00139ba43d0f3979804cbb700e F src/global.c 4f77cadbc5427d00139ba43d0f3979804cbb700e
F src/hash.c 4263fbc955f26c2e8cdc0cf214bc42435aa4e4f5 F src/hash.c 4263fbc955f26c2e8cdc0cf214bc42435aa4e4f5
F src/hash.h c8f3c31722cf3277d03713909761e152a5b81094 F src/hash.h c8f3c31722cf3277d03713909761e152a5b81094
F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08 F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08
F src/insert.c d6e1623a97ce33e9af2f1a0c1f0085a2f63327ef F src/insert.c b5f8b35a1b7924020e48cade5b2b5017bca7906b
F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d
F src/legacy.c ba1863ea58c4c840335a84ec276fc2b25e22bc4e F src/legacy.c ba1863ea58c4c840335a84ec276fc2b25e22bc4e
F src/lempar.c 7274c97d24bb46631e504332ccd3bd1b37841770 F src/lempar.c 7274c97d24bb46631e504332ccd3bd1b37841770
F src/loadext.c 29255bbe1cfb2ce9bbff2526a5ecfddcb49b9271 F src/loadext.c e722f4b832f923744788365df5fb8515c0bc8a47
F src/main.c 33562894d96cb65f4926cd5317725427cdb22770 F src/main.c fb40edfcda10062e4d1adab7f41635002e9b7e9d
F src/malloc.c 908c780fdddd472163c2d1b1820ae4081f01ad20 F src/malloc.c 908c780fdddd472163c2d1b1820ae4081f01ad20
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645 F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
F src/mem1.c abe6ee469b6c5a35c7f22bfeb9c9bac664a1c987 F src/mem1.c abe6ee469b6c5a35c7f22bfeb9c9bac664a1c987
@@ -300,7 +300,7 @@ F src/mem3.c 61c9d47b792908c532ca3a62b999cf21795c6534
F src/mem5.c 61eeb90134f9a5be6c2e68d8daae7628b25953fb F src/mem5.c 61eeb90134f9a5be6c2e68d8daae7628b25953fb
F src/memjournal.c 3eb2c0b51adbd869cb6a44780323f05fa904dc85 F src/memjournal.c 3eb2c0b51adbd869cb6a44780323f05fa904dc85
F src/msvc.h d9ba56c6851227ab44b3f228a35f3f5772296495 F src/msvc.h d9ba56c6851227ab44b3f228a35f3f5772296495
F src/mutex.c 19bf9acba69ca2f367c3761080f8a9f0cf4670a8 F src/mutex.c 529e95739f815300a33c73fd8a7d6bdf0c24bd18
F src/mutex.h 779d588e3b7756ec3ecf7d78cde1d84aba414f85 F src/mutex.h 779d588e3b7756ec3ecf7d78cde1d84aba414f85
F src/mutex_noop.c 529bab0743c3321c940f32c3464de494fd38cfa9 F src/mutex_noop.c 529bab0743c3321c940f32c3464de494fd38cfa9
F src/mutex_unix.c 5cf676464bd19e0a866297515d146e8bf1669dfb F src/mutex_unix.c 5cf676464bd19e0a866297515d146e8bf1669dfb
@@ -318,20 +318,20 @@ F src/pager.h c3476e7c89cdf1c6914e50a11f3714e30b4e0a77
F src/parse.y 6d60dda8f8d418b6dc034f1fbccd816c459983a8 F src/parse.y 6d60dda8f8d418b6dc034f1fbccd816c459983a8
F src/pcache.c 10539fb959849ad6efff80050541cab3d25089d4 F src/pcache.c 10539fb959849ad6efff80050541cab3d25089d4
F src/pcache.h b44658c9c932d203510279439d891a2a83e12ba8 F src/pcache.h b44658c9c932d203510279439d891a2a83e12ba8
F src/pcache1.c 69d137620a305f814398bd29a0c998038c0695e9 F src/pcache1.c 8e3799b33c41d517d86444d4abefc80d4f02adca
F src/pragma.c c1f4d012ea9f6b1ce52d341b2cd0ad72d560afd7 F src/pragma.c c1f4d012ea9f6b1ce52d341b2cd0ad72d560afd7
F src/pragma.h b8632d7cdda7b25323fa580e3e558a4f0d4502cc F src/pragma.h b8632d7cdda7b25323fa580e3e558a4f0d4502cc
F src/prepare.c 82e5db1013846a819f198336fed72c44c974e7b1 F src/prepare.c 82e5db1013846a819f198336fed72c44c974e7b1
F src/printf.c 13ce37e5574f9b0682fa86dbcf9faf76b9d82a15 F src/printf.c db11b5960105ee661dcac690f2ae6276e49bf251
F src/random.c ba2679f80ec82c4190062d756f22d0c358180696 F src/random.c ba2679f80ec82c4190062d756f22d0c358180696
F src/resolve.c 84c571794e3ee5806274d95158a4c0177c6c4708 F src/resolve.c 2d47554370de8de6dd5be060cef9559eec315005
F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e
F src/select.c 7bb5c6334128877a30d4644fb948098a3ec41bbc F src/select.c 09865f89997db6ec617a78440cc18d84855e3053
F src/shell.c 07dda7cd692911d2f22269953418d049f2e2c0ee F src/shell.c 8af3cced094aebb5f57a8ad739b9dafc7867eed7
F src/sqlite.h.in d165beeceb6b40af60f352a4d4e37e02d9af7df0 F src/sqlite.h.in 76d2f5637eb795b6300d9dd3c3ec3632ffafd721
F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad
F src/sqlite3ext.h 2ebeb634e751a61a6f0eebfa0f4669f46a42f6cd F src/sqlite3ext.h be1a718b7d2ce40ceba725ae92c8eb5f18003066
F src/sqliteInt.h bcf51f6ec3ad67dbdf1acf78fcb94884af93c183 F src/sqliteInt.h d5df694bc33870e77fb08f389d12309597fe3059
F src/sqliteLimit.h 216557999cb45f2e3578ed53ebefe228d779cb46 F src/sqliteLimit.h 216557999cb45f2e3578ed53ebefe228d779cb46
F src/status.c f266ad8a2892d659b74f0f50cb6a88b6e7c12179 F src/status.c f266ad8a2892d659b74f0f50cb6a88b6e7c12179
F src/table.c 51b46b2a62d1b3a959633d593b89bab5e2c9155e F src/table.c 51b46b2a62d1b3a959633d593b89bab5e2c9155e
@@ -382,19 +382,20 @@ F src/test_vfs.c 3b65d42e18b262805716bd96178c81da8f2d9283
F src/test_vfstrace.c bab9594adc976cbe696ff3970728830b4c5ed698 F src/test_vfstrace.c bab9594adc976cbe696ff3970728830b4c5ed698
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9 F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
F src/threads.c 6bbcc9fe50c917864d48287b4792d46d6e873481 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/trigger.c 322f23aad694e8f31d384dcfa386d52a48d3c52f
F src/update.c 487747b328b7216bb7f6af0695d6937d5c9e605f F src/update.c 487747b328b7216bb7f6af0695d6937d5c9e605f
F src/utf.c fc6b889ba0779b7722634cdeaa25f1930d93820c F src/utf.c fc6b889ba0779b7722634cdeaa25f1930d93820c
F src/util.c a6431c92803b975b7322724a7b433e538d243539 F src/util.c a6431c92803b975b7322724a7b433e538d243539
F src/vacuum.c 2ddd5cad2a7b9cef7f9e431b8c7771634c6b1701 F src/vacuum.c 2ddd5cad2a7b9cef7f9e431b8c7771634c6b1701
F src/vdbe.c 0a6a1df5c31415a0e974e74e7bd412616889453d F src/vdbe.c c9b8985dfc5df9bd512342ea2e56af4be30cb31a
F src/vdbe.h 7e538ecf47dccb307ea2d087c3ddc2dd8d70e79d F src/vdbe.h 90048aea1910f9df93e6044592bd4a466dc9c5e7
F src/vdbeInt.h f0ccddac48583d5f762dc554a9f79e85ea8807e0 F src/vdbeInt.h 20295e482121d13437f69985f77db211cdc8bac1
F src/vdbeapi.c 6a0d7757987018ff6b1b81bc5293219cd26bb299 F src/vdbeapi.c 6a0d7757987018ff6b1b81bc5293219cd26bb299
F src/vdbeaux.c 46f9bc4b32866082eb87a36b461e487a0bbdbe8e F src/vdbeaux.c 4c82d6f686f72ea7d266d26d528a171b728626f7
F src/vdbeblob.c 4f2e8e075d238392df98c5e03a64342465b03f90 F src/vdbeblob.c 4f2e8e075d238392df98c5e03a64342465b03f90
F src/vdbemem.c 67b302dc6df64b4d6785881c5d22bd4f9b17739d F src/vdbemem.c 4e947cd322bb531e3f7f6f58f0f536d182b38ef8
F src/vdbesort.c f5009e7a35e3065635d8918b9a31f498a499976b F src/vdbesort.c f5009e7a35e3065635d8918b9a31f498a499976b
F src/vdbetrace.c 8befe829faff6d9e6f6e4dee5a7d3f85cc85f1a0 F src/vdbetrace.c 8befe829faff6d9e6f6e4dee5a7d3f85cc85f1a0
F src/vtab.c 082b35a25a26e3d36f365ca8cd73c1922532f05e F src/vtab.c 082b35a25a26e3d36f365ca8cd73c1922532f05e
@@ -402,8 +403,10 @@ F src/vxworks.h c18586c8edc1bddbc15c004fa16aeb1e1342b4fb
F src/wal.c ce2cb2d06faab54d1bce3e739bec79e063dd9113 F src/wal.c ce2cb2d06faab54d1bce3e739bec79e063dd9113
F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4
F src/walker.c c253b95b4ee44b21c406e2a1052636c31ea27804 F src/walker.c c253b95b4ee44b21c406e2a1052636c31ea27804
F src/where.c dcdfee81d35ae9261a4c5bda6289ed5fa6d7e1ae F src/where.c 909eba3b6db984eb2adfbca9de2c237ee7056adb
F src/whereInt.h a6f5a762bc1b4b1c76e1cea79976b437ac35a435 F src/whereInt.h 5f87e3c4b0551747d119730dfebddd3c54f04047
F src/wherecode.c 0669481cabaf5caf934b6bb825df15bc57f60d40
F src/whereexpr.c 9ce1c9cfedbf80c93c7d899497025ec8256ce652
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
F test/affinity2.test a6d901b436328bd67a79b41bb0ac2663918fe3bd F test/affinity2.test a6d901b436328bd67a79b41bb0ac2663918fe3bd
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
@@ -430,7 +433,7 @@ F test/analyzeC.test 555a6cc388b9818b6eda6df816f01ce0a75d3a93
F test/analyzeD.test 08f9d0bee4e118a66fff3a32d02dbe0ee0a2b594 F test/analyzeD.test 08f9d0bee4e118a66fff3a32d02dbe0ee0a2b594
F test/analyzeE.test 8684e8ac5722fb97c251887ad97e5d496a98af1d F test/analyzeE.test 8684e8ac5722fb97c251887ad97e5d496a98af1d
F test/analyzeF.test 7ccd7a04f7d3061bde1a8a4dacc4792edccf6bf2 F test/analyzeF.test 7ccd7a04f7d3061bde1a8a4dacc4792edccf6bf2
F test/analyzer1.test e3bccac3be49382050464952998a631bf51e3ce1 F test/analyzer1.test 498e2ff4b62740c2751c3a2f8b744fe26689fae9
F test/async.test 1d0e056ba1bb9729283a0f22718d3a25e82c277b F test/async.test 1d0e056ba1bb9729283a0f22718d3a25e82c277b
F test/async2.test c0a9bd20816d7d6a2ceca7b8c03d3d69c28ffb8b F test/async2.test c0a9bd20816d7d6a2ceca7b8c03d3d69c28ffb8b
F test/async3.test d73a062002376d7edc1fe3edff493edbec1fc2f7 F test/async3.test d73a062002376d7edc1fe3edff493edbec1fc2f7
@@ -530,7 +533,7 @@ F test/corruptE.test 193b4ca4e927e77c1d5f4f56203ddc998432a7ee
F test/corruptF.test be9fde98e4c93648f1ba52b74e5318edc8f59fe4 F test/corruptF.test be9fde98e4c93648f1ba52b74e5318edc8f59fe4
F test/corruptG.test 1ab3bf97ee7bdba70e0ff3ba2320657df55d1804 F test/corruptG.test 1ab3bf97ee7bdba70e0ff3ba2320657df55d1804
F test/corruptH.test 5dd4fa98c6c1ed33b178f9e8a48c4fdd3cfc9067 F test/corruptH.test 5dd4fa98c6c1ed33b178f9e8a48c4fdd3cfc9067
F test/corruptI.test ddf8c7146db0bc6080eedced67453b4cc69b5340 F test/corruptI.test f2b10e4fec2a4315bca2b936ffa52ccbffac3422
F test/corruptJ.test 9e29e7a81ee3b6ac50f77ea7a9e2f3fa03f32d91 F test/corruptJ.test 9e29e7a81ee3b6ac50f77ea7a9e2f3fa03f32d91
F test/cost.test 19d314526616ce4473eb4e4e450fcb94499ce318 F test/cost.test 19d314526616ce4473eb4e4e450fcb94499ce318
F test/count.test cb2e0f934c6eb33670044520748d2ecccd46259c F test/count.test cb2e0f934c6eb33670044520748d2ecccd46259c
@@ -583,7 +586,7 @@ F test/e_update.test 312cb8f5ccfe41515a6bb092f8ea562a9bd54d52
F test/e_uri.test 5ae33760fb2039c61aa2d90886f1664664173585 F test/e_uri.test 5ae33760fb2039c61aa2d90886f1664664173585
F test/e_vacuum.test 5bfbdc21b65c0abf24398d0ba31dc88d93ca77a9 F test/e_vacuum.test 5bfbdc21b65c0abf24398d0ba31dc88d93ca77a9
F test/e_wal.test ae9a593207a77d711443ee69ffe081fda9243625 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_walckpt.test 65e29b6631e51f210f83e4ff11571e647ba93608
F test/e_walhook.test da3ea8b3483d1af72190337bda50155a91a4b664 F test/e_walhook.test da3ea8b3483d1af72190337bda50155a91a4b664
F test/enc.test e54531cd6bf941ee6760be041dff19a104c7acea F test/enc.test e54531cd6bf941ee6760be041dff19a104c7acea
@@ -599,8 +602,9 @@ F test/exec.test e949714dc127eaa5ecc7d723efec1ec27118fdd7
F test/exists.test 8f7b27b61c2fbe5822f0a1f899c715d14e416e30 F test/exists.test 8f7b27b61c2fbe5822f0a1f899c715d14e416e30
F test/expr.test 79c3e7502d9e571553b85f0ecc8ff2ac7d0e4931 F test/expr.test 79c3e7502d9e571553b85f0ecc8ff2ac7d0e4931
F test/extension01.test 00d13cec817f331a687a243e0e5a2d87b0e358c9 F test/extension01.test 00d13cec817f331a687a243e0e5a2d87b0e358c9
F test/extraquick.test cb254400bd42bfb777ff675356aabf3287978f79
F test/fallocate.test 3e979af17dfa7e5e9dda5eba1a696c04fa9d47f7 F test/fallocate.test 3e979af17dfa7e5e9dda5eba1a696c04fa9d47f7
F test/filectrl.test 14fa712e42c4cb791e09dfd58a6a03efb47ef13a F test/filectrl.test 7c13f96457435238da99aff7343ad6a3a4885787
F test/filefmt.test cb34663f126cbc2d358af552dcaf5c72769b0146 F test/filefmt.test cb34663f126cbc2d358af552dcaf5c72769b0146
F test/fkey1.test de5b287f6a480b36bd51e8debcf48168e26e4ed2 F test/fkey1.test de5b287f6a480b36bd51e8debcf48168e26e4ed2
F test/fkey2.test f3d27ecba480a348c328965d154214719bb158a9 F test/fkey2.test f3d27ecba480a348c328965d154214719bb158a9
@@ -675,7 +679,7 @@ F test/fts3conf.test ee8500c86dd58ec075e8831a1e216a79989436de
F test/fts3corrupt.test 2710b77983cc7789295ddbffea52c1d3b7506dbb F test/fts3corrupt.test 2710b77983cc7789295ddbffea52c1d3b7506dbb
F test/fts3corrupt2.test 6d96efae2f8a6af3eeaf283aba437e6d0e5447ba F test/fts3corrupt2.test 6d96efae2f8a6af3eeaf283aba437e6d0e5447ba
F test/fts3cov.test e0fb00d8b715ddae4a94c305992dfc3ef70353d7 F test/fts3cov.test e0fb00d8b715ddae4a94c305992dfc3ef70353d7
F test/fts3d.test 95c17d1b67b33a5eac0bf5a0d11116a0c0ac7a3a F test/fts3d.test d3e9c8fb75135ada06bf3bab4f9666224965d708
F test/fts3defer.test 0be4440b73a2e651fc1e472066686d6ada4b9963 F test/fts3defer.test 0be4440b73a2e651fc1e472066686d6ada4b9963
F test/fts3defer2.test c540f5f5c2840f70c68fd9b597df817ec7170468 F test/fts3defer2.test c540f5f5c2840f70c68fd9b597df817ec7170468
F test/fts3defer3.test dd53fc13223c6d8264a98244e9b19abd35ed71cd F test/fts3defer3.test dd53fc13223c6d8264a98244e9b19abd35ed71cd
@@ -709,14 +713,14 @@ F test/fts4content.test abb0c77bc3da3df64fec72e00844d2257a90025d
F test/fts4docid.test e33c383cfbdff0284685604d256f347a18fdbf01 F test/fts4docid.test e33c383cfbdff0284685604d256f347a18fdbf01
F test/fts4growth.test df10fde9f47cf5c71861e63fd8efcd573c4f7e53 F test/fts4growth.test df10fde9f47cf5c71861e63fd8efcd573c4f7e53
F test/fts4growth2.test 2f063be1902a73cd087355837c52fed42ac11a5d F test/fts4growth2.test 2f063be1902a73cd087355837c52fed42ac11a5d
F test/fts4incr.test 361960ed3550e781f3f313e17e2182ef9cefc0e9 F test/fts4incr.test 4e353a0bd886ea984e56fce9e77724fc923b8d0d
F test/fts4langid.test 24a6e41063b416bbdf371ff6b4476fa41c194aa7 F test/fts4langid.test 24a6e41063b416bbdf371ff6b4476fa41c194aa7
F test/fts4merge.test c424309743fdd203f8e56a1f1cd7872cd66cc0ee F test/fts4merge.test c424309743fdd203f8e56a1f1cd7872cd66cc0ee
F test/fts4merge2.test 5faa558d1b672f82b847d2a337465fa745e46891 F test/fts4merge2.test 5faa558d1b672f82b847d2a337465fa745e46891
F test/fts4merge3.test aab02a09f50fe6baaddc2e159c3eabc116d45fc7 F test/fts4merge3.test aab02a09f50fe6baaddc2e159c3eabc116d45fc7
F test/fts4merge4.test d895b1057a7798b67e03455d0fa50e9ea836c47b F test/fts4merge4.test d895b1057a7798b67e03455d0fa50e9ea836c47b
F test/fts4noti.test 524807f0c36d49deea7920cdd4cd687408b58849 F test/fts4noti.test 524807f0c36d49deea7920cdd4cd687408b58849
F test/fts4unicode.test 01ec3fe2a7c3cfff3b4c0581b83caa11b33efa36 F test/fts4unicode.test 27378af76394542cf490cf001d8d1505fe55f6a9
F test/full.test 6b3c8fb43c6beab6b95438c1675374b95fab245d F test/full.test 6b3c8fb43c6beab6b95438c1675374b95fab245d
F test/func.test ae97561957aba6ca9e3a7b8a13aac41830d701ef F test/func.test ae97561957aba6ca9e3a7b8a13aac41830d701ef
F test/func2.test 772d66227e4e6684b86053302e2d74a2500e1e0f F test/func2.test 772d66227e4e6684b86053302e2d74a2500e1e0f
@@ -729,10 +733,10 @@ F test/fuzz2.test 76dc35b32b6d6f965259508508abce75a6c4d7e1
F test/fuzz3.test efd384b896c647b61a2c1848ba70d42aad60a7b3 F test/fuzz3.test efd384b896c647b61a2c1848ba70d42aad60a7b3
F test/fuzz_common.tcl a87dfbb88c2a6b08a38e9a070dabd129e617b45b F test/fuzz_common.tcl a87dfbb88c2a6b08a38e9a070dabd129e617b45b
F test/fuzz_malloc.test 328f70aaca63adf29b4c6f06505ed0cf57ca7c26 F test/fuzz_malloc.test 328f70aaca63adf29b4c6f06505ed0cf57ca7c26
F test/fuzzcheck.c a60f926e3fa86c8d33908406d75eec868c22b9ca F test/fuzzcheck.c 5805b2236292f8643d56e727a3a6e4d88e0856a5
F test/fuzzdata1.db b60254eeb6bc11474071b883059662a73c48da7f F test/fuzzdata1.db 7ee3227bad0e7ccdeb08a9e6822916777073c664
F test/fuzzdata2.db f03a420d3b822cc82e4f894ca957618fbe9c4973 F test/fuzzdata2.db f03a420d3b822cc82e4f894ca957618fbe9c4973
F test/fuzzdata3.db 3632e598ff8574228aadf09897bd040d3c5f5ffb F test/fuzzdata3.db 77bed4fc8c4945124ed5616daf2dc4f4c3bf762a
F test/fuzzer1.test d4c52aaf3ef923da293a2653cfab33d02f718a36 F test/fuzzer1.test d4c52aaf3ef923da293a2653cfab33d02f718a36
F test/fuzzerfault.test 8792cd77fd5bce765b05d0c8e01b9edcf8af8536 F test/fuzzerfault.test 8792cd77fd5bce765b05d0c8e01b9edcf8af8536
F test/genesis.tcl 1e2e2e8e5cc4058549a154ff1892fe5c9de19f98 F test/genesis.tcl 1e2e2e8e5cc4058549a154ff1892fe5c9de19f98
@@ -740,7 +744,7 @@ F test/hexlit.test 1d312fa816dfd3650a3bb488093bc09a0c927f67
F test/hook.test 162d7cef7a2d2b04839fe14402934e6a1b79442f F test/hook.test 162d7cef7a2d2b04839fe14402934e6a1b79442f
F test/icu.test 70df4faca133254c042d02ae342c0a141f2663f4 F test/icu.test 70df4faca133254c042d02ae342c0a141f2663f4
F test/imposter1.test c3f1db2d3db2c24611a6596a3fc0ffc14f1466c8 F test/imposter1.test c3f1db2d3db2c24611a6596a3fc0ffc14f1466c8
F test/in.test b52fa96bcf6cebc5c8829c822315d0f87af9c6c2 F test/in.test 61a24ae38d4b64ec69f06ccdf022992f68a98176
F test/in2.test 5d4c61d17493c832f7d2d32bef785119e87bde75 F test/in2.test 5d4c61d17493c832f7d2d32bef785119e87bde75
F test/in3.test 3cbf58c87f4052cee3a58b37b6389777505aa0c0 F test/in3.test 3cbf58c87f4052cee3a58b37b6389777505aa0c0
F test/in4.test d2b38cba404bc4320f4fe1b595b3d163f212c068 F test/in4.test d2b38cba404bc4320f4fe1b595b3d163f212c068
@@ -760,8 +764,8 @@ F test/index.test 4d990005a67a36984e4f1a5f1bdccea8d08da4ee
F test/index2.test ee83c6b5e3173a3d7137140d945d9a5d4fdfb9d6 F test/index2.test ee83c6b5e3173a3d7137140d945d9a5d4fdfb9d6
F test/index3.test b6ec456cf3b81d9a32123fe7e449bde434db338b F test/index3.test b6ec456cf3b81d9a32123fe7e449bde434db338b
F test/index4.test ab92e736d5946840236cd61ac3191f91a7856bf6 F test/index4.test ab92e736d5946840236cd61ac3191f91a7856bf6
F test/index5.test 25b0b451aceed4ac5f7d49f856f6de7257470b3e F test/index5.test 8621491915800ec274609e42e02a97d67e9b13e7
F test/index6.test 3ae54e53c53f2adcacda269237d8e52bdb05a481 F test/index6.test fbf45ceb39eb8a01b837d22623b93b208e6509ef
F test/index7.test 9c6765a74fc3fcde7aebc5b3bd40d98df14a527c F test/index7.test 9c6765a74fc3fcde7aebc5b3bd40d98df14a527c
F test/indexedby.test 5f527a78bae74c61b8046ae3037f9dfb0bf0c353 F test/indexedby.test 5f527a78bae74c61b8046ae3037f9dfb0bf0c353
F test/indexfault.test 31d4ab9a7d2f6e9616933eb079722362a883eb1d F test/indexfault.test 31d4ab9a7d2f6e9616933eb079722362a883eb1d
@@ -782,7 +786,7 @@ F test/ioerr3.test d3cec5e1a11ad6d27527d0d38573fbff14c71bdd
F test/ioerr4.test f130fe9e71008577b342b8874d52984bd04ede2c F test/ioerr4.test f130fe9e71008577b342b8874d52984bd04ede2c
F test/ioerr5.test 2edfa4fb0f896f733071303b42224df8bedd9da4 F test/ioerr5.test 2edfa4fb0f896f733071303b42224df8bedd9da4
F test/ioerr6.test a395a6ab144b26a9e3e21059a1ab6a7149cca65b F test/ioerr6.test a395a6ab144b26a9e3e21059a1ab6a7149cca65b
F test/join.test 52d4d49f86d0cf46926672878c4eaf0da399104a F test/join.test f9d4a28dec81c6e9dc21b73518e024d73b5ebf57
F test/join2.test f2171c265e57ee298a27e57e7051d22962f9f324 F test/join2.test f2171c265e57ee298a27e57e7051d22962f9f324
F test/join3.test 6f0c774ff1ba0489e6c88a3e77b9d3528fb4fda0 F test/join3.test 6f0c774ff1ba0489e6c88a3e77b9d3528fb4fda0
F test/join4.test 1a352e4e267114444c29266ce79e941af5885916 F test/join4.test 1a352e4e267114444c29266ce79e941af5885916
@@ -897,13 +901,13 @@ F test/pagesize.test 5769fc62d8c890a83a503f67d47508dfdc543305
F test/pcache.test b09104b03160aca0d968d99e8cd2c5b1921a993d F test/pcache.test b09104b03160aca0d968d99e8cd2c5b1921a993d
F test/pcache2.test a83efe2dec0d392f814bfc998def1d1833942025 F test/pcache2.test a83efe2dec0d392f814bfc998def1d1833942025
F test/percentile.test 4243af26b8f3f4555abe166f723715a1f74c77ff F test/percentile.test 4243af26b8f3f4555abe166f723715a1f74c77ff
F test/permutations.test a54a4c5e66dc158cb2c05579bbb4f7d1a4fdb6c1 F test/permutations.test 6a88fd9ca15b804e9c20990773262ca67494058f
F test/pragma.test be7195f0aa72bdb8a512133e9640ac40f15b57a2 F test/pragma.test be7195f0aa72bdb8a512133e9640ac40f15b57a2
F test/pragma2.test f624a496a95ee878e81e59961eade66d5c00c028 F test/pragma2.test f624a496a95ee878e81e59961eade66d5c00c028
F test/pragma3.test 6f849ccffeee7e496d2f2b5e74152306c0b8757c F test/pragma3.test 6f849ccffeee7e496d2f2b5e74152306c0b8757c
F test/printf.test b3ff34e73d59124140eaf89f7672e21bc2ca5fcc F test/printf.test b3ff34e73d59124140eaf89f7672e21bc2ca5fcc
F test/printf2.test 0b61566dd1c0f0b802f59dffa228c5dc5aa6b054 F test/printf2.test 0b61566dd1c0f0b802f59dffa228c5dc5aa6b054
F test/progress.test a282973d1d17f08071bc58a77d6b80f2a81c354d F test/progress.test ebab27f670bd0d4eb9d20d49cef96e68141d92fb
F test/ptrchng.test ef1aa72d6cf35a2bbd0869a649b744e9d84977fc F test/ptrchng.test ef1aa72d6cf35a2bbd0869a649b744e9d84977fc
F test/queryonly.test 5f653159e0f552f0552d43259890c1089391dcca F test/queryonly.test 5f653159e0f552f0552d43259890c1089391dcca
F test/quick.test 1681febc928d686362d50057c642f77a02c62e57 F test/quick.test 1681febc928d686362d50057c642f77a02c62e57
@@ -916,7 +920,7 @@ F test/randexpr1.test eda062a97e60f9c38ae8d806b03b0ddf23d796df
F test/rdonly.test 64e2696c322e3538df0b1ed624e21f9a23ed9ff8 F test/rdonly.test 64e2696c322e3538df0b1ed624e21f9a23ed9ff8
F test/regexp1.test 497ea812f264d12b6198d6e50a76be4a1973a9d8 F test/regexp1.test 497ea812f264d12b6198d6e50a76be4a1973a9d8
F test/reindex.test 44edd3966b474468b823d481eafef0c305022254 F test/reindex.test 44edd3966b474468b823d481eafef0c305022254
F test/releasetest.tcl 3e906a8bbd047b8e1f035984fbdc96df4caaea47 F test/releasetest.tcl 2aaffa548a8f8d10053b20bcf68a1b5a01081e51
F test/resolver01.test f4022acafda7f4d40eca94dbf16bc5fc4ac30ceb F test/resolver01.test f4022acafda7f4d40eca94dbf16bc5fc4ac30ceb
F test/rollback.test 458fe73eb3ffdfdf9f6ba3e9b7350a6220414dea F test/rollback.test 458fe73eb3ffdfdf9f6ba3e9b7350a6220414dea
F test/rollback2.test fc14cf6d1a2b250d2735ef16124b971bce152f14 F test/rollback2.test fc14cf6d1a2b250d2735ef16124b971bce152f14
@@ -947,8 +951,8 @@ F test/select3.test 2ce595f8fb8e2ac10071d3b4e424cadd4634a054
F test/select4.test 6d5bc6d178a367e8b48fa1c1d3ea12cae9c2d650 F test/select4.test 6d5bc6d178a367e8b48fa1c1d3ea12cae9c2d650
F test/select5.test e758b8ef94f69b111df4cb819008856655dcd535 F test/select5.test e758b8ef94f69b111df4cb819008856655dcd535
F test/select6.test 39eac4a5c03650b2b473c532882273283ee8b7a0 F test/select6.test 39eac4a5c03650b2b473c532882273283ee8b7a0
F test/select7.test 7fd2ef598cfabb6b9ff6ac13973b91d0527df49d F test/select7.test 71f06cd37cb6f65bb08ba1ccf8e2f5818c09329f
F test/select8.test 391de11bdd52339c30580dabbbbe97e3e9a3c79d F test/select8.test 8c8f5ae43894c891efc5755ed905467d1d67ad5d
F test/select9.test aebc2bb0c3bc44606125033cbcaac2c8d1f33a95 F test/select9.test aebc2bb0c3bc44606125033cbcaac2c8d1f33a95
F test/selectA.test e452bdb975f488ea46d091382a9185b5853ed2c7 F test/selectA.test e452bdb975f488ea46d091382a9185b5853ed2c7
F test/selectB.test 954e4e49cf1f896d61794e440669e03a27ceea25 F test/selectB.test 954e4e49cf1f896d61794e440669e03a27ceea25
@@ -961,7 +965,7 @@ F test/server1.test 46803bd3fe8b99b30dbc5ff38ffc756f5c13a118
F test/shared.test 1da9dbad400cee0d93f252ccf76e1ae007a63746 F test/shared.test 1da9dbad400cee0d93f252ccf76e1ae007a63746
F test/shared2.test 03eb4a8d372e290107d34b6ce1809919a698e879 F test/shared2.test 03eb4a8d372e290107d34b6ce1809919a698e879
F test/shared3.test fcd65cb11d189eff5f5c85cc4fad246fb0933108 F test/shared3.test fcd65cb11d189eff5f5c85cc4fad246fb0933108
F test/shared4.test 72d90821e8d2fc918a08f16d32880868d8ee8e9d F test/shared4.test c75f476804e76e26bf6fa0e7b421fb0ca7d07558
F test/shared6.test 866bb4982c45ce216c61ded5e8fde4e7e2f3ffa9 F test/shared6.test 866bb4982c45ce216c61ded5e8fde4e7e2f3ffa9
F test/shared7.test a81e99f83e6c51b02ac99c96fb3a2a7b5978c956 F test/shared7.test a81e99f83e6c51b02ac99c96fb3a2a7b5978c956
F test/shared8.test 00a07bf5e1337ecf72e94542bdefdc330d7a2538 F test/shared8.test 00a07bf5e1337ecf72e94542bdefdc330d7a2538
@@ -1000,9 +1004,9 @@ F test/speed3.test d32043614c08c53eafdc80f33191d5bd9b920523
F test/speed4.test abc0ad3399dcf9703abed2fff8705e4f8e416715 F test/speed4.test abc0ad3399dcf9703abed2fff8705e4f8e416715
F test/speed4p.explain 6b5f104ebeb34a038b2f714150f51d01143e59aa F test/speed4p.explain 6b5f104ebeb34a038b2f714150f51d01143e59aa
F test/speed4p.test 0e51908951677de5a969b723e03a27a1c45db38b F test/speed4p.test 0e51908951677de5a969b723e03a27a1c45db38b
F test/speedtest1.c 9f1b745c24886cced3f70ffc666300152a39013c F test/speedtest1.c f42fd04a34a0c1dc289cbe536ef62d706227a736
F test/spellfix.test 24f676831acddd2f4056a598fd731a72c6311f49 F test/spellfix.test 24f676831acddd2f4056a598fd731a72c6311f49
F test/sqldiff1.test e5ecfe95b3a2ff6380f0db6ea8bec246b675e122 F test/sqldiff1.test 8f6bc7c6a5b3585d350d779c6078869ba402f8f5
F test/sqllimits1.test e05786eaed7950ff6a2d00031d001d8a26131e68 F test/sqllimits1.test e05786eaed7950ff6a2d00031d001d8a26131e68
F test/stat.test 8de91498c99f5298b303f70f1d1f3b9557af91bf F test/stat.test 8de91498c99f5298b303f70f1d1f3b9557af91bf
F test/statfault.test f525a7bf633e50afd027700e9a486090684b1ac1 F test/statfault.test f525a7bf633e50afd027700e9a486090684b1ac1
@@ -1015,14 +1019,14 @@ F test/superlock.test 1cde669f68d2dd37d6c9bd35eee1d95491ae3fc2
F test/sync.test a34cd43e98b7fb84eabbf38f7ed8f7349b3f3d85 F test/sync.test a34cd43e98b7fb84eabbf38f7ed8f7349b3f3d85
F test/syscall.test d2fdaad713f103ac611fe7ef9b724c7b69f8149c F test/syscall.test d2fdaad713f103ac611fe7ef9b724c7b69f8149c
F test/sysfault.test fa776e60bf46bdd3ae69f0b73e46ee3977a58ae6 F test/sysfault.test fa776e60bf46bdd3ae69f0b73e46ee3977a58ae6
F test/table.test bd841e8df69b99172ce9c7d53587463913d711ca F test/table.test 33bf0d1fd07f304582695184b8e6feb017303816
F test/tableapi.test 2674633fa95d80da917571ebdd759a14d9819126 F test/tableapi.test 2674633fa95d80da917571ebdd759a14d9819126
F test/tableopts.test dba698ba97251017b7c80d738c198d39ab747930 F test/tableopts.test dba698ba97251017b7c80d738c198d39ab747930
F test/tclsqlite.test 7fb866443c7deceed22b63948ccd6f76b52ad054 F test/tclsqlite.test 7fb866443c7deceed22b63948ccd6f76b52ad054
F test/tempdb.test 19d0f66e2e3eeffd68661a11c83ba5e6ace9128c F test/tempdb.test 19d0f66e2e3eeffd68661a11c83ba5e6ace9128c
F test/temptable.test d2c9b87a54147161bcd1822e30c1d1cd891e5b30 F test/temptable.test d2c9b87a54147161bcd1822e30c1d1cd891e5b30
F test/temptrigger.test 8ec228b0db5d7ebc4ee9b458fc28cb9e7873f5e1 F test/temptrigger.test 8ec228b0db5d7ebc4ee9b458fc28cb9e7873f5e1
F test/tester.tcl c18dbf42f4b0c1fb889b0efeb8a59d5143dd9828 F test/tester.tcl b3a41e20f98a029a76e930b33d0711c5854267bb
F test/thread001.test 9f22fd3525a307ff42a326b6bc7b0465be1745a5 F test/thread001.test 9f22fd3525a307ff42a326b6bc7b0465be1745a5
F test/thread002.test e630504f8a06c00bf8bbe68528774dd96aeb2e58 F test/thread002.test e630504f8a06c00bf8bbe68528774dd96aeb2e58
F test/thread003.test ee4c9efc3b86a6a2767516a37bd64251272560a7 F test/thread003.test ee4c9efc3b86a6a2767516a37bd64251272560a7
@@ -1220,7 +1224,7 @@ F test/vacuum4.test d3f8ecff345f166911568f397d2432c16d2867d9
F test/varint.test ab7b110089a08b9926ed7390e7e97bdefeb74102 F test/varint.test ab7b110089a08b9926ed7390e7e97bdefeb74102
F test/veryquick.test 57ab846bacf7b90cf4e9a672721ea5c5b669b661 F test/veryquick.test 57ab846bacf7b90cf4e9a672721ea5c5b669b661
F test/view.test f311691d696a5cc27e3c1b875cec1b0866b4ccd9 F test/view.test f311691d696a5cc27e3c1b875cec1b0866b4ccd9
F test/vtab1.test dbe0e9e121102d0ba365f20d126a72676aa2343f F test/vtab1.test 6210e076997f176bedc300a87ad6404651b601dd
F test/vtab2.test f8cd1bb9aba7143eba97812d9617880a36d247ad F test/vtab2.test f8cd1bb9aba7143eba97812d9617880a36d247ad
F test/vtab3.test b45f47d20f225ccc9c28dc915d92740c2dee311e F test/vtab3.test b45f47d20f225ccc9c28dc915d92740c2dee311e
F test/vtab4.test 942f8b8280b3ea8a41dae20e7822d065ca1cb275 F test/vtab4.test 942f8b8280b3ea8a41dae20e7822d065ca1cb275
@@ -1281,7 +1285,7 @@ F test/whereC.test cae295158703cb3fc23bf1a108a9ab730efff0f6
F test/whereD.test 9eba1f9b18e5b19a0b0bcaae5e8c037260195f2b F test/whereD.test 9eba1f9b18e5b19a0b0bcaae5e8c037260195f2b
F test/whereE.test b3a055eef928c992b0a33198a7b8dc10eea5ad2f F test/whereE.test b3a055eef928c992b0a33198a7b8dc10eea5ad2f
F test/whereF.test 5b2ba0dbe8074aa13e416b37c753991f0a2492d7 F test/whereF.test 5b2ba0dbe8074aa13e416b37c753991f0a2492d7
F test/whereG.test 69f5ec4b15760a8c860f80e2d55525669390aab3 F test/whereG.test dde4c52a97385a55be6a7cd46be8373f0cf35501
F test/whereH.test e4b07f7a3c2f5d31195cd33710054c78667573b2 F test/whereH.test e4b07f7a3c2f5d31195cd33710054c78667573b2
F test/whereI.test 1d89199697919d4930be05a71e7fe620f114e622 F test/whereI.test 1d89199697919d4930be05a71e7fe620f114e622
F test/whereJ.test 55a3221706a7ab706293f17cc8f96da563bf0767 F test/whereJ.test 55a3221706a7ab706293f17cc8f96da563bf0767
@@ -1324,7 +1328,7 @@ F tool/mkopts.tcl 66ac10d240cc6e86abd37dc908d50382f84ff46e
F tool/mkpragmatab.tcl 40c287d3f929ece67da6e9e7c49885789960accf F tool/mkpragmatab.tcl 40c287d3f929ece67da6e9e7c49885789960accf
F tool/mkspeedsql.tcl a1a334d288f7adfe6e996f2e712becf076745c97 F tool/mkspeedsql.tcl a1a334d288f7adfe6e996f2e712becf076745c97
F tool/mksqlite3c-noext.tcl 69bae8ce4aa52d2ff82d4a8a856bf283ec035b2e F tool/mksqlite3c-noext.tcl 69bae8ce4aa52d2ff82d4a8a856bf283ec035b2e
F tool/mksqlite3c.tcl ccee8fe53dabbeb00d55fe0a4a24005f69eccec9 F tool/mksqlite3c.tcl b601b174d783094edd926d913a8f545709e89f8a
F tool/mksqlite3h.tcl 44730d586c9031638cdd2eb443b801c0d2dbd9f8 F tool/mksqlite3h.tcl 44730d586c9031638cdd2eb443b801c0d2dbd9f8
F tool/mksqlite3internalh.tcl eb994013e833359137eb53a55acdad0b5ae1049b F tool/mksqlite3internalh.tcl eb994013e833359137eb53a55acdad0b5ae1049b
F tool/mkvsix.tcl 3b58b9398f91c7dbf18d49eb87cefeee9efdbce1 F tool/mkvsix.tcl 3b58b9398f91c7dbf18d49eb87cefeee9efdbce1
@@ -1357,9 +1361,9 @@ F tool/varint.c 5d94cb5003db9dbbcbcc5df08d66f16071aee003
F tool/vdbe-compress.tcl 5926c71f9c12d2ab73ef35c29376e756eb68361c F tool/vdbe-compress.tcl 5926c71f9c12d2ab73ef35c29376e756eb68361c
F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/warnings.sh 48bd54594752d5be3337f12c72f28d2080cb630b
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
P aa12f9d9b79c2f523fd6b00e47bcb66dba09ce0c P 0f7fd51325875fbf0f1eaca3bbbd170ef99c4208 4df852ce26c95d5d23c83dbe9c59d2c3435acddf
R 92d332093f5da6f2c10bbd12aba6b7b5 R 3ac475f744e56c1ad80818d65ed40944
U dan U dan
Z 4c307463292fc937d885d935d5d6ac74 Z b74a37a10556c5365b257dc3f6c234f4

View File

@@ -1 +1 @@
0f7fd51325875fbf0f1eaca3bbbd170ef99c4208 ef44c71a22518727030dd90c0139af8973b05841

View File

@@ -980,11 +980,73 @@ static u8 *findOverflowCell(MemPage *pPage, int iCell){
} }
/* /*
** Parse a cell content block and fill in the CellInfo structure. There ** This is common tail processing for btreeParseCellPtr() and
** are two versions of this function. btreeParseCell() takes a ** btreeParseCellPtrIndex() for the case when the cell does not fit entirely
** cell index as the second argument and btreeParseCellPtr() ** on a single B-tree page. Make necessary adjustments to the CellInfo
** takes a pointer to the body of the cell as its second argument. ** 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( static void btreeParseCellPtr(
MemPage *pPage, /* Page containing the cell */ MemPage *pPage, /* Page containing the cell */
u8 *pCell, /* Pointer to the cell text. */ u8 *pCell, /* Pointer to the cell text. */
@@ -992,26 +1054,54 @@ static void btreeParseCellPtr(
){ ){
u8 *pIter; /* For scanning through pCell */ u8 *pIter; /* For scanning through pCell */
u32 nPayload; /* Number of bytes of cell payload */ u32 nPayload; /* Number of bytes of cell payload */
u64 iKey; /* Extracted Key value */
assert( sqlite3_mutex_held(pPage->pBt->mutex) ); assert( sqlite3_mutex_held(pPage->pBt->mutex) );
assert( pPage->leaf==0 || pPage->leaf==1 ); assert( pPage->leaf==0 || pPage->leaf==1 );
if( pPage->intKeyLeaf ){ assert( pPage->intKeyLeaf || pPage->noPayload );
assert( pPage->childPtrSize==0 ); assert( pPage->noPayload==0 );
pIter = pCell + getVarint32(pCell, nPayload); assert( pPage->intKeyLeaf );
pIter += getVarint(pIter, (u64*)&pInfo->nKey); assert( pPage->childPtrSize==0 );
}else if( pPage->noPayload ){ pIter = pCell;
assert( pPage->childPtrSize==4 );
pInfo->nSize = 4 + getVarint(&pCell[4], (u64*)&pInfo->nKey); /* The next block of code is equivalent to:
pInfo->nPayload = 0; **
pInfo->nLocal = 0; ** pIter += getVarint32(pIter, nPayload);
pInfo->iOverflow = 0; **
pInfo->pPayload = 0; ** The code is inlined to avoid a function call.
return; */
}else{ nPayload = *pIter;
pIter = pCell + pPage->childPtrSize; if( nPayload>=0x80 ){
pIter += getVarint32(pIter, nPayload); u8 *pEnd = &pIter[8];
pInfo->nKey = nPayload; 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->nPayload = nPayload;
pInfo->pPayload = pIter; pInfo->pPayload = pIter;
testcase( nPayload==pPage->maxLocal ); testcase( nPayload==pPage->maxLocal );
@@ -1025,31 +1115,46 @@ static void btreeParseCellPtr(
pInfo->nLocal = (u16)nPayload; pInfo->nLocal = (u16)nPayload;
pInfo->iOverflow = 0; pInfo->iOverflow = 0;
}else{ }else{
/* If the payload will not fit completely on the local page, we have btreeParseCellAdjustSizeForOverflow(pPage, pCell, pInfo);
** 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 static void btreeParseCellPtrIndex(
** in between minLocal and maxLocal. MemPage *pPage, /* Page containing the cell */
** u8 *pCell, /* Pointer to the cell text. */
** Warning: changing the way overflow payload is distributed in any CellInfo *pInfo /* Fill in this structure */
** way will result in an incompatible file format. ){
*/ u8 *pIter; /* For scanning through pCell */
int minLocal; /* Minimum amount of payload held locally */ u32 nPayload; /* Number of bytes of cell payload */
int maxLocal; /* Maximum amount of payload held locally */
int surplus; /* Overflow payload available for local storage */
minLocal = pPage->minLocal; assert( sqlite3_mutex_held(pPage->pBt->mutex) );
maxLocal = pPage->maxLocal; assert( pPage->leaf==0 || pPage->leaf==1 );
surplus = minLocal + (nPayload - minLocal)%(pPage->pBt->usableSize - 4); assert( pPage->intKeyLeaf==0 );
testcase( surplus==maxLocal ); assert( pPage->noPayload==0 );
testcase( surplus==maxLocal+1 ); pIter = pCell + pPage->childPtrSize;
if( surplus <= maxLocal ){ nPayload = *pIter;
pInfo->nLocal = (u16)surplus; if( nPayload>=0x80 ){
}else{ u8 *pEnd = &pIter[8];
pInfo->nLocal = (u16)minLocal; nPayload &= 0x7f;
} do{
pInfo->iOverflow = (u16)(&pInfo->pPayload[pInfo->nLocal] - pCell); nPayload = (nPayload<<7) | (*++pIter & 0x7f);
pInfo->nSize = pInfo->iOverflow + 4; }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( static void btreeParseCell(
@@ -1057,14 +1162,20 @@ static void btreeParseCell(
int iCell, /* The cell index. First cell is 0 */ int iCell, /* The cell index. First cell is 0 */
CellInfo *pInfo /* Fill in this structure */ 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 ** 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 area of the btree-page. The return number includes the cell
** data header and the local payload, but not any overflow page or ** data header and the local payload, but not any overflow page or
** the space used by the cell pointer. ** 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){ static u16 cellSizePtr(MemPage *pPage, u8 *pCell){
u8 *pIter = pCell + pPage->childPtrSize; /* For looping over bytes of 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 ** cell. If SQLITE_DEBUG is defined, an assert() at the bottom of
** this function verifies that this invariant is not violated. */ ** this function verifies that this invariant is not violated. */
CellInfo debuginfo; CellInfo debuginfo;
btreeParseCellPtr(pPage, pCell, &debuginfo); pPage->xParseCell(pPage, pCell, &debuginfo);
#endif #endif
if( pPage->noPayload ){ assert( pPage->noPayload==0 );
pEnd = &pIter[9];
while( (*pIter++)&0x80 && pIter<pEnd );
assert( pPage->childPtrSize==4 );
return (u16)(pIter - pCell);
}
nSize = *pIter; nSize = *pIter;
if( nSize>=0x80 ){ if( nSize>=0x80 ){
pEnd = &pIter[9]; pEnd = &pIter[8];
nSize &= 0x7f; nSize &= 0x7f;
do{ do{
nSize = (nSize<<7) | (*++pIter & 0x7f); nSize = (nSize<<7) | (*++pIter & 0x7f);
@@ -1120,12 +1226,32 @@ static u16 cellSizePtr(MemPage *pPage, u8 *pCell){
assert( nSize==debuginfo.nSize || CORRUPT_DB ); assert( nSize==debuginfo.nSize || CORRUPT_DB );
return (u16)nSize; 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 #ifdef SQLITE_DEBUG
/* This variation on cellSizePtr() is used inside of assert() statements /* This variation on cellSizePtr() is used inside of assert() statements
** only. */ ** only. */
static u16 cellSize(MemPage *pPage, int iCell){ static u16 cellSize(MemPage *pPage, int iCell){
return cellSizePtr(pPage, findCell(pPage, iCell)); return pPage->xCellSize(pPage, findCell(pPage, iCell));
} }
#endif #endif
@@ -1139,7 +1265,7 @@ static void ptrmapPutOvflPtr(MemPage *pPage, u8 *pCell, int *pRC){
CellInfo info; CellInfo info;
if( *pRC ) return; if( *pRC ) return;
assert( pCell!=0 ); assert( pCell!=0 );
btreeParseCellPtr(pPage, pCell, &info); pPage->xParseCell(pPage, pCell, &info);
if( info.iOverflow ){ if( info.iOverflow ){
Pgno ovfl = get4byte(&pCell[info.iOverflow]); Pgno ovfl = get4byte(&pCell[info.iOverflow]);
ptrmapPut(pPage->pBt, ovfl, PTRMAP_OVERFLOW1, pPage->pgno, pRC); ptrmapPut(pPage->pBt, ovfl, PTRMAP_OVERFLOW1, pPage->pgno, pRC);
@@ -1203,7 +1329,7 @@ static int defragmentPage(MemPage *pPage){
return SQLITE_CORRUPT_BKPT; return SQLITE_CORRUPT_BKPT;
} }
assert( pc>=iCellFirst && pc<=iCellLast ); assert( pc>=iCellFirst && pc<=iCellLast );
size = cellSizePtr(pPage, &src[pc]); size = pPage->xCellSize(pPage, &src[pc]);
cbrk -= size; cbrk -= size;
if( cbrk<iCellFirst || pc+size>usableSize ){ if( cbrk<iCellFirst || pc+size>usableSize ){
return SQLITE_CORRUPT_BKPT; return SQLITE_CORRUPT_BKPT;
@@ -1272,7 +1398,10 @@ static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc, int *pbDefrag){
int x = size - nByte; int x = size - nByte;
testcase( x==4 ); testcase( x==4 );
testcase( x==3 ); 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 /* EVIDENCE-OF: R-11498-58022 In a well-formed b-tree page, the total
** number of bytes in fragments may not exceed 60. */ ** number of bytes in fragments may not exceed 60. */
if( aData[hdr+7]>=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. */ ** fragmented bytes within the page. */
memcpy(&aData[iAddr], &aData[pc], 2); memcpy(&aData[iAddr], &aData[pc], 2);
aData[hdr+7] += (u8)x; aData[hdr+7] += (u8)x;
}else if( pc < pPg->cellOffset+2*pPg->nCell || size+pc > usableSize ){
*pRc = SQLITE_CORRUPT_BKPT;
return 0;
}else{ }else{
/* The slot remains on the free-list. Reduce its size to account /* The slot remains on the free-list. Reduce its size to account
** for the portion used by the new allocation. */ ** for the portion used by the new allocation. */
@@ -1441,7 +1567,7 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
/* At this point: /* At this point:
** iFreeBlk: First freeblock after iStart, or zero if none ** 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. ** 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; nFrag = iFreeBlk - iEnd;
if( iEnd>iFreeBlk ) return SQLITE_CORRUPT_BKPT; if( iEnd>iFreeBlk ) return SQLITE_CORRUPT_BKPT;
iEnd = iFreeBlk + get2byte(&data[iFreeBlk+2]); iEnd = iFreeBlk + get2byte(&data[iFreeBlk+2]);
if( iEnd > pPage->pBt->usableSize ) return SQLITE_CORRUPT_BKPT;
iSize = iEnd - iStart; iSize = iEnd - iStart;
iFreeBlk = get2byte(&data[iFreeBlk]); 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 ); pPage->leaf = (u8)(flagByte>>3); assert( PTF_LEAF == 1<<3 );
flagByte &= ~PTF_LEAF; flagByte &= ~PTF_LEAF;
pPage->childPtrSize = 4-4*pPage->leaf; pPage->childPtrSize = 4-4*pPage->leaf;
pPage->xCellSize = cellSizePtr;
pBt = pPage->pBt; pBt = pPage->pBt;
if( flagByte==(PTF_LEAFDATA | PTF_INTKEY) ){ if( flagByte==(PTF_LEAFDATA | PTF_INTKEY) ){
/* EVIDENCE-OF: R-03640-13415 A value of 5 means the page is an interior /* 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. */ ** table b-tree page. */
assert( (PTF_LEAFDATA|PTF_INTKEY|PTF_LEAF)==13 ); assert( (PTF_LEAFDATA|PTF_INTKEY|PTF_LEAF)==13 );
pPage->intKey = 1; pPage->intKey = 1;
pPage->intKeyLeaf = pPage->leaf; if( pPage->leaf ){
pPage->noPayload = !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->maxLocal = pBt->maxLeaf;
pPage->minLocal = pBt->minLeaf; pPage->minLocal = pBt->minLeaf;
}else if( flagByte==PTF_ZERODATA ){ }else if( flagByte==PTF_ZERODATA ){
@@ -1529,6 +1665,7 @@ static int decodeFlags(MemPage *pPage, int flagByte){
pPage->intKey = 0; pPage->intKey = 0;
pPage->intKeyLeaf = 0; pPage->intKeyLeaf = 0;
pPage->noPayload = 0; pPage->noPayload = 0;
pPage->xParseCell = btreeParseCellPtrIndex;
pPage->maxLocal = pBt->maxLocal; pPage->maxLocal = pBt->maxLocal;
pPage->minLocal = pBt->minLocal; pPage->minLocal = pBt->minLocal;
}else{ }else{
@@ -1623,7 +1760,7 @@ static int btreeInitPage(MemPage *pPage){
if( pc<iCellFirst || pc>iCellLast ){ if( pc<iCellFirst || pc>iCellLast ){
return SQLITE_CORRUPT_BKPT; return SQLITE_CORRUPT_BKPT;
} }
sz = cellSizePtr(pPage, &data[pc]); sz = pPage->xCellSize(pPage, &data[pc]);
testcase( pc+sz==usableSize ); testcase( pc+sz==usableSize );
if( pc+sz>usableSize ){ if( pc+sz>usableSize ){
return SQLITE_CORRUPT_BKPT; return SQLITE_CORRUPT_BKPT;
@@ -3119,7 +3256,7 @@ static int modifyPagePointer(MemPage *pPage, Pgno iFrom, Pgno iTo, u8 eType){
u8 *pCell = findCell(pPage, i); u8 *pCell = findCell(pPage, i);
if( eType==PTRMAP_OVERFLOW1 ){ if( eType==PTRMAP_OVERFLOW1 ){
CellInfo info; CellInfo info;
btreeParseCellPtr(pPage, pCell, &info); pPage->xParseCell(pPage, pCell, &info);
if( info.iOverflow if( info.iOverflow
&& pCell+info.iOverflow+3<=pPage->aData+pPage->maskPage && pCell+info.iOverflow+3<=pPage->aData+pPage->maskPage
&& iFrom==get4byte(&pCell[info.iOverflow]) && 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. ** BtCursor.info is a cache of the information in the current cell.
** Using this cache reduces the number of calls to btreeParseCell(). ** 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 #ifndef NDEBUG
static void assertCellInfo(BtCursor *pCur){ static void assertCellInfo(BtCursor *pCur){
@@ -4003,28 +4133,15 @@ int sqlite3BtreeCloseCursor(BtCursor *pCur){
#else #else
#define assertCellInfo(x) #define assertCellInfo(x)
#endif #endif
#ifdef _MSC_VER static SQLITE_NOINLINE void getCellInfo(BtCursor *pCur){
/* Use a real function in MSVC to work around bugs in that compiler. */ if( pCur->info.nSize==0 ){
static void getCellInfo(BtCursor *pCur){ int iPage = pCur->iPage;
if( pCur->info.nSize==0 ){ pCur->curFlags |= BTCF_ValidNKey;
int iPage = pCur->iPage; btreeParseCell(pCur->apPage[iPage],pCur->aiIdx[iPage],&pCur->info);
btreeParseCell(pCur->apPage[iPage],pCur->aiIdx[iPage],&pCur->info); }else{
pCur->curFlags |= BTCF_ValidNKey; assertCellInfo(pCur);
}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 */ #ifndef NDEBUG /* The next routine used only within assert() statements */
/* /*
@@ -4984,7 +5101,7 @@ int sqlite3BtreeMovetoUnpacked(
** case this happens. */ ** case this happens. */
void *pCellKey; void *pCellKey;
u8 * const pCellBody = pCell - pPage->childPtrSize; u8 * const pCellBody = pCell - pPage->childPtrSize;
btreeParseCellPtr(pPage, pCellBody, &pCur->info); pPage->xParseCell(pPage, pCellBody, &pCur->info);
nCell = (int)pCur->info.nKey; nCell = (int)pCur->info.nKey;
testcase( nCell<0 ); /* True if key size is 2^32 or more */ testcase( nCell<0 ); /* True if key size is 2^32 or more */
testcase( nCell==0 ); /* Invalid key size: 0x80 0x80 0x00 */ testcase( nCell==0 ); /* Invalid key size: 0x80 0x80 0x00 */
@@ -5773,7 +5890,7 @@ static int clearCell(
u32 ovflPageSize; u32 ovflPageSize;
assert( sqlite3_mutex_held(pPage->pBt->mutex) ); assert( sqlite3_mutex_held(pPage->pBt->mutex) );
btreeParseCellPtr(pPage, pCell, &info); pPage->xParseCell(pPage, pCell, &info);
*pnSize = info.nSize; *pnSize = info.nSize;
if( info.iOverflow==0 ){ if( info.iOverflow==0 ){
return SQLITE_OK; /* No overflow pages. Return without doing anything */ return SQLITE_OK; /* No overflow pages. Return without doing anything */
@@ -5927,7 +6044,7 @@ static int fillInCell(
#if SQLITE_DEBUG #if SQLITE_DEBUG
{ {
CellInfo info; CellInfo info;
btreeParseCellPtr(pPage, pCell, &info); pPage->xParseCell(pPage, pCell, &info);
assert( nHeader=(int)(info.pPayload - pCell) ); assert( nHeader=(int)(info.pPayload - pCell) );
assert( info.nKey==nKey ); assert( info.nKey==nKey );
assert( *pnSize == info.nSize ); 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 ** 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 ** might be less than 8 (leaf-size + pointer) on the interior node. Hence
** the term after the || in the following assert(). */ ** 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( pPage->nOverflow || sz+2>pPage->nFree ){
if( pTemp ){ if( pTemp ){
memcpy(pTemp, pCell, sz); memcpy(pTemp, pCell, sz);
@@ -6206,8 +6323,8 @@ static void rebuildPage(
memcpy(pData, pCell, szCell[i]); memcpy(pData, pCell, szCell[i]);
put2byte(pCellptr, (pData - aData)); put2byte(pCellptr, (pData - aData));
pCellptr += 2; pCellptr += 2;
assert( szCell[i]==cellSizePtr(pPg, pCell) || CORRUPT_DB ); assert( szCell[i]==pPg->xCellSize(pPg, pCell) || CORRUPT_DB );
testcase( szCell[i]==cellSizePtr(pPg,pCell) ); testcase( szCell[i]==pPg->xCellSize(pPg,pCell) );
} }
/* The pPg->nFree field is now set incorrectly. The caller will fix it. */ /* 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 *pOut = &pSpace[4];
u8 *pCell = pPage->apOvfl[0]; u8 *pCell = pPage->apOvfl[0];
u16 szCell = cellSizePtr(pPage, pCell); u16 szCell = pPage->xCellSize(pPage, pCell);
u8 *pStop; u8 *pStop;
assert( sqlite3PagerIswriteable(pNew->pDbPage) ); assert( sqlite3PagerIswriteable(pNew->pDbPage) );
@@ -6576,7 +6693,7 @@ static int ptrmapCheckPages(MemPage **apPage, int nPage){
u8 *z; u8 *z;
z = findCell(pPage, j); z = findCell(pPage, j);
btreeParseCellPtr(pPage, z, &info); pPage->xParseCell(pPage, z, &info);
if( info.iOverflow ){ if( info.iOverflow ){
Pgno ovfl = get4byte(&z[info.iOverflow]); Pgno ovfl = get4byte(&z[info.iOverflow]);
ptrmapGet(pBt, ovfl, &e, &n); ptrmapGet(pBt, ovfl, &e, &n);
@@ -6803,12 +6920,12 @@ static int balance_nonroot(
if( i+nxDiv==pParent->aiOvfl[0] && pParent->nOverflow ){ if( i+nxDiv==pParent->aiOvfl[0] && pParent->nOverflow ){
apDiv[i] = pParent->apOvfl[0]; apDiv[i] = pParent->apOvfl[0];
pgno = get4byte(apDiv[i]); pgno = get4byte(apDiv[i]);
szNew[i] = cellSizePtr(pParent, apDiv[i]); szNew[i] = pParent->xCellSize(pParent, apDiv[i]);
pParent->nOverflow = 0; pParent->nOverflow = 0;
}else{ }else{
apDiv[i] = findCell(pParent, i+nxDiv-pParent->nOverflow); apDiv[i] = findCell(pParent, i+nxDiv-pParent->nOverflow);
pgno = get4byte(apDiv[i]); 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 /* Drop the cell from the parent page. apDiv[i] still points to
** the cell within the parent, even though it has been dropped. ** 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++){ for(j=0; j<limit; j++){
assert( nCell<nMaxCells ); assert( nCell<nMaxCells );
apCell[nCell] = findOverflowCell(pOld, j); apCell[nCell] = findOverflowCell(pOld, j);
szCell[nCell] = cellSizePtr(pOld, apCell[nCell]); szCell[nCell] = pOld->xCellSize(pOld, apCell[nCell]);
nCell++; nCell++;
} }
}else{ }else{
@@ -6908,7 +7025,7 @@ static int balance_nonroot(
for(j=0; j<limit; j++){ for(j=0; j<limit; j++){
assert( nCell<nMaxCells ); assert( nCell<nMaxCells );
apCell[nCell] = findCellv2(aData, maskPage, cellOffset, j); apCell[nCell] = findCellv2(aData, maskPage, cellOffset, j);
szCell[nCell] = cellSizePtr(pOld, apCell[nCell]); szCell[nCell] = pOld->xCellSize(pOld, apCell[nCell]);
nCell++; nCell++;
} }
} }
@@ -7207,7 +7324,7 @@ static int balance_nonroot(
*/ */
CellInfo info; CellInfo info;
j--; j--;
btreeParseCellPtr(pNew, apCell[j], &info); pNew->xParseCell(pNew, apCell[j], &info);
pCell = pTemp; pCell = pTemp;
sz = 4 + putVarint(&pCell[4], info.nKey); sz = 4 + putVarint(&pCell[4], info.nKey);
pTemp = 0; pTemp = 0;
@@ -7226,7 +7343,7 @@ static int balance_nonroot(
*/ */
if( szCell[j]==4 ){ if( szCell[j]==4 ){
assert(leafCorrection==4); assert(leafCorrection==4);
sz = cellSizePtr(pParent, pCell); sz = pParent->xCellSize(pParent, pCell);
} }
} }
iOvflSpace += sz; iOvflSpace += sz;
@@ -7671,7 +7788,7 @@ int sqlite3BtreeInsert(
assert( newCell!=0 ); assert( newCell!=0 );
rc = fillInCell(pPage, newCell, pKey, nKey, pData, nData, nZero, &szNew); rc = fillInCell(pPage, newCell, pKey, nKey, pData, nData, nZero, &szNew);
if( rc ) goto end_insert; if( rc ) goto end_insert;
assert( szNew==cellSizePtr(pPage, newCell) ); assert( szNew==pPage->xCellSize(pPage, newCell) );
assert( szNew <= MX_CELL_SIZE(pBt) ); assert( szNew <= MX_CELL_SIZE(pBt) );
idx = pCur->aiIdx[pCur->iPage]; idx = pCur->aiIdx[pCur->iPage];
if( loc==0 ){ if( loc==0 ){
@@ -7813,7 +7930,7 @@ int sqlite3BtreeDelete(BtCursor *pCur){
pCell = findCell(pLeaf, pLeaf->nCell-1); pCell = findCell(pLeaf, pLeaf->nCell-1);
if( pCell<&pLeaf->aData[4] ) return SQLITE_CORRUPT_BKPT; if( pCell<&pLeaf->aData[4] ) return SQLITE_CORRUPT_BKPT;
nCell = cellSizePtr(pLeaf, pCell); nCell = pLeaf->xCellSize(pLeaf, pCell);
assert( MX_CELL_SIZE(pBt) >= nCell ); assert( MX_CELL_SIZE(pBt) >= nCell );
pTmp = pBt->pTmpSpace; pTmp = pBt->pTmpSpace;
assert( pTmp!=0 ); assert( pTmp!=0 );
@@ -8707,7 +8824,7 @@ static int checkTreePage(
pCheck->v1 = iPage; pCheck->v1 = iPage;
pCheck->v2 = i; pCheck->v2 = i;
pCell = findCell(pPage,i); pCell = findCell(pPage,i);
btreeParseCellPtr(pPage, pCell, &info); pPage->xParseCell(pPage, pCell, &info);
sz = info.nPayload; sz = info.nPayload;
/* For intKey pages, check that the keys are in order. /* For intKey pages, check that the keys are in order.
*/ */
@@ -8825,7 +8942,7 @@ static int checkTreePage(
int pc = get2byte(&data[cellStart+i*2]); int pc = get2byte(&data[cellStart+i*2]);
u32 size = 65536; u32 size = 65536;
if( pc<=usableSize-4 ){ if( pc<=usableSize-4 ){
size = cellSizePtr(pPage, &data[pc]); size = pPage->xCellSize(pPage, &data[pc]);
} }
if( (int)(pc+size-1)>=usableSize ){ if( (int)(pc+size-1)>=usableSize ){
pCheck->zPfx = 0; pCheck->zPfx = 0;

View File

@@ -231,6 +231,7 @@
/* Forward declarations */ /* Forward declarations */
typedef struct MemPage MemPage; typedef struct MemPage MemPage;
typedef struct BtLock BtLock; typedef struct BtLock BtLock;
typedef struct CellInfo CellInfo;
/* /*
** This is a magic string that appears at the beginning of every ** 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 *aDataEnd; /* One byte past the end of usable data */
u8 *aCellIdx; /* The cell index area */ u8 *aCellIdx; /* The cell index area */
DbPage *pDbPage; /* Pager page handle */ 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 */ Pgno pgno; /* Page number for this page */
}; };
@@ -460,7 +463,6 @@ struct BtShared {
** about a cell. The parseCellPtr() function fills in this structure ** about a cell. The parseCellPtr() function fills in this structure
** based on information extract from the raw disk page. ** based on information extract from the raw disk page.
*/ */
typedef struct CellInfo CellInfo;
struct CellInfo { struct CellInfo {
i64 nKey; /* The key for INTKEY tables, or nPayload otherwise */ i64 nKey; /* The key for INTKEY tables, or nPayload otherwise */
u8 *pPayload; /* Pointer to the start of payload */ u8 *pPayload; /* Pointer to the start of payload */

View File

@@ -976,7 +976,7 @@ void sqlite3StartTable(
int j1; int j1;
int fileFormat; int fileFormat;
int reg1, reg2, reg3; int reg1, reg2, reg3;
sqlite3BeginWriteOperation(pParse, 0, iDb); sqlite3BeginWriteOperation(pParse, 1, iDb);
#ifndef SQLITE_OMIT_VIRTUALTABLE #ifndef SQLITE_OMIT_VIRTUALTABLE
if( isVirtual ){ if( isVirtual ){
@@ -1924,6 +1924,7 @@ void sqlite3EndTable(
regRec = ++pParse->nMem; regRec = ++pParse->nMem;
regRowid = ++pParse->nMem; regRowid = ++pParse->nMem;
assert(pParse->nTab==1); assert(pParse->nTab==1);
sqlite3MayAbort(pParse);
sqlite3VdbeAddOp3(v, OP_OpenWrite, 1, pParse->regRoot, iDb); sqlite3VdbeAddOp3(v, OP_OpenWrite, 1, pParse->regRoot, iDb);
sqlite3VdbeChangeP5(v, OPFLAG_P2ISREG); sqlite3VdbeChangeP5(v, OPFLAG_P2ISREG);
pParse->nTab = 2; pParse->nTab = 2;
@@ -3701,7 +3702,7 @@ void sqlite3SrcListDelete(sqlite3 *db, SrcList *pList){
sqlite3DbFree(db, pItem->zDatabase); sqlite3DbFree(db, pItem->zDatabase);
sqlite3DbFree(db, pItem->zName); sqlite3DbFree(db, pItem->zName);
sqlite3DbFree(db, pItem->zAlias); sqlite3DbFree(db, pItem->zAlias);
sqlite3DbFree(db, pItem->zIndex); sqlite3DbFree(db, pItem->zIndexedBy);
sqlite3DeleteTable(db, pItem->pTab); sqlite3DeleteTable(db, pItem->pTab);
sqlite3SelectDelete(db, pItem->pSelect); sqlite3SelectDelete(db, pItem->pSelect);
sqlite3ExprDelete(db, pItem->pOn); sqlite3ExprDelete(db, pItem->pOn);
@@ -3774,13 +3775,13 @@ void sqlite3SrcListIndexedBy(Parse *pParse, SrcList *p, Token *pIndexedBy){
assert( pIndexedBy!=0 ); assert( pIndexedBy!=0 );
if( p && ALWAYS(p->nSrc>0) ){ if( p && ALWAYS(p->nSrc>0) ){
struct SrcList_item *pItem = &p->a[p->nSrc-1]; 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 ){ if( pIndexedBy->n==1 && !pIndexedBy->z ){
/* A "NOT INDEXED" clause was supplied. See parse.y /* A "NOT INDEXED" clause was supplied. See parse.y
** construct "indexed_opt" for details. */ ** construct "indexed_opt" for details. */
pItem->notIndexed = 1; pItem->notIndexed = 1;
}else{ }else{
pItem->zIndex = sqlite3NameFromToken(pParse->db, pIndexedBy); pItem->zIndexedBy = sqlite3NameFromToken(pParse->db, pIndexedBy);
} }
} }
} }

View File

@@ -798,8 +798,8 @@ int sqlite3GenerateIndexKey(
*piPartIdxLabel = sqlite3VdbeMakeLabel(v); *piPartIdxLabel = sqlite3VdbeMakeLabel(v);
pParse->iPartIdxTab = iDataCur; pParse->iPartIdxTab = iDataCur;
sqlite3ExprCachePush(pParse); sqlite3ExprCachePush(pParse);
sqlite3ExprIfFalse(pParse, pIdx->pPartIdxWhere, *piPartIdxLabel, sqlite3ExprIfFalseDup(pParse, pIdx->pPartIdxWhere, *piPartIdxLabel,
SQLITE_JUMPIFNULL); SQLITE_JUMPIFNULL);
}else{ }else{
*piPartIdxLabel = 0; *piPartIdxLabel = 0;
} }

View File

@@ -1041,7 +1041,7 @@ SrcList *sqlite3SrcListDup(sqlite3 *db, SrcList *p, int flags){
pNewItem->isCorrelated = pOldItem->isCorrelated; pNewItem->isCorrelated = pOldItem->isCorrelated;
pNewItem->viaCoroutine = pOldItem->viaCoroutine; pNewItem->viaCoroutine = pOldItem->viaCoroutine;
pNewItem->isRecursive = pOldItem->isRecursive; pNewItem->isRecursive = pOldItem->isRecursive;
pNewItem->zIndex = sqlite3DbStrDup(db, pOldItem->zIndex); pNewItem->zIndexedBy = sqlite3DbStrDup(db, pOldItem->zIndexedBy);
pNewItem->notIndexed = pOldItem->notIndexed; pNewItem->notIndexed = pOldItem->notIndexed;
pNewItem->pIndex = pOldItem->pIndex; pNewItem->pIndex = pOldItem->pIndex;
pTab = pNewItem->pTab = pOldItem->pTab; pTab = pNewItem->pTab = pOldItem->pTab;
@@ -2208,17 +2208,6 @@ static void sqlite3ExprCodeIN(
} }
#endif /* SQLITE_OMIT_SUBQUERY */ #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 #ifndef SQLITE_OMIT_FLOATING_POINT
/* /*
** Generate an instruction that will put the 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){ static void codeReal(Vdbe *v, const char *z, int negateFlag, int iMem){
if( ALWAYS(z!=0) ){ if( ALWAYS(z!=0) ){
double value; double value;
char *zV;
sqlite3AtoF(z, &value, sqlite3Strlen30(z), SQLITE_UTF8); sqlite3AtoF(z, &value, sqlite3Strlen30(z), SQLITE_UTF8);
assert( !sqlite3IsNaN(value) ); /* The new AtoF never returns NaN */ assert( !sqlite3IsNaN(value) ); /* The new AtoF never returns NaN */
if( negateFlag ) value = -value; if( negateFlag ) value = -value;
zV = dup8bytes(v, (char*)&value); sqlite3VdbeAddOp4Dup8(v, OP_Real, 0, iMem, 0, (u8*)&value, P4_REAL);
sqlite3VdbeAddOp4(v, OP_Real, 0, iMem, 0, zV, P4_REAL);
} }
} }
#endif #endif
@@ -2262,10 +2249,8 @@ static void codeInteger(Parse *pParse, Expr *pExpr, int negFlag, int iMem){
assert( z!=0 ); assert( z!=0 );
c = sqlite3DecOrHexToI64(z, &value); c = sqlite3DecOrHexToI64(z, &value);
if( c==0 || (c==2 && negFlag) ){ if( c==0 || (c==2 && negFlag) ){
char *zV;
if( negFlag ){ value = c==2 ? SMALLEST_INT64 : -value; } if( negFlag ){ value = c==2 ? SMALLEST_INT64 : -value; }
zV = dup8bytes(v, (char*)&value); sqlite3VdbeAddOp4Dup8(v, OP_Int64, 0, iMem, 0, (u8*)&value, P4_INT64);
sqlite3VdbeAddOp4(v, OP_Int64, 0, iMem, 0, zV, P4_INT64);
}else{ }else{
#ifdef SQLITE_OMIT_FLOATING_POINT #ifdef SQLITE_OMIT_FLOATING_POINT
sqlite3ErrorMsg(pParse, "oversized integer: %s%s", negFlag ? "-" : "", z); 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 ){ if( pDef->funcFlags & SQLITE_FUNC_UNLIKELY ){
assert( nFarg>=1 ); assert( nFarg>=1 );
sqlite3ExprCode(pParse, pFarg->a[0].pExpr, target); inReg = sqlite3ExprCodeTarget(pParse, pFarg->a[0].pExpr, target);
break; break;
} }
@@ -3311,268 +3296,6 @@ void sqlite3ExprCodeAndCache(Parse *pParse, Expr *pExpr, int target){
exprToRegister(pExpr, iMem); 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 ** Generate code that pushes the value of every element of the given
** expression list into a sequence of registers beginning at target. ** 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); 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 ** Do a deep comparison of two expression trees. Return 0 if the two
** expressions are completely identical. Return 1 if they differ only ** expressions are completely identical. Return 1 if they differ only

View File

@@ -575,17 +575,15 @@ struct compareInfo {
/* /*
** For LIKE and GLOB matching on EBCDIC machines, assume that every ** For LIKE and GLOB matching on EBCDIC machines, assume that every
** character is exactly one byte in size. Also, all characters are ** character is exactly one byte in size. Also, provde the Utf8Read()
** able to participate in upper-case-to-lower-case mappings in EBCDIC ** macro for fast reading of the next character in the common case where
** whereas only characters less than 0x80 do in ASCII. ** the next character is ASCII.
*/ */
#if defined(SQLITE_EBCDIC) #if defined(SQLITE_EBCDIC)
# define sqlite3Utf8Read(A) (*((*A)++)) # define sqlite3Utf8Read(A) (*((*A)++))
# define GlobUpperToLower(A) A = sqlite3UpperToLower[A] # define Utf8Read(A) (*(A++))
# define GlobUpperToLowerAscii(A) A = sqlite3UpperToLower[A]
#else #else
# define GlobUpperToLower(A) if( A<=0x7f ){ A = sqlite3UpperToLower[A]; } # define Utf8Read(A) (A[0]<0x80?*(A++):sqlite3Utf8Read(&A))
# define GlobUpperToLowerAscii(A) A = sqlite3UpperToLower[A]
#endif #endif
static const struct compareInfo globInfo = { '*', '?', '[', 0 }; 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 ** Ec Where E is the "esc" character and c is any other
** character, including '%', '_', and esc, match exactly c. ** 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. ** 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; matchOther = esc ? esc : pInfo->matchSet;
while( (c = sqlite3Utf8Read(&zPattern))!=0 ){ while( (c = Utf8Read(zPattern))!=0 ){
if( c==matchAll ){ /* Match "*" */ if( c==matchAll ){ /* Match "*" */
/* Skip over multiple "*" characters in the pattern. If there /* Skip over multiple "*" characters in the pattern. If there
** are also "?" characters, skip those as well, but consume a ** are also "?" characters, skip those as well, but consume a
** single character of the input string for each "?" skipped */ ** single character of the input string for each "?" skipped */
while( (c=sqlite3Utf8Read(&zPattern)) == matchAll while( (c=Utf8Read(zPattern)) == matchAll || c == matchOne ){
|| c == matchOne ){
if( c==matchOne && sqlite3Utf8Read(&zString)==0 ){ if( c==matchOne && sqlite3Utf8Read(&zString)==0 ){
return 0; return 0;
} }
@@ -702,7 +699,7 @@ static int patternCompare(
if( patternCompare(zPattern,zString,pInfo,esc) ) return 1; if( patternCompare(zPattern,zString,pInfo,esc) ) return 1;
} }
}else{ }else{
while( (c2 = sqlite3Utf8Read(&zString))!=0 ){ while( (c2 = Utf8Read(zString))!=0 ){
if( c2!=c ) continue; if( c2!=c ) continue;
if( patternCompare(zPattern,zString,pInfo,esc) ) return 1; if( patternCompare(zPattern,zString,pInfo,esc) ) return 1;
} }
@@ -748,7 +745,7 @@ static int patternCompare(
continue; continue;
} }
} }
c2 = sqlite3Utf8Read(&zString); c2 = Utf8Read(zString);
if( c==c2 ) continue; if( c==c2 ) continue;
if( noCase && c<0x80 && c2<0x80 && sqlite3Tolower(c)==sqlite3Tolower(c2) ){ if( noCase && c<0x80 && c2<0x80 && sqlite3Tolower(c)==sqlite3Tolower(c2) ){
continue; continue;

View File

@@ -1381,8 +1381,8 @@ void sqlite3GenerateConstraintChecks(
if( pIdx->pPartIdxWhere ){ if( pIdx->pPartIdxWhere ){
sqlite3VdbeAddOp2(v, OP_Null, 0, aRegIdx[ix]); sqlite3VdbeAddOp2(v, OP_Null, 0, aRegIdx[ix]);
pParse->ckBase = regNewData+1; pParse->ckBase = regNewData+1;
sqlite3ExprIfFalse(pParse, pIdx->pPartIdxWhere, addrUniqueOk, sqlite3ExprIfFalseDup(pParse, pIdx->pPartIdxWhere, addrUniqueOk,
SQLITE_JUMPIFNULL); SQLITE_JUMPIFNULL);
pParse->ckBase = 0; pParse->ckBase = 0;
} }

View File

@@ -402,7 +402,10 @@ static const sqlite3_api_routines sqlite3Apis = {
sqlite3_reset_auto_extension, sqlite3_reset_auto_extension,
sqlite3_result_blob64, sqlite3_result_blob64,
sqlite3_result_text64, sqlite3_result_text64,
sqlite3_strglob sqlite3_strglob,
/* Version 3.8.11 and later */
(sqlite3_value*(*)(const sqlite3_value*))sqlite3_value_dup,
sqlite3_value_free
}; };
/* /*

View File

@@ -2085,9 +2085,11 @@ int sqlite3TempInMemory(const sqlite3 *db){
return ( db->temp_store!=1 ); return ( db->temp_store!=1 );
#endif #endif
#if SQLITE_TEMP_STORE==3 #if SQLITE_TEMP_STORE==3
UNUSED_PARAMETER(db);
return 1; return 1;
#endif #endif
#if SQLITE_TEMP_STORE<1 || SQLITE_TEMP_STORE>3 #if SQLITE_TEMP_STORE<1 || SQLITE_TEMP_STORE>3
UNUSED_PARAMETER(db);
return 0; return 0;
#endif #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 sqlite3_test_control(int op, ...){
int rc = 0; int rc = 0;
#ifndef SQLITE_OMIT_BUILTIN_TEST #ifdef SQLITE_OMIT_BUILTIN_TEST
UNUSED_PARAMETER(op);
#else
va_list ap; va_list ap;
va_start(ap, op); va_start(ap, op);
switch( op ){ switch( op ){

View File

@@ -45,9 +45,14 @@ int sqlite3MutexInit(void){
}else{ }else{
pFrom = sqlite3NoopMutex(); pFrom = sqlite3NoopMutex();
} }
memcpy(pTo, pFrom, offsetof(sqlite3_mutex_methods, xMutexAlloc)); pTo->xMutexInit = pFrom->xMutexInit;
memcpy(&pTo->xMutexFree, &pFrom->xMutexFree, pTo->xMutexEnd = pFrom->xMutexEnd;
sizeof(*pTo) - offsetof(sqlite3_mutex_methods, xMutexFree)); 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; pTo->xMutexAlloc = pFrom->xMutexAlloc;
} }
rc = sqlite3GlobalConfig.mutex.xMutexInit(); rc = sqlite3GlobalConfig.mutex.xMutexInit();

View File

@@ -148,8 +148,15 @@ static SQLITE_WSD struct PCacheGlobal {
/* /*
** Macros to enter and leave the PCache LRU mutex. ** Macros to enter and leave the PCache LRU mutex.
*/ */
#define pcache1EnterMutex(X) sqlite3_mutex_enter((X)->mutex) #if !defined(SQLITE_ENABLE_MEMORY_MANAGEMENT) || SQLITE_THREADSAFE==0
#define pcache1LeaveMutex(X) sqlite3_mutex_leave((X)->mutex) # 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 **************/ /******** 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. ** The PGroup mutex must be held when this function is called.
*/ */
static void pcache1PinPage(PgHdr1 *pPage){ static PgHdr1 *pcache1PinPage(PgHdr1 *pPage){
PCache1 *pCache; PCache1 *pCache;
PGroup *pGroup;
assert( pPage!=0 ); assert( pPage!=0 );
assert( pPage->isPinned==0 ); assert( pPage->isPinned==0 );
pCache = pPage->pCache; pCache = pPage->pCache;
pGroup = pCache->pGroup; assert( pPage->pLruNext || pPage==pCache->pGroup->pLruTail );
assert( pPage->pLruNext || pPage==pGroup->pLruTail ); assert( pPage->pLruPrev || pPage==pCache->pGroup->pLruHead );
assert( pPage->pLruPrev || pPage==pGroup->pLruHead ); assert( sqlite3_mutex_held(pCache->pGroup->mutex) );
assert( sqlite3_mutex_held(pGroup->mutex) );
if( pPage->pLruPrev ){ if( pPage->pLruPrev ){
pPage->pLruPrev->pLruNext = pPage->pLruNext; pPage->pLruPrev->pLruNext = pPage->pLruNext;
}else{ }else{
pGroup->pLruHead = pPage->pLruNext; pCache->pGroup->pLruHead = pPage->pLruNext;
} }
if( pPage->pLruNext ){ if( pPage->pLruNext ){
pPage->pLruNext->pLruPrev = pPage->pLruPrev; pPage->pLruNext->pLruPrev = pPage->pLruPrev;
}else{ }else{
pGroup->pLruTail = pPage->pLruPrev; pCache->pGroup->pLruTail = pPage->pLruPrev;
} }
pPage->pLruNext = 0; pPage->pLruNext = 0;
pPage->pLruPrev = 0; pPage->pLruPrev = 0;
pPage->isPinned = 1; pPage->isPinned = 1;
pCache->nRecyclable--; pCache->nRecyclable--;
return pPage;
} }
@@ -530,10 +536,12 @@ static int pcache1Init(void *NotUsed){
UNUSED_PARAMETER(NotUsed); UNUSED_PARAMETER(NotUsed);
assert( pcache1.isInit==0 ); assert( pcache1.isInit==0 );
memset(&pcache1, 0, sizeof(pcache1)); memset(&pcache1, 0, sizeof(pcache1));
#if SQLITE_THREADSAFE
if( sqlite3GlobalConfig.bCoreMutex ){ if( sqlite3GlobalConfig.bCoreMutex ){
pcache1.grp.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_LRU); pcache1.grp.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_LRU);
pcache1.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_PMEM); pcache1.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_PMEM);
} }
#endif
pcache1.grp.mxPinned = 10; pcache1.grp.mxPinned = 10;
pcache1.isInit = 1; pcache1.isInit = 1;
return SQLITE_OK; return SQLITE_OK;
@@ -729,9 +737,9 @@ static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2(
** attempt to allocate a new one. ** attempt to allocate a new one.
*/ */
if( !pPage ){ if( !pPage ){
if( createFlag==1 ) sqlite3BeginBenignMalloc(); if( createFlag==1 ){ sqlite3BeginBenignMalloc(); }
pPage = pcache1AllocPage(pCache); pPage = pcache1AllocPage(pCache);
if( createFlag==1 ) sqlite3EndBenignMalloc(); if( createFlag==1 ){ sqlite3EndBenignMalloc(); }
} }
if( pPage ){ if( pPage ){
@@ -805,8 +813,13 @@ static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2(
** proceed to step 5. ** proceed to step 5.
** **
** 5. Otherwise, allocate and return a new page buffer. ** 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, sqlite3_pcache *p,
unsigned int iKey, unsigned int iKey,
int createFlag int createFlag
@@ -814,28 +827,63 @@ static sqlite3_pcache_page *pcache1Fetch(
PCache1 *pCache = (PCache1 *)p; PCache1 *pCache = (PCache1 *)p;
PgHdr1 *pPage = 0; 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. */ /* Step 1: Search the hash table for an existing entry. */
pPage = pCache->apHash[iKey % pCache->nHash]; pPage = pCache->apHash[iKey % pCache->nHash];
while( pPage && pPage->iKey!=iKey ){ pPage = pPage->pNext; } while( pPage && pPage->iKey!=iKey ){ pPage = pPage->pNext; }
/* Step 2: Abort if no existing page is found and createFlag is 0 */ /* Step 2: Abort if no existing page is found and createFlag is 0 */
if( pPage ){ if( pPage ){
if( !pPage->isPinned ) pcache1PinPage(pPage); if( !pPage->isPinned ){
return pcache1PinPage(pPage);
}else{
return pPage;
}
}else if( createFlag ){ }else if( createFlag ){
/* Steps 3, 4, and 5 implemented by this subroutine */ /* 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 ); assert( pPage==0 || pCache->iMaxKey>=iKey );
pcache1LeaveMutex(pCache->pGroup); 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);
}
} }

View File

@@ -1,16 +1,13 @@
/* /*
** The "printf" code that follows dates from the 1980's. It is in ** The "printf" code that follows dates from the 1980's. It is in
** the public domain. The original comments are included here for ** the public domain.
** 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().
** **
************************************************************************** **************************************************************************
** **
** This file contains code for a set of "printf"-like routines. These ** This file contains code for a set of "printf"-like routines. These
** routines format strings much like the printf() from the standard C ** routines format strings much like the printf() from the standard C
** library, though the implementation here has enhancements to support ** library, though the implementation here has enhancements to support
** SQLlite. ** SQLite.
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
@@ -1058,67 +1055,6 @@ void sqlite3DebugPrintf(const char *zFormat, ...){
} }
#endif #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(). ** variable-argument wrapper around sqlite3VXPrintf().

View File

@@ -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 /* Advance to the next term of the compound
*/ */
p = p->pPrior; p = p->pPrior;

View File

@@ -21,7 +21,8 @@
/***/ int sqlite3SelectTrace = 0; /***/ int sqlite3SelectTrace = 0;
# define SELECTTRACE(K,P,S,X) \ # define SELECTTRACE(K,P,S,X) \
if(sqlite3SelectTrace&(K)) \ 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 sqlite3DebugPrintf X
#else #else
# define SELECTTRACE(K,P,S,X) # define SELECTTRACE(K,P,S,X)
@@ -365,6 +366,12 @@ static void setJoinExpr(Expr *p, int iTable){
assert( !ExprHasProperty(p, EP_TokenOnly|EP_Reduced) ); assert( !ExprHasProperty(p, EP_TokenOnly|EP_Reduced) );
ExprSetVVAProperty(p, EP_NoReduce); ExprSetVVAProperty(p, EP_NoReduce);
p->iRightJoinTable = (i16)iTable; 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); setJoinExpr(p->pLeft, iTable);
p = p->pRight; p = p->pRight;
} }
@@ -774,7 +781,8 @@ static void selectInnerLoop(
default: { default: {
assert( pDistinct->eTnctType==WHERE_DISTINCT_UNORDERED ); assert( pDistinct->eTnctType==WHERE_DISTINCT_UNORDERED );
codeDistinct(pParse, pDistinct->tabTnct, iContinue, nResultCol, regResult); codeDistinct(pParse, pDistinct->tabTnct, iContinue, nResultCol,
regResult);
break; break;
} }
} }
@@ -827,7 +835,8 @@ static void selectInnerLoop(
** current row to the index and proceed with writing it to the ** current row to the index and proceed with writing it to the
** output table as well. */ ** output table as well. */
int addr = sqlite3VdbeCurrentAddr(v) + 4; 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); sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm+1, r1);
assert( pSort==0 ); assert( pSort==0 );
} }
@@ -1310,28 +1319,27 @@ static void generateSortTail(
*/ */
#ifdef SQLITE_ENABLE_COLUMN_METADATA #ifdef SQLITE_ENABLE_COLUMN_METADATA
# define columnType(A,B,C,D,E,F) columnTypeImpl(A,B,C,D,E,F) # 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( static const char *columnTypeImpl(
NameContext *pNC, NameContext *pNC,
Expr *pExpr, Expr *pExpr,
#ifdef SQLITE_ENABLE_COLUMN_METADATA
const char **pzOrigDb, const char **pzOrigDb,
const char **pzOrigTab, const char **pzOrigTab,
const char **pzOrigCol, const char **pzOrigCol,
#endif
u8 *pEstWidth 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; char const *zType = 0;
int j; int j;
u8 estWidth = 1; 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; if( NEVER(pExpr==0) || pNC->pSrcList==0 ) return 0;
switch( pExpr->op ){ switch( pExpr->op ){
@@ -1705,7 +1713,8 @@ static void selectAddColumnTypeAndCollation(
for(i=0, pCol=pTab->aCol; i<pTab->nCol; i++, pCol++){ for(i=0, pCol=pTab->aCol; i<pTab->nCol; i++, pCol++){
p = a[i].pExpr; p = a[i].pExpr;
if( pCol->zType==0 ){ 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; szAll += pCol->szEst;
pCol->affinity = sqlite3ExprAffinity(p); 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 ** Error message for when two or more terms of a compound select have different
** size result sets. ** size result sets.
*/ */
static void selectWrongNumTermsError(Parse *pParse, Select *p){ void sqlite3SelectWrongNumTermsError(Parse *pParse, Select *p){
if( p->selFlags & SF_Values ){ if( p->selFlags & SF_Values ){
sqlite3ErrorMsg(pParse, "all VALUES must have the same number of terms"); sqlite3ErrorMsg(pParse, "all VALUES must have the same number of terms");
}else{ }else{
@@ -2110,7 +2119,6 @@ static int multiSelectValues(
SelectDest *pDest /* What to do with query results */ SelectDest *pDest /* What to do with query results */
){ ){
Select *pPrior; Select *pPrior;
int nExpr = p->pEList->nExpr;
int nRow = 1; int nRow = 1;
int rc = 0; int rc = 0;
assert( p->selFlags & SF_MultiValue ); 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->op==TK_ALL || (p->op==TK_SELECT && p->pPrior==0) );
assert( p->pLimit==0 ); assert( p->pLimit==0 );
assert( p->pOffset==0 ); assert( p->pOffset==0 );
if( p->pEList->nExpr!=nExpr ){ assert( p->pNext==0 || p->pEList->nExpr==p->pNext->pEList->nExpr );
selectWrongNumTermsError(pParse, p);
return 1;
}
if( p->pPrior==0 ) break; if( p->pPrior==0 ) break;
assert( p->pPrior->pNext==p ); assert( p->pPrior->pNext==p );
p = p->pPrior; p = p->pPrior;
@@ -2231,11 +2236,7 @@ static int multiSelect(
** in their result sets. ** in their result sets.
*/ */
assert( p->pEList && pPrior->pEList ); assert( p->pEList && pPrior->pEList );
if( p->pEList->nExpr!=pPrior->pEList->nExpr ){ assert( p->pEList->nExpr==pPrior->pEList->nExpr );
selectWrongNumTermsError(pParse, p);
rc = 1;
goto multi_select_end;
}
#ifndef SQLITE_OMIT_CTE #ifndef SQLITE_OMIT_CTE
if( p->selFlags & SF_Recursive ){ 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 ** (**) Restriction (10) was removed from the code on 2005-02-05 but we
** accidently carried the comment forward until 2014-09-15. Original ** accidently carried the comment forward until 2014-09-15. Original
** text: "The subquery does not use aggregates or the outer query does not ** text: "The subquery does not use aggregates or the outer query
** use LIMIT." ** does not use LIMIT."
** **
** (11) The subquery and the outer query do not both have ORDER BY clauses. ** (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 SELECTTRACE_ENABLED
if( sqlite3SelectTrace & 0x100 ){ if( sqlite3SelectTrace & 0x100 ){
sqlite3DebugPrintf("After flattening:\n"); SELECTTRACE(0x100,pParse,p,("After flattening:\n"));
sqlite3TreeViewSelect(0, p, 0); sqlite3TreeViewSelect(0, p, 0);
} }
#endif #endif
@@ -3718,6 +3719,73 @@ static int flattenSubquery(
} }
#endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */ #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 ** Based on the contents of the AggInfo structure indicated by the first
** argument, this function checks if the following are true: ** 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. ** pFrom->pIndex and return SQLITE_OK.
*/ */
int sqlite3IndexedByLookup(Parse *pParse, struct SrcList_item *pFrom){ int sqlite3IndexedByLookup(Parse *pParse, struct SrcList_item *pFrom){
if( pFrom->pTab && pFrom->zIndex ){ if( pFrom->pTab && pFrom->zIndexedBy ){
Table *pTab = pFrom->pTab; Table *pTab = pFrom->pTab;
char *zIndex = pFrom->zIndex; char *zIndexedBy = pFrom->zIndexedBy;
Index *pIdx; Index *pIdx;
for(pIdx=pTab->pIndex; for(pIdx=pTab->pIndex;
pIdx && sqlite3StrICmp(pIdx->zName, zIndex); pIdx && sqlite3StrICmp(pIdx->zName, zIndexedBy);
pIdx=pIdx->pNext pIdx=pIdx->pNext
); );
if( !pIdx ){ if( !pIdx ){
sqlite3ErrorMsg(pParse, "no such index: %s", zIndex, 0); sqlite3ErrorMsg(pParse, "no such index: %s", zIndexedBy, 0);
pParse->checkSchema = 1; pParse->checkSchema = 1;
return SQLITE_ERROR; return SQLITE_ERROR;
} }
@@ -4747,12 +4815,11 @@ int sqlite3Select(
memset(&sSort, 0, sizeof(sSort)); memset(&sSort, 0, sizeof(sSort));
sSort.pOrderBy = p->pOrderBy; sSort.pOrderBy = p->pOrderBy;
pTabList = p->pSrc; pTabList = p->pSrc;
pEList = p->pEList;
if( pParse->nErr || db->mallocFailed ){ if( pParse->nErr || db->mallocFailed ){
goto select_end; goto select_end;
} }
assert( p->pEList!=0 );
isAgg = (p->selFlags & SF_Aggregate)!=0; isAgg = (p->selFlags & SF_Aggregate)!=0;
assert( pEList!=0 );
#if SELECTTRACE_ENABLED #if SELECTTRACE_ENABLED
if( sqlite3SelectTrace & 0x100 ){ if( sqlite3SelectTrace & 0x100 ){
SELECTTRACE(0x100,pParse,p, ("after name resolution:\n")); SELECTTRACE(0x100,pParse,p, ("after name resolution:\n"));
@@ -4761,29 +4828,67 @@ int sqlite3Select(
#endif #endif
/* Begin generating code.
*/
v = sqlite3GetVdbe(pParse);
if( v==0 ) goto select_end;
/* If writing to memory or generating a set /* If writing to memory or generating a set
** only a single column may be output. ** only a single column may be output.
*/ */
#ifndef SQLITE_OMIT_SUBQUERY #ifndef SQLITE_OMIT_SUBQUERY
if( checkForMultiColumnSelectError(pParse, pDest, pEList->nExpr) ){ if( checkForMultiColumnSelectError(pParse, pDest, p->pEList->nExpr) ){
goto select_end; goto select_end;
} }
#endif #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 /* Generate code for all sub-queries in the FROM clause
*/ */
#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) #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]; struct SrcList_item *pItem = &pTabList->a[i];
SelectDest dest; SelectDest dest;
Select *pSub = pItem->pSelect; Select *pSub = pItem->pSelect;
int isAggSub;
if( pSub==0 ) continue; if( pSub==0 ) continue;
/* Sometimes the code for a subquery will be generated more than /* Sometimes the code for a subquery will be generated more than
@@ -4808,17 +4913,25 @@ int sqlite3Select(
*/ */
pParse->nHeight += sqlite3SelectExprHeight(p); pParse->nHeight += sqlite3SelectExprHeight(p);
isAggSub = (pSub->selFlags & SF_Aggregate)!=0; /* Make copies of constant WHERE-clause terms in the outer query down
if( flattenSubquery(pParse, p, i, isAgg, isAggSub) ){ ** inside the subquery. This can help the subquery to run more efficiently.
/* This subquery can be absorbed into its parent. */ */
if( isAggSub ){ if( (pItem->jointype & JT_OUTER)==0
isAgg = 1; && pushDownWhereTerms(db, pSub, p->pWhere, pItem->iCursor)
p->selFlags |= SF_Aggregate; ){
#if SELECTTRACE_ENABLED
if( sqlite3SelectTrace & 0x100 ){
SELECTTRACE(0x100,pParse,p,("After WHERE-clause push-down:\n"));
sqlite3TreeViewSelect(0, p, 0);
} }
i = -1; #endif
}else if( pTabList->nSrc==1 }
&& (p->selFlags & SF_All)==0
&& OptimizationEnabled(db, SQLITE_SubqCoroutine) /* 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 /* Implement a co-routine that will return a single row of the result
** set on each invocation. ** set on each invocation.
@@ -4869,33 +4982,23 @@ int sqlite3Select(
sqlite3VdbeChangeP1(v, topAddr, retAddr); sqlite3VdbeChangeP1(v, topAddr, retAddr);
sqlite3ClearTempRegCache(pParse); sqlite3ClearTempRegCache(pParse);
} }
if( /*pParse->nErr ||*/ db->mallocFailed ){ if( db->mallocFailed ) goto select_end;
goto select_end;
}
pParse->nHeight -= sqlite3SelectExprHeight(p); pParse->nHeight -= sqlite3SelectExprHeight(p);
pTabList = p->pSrc;
if( !IgnorableOrderby(pDest) ){
sSort.pOrderBy = p->pOrderBy;
}
} }
pEList = p->pEList;
#endif #endif
/* Various elements of the SELECT copied into local variables for
** convenience */
pEList = p->pEList;
pWhere = p->pWhere; pWhere = p->pWhere;
pGroupBy = p->pGroupBy; pGroupBy = p->pGroupBy;
pHaving = p->pHaving; pHaving = p->pHaving;
sDistinct.isTnct = (p->selFlags & SF_Distinct)!=0; 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 #if SELECTTRACE_ENABLED
SELECTTRACE(1,pParse,p,("end compound-select processing\n")); if( sqlite3SelectTrace & 0x400 ){
pParse->nSelectIndent--; SELECTTRACE(0x400,pParse,p,("After all FROM-clause analysis:\n"));
#endif sqlite3TreeViewSelect(0, p, 0);
return rc;
} }
#endif #endif
@@ -4915,23 +5018,23 @@ int sqlite3Select(
** BY and DISTINCT, and an index or separate temp-table for the other. ** BY and DISTINCT, and an index or separate temp-table for the other.
*/ */
if( (p->selFlags & (SF_Distinct|SF_Aggregate))==SF_Distinct 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->selFlags &= ~SF_Distinct;
p->pGroupBy = sqlite3ExprListDup(db, p->pEList, 0); pGroupBy = p->pGroupBy = sqlite3ExprListDup(db, pEList, 0);
pGroupBy = p->pGroupBy;
/* Notice that even thought SF_Distinct has been cleared from p->selFlags, /* Notice that even thought SF_Distinct has been cleared from p->selFlags,
** the sDistinct.isTnct is still set. Hence, isTnct represents the ** the sDistinct.isTnct is still set. Hence, isTnct represents the
** original setting of the SF_Distinct flag, not the current setting */ ** original setting of the SF_Distinct flag, not the current setting */
assert( sDistinct.isTnct ); assert( sDistinct.isTnct );
} }
/* If there is an ORDER BY clause, then this sorting /* If there is an ORDER BY clause, then create an ephemeral index to
** index might end up being unused if the data can be ** do the sorting. But this sorting ephemeral index might end up
** extracted in pre-sorted order. If that is the case, then the ** being unused if the data can be extracted in pre-sorted order.
** OP_OpenEphemeral instruction will be changed to an OP_Noop once ** If that is the case, then the OP_OpenEphemeral instruction will be
** we figure out that the sorting index is not needed. The addrSortIndex ** changed to an OP_Noop once we figure out that the sorting index is
** variable is used to facilitate that change. ** not needed. The sSort.addrSortIndex variable is used to facilitate
** that change.
*/ */
if( sSort.pOrderBy ){ if( sSort.pOrderBy ){
KeyInfo *pKeyInfo; KeyInfo *pKeyInfo;
@@ -4962,14 +5065,14 @@ int sqlite3Select(
sSort.sortFlags |= SORTFLAG_UseSorter; 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 ){ if( p->selFlags & SF_Distinct ){
sDistinct.tabTnct = pParse->nTab++; sDistinct.tabTnct = pParse->nTab++;
sDistinct.addrTnct = sqlite3VdbeAddOp4(v, OP_OpenEphemeral, sDistinct.addrTnct = sqlite3VdbeAddOp4(v, OP_OpenEphemeral,
sDistinct.tabTnct, 0, 0, sDistinct.tabTnct, 0, 0,
(char*)keyInfoFromExprList(pParse, p->pEList,0,0), (char*)keyInfoFromExprList(pParse, p->pEList,0,0),
P4_KEYINFO); P4_KEYINFO);
sqlite3VdbeChangeP5(v, BTREE_UNORDERED); sqlite3VdbeChangeP5(v, BTREE_UNORDERED);
sDistinct.eTnctType = WHERE_DISTINCT_UNORDERED; sDistinct.eTnctType = WHERE_DISTINCT_UNORDERED;
}else{ }else{
@@ -5047,11 +5150,10 @@ int sqlite3Select(
p->nSelectRow = 1; p->nSelectRow = 1;
} }
/* If there is both a GROUP BY and an ORDER BY clause and they are /* 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 ** 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 ** 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 ** database index that causes rows to be grouped together as required
** but not actually sorted. Either way, record the fact that the ** but not actually sorted. Either way, record the fact that the
** ORDER BY and GROUP BY clauses are the same by setting the orderByGrp ** ORDER BY and GROUP BY clauses are the same by setting the orderByGrp
@@ -5229,7 +5331,8 @@ int sqlite3Select(
addrTopOfLoop = sqlite3VdbeCurrentAddr(v); addrTopOfLoop = sqlite3VdbeCurrentAddr(v);
sqlite3ExprCacheClear(pParse); sqlite3ExprCacheClear(pParse);
if( groupBySort ){ 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++){ for(j=0; j<pGroupBy->nExpr; j++){
if( groupBySort ){ if( groupBySort ){
@@ -5301,7 +5404,8 @@ int sqlite3Select(
sqlite3VdbeAddOp1(v, OP_Return, regOutputRow); sqlite3VdbeAddOp1(v, OP_Return, regOutputRow);
sqlite3VdbeResolveLabel(v, addrOutputRow); sqlite3VdbeResolveLabel(v, addrOutputRow);
addrOutputRow = sqlite3VdbeCurrentAddr(v); 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")); VdbeComment((v, "Groupby result generator entry point"));
sqlite3VdbeAddOp1(v, OP_Return, regOutputRow); sqlite3VdbeAddOp1(v, OP_Return, regOutputRow);
finalizeAggFunctions(pParse, &sAggInfo); finalizeAggFunctions(pParse, &sAggInfo);
@@ -5465,7 +5569,8 @@ int sqlite3Select(
** and send them to the callback one by one. ** and send them to the callback one by one.
*/ */
if( sSort.pOrderBy ){ 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); generateSortTail(pParse, p, &sSort, pEList->nExpr, pDest);
} }
@@ -5497,97 +5602,3 @@ select_end:
#endif #endif
return rc; 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 */

View File

@@ -101,28 +101,26 @@
#if defined(_WIN32) || defined(WIN32) #if defined(_WIN32) || defined(WIN32)
# include <io.h> # include <io.h>
# include <fcntl.h> # include <fcntl.h>
#define isatty(h) _isatty(h) # define isatty(h) _isatty(h)
#ifndef access # ifndef access
# define access(f,m) _access((f),(m)) # define access(f,m) _access((f),(m))
#endif # endif
#undef popen # undef popen
#define popen _popen # define popen _popen
#undef pclose # undef pclose
#define pclose _pclose # define pclose _pclose
#else #else
/* Make sure isatty() has a prototype. /* Make sure isatty() has a prototype. */
*/ extern int isatty(int);
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
# 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 #endif
#if defined(_WIN32_WCE) #if defined(_WIN32_WCE)
@@ -1331,7 +1329,10 @@ static void display_scanstats(
sqlite3 *db, /* Database to query */ sqlite3 *db, /* Database to query */
ShellState *pArg /* Pointer to ShellState */ 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; int i, k, n, mx;
fprintf(pArg->out, "-------- scanstats --------\n"); fprintf(pArg->out, "-------- scanstats --------\n");
mx = 0; mx = 0;
@@ -1866,6 +1867,7 @@ static void readfileFunc(
long nIn; long nIn;
void *pBuf; void *pBuf;
UNUSED_PARAMETER(argc);
zName = (const char*)sqlite3_value_text(argv[0]); zName = (const char*)sqlite3_value_text(argv[0]);
if( zName==0 ) return; if( zName==0 ) return;
in = fopen(zName, "rb"); in = fopen(zName, "rb");
@@ -1898,6 +1900,7 @@ static void writefileFunc(
sqlite3_int64 rc; sqlite3_int64 rc;
const char *zFile; const char *zFile;
UNUSED_PARAMETER(argc);
zFile = (const char*)sqlite3_value_text(argv[0]); zFile = (const char*)sqlite3_value_text(argv[0]);
if( zFile==0 ) return; if( zFile==0 ) return;
out = fopen(zFile, "wb"); 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", "write format:", aHdr[18]);
fprintf(p->out, "%-20s %d\n", "read format:", aHdr[19]); fprintf(p->out, "%-20s %d\n", "read format:", aHdr[19]);
fprintf(p->out, "%-20s %d\n", "reserved bytes:", aHdr[20]); 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; int ofst = aField[i].ofst;
unsigned int val = get4byteInt(aHdr + ofst); unsigned int val = get4byteInt(aHdr + ofst);
fprintf(p->out, "%-20s %u", aField[i].zName, val); 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{ }else{
zSchemaTab = sqlite3_mprintf("\"%w\".sqlite_master", zDb); 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); char *zSql = sqlite3_mprintf(aQuery[i].zSql, zSchemaTab);
int val = db_int(p, zSql); int val = db_int(p, zSql);
sqlite3_free(zSql); sqlite3_free(zSql);
@@ -3228,7 +3231,7 @@ static int do_meta_command(char *zLine, ShellState *p){
int i, n2; int i, n2;
open_db(p, 0); open_db(p, 0);
if( nArg==1 ){ 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, printf("%20s %d\n", aLimit[i].zLimitName,
sqlite3_limit(p->db, aLimit[i].limitCode, -1)); sqlite3_limit(p->db, aLimit[i].limitCode, -1));
} }
@@ -3239,7 +3242,7 @@ static int do_meta_command(char *zLine, ShellState *p){
}else{ }else{
int iLimit = -1; int iLimit = -1;
n2 = strlen30(azArg[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( sqlite3_strnicmp(aLimit[i].zLimitName, azArg[1], n2)==0 ){
if( iLimit<0 ){ if( iLimit<0 ){
iLimit = i; iLimit = i;
@@ -3349,9 +3352,8 @@ static int do_meta_command(char *zLine, ShellState *p){
const char *zSavedFilename = p->zDbFilename; const char *zSavedFilename = p->zDbFilename;
char *zNewFilename = 0; char *zNewFilename = 0;
p->db = 0; p->db = 0;
if( nArg>=2 ){ if( nArg>=2 ) zNewFilename = sqlite3_mprintf("%s", azArg[1]);
p->zDbFilename = zNewFilename = sqlite3_mprintf("%s", azArg[1]); p->zDbFilename = zNewFilename;
}
open_db(p, 1); open_db(p, 1);
if( p->db!=0 ){ if( p->db!=0 ){
sqlite3_close(savedDb); 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 /* convert testctrl text option to value. allow any unique prefix
** of the option name, or a numerical value. */ ** of the option name, or a numerical value. */
n2 = strlen30(azArg[1]); 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( strncmp(azArg[1], aCtrl[i].zCtrlName, n2)==0 ){
if( testctrl<0 ){ if( testctrl<0 ){
testctrl = aCtrl[i].ctrlCode; testctrl = aCtrl[i].ctrlCode;
@@ -4792,7 +4794,7 @@ int SQLITE_CDECL main(int argc, char **argv){
sqlite3_snprintf(nHistory, zHistory,"%s/.sqlite_history", zHome); 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); rc = process_input(&data, 0);
if( zHistory ){ if( zHistory ){
shell_stifle_history(100); shell_stifle_history(100);

View File

@@ -23,7 +23,7 @@
** **
** The official C-language API documentation for SQLite is derived ** The official C-language API documentation for SQLite is derived
** from comments in this file. This file is the authoritative source ** 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 name of this file under configuration management is "sqlite.h.in".
** The makefile makes some minor changes to this file (such as inserting ** The makefile makes some minor changes to this file (such as inserting

View File

@@ -267,7 +267,8 @@ struct sqlite3_api_routines {
void (*result_text64)(sqlite3_context*,const char*,sqlite3_uint64, void (*result_text64)(sqlite3_context*,const char*,sqlite3_uint64,
void(*)(void*), unsigned char); void(*)(void*), unsigned char);
int (*strglob)(const char*,const 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*); void (*value_free)(sqlite3_value*);
}; };

View File

@@ -2260,7 +2260,7 @@ struct SrcList {
Expr *pOn; /* The ON clause of a join */ Expr *pOn; /* The ON clause of a join */
IdList *pUsing; /* The USING 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 */ 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 */ Index *pIndex; /* Index structure corresponding to zIndex, if any */
} a[1]; /* One entry for each identifier on the list */ } 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 sqlite3Isxdigit(x) isxdigit((unsigned char)(x))
# define sqlite3Tolower(x) tolower((unsigned char)(x)) # define sqlite3Tolower(x) tolower((unsigned char)(x))
#endif #endif
#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
int sqlite3IsIdChar(u8); int sqlite3IsIdChar(u8);
#endif
/* /*
** Internal function prototypes ** Internal function prototypes
@@ -3094,7 +3096,9 @@ void sqlite3ScratchFree(void*);
void *sqlite3PageMalloc(int); void *sqlite3PageMalloc(int);
void sqlite3PageFree(void*); void sqlite3PageFree(void*);
void sqlite3MemSetDefault(void); void sqlite3MemSetDefault(void);
#ifndef SQLITE_OMIT_BUILTIN_TEST
void sqlite3BenignMallocHooks(void (*)(void), void (*)(void)); void sqlite3BenignMallocHooks(void (*)(void), void (*)(void));
#endif
int sqlite3HeapNearlyFull(void); int sqlite3HeapNearlyFull(void);
/* /*
@@ -3170,10 +3174,6 @@ char *sqlite3VMPrintf(sqlite3*,const char*, va_list);
#endif #endif
#if defined(SQLITE_DEBUG) #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 sqlite3TreeViewExpr(TreeView*, const Expr*, u8);
void sqlite3TreeViewExprList(TreeView*, const ExprList*, u8, const char*); void sqlite3TreeViewExprList(TreeView*, const ExprList*, u8, const char*);
void sqlite3TreeViewSelect(TreeView*, const Select*, u8); void sqlite3TreeViewSelect(TreeView*, const Select*, u8);
@@ -3242,7 +3242,9 @@ int sqlite3BitvecSet(Bitvec*, u32);
void sqlite3BitvecClear(Bitvec*, u32, void*); void sqlite3BitvecClear(Bitvec*, u32, void*);
void sqlite3BitvecDestroy(Bitvec*); void sqlite3BitvecDestroy(Bitvec*);
u32 sqlite3BitvecSize(Bitvec*); u32 sqlite3BitvecSize(Bitvec*);
#ifndef SQLITE_OMIT_BUILTIN_TEST
int sqlite3BitvecBuiltinTest(int,int*); int sqlite3BitvecBuiltinTest(int,int*);
#endif
RowSet *sqlite3RowSetInit(sqlite3*, void*, unsigned int); RowSet *sqlite3RowSetInit(sqlite3*, void*, unsigned int);
void sqlite3RowSetClear(RowSet*); void sqlite3RowSetClear(RowSet*);
@@ -3330,6 +3332,7 @@ int sqlite3ExprCodeExprList(Parse*, ExprList*, int, u8);
#define SQLITE_ECEL_FACTOR 0x02 /* Factor out constant terms */ #define SQLITE_ECEL_FACTOR 0x02 /* Factor out constant terms */
void sqlite3ExprIfTrue(Parse*, Expr*, int, int); void sqlite3ExprIfTrue(Parse*, Expr*, int, int);
void sqlite3ExprIfFalse(Parse*, Expr*, int, int); void sqlite3ExprIfFalse(Parse*, Expr*, int, int);
void sqlite3ExprIfFalseDup(Parse*, Expr*, int, int);
Table *sqlite3FindTable(sqlite3*,const char*, const char*); Table *sqlite3FindTable(sqlite3*,const char*, const char*);
Table *sqlite3LocateTable(Parse*,int isView,const char*, const char*); Table *sqlite3LocateTable(Parse*,int isView,const char*, const char*);
Table *sqlite3LocateTableItem(Parse*,int isView,struct SrcList_item *); Table *sqlite3LocateTableItem(Parse*,int isView,struct SrcList_item *);
@@ -3346,8 +3349,10 @@ void sqlite3ExprAnalyzeAggregates(NameContext*, Expr*);
void sqlite3ExprAnalyzeAggList(NameContext*,ExprList*); void sqlite3ExprAnalyzeAggList(NameContext*,ExprList*);
int sqlite3FunctionUsesThisSrc(Expr*, SrcList*); int sqlite3FunctionUsesThisSrc(Expr*, SrcList*);
Vdbe *sqlite3GetVdbe(Parse*); Vdbe *sqlite3GetVdbe(Parse*);
#ifndef SQLITE_OMIT_BUILTIN_TEST
void sqlite3PrngSaveState(void); void sqlite3PrngSaveState(void);
void sqlite3PrngRestoreState(void); void sqlite3PrngRestoreState(void);
#endif
void sqlite3RollbackAll(sqlite3*,int); void sqlite3RollbackAll(sqlite3*,int);
void sqlite3CodeVerifySchema(Parse*, int); void sqlite3CodeVerifySchema(Parse*, int);
void sqlite3CodeVerifyNamedSchema(Parse*, const char *zDb); void sqlite3CodeVerifyNamedSchema(Parse*, const char *zDb);
@@ -3565,6 +3570,7 @@ void sqlite3NestedParse(Parse*, const char*, ...);
void sqlite3ExpirePreparedStatements(sqlite3*); void sqlite3ExpirePreparedStatements(sqlite3*);
int sqlite3CodeSubselect(Parse *, Expr *, int, int); int sqlite3CodeSubselect(Parse *, Expr *, int, int);
void sqlite3SelectPrep(Parse*, Select*, NameContext*); void sqlite3SelectPrep(Parse*, Select*, NameContext*);
void sqlite3SelectWrongNumTermsError(Parse *pParse, Select *p);
int sqlite3MatchSpanName(const char*, const char*, const char*, const char*); int sqlite3MatchSpanName(const char*, const char*, const char*, const char*);
int sqlite3ResolveExprNames(NameContext*, Expr*); int sqlite3ResolveExprNames(NameContext*, Expr*);
void sqlite3ResolveSelectNames(Parse*, Select*, NameContext*); void sqlite3ResolveSelectNames(Parse*, Select*, NameContext*);

View File

@@ -102,7 +102,11 @@ const char sqlite3IsEbcdicIdChar[] = {
}; };
#define IdChar(C) (((c=C)>=0x42 && sqlite3IsEbcdicIdChar[c-0x40])) #define IdChar(C) (((c=C)>=0x42 && sqlite3IsEbcdicIdChar[c-0x40]))
#endif #endif
/* Make the IdChar function accessible from ctime.c */
#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
int sqlite3IsIdChar(u8 c){ return IdChar(c); } int sqlite3IsIdChar(u8 c){ return IdChar(c); }
#endif
/* /*

431
src/treeview.c Normal file
View 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 */

View File

@@ -3511,6 +3511,26 @@ case OP_Close: {
break; 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 * /* Opcode: SeekGE P1 P2 P3 P4 *
** Synopsis: key=r[P3@P4] ** Synopsis: key=r[P3@P4]
** **

View File

@@ -169,6 +169,7 @@ int sqlite3VdbeAddOp1(Vdbe*,int,int);
int sqlite3VdbeAddOp2(Vdbe*,int,int,int); int sqlite3VdbeAddOp2(Vdbe*,int,int,int);
int sqlite3VdbeAddOp3(Vdbe*,int,int,int,int); int sqlite3VdbeAddOp3(Vdbe*,int,int,int,int);
int sqlite3VdbeAddOp4(Vdbe*,int,int,int,int,const char *zP4,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 sqlite3VdbeAddOp4Int(Vdbe*,int,int,int,int,int);
int sqlite3VdbeAddOpList(Vdbe*, int nOp, VdbeOpList const *aOp, int iLineno); int sqlite3VdbeAddOpList(Vdbe*, int nOp, VdbeOpList const *aOp, int iLineno);
void sqlite3VdbeAddParseSchemaOp(Vdbe*,int,char*); void sqlite3VdbeAddParseSchemaOp(Vdbe*,int,char*);

View File

@@ -83,6 +83,9 @@ struct VdbeCursor {
i64 seqCount; /* Sequence counter */ i64 seqCount; /* Sequence counter */
i64 movetoTarget; /* Argument to the deferred sqlite3BtreeMoveto() */ i64 movetoTarget; /* Argument to the deferred sqlite3BtreeMoveto() */
VdbeSorter *pSorter; /* Sorter object for OP_SorterOpen cursors */ 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 /* Cached information about the header for the data record that the
** cursor is currently pointing to. Only valid if cacheStatus matches ** cursor is currently pointing to. Only valid if cacheStatus matches

View File

@@ -233,6 +233,23 @@ int sqlite3VdbeAddOp4(
return addr; 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 ** Add an OP_ParseSchema opcode. This routine is broken out from
** sqlite3VdbeAddOp4() since it needs to also needs to mark all btrees ** sqlite3VdbeAddOp4() since it needs to also needs to mark all btrees
@@ -397,6 +414,7 @@ static Op *opIterNext(VdbeOpIter *p){
** * OP_VUpdate ** * OP_VUpdate
** * OP_VRename ** * OP_VRename
** * OP_FkCounter with P2==0 (immediate foreign key constraint) ** * 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 ** Then check that the value of Parse.mayAbort is true if an
** ABORT may be thrown, or false otherwise. Return true if it does ** 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 sqlite3VdbeAssertMayAbort(Vdbe *v, int mayAbort){
int hasAbort = 0; int hasAbort = 0;
int hasFkCounter = 0; int hasFkCounter = 0;
int hasCreateTable = 0;
int hasInitCoroutine = 0;
Op *pOp; Op *pOp;
VdbeOpIter sIter; VdbeOpIter sIter;
memset(&sIter, 0, sizeof(sIter)); memset(&sIter, 0, sizeof(sIter));
@@ -422,6 +442,8 @@ int sqlite3VdbeAssertMayAbort(Vdbe *v, int mayAbort){
hasAbort = 1; hasAbort = 1;
break; break;
} }
if( opcode==OP_CreateTable ) hasCreateTable = 1;
if( opcode==OP_InitCoroutine ) hasInitCoroutine = 1;
#ifndef SQLITE_OMIT_FOREIGN_KEY #ifndef SQLITE_OMIT_FOREIGN_KEY
if( opcode==OP_FkCounter && pOp->p1==0 && pOp->p2==1 ){ if( opcode==OP_FkCounter && pOp->p1==0 && pOp->p2==1 ){
hasFkCounter = 1; hasFkCounter = 1;
@@ -435,7 +457,8 @@ int sqlite3VdbeAssertMayAbort(Vdbe *v, int mayAbort){
** through all opcodes and hasAbort may be set incorrectly. Return ** through all opcodes and hasAbort may be set incorrectly. Return
** true for this case to prevent the assert() in the callers frame ** true for this case to prevent the assert() in the callers frame
** from failing. */ ** from failing. */
return ( v->db->mallocFailed || hasAbort==mayAbort || hasFkCounter ); return ( v->db->mallocFailed || hasAbort==mayAbort || hasFkCounter
|| (hasCreateTable && hasInitCoroutine) );
} }
#endif /* SQLITE_DEBUG - the sqlite3AssertMayAbort() function */ #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(). ** 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; int i;
sqlite3 *db; sqlite3 *db;
Db *aDb; Db *aDb;
int nDb; int nDb;
if( DbMaskAllZero(p->lockMask) ) return; /* The common case */
db = p->db; db = p->db;
aDb = db->aDb; aDb = db->aDb;
nDb = db->nDb; 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 #endif
#if defined(VDBE_PROFILE) || defined(SQLITE_DEBUG) #if defined(VDBE_PROFILE) || defined(SQLITE_DEBUG)

View File

@@ -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 ** 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). ** 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){ void sqlite3VdbeMemShallowCopy(Mem *pTo, const Mem *pFrom, int srcType){
assert( (pFrom->flags & MEM_RowSet)==0 ); assert( (pFrom->flags & MEM_RowSet)==0 );
assert( pTo->db==pFrom->db ); assert( pTo->db==pFrom->db );
if( VdbeMemDynamic(pTo) ) vdbeMemClearExternAndSetNull(pTo); if( VdbeMemDynamic(pTo) ){ vdbeClrCopy(pTo,pFrom,srcType); return; }
memcpy(pTo, pFrom, MEMCELLSIZE); memcpy(pTo, pFrom, MEMCELLSIZE);
if( (pFrom->flags&MEM_Static)==0 ){ if( (pFrom->flags&MEM_Static)==0 ){
pTo->flags &= ~(MEM_Dyn|MEM_Static|MEM_Ephem); 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 ** 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. ** 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( int sqlite3VdbeMemFromBtree(
BtCursor *pCur, /* Cursor pointing at record to retrieve. */ BtCursor *pCur, /* Cursor pointing at record to retrieve. */
u32 offset, /* Offset from the start of data to return bytes from. */ 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->flags = MEM_Blob|MEM_Ephem;
pMem->n = (int)amt; pMem->n = (int)amt;
}else{ }else{
pMem->flags = MEM_Null; rc = vdbeMemFromBtreeResize(pCur, offset, amt, key, pMem);
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; return rc;

File diff suppressed because it is too large Load Diff

View File

@@ -19,7 +19,7 @@
** Trace output macros ** Trace output macros
*/ */
#if defined(SQLITE_TEST) || defined(SQLITE_DEBUG) #if defined(SQLITE_TEST) || defined(SQLITE_DEBUG)
/***/ int sqlite3WhereTrace = 0; /***/ int sqlite3WhereTrace;
#endif #endif
#if defined(SQLITE_DEBUG) \ #if defined(SQLITE_DEBUG) \
&& (defined(SQLITE_TEST) || defined(SQLITE_ENABLE_WHERETRACE)) && (defined(SQLITE_TEST) || defined(SQLITE_ENABLE_WHERETRACE))
@@ -161,10 +161,6 @@ struct WhereOrSet {
WhereOrCost a[N_OR_COST]; /* Set of best costs */ 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 ** Each instance of this object holds a sequence of WhereLoop objects
** that implement some or all of a query plan. ** that implement some or all of a query plan.
@@ -372,6 +368,11 @@ struct WhereMaskSet {
int ix[BMS]; /* Cursor assigned to each bit */ 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 ** This object is a convenience wrapper holding all information needed
** to construct WhereLoop objects for a particular query. ** to construct WhereLoop objects for a particular query.
@@ -423,6 +424,62 @@ struct WhereInfo {
WhereLevel a[1]; /* Information about each nest loop in WHERE */ 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 ** Bitmasks for the operators on WhereTerm objects. These are all
** operators that are of interest to the query planner. An ** operators that are of interest to the query planner. An

1501
src/wherecode.c Normal file

File diff suppressed because it is too large Load Diff

1249
src/whereexpr.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -24,6 +24,11 @@ if {$tcl_platform(platform)=="windows"} {
} else { } else {
set PROG "./sqlite3_analyzer" set PROG "./sqlite3_analyzer"
} }
if {![file exe $PROG]} {
puts "analyzer1 cannot run because $PROG is not available"
finish_test
return
}
db close db close
forcedelete test.db test.db-journal test.db-wal forcedelete test.db test.db-journal test.db-wal
sqlite3 db test.db sqlite3 db test.db

View File

@@ -204,7 +204,7 @@ do_execsql_test 6.0 {
} {} } {}
do_test 6.1 { do_test 6.1 {
db close db close
hexio_write test.db 616 EAFFFFFF0202 hexio_write test.db 616 8FFFFFFF7F02
sqlite3 db test.db sqlite3 db test.db
breakpoint breakpoint
execsql { DELETE FROM t1 WHERE rowid=2 } execsql { DELETE FROM t1 WHERE rowid=2 }

View File

@@ -171,7 +171,6 @@ foreach {tn code} {
# #
set ::busy_callback_count 0 set ::busy_callback_count 0
proc busy_callback {args} { proc busy_callback {args} {
puts Hello
incr ::busy_callback_count incr ::busy_callback_count
return 0 return 0
} }

16
test/extraquick.test Normal file
View 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

View File

@@ -39,7 +39,6 @@ do_test filectrl-1.5 {
do_test filectrl-1.6 { do_test filectrl-1.6 {
sqlite3 db test.db sqlite3 db test.db
set fn [file_control_tempfilename db] set fn [file_control_tempfilename db]
puts -nonewline \[$fn\]
set fn set fn
} {/etilqs_/} } {/etilqs_/}
db close db close

View File

@@ -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 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}] {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_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.1 a {[1 0[2]] [2 0[2]] [3 0[2]]}
check_doclist_all fts3d-4.1.2 four {} check_doclist_all fts3d-4.1.2 four {}

View File

@@ -47,7 +47,9 @@ foreach {tn q res} {
do_execsql_test 2.$tn.$s $q $res do_execsql_test 2.$tn.$s $q $res
set t($s) [lindex [time [list execsql $q] 100] 0] 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 { do_test 2.1 {

View File

@@ -362,11 +362,17 @@ ifcapable icu { lappend tokenizers icu }
# Some tests to check that the tokenizers can both identify white-space # Some tests to check that the tokenizers can both identify white-space
# codepoints. All codepoints tested below are of type "Zs" in the # codepoints. All codepoints tested below are of type "Zs" in the
# UnicodeData.txt file. # 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 { foreach T $tokenizers {
do_isspace_test 6.$T.1 $T 32 do_isspace_test 6.$T.1 $T 32
do_isspace_test 6.$T.2 $T 160 do_isspace_test 6.$T.2 $T 160
do_isspace_test 6.$T.3 $T 5760 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.5 $T 8192
do_isspace_test 6.$T.6 $T 8193 do_isspace_test 6.$T.6 $T 8193
do_isspace_test 6.$T.7 $T 8194 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.17 $T 8287
do_isspace_test 6.$T.18 $T 12288 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.20 $T {8192 8193 8194 8195}
do_isspace_test 6.$T.21 $T {8196 8197 8198 8199} do_isspace_test 6.$T.21 $T {8196 8197 8198 8199}
do_isspace_test 6.$T.22 $T {8200 8201 8202 8239} do_isspace_test 6.$T.22 $T {8200 8201 8202 8239}

View File

@@ -10,8 +10,8 @@
** **
************************************************************************* *************************************************************************
** **
** This is a utility program designed to aid running regressions tests ** This is a utility program designed to aid running regressions tests on
** on SQLite library using data from an external fuzzer, such as American ** the SQLite library using data from an external fuzzer, such as American
** Fuzzy Lop (AFL) (http://lcamtuf.coredump.cx/afl/). ** Fuzzy Lop (AFL) (http://lcamtuf.coredump.cx/afl/).
** **
** This program reads content from an SQLite database file with the following ** This program reads content from an SQLite database file with the following
@@ -25,16 +25,44 @@
** sqlid INTEGER PRIMARY KEY, -- SQL script id ** sqlid INTEGER PRIMARY KEY, -- SQL script id
** sqltext TEXT -- Text of SQL statements to run ** 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 ** 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, ** is run against that database. All README.MSG values are printed prior
** assertion faults, and/or memory leaks. No attempt is made to verify ** to the start of the test (unless the --quiet option is used). If the
** the output. The assumption is that either all of the database files ** DB table is empty, then all entries in XSQL are run against an empty
** or all of the SQL statements are malformed inputs, generated by a fuzzer, ** in-memory database.
** that need to be checked to make sure they do not present a security risk. **
** 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 ** 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 <stdio.h>
#include <stdlib.h> #include <stdlib.h>

Binary file not shown.

Binary file not shown.

View File

@@ -450,28 +450,42 @@ do_test in-12.10 {
SELECT a FROM t3 UNION ALL SELECT a, b FROM t2 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 { do_test in-12.11 {
catchsql { catchsql {
SELECT * FROM t2 WHERE a IN ( SELECT * FROM t2 WHERE a IN (
SELECT a FROM t3 UNION SELECT a, b FROM t2 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 { do_test in-12.12 {
catchsql { catchsql {
SELECT * FROM t2 WHERE a IN ( SELECT * FROM t2 WHERE a IN (
SELECT a FROM t3 EXCEPT SELECT a, b FROM t2 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 { do_test in-12.13 {
catchsql { catchsql {
SELECT * FROM t2 WHERE a IN ( SELECT * FROM t2 WHERE a IN (
SELECT a FROM t3 INTERSECT SELECT a, b FROM t2 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}} } {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 }; #ifcapable compound

View File

@@ -67,8 +67,10 @@ do_test 1.3 {
} }
set iPrev $iNext set iPrev $iNext
} }
puts -nonewline \ if {0} {
" (forward=$nForward, back=$nBackward, noncontiguous=$nNoncont)" puts -nonewline \
" (forward=$nForward, back=$nBackward, noncontiguous=$nNoncont)"
}
expr {$nForward > 2*($nBackward + $nNoncont)} expr {$nForward > 2*($nBackward + $nNoncont)}
} {1} } {1}

View File

@@ -327,4 +327,23 @@ do_execsql_test index6-8.2 {
3 three value 3 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 finish_test

View File

@@ -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 finish_test

View File

@@ -96,7 +96,7 @@ if {$::tcl_platform(platform)!="unix"} {
set alltests [test_set $alltests -exclude { set alltests [test_set $alltests -exclude {
all.test async.test quick.test veryquick.test all.test async.test quick.test veryquick.test
memleak.test permutations.test soak.test fts3.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 { set allquicktests [test_set $alltests -exclude {
@@ -146,11 +146,22 @@ if {[info exists ::env(TEST_FAILURE)]} {
lappend ::testsuitelist xxx lappend ::testsuitelist xxx
test_suite "veryquick" -prefix "" -description { 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 This test suite is the same as the "quick" tests, except that some files
that test malloc and IO errors are omitted. that test malloc and IO errors are omitted.
} -files [ } -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 { test_suite "mmap" -prefix "mm-" -description {

View File

@@ -164,7 +164,6 @@ do_test progress-1.7 {
} }
set ::res [list] set ::res [list]
explain {SELECT a, b, c FROM abc}
db eval {SELECT a, b, c FROM abc} { db eval {SELECT a, b, c FROM abc} {
lappend ::res $a $b $c lappend ::res $a $b $c
db progress 5 "expr 1" db progress 5 "expr 1"

View File

@@ -547,7 +547,10 @@ proc process_options {argv} {
puts " --srcdir $::SRCDIR" puts " --srcdir $::SRCDIR"
puts " --platform [list $platform]" puts " --platform [list $platform]"
puts " --config [list $config]" 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 {$::MSVC} {puts " --msvc"}
if {$::BUILDONLY} {puts " --buildonly"} if {$::BUILDONLY} {puts " --buildonly"}
if {$::DRYRUN} {puts " --dryrun"} if {$::DRYRUN} {puts " --dryrun"}
@@ -645,7 +648,7 @@ proc main {argv} {
} }
if {$target ne "checksymbols"} { if {$target ne "checksymbols"} {
switch -- $::QUICK { switch -- $::QUICK {
1 {set target test} 1 {set target quicktest}
2 {set target smoketest} 2 {set target smoketest}
} }
if {$::BUILDONLY} { if {$::BUILDONLY} {

View File

@@ -15,6 +15,7 @@
set testdir [file dirname $argv0] set testdir [file dirname $argv0]
source $testdir/tester.tcl source $testdir/tester.tcl
set testprefix select7
ifcapable compound { ifcapable compound {
@@ -201,4 +202,23 @@ do_test select7-7.7 {
} }
} {text 123} } {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 finish_test

View File

@@ -32,7 +32,6 @@ set result [execsql {
FROM songs FROM songs
GROUP BY LOWER(artist) GROUP BY LOWER(artist)
}] }]
puts result=$result
do_test select8-1.1 { do_test select8-1.1 {
execsql { execsql {
SELECT DISTINCT artist,sum(timesplayed) AS total SELECT DISTINCT artist,sum(timesplayed) AS total

View File

@@ -16,7 +16,6 @@
set testdir [file dirname $argv0] set testdir [file dirname $argv0]
source $testdir/tester.tcl source $testdir/tester.tcl
db close db close
puts hello
# This script is only valid if we are running shared-cache mode in a # This script is only valid if we are running shared-cache mode in a
# threadsafe-capable database engine. # threadsafe-capable database engine.

View File

@@ -43,6 +43,9 @@ static const char zHelp[] =
#include <string.h> #include <string.h>
#include <ctype.h> #include <ctype.h>
#if SQLITE_VERSION_NUMBER<3005000
# define sqlite3_int64 sqlite_int64
#endif
#ifdef SQLITE_ENABLE_OTA #ifdef SQLITE_ENABLE_OTA
# include "sqlite3ota.h" # include "sqlite3ota.h"
#endif #endif
@@ -143,6 +146,9 @@ static int integerValue(const char *zArg){
/* Return the current wall-clock time, in milliseconds */ /* Return the current wall-clock time, in milliseconds */
sqlite3_int64 speedtest1_timestamp(void){ sqlite3_int64 speedtest1_timestamp(void){
#if SQLITE_VERSION_NUMBER<3005000
return 0;
#else
static sqlite3_vfs *clockVfs = 0; static sqlite3_vfs *clockVfs = 0;
sqlite3_int64 t; sqlite3_int64 t;
if( clockVfs==0 ) clockVfs = sqlite3_vfs_find(0); if( clockVfs==0 ) clockVfs = sqlite3_vfs_find(0);
@@ -157,6 +163,7 @@ sqlite3_int64 speedtest1_timestamp(void){
t = (sqlite3_int64)(r*86400000.0); t = (sqlite3_int64)(r*86400000.0);
} }
return t; return t;
#endif
} }
/* Return a pseudo-random unsigned integer */ /* Return a pseudo-random unsigned integer */
@@ -306,7 +313,7 @@ static void printSql(const char *zSql){
if( g.bExplain ) printf("EXPLAIN "); if( g.bExplain ) printf("EXPLAIN ");
printf("%.*s;\n", n, zSql); printf("%.*s;\n", n, zSql);
if( g.bExplain if( g.bExplain
#if SQLITE_VERSION_NUMBER>=3007010 #if SQLITE_VERSION_NUMBER>=3007017
&& ( sqlite3_strglob("CREATE *", zSql)==0 && ( sqlite3_strglob("CREATE *", zSql)==0
|| sqlite3_strglob("DROP *", zSql)==0 || sqlite3_strglob("DROP *", zSql)==0
|| sqlite3_strglob("ALTER *", zSql)==0 || sqlite3_strglob("ALTER *", zSql)==0
@@ -374,12 +381,15 @@ void speedtest1_run(void){
} }
} }
} }
#if SQLITE_VERSION_NUMBER>=3006001
if( g.bReprepare ){ if( g.bReprepare ){
sqlite3_stmt *pNew; sqlite3_stmt *pNew;
sqlite3_prepare_v2(g.db, sqlite3_sql(g.pStmt), -1, &pNew, 0); sqlite3_prepare_v2(g.db, sqlite3_sql(g.pStmt), -1, &pNew, 0);
sqlite3_finalize(g.pStmt); sqlite3_finalize(g.pStmt);
g.pStmt = pNew; g.pStmt = pNew;
}else{ }else
#endif
{
sqlite3_reset(g.pStmt); sqlite3_reset(g.pStmt);
} }
} }
@@ -1273,6 +1283,7 @@ int main(int argc, char **argv){
fatal_error(zHelp, argv[0]); fatal_error(zHelp, argv[0]);
} }
#endif #endif
#if SQLITE_VERSION_NUMBER>=3006001
if( nHeap>0 ){ if( nHeap>0 ){
pHeap = malloc( nHeap ); pHeap = malloc( nHeap );
if( pHeap==0 ) fatal_error("cannot allocate %d-byte heap\n", 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 ){ if( nLook>0 ){
sqlite3_config(SQLITE_CONFIG_LOOKASIDE, 0, 0); sqlite3_config(SQLITE_CONFIG_LOOKASIDE, 0, 0);
} }
#endif
/* Open the database and the input file */ /* Open the database and the input file */
if( sqlite3_open(zDbName, &g.db) ){ if( sqlite3_open(zDbName, &g.db) ){
fatal_error("Cannot open database file: %s\n", zDbName); fatal_error("Cannot open database file: %s\n", zDbName);
} }
#if SQLITE_VERSION_NUMBER>=3006001
if( nLook>0 && szLook>0 ){ if( nLook>0 && szLook>0 ){
pLook = malloc( nLook*szLook ); pLook = malloc( nLook*szLook );
rc = sqlite3_db_config(g.db, SQLITE_DBCONFIG_LOOKASIDE, pLook, szLook,nLook); rc = sqlite3_db_config(g.db, SQLITE_DBCONFIG_LOOKASIDE, pLook, szLook,nLook);
if( rc ) fatal_error("lookaside configuration failed: %d\n", rc); if( rc ) fatal_error("lookaside configuration failed: %d\n", rc);
} }
#endif
/* Set database connection options */ /* Set database connection options */
sqlite3_create_function(g.db, "random", 0, SQLITE_UTF8, 0, randomFunc, 0, 0); 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); sqlite3_close(g.db);
#if SQLITE_VERSION_NUMBER>=3006001
/* Global memory usage statistics printed after the database connection /* Global memory usage statistics printed after the database connection
** has closed. Memory usage should be zero at this point. */ ** has closed. Memory usage should be zero at this point. */
if( showStats ){ if( showStats ){
@@ -1407,6 +1422,7 @@ int main(int argc, char **argv){
sqlite3_status(SQLITE_STATUS_SCRATCH_SIZE, &iCur, &iHi, 0); sqlite3_status(SQLITE_STATUS_SCRATCH_SIZE, &iCur, &iHi, 0);
printf("-- Largest Scratch Allocation: %d bytes\n", iHi); printf("-- Largest Scratch Allocation: %d bytes\n", iHi);
} }
#endif
/* Release memory */ /* Release memory */
free( pLook ); free( pLook );

View File

@@ -19,6 +19,11 @@ if {$tcl_platform(platform)=="windows"} {
} else { } else {
set PROG "./sqldiff" set PROG "./sqldiff"
} }
if {![file exe $PROG]} {
puts "sqldiff cannot run because $PROG is not available"
finish_test
return
}
db close db close
forcedelete test.db test2.db forcedelete test.db test2.db
sqlite3 db test.db sqlite3 db test.db

View File

@@ -808,4 +808,20 @@ do_execsql_test table-17.1 {
SELECT p, q, '|' FROM t3 ORDER BY p; SELECT p, q, '|' FROM t3 ORDER BY p;
} {1 1 | 2 2 |} } {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 finish_test

View File

@@ -81,6 +81,12 @@
# permutation # permutation
# presql # 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 # Set the precision of FP arithmatic used by the interpreter. And
# configure SQLite to take database file locks on the page that begins # 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 # --file-retry-delay=N
# --start=[$permutation:]$testfile # --start=[$permutation:]$testfile
# --match=$pattern # --match=$pattern
# --verbose=$val
# --output=$filename
# --help
# #
set cmdlinearg(soft-heap-limit) 0 set cmdlinearg(soft-heap-limit) 0
set cmdlinearg(maxerror) 1000 set cmdlinearg(maxerror) 1000
@@ -399,6 +408,8 @@ if {[info exists cmdlinearg]==0} {
set cmdlinearg(file-retry-delay) 0 set cmdlinearg(file-retry-delay) 0
set cmdlinearg(start) "" set cmdlinearg(start) ""
set cmdlinearg(match) "" set cmdlinearg(match) ""
set cmdlinearg(verbose) ""
set cmdlinearg(output) ""
set leftover [list] set leftover [list]
foreach a $argv { foreach a $argv {
@@ -457,6 +468,22 @@ if {[info exists cmdlinearg]==0} {
set ::G(match) $cmdlinearg(match) set ::G(match) $cmdlinearg(match)
if {$::G(match) == ""} {unset ::G(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 { default {
lappend leftover $a lappend leftover $a
} }
@@ -484,6 +511,16 @@ if {[info exists cmdlinearg]==0} {
if {$cmdlinearg(malloctrace)} { if {$cmdlinearg(malloctrace)} {
sqlite3_memdebug_backtrace $cmdlinearg(backtrace) 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 # 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] set nFail [set_test_counter errors]
if {$nFail>=$::cmdlinearg(maxerror)} { if {$nFail>=$::cmdlinearg(maxerror)} {
puts "*** Giving up..." output2 "*** Giving up..."
finalize_testing finalize_testing
} }
} }
@@ -562,7 +599,7 @@ proc fail_test {name} {
# Remember a warning message to be displayed at the conclusion of all testing # Remember a warning message to be displayed at the conclusion of all testing
# #
proc warning {msg {append 1}} { proc warning {msg {append 1}} {
puts "Warning: $msg" output2 "Warning: $msg"
set warnList [set_test_counter warn_list] set warnList [set_test_counter warn_list]
if {$append} { if {$append} {
lappend warnList $msg lappend warnList $msg
@@ -577,6 +614,61 @@ proc incr_ntest {} {
set_test_counter count [expr [set_test_counter count] + 1] 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 # Invoke the do_test procedure to run a single test
# #
@@ -604,12 +696,13 @@ proc do_test {name cmd expected} {
} }
incr_ntest incr_ntest
puts -nonewline $name... output1 -nonewline $name...
flush stdout flush stdout
if {![info exists ::G(match)] || [string match $::G(match) $name]} { if {![info exists ::G(match)] || [string match $::G(match) $name]} {
if {[catch {uplevel #0 "$cmd;\n"} result]} { if {[catch {uplevel #0 "$cmd;\n"} result]} {
puts "\nError: $result" output2_if_no_verbose -nonewline $name...
output2 "\nError: $result"
fail_test $name fail_test $name
} else { } else {
if {[regexp {^~?/.*/$} $expected]} { if {[regexp {^~?/.*/$} $expected]} {
@@ -653,14 +746,15 @@ proc do_test {name cmd expected} {
# if {![info exists ::testprefix] || $::testprefix eq ""} { # if {![info exists ::testprefix] || $::testprefix eq ""} {
# error "no test prefix" # 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 fail_test $name
} else { } else {
puts " Ok" output1 " Ok"
} }
} }
} else { } else {
puts " Omitted" output1 " Omitted"
omit_test $name "pattern mismatch" 0 omit_test $name "pattern mismatch" 0
} }
flush stdout flush stdout
@@ -837,7 +931,7 @@ proc delete_all_data {} {
# Return the number of microseconds per statement. # Return the number of microseconds per statement.
# #
proc speed_trial {name numstmt units sql} { proc speed_trial {name numstmt units sql} {
puts -nonewline [format {%-21.21s } $name...] output2 -nonewline [format {%-21.21s } $name...]
flush stdout flush stdout
set speed [time {sqlite3_exec_nr db $sql}] set speed [time {sqlite3_exec_nr db $sql}]
set tm [lindex $speed 0] 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 rate [format %20.5f [expr {1000000.0*$numstmt/$tm}]]
} }
set u2 $units/s 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 global total_time
set total_time [expr {$total_time+$tm}] set total_time [expr {$total_time+$tm}]
lappend ::speed_trial_times $name $tm lappend ::speed_trial_times $name $tm
} }
proc speed_trial_tcl {name numstmt units script} { proc speed_trial_tcl {name numstmt units script} {
puts -nonewline [format {%-21.21s } $name...] output2 -nonewline [format {%-21.21s } $name...]
flush stdout flush stdout
set speed [time {eval $script}] set speed [time {eval $script}]
set tm [lindex $speed 0] 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 rate [format %20.5f [expr {1000000.0*$numstmt/$tm}]]
} }
set u2 $units/s 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 global total_time
set total_time [expr {$total_time+$tm}] set total_time [expr {$total_time+$tm}]
lappend ::speed_trial_times $name $tm lappend ::speed_trial_times $name $tm
@@ -875,19 +969,19 @@ proc speed_trial_init {name} {
sqlite3 versdb :memory: sqlite3 versdb :memory:
set vers [versdb one {SELECT sqlite_source_id()}] set vers [versdb one {SELECT sqlite_source_id()}]
versdb close versdb close
puts "SQLite $vers" output2 "SQLite $vers"
} }
proc speed_trial_summary {name} { proc speed_trial_summary {name} {
global total_time 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 } { if { 0 } {
sqlite3 versdb :memory: sqlite3 versdb :memory:
set vers [lindex [versdb one {SELECT sqlite_source_id()}] 0] set vers [lindex [versdb one {SELECT sqlite_source_id()}] 0]
versdb close 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 { 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} { 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" out of $nTest tests"
} else { } else {
puts "$nErr errors out of $nTest tests" output2 "$nErr errors out of $nTest tests"
} }
if {$nErr>$nKnown} { if {$nErr>$nKnown} {
puts -nonewline "Failures on these tests:" output2 -nonewline "Failures on these tests:"
foreach x [set_test_counter fail_list] { 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] { foreach warning [set_test_counter warn_list] {
puts "Warning: $warning" output2 "Warning: $warning"
} }
run_thread_tests 1 run_thread_tests 1
if {[llength $omitList]>0} { if {[llength $omitList]>0} {
puts "Omitted test cases:" output2 "Omitted test cases:"
set prec {} set prec {}
foreach {rec} [lsort $omitList] { foreach {rec} [lsort $omitList] {
if {$rec==$prec} continue if {$rec==$prec} continue
set prec $rec 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]} { if {$nErr>0 && ![working_64bit_int]} {
puts "******************************************************************" output2 "******************************************************************"
puts "N.B.: The version of TCL that you used to build this test harness" output2 "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" output2 "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" output2 "all of the test failures above might be a result from this defect"
puts "in your TCL build." output2 "in your TCL build."
puts "******************************************************************" output2 "******************************************************************"
} }
if {$::cmdlinearg(binarylog)} { if {$::cmdlinearg(binarylog)} {
vfslog finalize binarylog vfslog finalize binarylog
} }
if {$sqlite_open_file_count} { 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 incr nErr
} }
if {[lindex [sqlite3_status SQLITE_STATUS_MALLOC_COUNT 0] 1]>0 || if {[lindex [sqlite3_status SQLITE_STATUS_MALLOC_COUNT 0] 1]>0 ||
[sqlite3_memory_used]>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" [lindex [sqlite3_status SQLITE_STATUS_MALLOC_COUNT 0] 1] allocations"
incr nErr incr nErr
ifcapable memdebug||mem5||(mem3&&debug) { 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 sqlite3_memdebug_dump ./memleak.txt
} }
} else { } else {
puts "All memory allocations freed - no leaks" output2 "All memory allocations freed - no leaks"
ifcapable memdebug||mem5 { ifcapable memdebug||mem5 {
sqlite3_memdebug_dump ./memusage.txt sqlite3_memdebug_dump ./memusage.txt
} }
} }
show_memstats show_memstats
puts "Maximum memory usage: [sqlite3_memory_highwater 1] bytes" output2 "Maximum memory usage: [sqlite3_memory_highwater 1] bytes"
puts "Current memory usage: [sqlite3_memory_highwater] bytes" output2 "Current memory usage: [sqlite3_memory_highwater] bytes"
if {[info commands sqlite3_memdebug_malloc_count] ne ""} { 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)} { if {$::cmdlinearg(malloctrace)} {
puts "Writing mallocs.sql..." output2 "Writing mallocs.sql..."
memdebug_log_sql memdebug_log_sql
sqlite3_memdebug_log stop sqlite3_memdebug_log stop
sqlite3_memdebug_log clear sqlite3_memdebug_log clear
if {[sqlite3_memory_used]>0} { if {[sqlite3_memory_used]>0} {
puts "Writing leaks.sql..." output2 "Writing leaks.sql..."
sqlite3_memdebug_log sync sqlite3_memdebug_log sync
memdebug_log_sql leaks.sql memdebug_log_sql leaks.sql
} }
@@ -1020,30 +1114,30 @@ proc show_memstats {} {
set y [sqlite3_status SQLITE_STATUS_MALLOC_SIZE 0] set y [sqlite3_status SQLITE_STATUS_MALLOC_SIZE 0]
set val [format {now %10d max %10d max-size %10d} \ set val [format {now %10d max %10d max-size %10d} \
[lindex $x 1] [lindex $x 2] [lindex $y 2]] [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 x [sqlite3_status SQLITE_STATUS_MALLOC_COUNT 0]
set val [format {now %10d max %10d} [lindex $x 1] [lindex $x 2]] 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 x [sqlite3_status SQLITE_STATUS_PAGECACHE_USED 0]
set y [sqlite3_status SQLITE_STATUS_PAGECACHE_SIZE 0] set y [sqlite3_status SQLITE_STATUS_PAGECACHE_SIZE 0]
set val [format {now %10d max %10d max-size %10d} \ set val [format {now %10d max %10d max-size %10d} \
[lindex $x 1] [lindex $x 2] [lindex $y 2]] [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 x [sqlite3_status SQLITE_STATUS_PAGECACHE_OVERFLOW 0]
set val [format {now %10d max %10d} [lindex $x 1] [lindex $x 2]] 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 x [sqlite3_status SQLITE_STATUS_SCRATCH_USED 0]
set val [format {now %10d max %10d} [lindex $x 1] [lindex $x 2]] 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 x [sqlite3_status SQLITE_STATUS_SCRATCH_OVERFLOW 0]
set y [sqlite3_status SQLITE_STATUS_SCRATCH_SIZE 0] set y [sqlite3_status SQLITE_STATUS_SCRATCH_SIZE 0]
set val [format {now %10d max %10d max-size %10d} \ set val [format {now %10d max %10d max-size %10d} \
[lindex $x 1] [lindex $x 2] [lindex $y 2]] [lindex $x 1] [lindex $x 2] [lindex $y 2]]
puts "Scratch overflow: $val" output1 "Scratch overflow: $val"
ifcapable yytrackmaxstackdepth { ifcapable yytrackmaxstackdepth {
set x [sqlite3_status SQLITE_STATUS_PARSER_STACK 0] set x [sqlite3_status SQLITE_STATUS_PARSER_STACK 0]
set val [format { max %10d} [lindex $x 2]] 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]] set x [uplevel [list $db eval $sql]]
} 1] } 1]
set tm [lindex $tm 0] set tm [lindex $tm 0]
puts -nonewline " ([expr {$tm*0.001}]ms) " output1 -nonewline " ([expr {$tm*0.001}]ms) "
set x set x
} }
@@ -1074,20 +1168,20 @@ proc catchsql {sql {db db}} {
# Do an VDBE code dump on the SQL given # Do an VDBE code dump on the SQL given
# #
proc explain {sql {db db}} { proc explain {sql {db db}} {
puts "" output2 ""
puts "addr opcode p1 p2 p3 p4 p5 #" output2 "addr opcode p1 p2 p3 p4 p5 #"
puts "---- ------------ ------ ------ ------ --------------- -- -" output2 "---- ------------ ------ ------ ------ --------------- -- -"
$db eval "explain $sql" {} { $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 $addr $opcode $p1 $p2 $p3 $p4 $p5 $comment
] ]
} }
} }
proc explain_i {sql {db db}} { proc explain_i {sql {db db}} {
puts "" output2 ""
puts "addr opcode p1 p2 p3 p4 p5 #" output2 "addr opcode p1 p2 p3 p4 p5 #"
puts "---- ------------ ------ ------ ------ ---------------- -- -" output2 "---- ------------ ------ ------ ------ ---------------- -- -"
# Set up colors for the different opcodes. Scheme is as follows: # 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" {} { $db eval "explain $sql" {} {
if {[info exists linebreak($addr)]} { if {[info exists linebreak($addr)]} {
puts "" output2 ""
} }
set I [string repeat " " $x($addr)] set I [string repeat " " $x($addr)]
set col "" set col ""
catch { set col $color($opcode) } 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 $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 # 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 nowcksum [cksum]
set res [expr {$nowcksum==$::checksum || $nowcksum==$::goodcksum}] set res [expr {$nowcksum==$::checksum || $nowcksum==$::goodcksum}]
if {$res==0} { if {$res==0} {
puts "now=$nowcksum" output2 "now=$nowcksum"
puts "the=$::checksum" output2 "the=$::checksum"
puts "fwd=$::goodcksum" output2 "fwd=$::goodcksum"
} }
set res set res
} 1 } 1
@@ -1821,6 +1915,12 @@ proc slave_test_script {script} {
interp eval tinterp [list set $var $value] 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. # The alias used to access the global test counters.
tinterp alias set_test_counter set_test_counter tinterp alias set_test_counter set_test_counter
@@ -1889,7 +1989,7 @@ proc slave_test_file {zFile} {
# Add some info to the output. # Add some info to the output.
# #
puts "Time: $tail $ms ms" output2 "Time: $tail $ms ms"
show_memstats show_memstats
} }

View File

@@ -56,9 +56,6 @@ ifcapable !vtab||!schema_pragmas {
# We cannot create a virtual table if the module has not been registered. # We cannot create a virtual table if the module has not been registered.
# #
do_test vtab1-1.1.1 { do_test vtab1-1.1.1 {
explain {
CREATE VIRTUAL TABLE t1 USING echo;
}
catchsql { catchsql {
CREATE VIRTUAL TABLE t1 USING echo; CREATE VIRTUAL TABLE t1 USING echo;
} }

View File

@@ -230,4 +230,41 @@ do_eqp_test 5.3.3 {
SELECT * FROM t1 WHERE likely(a=?) SELECT * FROM t1 WHERE likely(a=?)
} {0 0 0 {SCAN TABLE t1}} } {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 finish_test

View File

@@ -292,6 +292,7 @@ foreach file {
mutex_w32.c mutex_w32.c
malloc.c malloc.c
printf.c printf.c
treeview.c
random.c random.c
threads.c threads.c
utf.c utf.c
@@ -346,6 +347,8 @@ foreach file {
update.c update.c
vacuum.c vacuum.c
vtab.c vtab.c
wherecode.c
whereexpr.c
where.c where.c
parse.c parse.c

View File

@@ -9,6 +9,28 @@ echo '********** No optimizations. Includes FTS4 and RTREE *********'
gcc -c -Wshadow -Wall -Wextra -pedantic-errors -Wno-long-long -std=c89 \ gcc -c -Wshadow -Wall -Wextra -pedantic-errors -Wno-long-long -std=c89 \
-ansi -DHAVE_STDINT_H -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_RTREE \ -ansi -DHAVE_STDINT_H -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_RTREE \
sqlite3.c 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 *******' echo '********** No optimizations. ENABLE_STAT4. THREADSAFE=0 *******'
gcc -c -Wshadow -Wall -Wextra -pedantic-errors -Wno-long-long -std=c89 \ gcc -c -Wshadow -Wall -Wextra -pedantic-errors -Wno-long-long -std=c89 \
-ansi -DSQLITE_ENABLE_STAT4 -DSQLITE_THREADSAFE=0 \ -ansi -DSQLITE_ENABLE_STAT4 -DSQLITE_THREADSAFE=0 \