From 4d9565b80555347bc6d0a1eb431ef32114b9fbdb Mon Sep 17 00:00:00 2001
From: Stephen Lombardo
Date: Wed, 12 Dec 2018 19:43:10 -0500
Subject: [PATCH] Snapshot of upstream SQLite 3.26.0
---
Makefile.in | 81 +-
Makefile.msc | 15 +-
VERSION | 2 +-
configure | 18 +-
doc/lemon.html | 3 +
ext/expert/sqlite3expert.c | 1 +
ext/fts3/fts3.c | 30 +-
ext/fts3/fts3_aux.c | 3 +-
ext/fts3/fts3_term.c | 3 +-
ext/fts3/fts3_tokenize_vtab.c | 3 +-
ext/fts3/fts3_write.c | 23 +-
ext/fts5/fts5_index.c | 2 +-
ext/fts5/fts5_main.c | 18 +-
ext/fts5/fts5_test_tok.c | 3 +-
ext/fts5/fts5_vocab.c | 7 +-
ext/fts5/test/fts5aa.test | 1 +
ext/fts5/test/fts5connect.test | 1 -
ext/fts5/test/fts5corrupt.test | 4 +-
ext/fts5/test/fts5corrupt2.test | 2 +
ext/fts5/test/fts5corrupt3.test | 9 +
ext/fts5/test/fts5first.test | 1 -
ext/fts5/test/fts5integrity.test | 1 +
ext/fts5/test/fts5rank.test | 1 -
ext/fts5/test/fts5rebuild.test | 1 +
ext/fts5/test/fts5rowid.test | 1 +
ext/fts5/test/fts5version.test | 4 +-
ext/fts5/test/fts5vocab.test | 2 +-
ext/fts5/test/fts5vocab2.test | 3 +-
ext/misc/amatch.c | 3 +-
ext/misc/btreeinfo.c | 1 +
ext/misc/closure.c | 3 +-
ext/misc/completion.c | 3 +-
ext/misc/csv.c | 131 ++-
ext/misc/explain.c | 322 ++++++++
ext/misc/fileio.c | 88 +-
ext/misc/json1.c | 64 +-
ext/misc/memstat.c | 428 ++++++++++
ext/misc/series.c | 62 +-
ext/misc/sha1.c | 2 +-
ext/misc/shathree.c | 2 +-
ext/misc/spellfix.c | 12 +
ext/misc/stmt.c | 1 +
ext/misc/templatevtab.c | 3 +-
ext/misc/unionvtab.c | 3 +-
ext/misc/vtablog.c | 1 +
ext/misc/zipfile.c | 23 +-
ext/rbu/rbu1.test | 1 -
ext/rbu/rbu10.test | 1 -
ext/rbu/rbu11.test | 1 -
ext/rbu/rbu12.test | 1 -
ext/rbu/rbu13.test | 1 -
ext/rbu/rbu14.test | 1 -
ext/rbu/rbu3.test | 2 -
ext/rbu/rbu5.test | 4 -
ext/rbu/rbu6.test | 1 -
ext/rbu/rbu7.test | 2 -
ext/rbu/rbu8.test | 1 -
ext/rbu/rbu9.test | 1 -
ext/rbu/rbuA.test | 1 -
ext/rbu/rbuB.test | 1 -
ext/rbu/rbuC.test | 1 -
ext/rbu/rbucollate.test | 1 -
ext/rbu/rbucrash.test | 1 -
ext/rbu/rbucrash2.test | 1 -
ext/rbu/rbudiff.test | 1 -
ext/rbu/rbudor.test | 1 -
ext/rbu/rbufault.test | 1 -
ext/rbu/rbufault2.test | 1 -
ext/rbu/rbufault3.test | 1 -
ext/rbu/rbufault4.test | 1 -
ext/rbu/rbufts.test | 1 -
ext/rbu/rbumulti.test | 1 -
ext/rbu/rbuprogress.test | 1 -
ext/rbu/rburesume.test | 1 -
ext/rbu/rbusave.test | 1 -
ext/rbu/rbusplit.test | 1 -
ext/rbu/rbutemplimit.test | 1 -
ext/rbu/rbuvacuum.test | 1 -
ext/rbu/rbuvacuum2.test | 1 -
ext/rbu/sqlite3rbu.c | 100 ++-
ext/repair/test/checkindex01.test | 2 -
ext/rtree/geopoly.c | 204 ++++-
ext/rtree/rtree.c | 19 +-
ext/rtree/rtree8.test | 2 +
ext/rtree/rtreeA.test | 3 +-
ext/rtree/rtreecheck.test | 4 +-
ext/rtree/sqlite3rtree.h | 2 +-
ext/rtree/visual01.txt | 13 +
ext/session/changesetfuzz.c | 1240 +++++++++++++++++++++++++++++
ext/session/changesetfuzz1.test | 84 ++
ext/session/session1.test | 7 +
ext/session/sessionC.test | 1 -
ext/session/sessionD.test | 1 -
ext/session/sessionE.test | 2 -
ext/session/sessionF.test | 1 -
ext/session/sessionG.test | 1 -
ext/session/sessionH.test | 1 -
ext/session/session_common.tcl | 17 +
ext/session/sessionfault2.test | 1 -
ext/session/sessioninvert.test | 159 ++++
ext/session/sessionrebase.test | 1 -
ext/session/sessionstat1.test | 1 -
ext/session/sessionwor.test | 1 -
ext/session/sqlite3session.c | 201 +++--
ext/session/sqlite3session.h | 79 +-
ext/session/test_session.c | 117 ++-
main.mk | 43 +-
manifest | 564 ++++++-------
manifest.uuid | 2 +-
src/alter.c | 44 +-
src/attach.c | 2 +-
src/auth.c | 2 +
src/btree.c | 13 +-
src/build.c | 89 ++-
src/callback.c | 19 +-
src/ctime.c | 6 +
src/dbpage.c | 10 +-
src/dbstat.c | 45 +-
src/delete.c | 51 +-
src/expr.c | 101 +--
src/fkey.c | 2 +-
src/global.c | 1 +
src/hash.c | 56 ++
src/insert.c | 37 +-
src/loadext.c | 9 +-
src/main.c | 21 +-
src/os_unix.c | 125 +--
src/os_win.c | 30 +-
src/pager.c | 35 +-
src/pager.h | 9 +-
src/parse.y | 5 +-
src/pcache.c | 11 +-
src/pcache.h | 4 +
src/pcache1.c | 3 +-
src/pragma.c | 66 +-
src/pragma.h | 157 ++--
src/prepare.c | 292 ++++++-
src/resolve.c | 64 +-
src/select.c | 46 +-
src/shell.c.in | 423 ++++++----
src/sqlite.h.in | 55 +-
src/sqlite3ext.h | 5 +
src/sqliteInt.h | 68 +-
src/test1.c | 120 ++-
src/test_config.c | 8 +-
src/test_intarray.c | 5 +-
src/test_intarray.h | 9 +-
src/test_onefile.c | 1 +
src/tokenize.c | 67 ++
src/treeview.c | 70 +-
src/update.c | 62 +-
src/vacuum.c | 3 +-
src/vdbe.c | 32 +-
src/vdbeInt.h | 7 +
src/vdbeapi.c | 10 +
src/vdbeaux.c | 19 +-
src/vdbemem.c | 3 +-
src/vtab.c | 7 +-
src/walker.c | 4 +-
src/where.c | 57 +-
src/whereInt.h | 21 +
src/wherecode.c | 4 +-
src/whereexpr.c | 21 +-
src/window.c | 12 +-
test/alter.test | 9 +
test/alter2.test | 2 +
test/alterauth2.test | 98 +++
test/altercol.test | 11 +
test/alterlegacy.test | 1 -
test/altermalloc.test | 2 +-
test/altertab.test | 46 +-
test/altertab2.test | 45 +-
test/analyze.test | 1 +
test/attach.test | 26 +
test/attachmalloc.test | 2 +-
test/autoinc.test | 7 +
test/autoindex5.test | 85 ++
test/bestindex4.test | 55 ++
test/bestindex5.test | 1 -
test/capi3.test | 4 +-
test/capi3c.test | 4 +-
test/corrupt.test | 1 +
test/corrupt2.test | 2 +
test/corrupt5.test | 1 +
test/corruptI.test | 1 +
test/corruptK.test | 2 +-
test/countofview.test | 1 -
test/crash5.test | 2 +-
test/csv01.test | 61 +-
test/dbfuzz2-seed1.db | Bin 0 -> 3584 bytes
test/dbfuzz2.c | 138 ++++
test/dbpage.test | 1 +
test/dbstatus.test | 4 +-
test/default.test | 1 +
test/e_fkey.test | 2 +
test/e_fts3.test | 1 +
test/e_reindex.test | 2 +
test/fkey2.test | 6 +
test/fts3auto.test | 1 +
test/fts3corrupt.test | 1 +
test/fts3corrupt2.test | 1 +
test/fts3corrupt3.test | 1 +
test/fts3corrupt4.test | 148 ++++
test/fts3cov.test | 2 +
test/fts3d.test | 1 +
test/fts3defer.test | 4 +
test/fts3defer2.test | 3 +
test/fts3matchinfo.test | 3 +
test/fts3misc.test | 1 +
test/fts3query.test | 1 +
test/fts3snippet.test | 1 +
test/fts4check.test | 5 +
test/fts4growth.test | 1 +
test/fts4merge.test | 1 +
test/fts4opt.test | 1 +
test/fuzz_malloc.test | 5 -
test/fuzzcheck.c | 6 +-
test/fuzzdata7.db | Bin 0 -> 16369664 bytes
test/incrblob_err.test | 2 +-
test/incrvacuum.test | 50 ++
test/index.test | 6 +
test/index3.test | 1 +
test/indexexpr2.test | 72 ++
test/intarray.test | 7 +
test/lemon-test01.y | 75 ++
test/like3.test | 2 +
test/loadext.test | 6 +-
test/malloctraceviewer.tcl | 253 ++++++
test/misc1.test | 3 +
test/misc4.test | 1 +
test/misc5.test | 1 +
test/misc7.test | 1 +
test/mjournal.test | 1 -
test/normalize.test | 289 +++++++
test/notnull.test | 1 -
test/ossfuzz.c | 21 +-
test/pager1.test | 2 +
test/parser1.test | 1 +
test/permutations.test | 127 +--
test/pragma.test | 1 +
test/pragma3.test | 6 +-
test/pragma4.test | 142 ++++
test/printf.test | 36 +-
test/releasetest.tcl | 4 +
test/resetdb.test | 3 +
test/rowvalue.test | 11 +
test/shared.test | 62 +-
test/shared8.test | 1 +
test/shell1.test | 2 +-
test/snapshot2.test | 1 -
test/snapshot3.test | 1 -
test/snapshot4.test | 1 -
test/snapshot_up.test | 1 -
test/swarmvtab3.test | 1 -
test/swarmvtabfault.test | 1 -
test/tabfunc01.test | 13 +-
test/table.test | 1 +
test/tableapi.test | 26 +-
test/tempdb2.test | 21 +
test/tester.tcl | 32 +-
test/trigger7.test | 1 +
test/triggerA.test | 7 -
test/triggerE.test | 1 +
test/unionvtab.test | 1 -
test/unionvtabfault.test | 1 -
test/vtab1.test | 1 +
test/vtab_err.test | 28 +-
test/wal64k.test | 12 +
test/where.test | 13 +
test/whereL.test | 11 +
test/wherelimit2.test | 1 -
test/window1.test | 45 ++
test/window5.test | 1 -
test/window6.test | 31 +-
test/windowfault.test | 1 -
test/with1.test | 21 +
test/without_rowid3.test | 6 +
test/zipfile.test | 34 +
test/zipfile2.test | 1 -
tool/genfkey.test | 1 -
tool/lempar.c | 4 +-
tool/mkpragmatab.tcl | 65 +-
tool/sqldiff.c | 30 +-
tool/warnings.sh | 8 +-
284 files changed, 7619 insertions(+), 1561 deletions(-)
create mode 100644 ext/misc/explain.c
create mode 100644 ext/misc/memstat.c
create mode 100644 ext/session/changesetfuzz.c
create mode 100644 ext/session/changesetfuzz1.test
create mode 100644 ext/session/sessioninvert.test
create mode 100644 test/alterauth2.test
create mode 100644 test/dbfuzz2-seed1.db
create mode 100644 test/dbfuzz2.c
create mode 100644 test/fts3corrupt4.test
create mode 100644 test/fuzzdata7.db
create mode 100644 test/lemon-test01.y
create mode 100644 test/malloctraceviewer.tcl
diff --git a/Makefile.in b/Makefile.in
index f84dcc2..d2f9710 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -22,7 +22,7 @@ TOP = @abs_srcdir@
#
BCC = @BUILD_CC@ @BUILD_CFLAGS@
-# TCC is the C Compile and options for use in building executables that
+# TCC is the C Compile and options for use in building executables that
# will run on the target platform. (BCC and TCC are usually the
# same unless your are cross-compiling.) Separate CC and CFLAGS macros
# are provide so that these aspects of the build process can be changed
@@ -32,10 +32,11 @@ CC = @CC@
CFLAGS = @CPPFLAGS@ @CFLAGS@
TCC = ${CC} ${CFLAGS} -I. -I${TOP}/src -I${TOP}/ext/rtree -I${TOP}/ext/icu
TCC += -I${TOP}/ext/fts3 -I${TOP}/ext/async -I${TOP}/ext/session
+TCC += -I${TOP}/ext/userauth
# Define this for the autoconf-based build, so that the code knows it can
# include the generated config.h
-#
+#
TCC += -D_HAVE_SQLITE_CONFIG_H -DBUILD_sqlite
# Define -DNDEBUG to compile without debugging (i.e., for production usage)
@@ -66,7 +67,7 @@ LIBREADLINE = @TARGET_READLINE_LIBS@
TCC += -DSQLITE_THREADSAFE=@SQLITE_THREADSAFE@
# Any target libraries which libsqlite must be linked against
-#
+#
TLIBS = @LIBS@ $(LIBS)
# Flags controlling use of the in memory btree implementation
@@ -78,8 +79,8 @@ TLIBS = @LIBS@ $(LIBS)
TEMP_STORE = -DSQLITE_TEMP_STORE=@TEMP_STORE@
# Enable/disable loadable extensions, and other optional features
-# based on configuration. (-DSQLITE_OMIT*, -DSQLITE_ENABLE*).
-# The same set of OMIT and ENABLE flags should be passed to the
+# based on configuration. (-DSQLITE_OMIT*, -DSQLITE_ENABLE*).
+# The same set of OMIT and ENABLE flags should be passed to the
# LEMON parser generator and the mkkeywordhash tool as well.
OPT_FEATURE_FLAGS = @OPT_FEATURE_FLAGS@
@@ -126,8 +127,8 @@ SHLIB_SUFFIX = @TCL_SHLIB_SUFFIX@
# If gcov support was enabled by the configure script, add the appropriate
# flags here. It's not always as easy as just having the user add the right
# CFLAGS / LDFLAGS, because libtool wants to use CFLAGS when linking, which
-# causes build errors with -fprofile-arcs -ftest-coverage with some GCCs.
-# Supposedly GCC does the right thing if you use --coverage, but in
+# causes build errors with -fprofile-arcs -ftest-coverage with some GCCs.
+# Supposedly GCC does the right thing if you use --coverage, but in
# practice it still fails. See:
#
# http://www.mail-archive.com/debian-gcc@lists.debian.org/msg26197.html
@@ -187,7 +188,7 @@ LIBOBJS0 = alter.lo analyze.lo attach.lo auth.lo \
random.lo resolve.lo rowset.lo rtree.lo \
sqlite3session.lo select.lo sqlite3rbu.lo status.lo stmt.lo \
table.lo threads.lo tokenize.lo treeview.lo trigger.lo \
- update.lo upsert.lo util.lo vacuum.lo \
+ update.lo userauth.lo upsert.lo util.lo vacuum.lo \
vdbe.lo vdbeapi.lo vdbeaux.lo vdbeblob.lo vdbemem.lo vdbesort.lo \
vdbetrace.lo wal.lo walker.lo where.lo wherecode.lo whereexpr.lo \
window.lo utf.lo vtab.lo
@@ -355,6 +356,9 @@ SRC += \
SRC += \
$(TOP)/ext/session/sqlite3session.c \
$(TOP)/ext/session/sqlite3session.h
+SRC += \
+ $(TOP)/ext/userauth/userauth.c \
+ $(TOP)/ext/userauth/sqlite3userauth.h
SRC += \
$(TOP)/ext/rbu/sqlite3rbu.h \
$(TOP)/ext/rbu/sqlite3rbu.c
@@ -425,7 +429,7 @@ TESTSRC = \
$(TOP)/ext/fts3/fts3_term.c \
$(TOP)/ext/fts3/fts3_test.c \
$(TOP)/ext/session/test_session.c \
- $(TOP)/ext/rbu/test_rbu.c
+ $(TOP)/ext/rbu/test_rbu.c
# Statically linked extensions
#
@@ -437,6 +441,7 @@ TESTSRC += \
$(TOP)/ext/misc/closure.c \
$(TOP)/ext/misc/csv.c \
$(TOP)/ext/misc/eval.c \
+ $(TOP)/ext/misc/explain.c \
$(TOP)/ext/misc/fileio.c \
$(TOP)/ext/misc/fuzzer.c \
$(TOP)/ext/fts5/fts5_tcl.c \
@@ -454,7 +459,8 @@ TESTSRC += \
$(TOP)/ext/misc/totype.c \
$(TOP)/ext/misc/unionvtab.c \
$(TOP)/ext/misc/wholenumber.c \
- $(TOP)/ext/misc/zipfile.c
+ $(TOP)/ext/misc/zipfile.c \
+ $(TOP)/ext/userauth/userauth.c
# Source code to the library files needed by the test fixture
#
@@ -470,6 +476,7 @@ TESTSRC2 = \
$(TOP)/src/dbstat.c \
$(TOP)/src/expr.c \
$(TOP)/src/func.c \
+ $(TOP)/src/global.c \
$(TOP)/src/insert.c \
$(TOP)/src/wal.c \
$(TOP)/src/main.c \
@@ -506,7 +513,7 @@ TESTSRC2 = \
$(TOP)/ext/fts3/fts3_write.c \
$(TOP)/ext/async/sqlite3async.c \
$(TOP)/ext/session/sqlite3session.c \
- $(TOP)/ext/misc/stmt.c
+ $(TOP)/ext/misc/stmt.c
# Header files used by all library source files.
#
@@ -559,6 +566,8 @@ EXTHDR += \
$(TOP)/ext/icu/sqliteicu.h
EXTHDR += \
$(TOP)/ext/rtree/sqlite3rtree.h
+EXTHDR += \
+ $(TOP)/ext/userauth/sqlite3userauth.h
# executables needed for testing
#
@@ -578,7 +587,8 @@ FUZZDATA = \
$(TOP)/test/fuzzdata3.db \
$(TOP)/test/fuzzdata4.db \
$(TOP)/test/fuzzdata5.db \
- $(TOP)/test/fuzzdata6.db
+ $(TOP)/test/fuzzdata6.db \
+ $(TOP)/test/fuzzdata7.db
# Standard options to testfixture
#
@@ -595,13 +605,14 @@ SHELL_OPT += -DSQLITE_ENABLE_STMTVTAB
SHELL_OPT += -DSQLITE_ENABLE_DBPAGE_VTAB
SHELL_OPT += -DSQLITE_ENABLE_DBSTAT_VTAB
SHELL_OPT += -DSQLITE_ENABLE_OFFSET_SQL_FUNC
+SHELL_OPT += -DSQLITE_ENABLE_DESERIALIZE
SHELL_OPT += -DSQLITE_INTROSPECTION_PRAGMAS
FUZZERSHELL_OPT = -DSQLITE_ENABLE_JSON1
FUZZCHECK_OPT = -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_MEMSYS5 -DSQLITE_OSS_FUZZ
FUZZCHECK_OPT += -DSQLITE_MAX_MEMORY=50000000
FUZZCHECK_OPT += -DSQLITE_PRINTF_PRECISION_LIMIT=1000
FUZZCHECK_SRC = $(TOP)/test/fuzzcheck.c $(TOP)/test/ossfuzz.c
-DBFUZZ_OPT =
+DBFUZZ_OPT =
# This is the default Makefile target. The objects listed here
# are what get build when you type just "make" with no arguments.
@@ -663,6 +674,22 @@ sessionfuzz$(TEXE): $(TOP)/test/sessionfuzz.c sqlite3.c sqlite3.h
dbfuzz$(TEXE): $(TOP)/test/dbfuzz.c sqlite3.c sqlite3.h
$(LTLINK) -o $@ $(DBFUZZ_OPT) $(TOP)/test/dbfuzz.c sqlite3.c $(TLIBS)
+DBFUZZ2_OPTS = \
+ -DSQLITE_THREADSAFE=0 \
+ -DSQLITE_OMIT_LOAD_EXTENSION \
+ -DSQLITE_ENABLE_DESERIALIZE \
+ -DSQLITE_DEBUG \
+ -DSQLITE_ENABLE_DBSTAT_VTAB \
+ -DSQLITE_ENABLE_RTREE \
+ -DSQLITE_ENABLE_FTS4 \
+ -DSQLITE_EANBLE_FTS5
+
+dbfuzz2: $(TOP)/test/dbfuzz2.c sqlite3.c sqlite3.h
+ clang-6.0 -I. -g -O0 -fsanitize=fuzzer,undefined,address -o dbfuzz2 \
+ $(DBFUZZ2_OPTS) $(TOP)/test/dbfuzz2.c sqlite3.c
+ mkdir -p dbfuzz2-dir
+ cp $(TOP)/test/dbfuzz2-seed* dbfuzz2-dir
+
mptester$(TEXE): sqlite3.lo $(TOP)/mptest/mptest.c
$(LTLINK) -o $@ -I. $(TOP)/mptest/mptest.c sqlite3.lo \
$(TLIBS) -rpath "$(libdir)"
@@ -1098,7 +1125,10 @@ fts3_write.lo: $(TOP)/ext/fts3/fts3_write.c $(HDR) $(EXTHDR)
rtree.lo: $(TOP)/ext/rtree/rtree.c $(HDR) $(EXTHDR)
$(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/rtree/rtree.c
-sqlite3session.lo: $(TOP)/ext/session/sqlite3session.c $(HDR) $(EXTHDR)
+sqlite3session.lo: $(TOP)/ext/userauth/userauth.c $(HDR) $(EXTHDR)
+ $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/userauth/userauth.c
+
+userauth.lo: $(TOP)/ext/session/sqlite3session.c $(HDR) $(EXTHDR)
$(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/session/sqlite3session.c
json1.lo: $(TOP)/ext/misc/json1.c
@@ -1126,7 +1156,7 @@ FTS5_SRC = \
$(TOP)/ext/fts5/fts5_varint.c \
$(TOP)/ext/fts5/fts5_vocab.c \
-fts5parse.c: $(TOP)/ext/fts5/fts5parse.y lemon
+fts5parse.c: $(TOP)/ext/fts5/fts5parse.y lemon
cp $(TOP)/ext/fts5/fts5parse.y .
rm -f fts5parse.h
./lemon$(BEXE) $(OPTS) fts5parse.y
@@ -1153,7 +1183,7 @@ sqlite3rbu.lo: $(TOP)/ext/rbu/sqlite3rbu.c $(HDR) $(EXTHDR)
#
TESTFIXTURE_FLAGS = -DSQLITE_TEST=1 -DSQLITE_CRASH_TEST=1
TESTFIXTURE_FLAGS += -DTCLSH_INIT_PROC=sqlite3TestInit
-TESTFIXTURE_FLAGS += -DSQLITE_SERVER=1 -DSQLITE_PRIVATE="" -DSQLITE_CORE
+TESTFIXTURE_FLAGS += -DSQLITE_SERVER=1 -DSQLITE_PRIVATE="" -DSQLITE_CORE
TESTFIXTURE_FLAGS += -DBUILD_sqlite
TESTFIXTURE_FLAGS += -DSQLITE_SERIES_CONSTRAINT_VERIFY=1
TESTFIXTURE_FLAGS += -DSQLITE_DEFAULT_PAGE_SIZE=1024
@@ -1169,6 +1199,10 @@ testfixture$(TEXE): $(TESTFIXTURE_SRC)
$(LTLINK) -DSQLITE_NO_SYNC=1 $(TEMP_STORE) $(TESTFIXTURE_FLAGS) \
-o $@ $(TESTFIXTURE_SRC) $(LIBTCL) $(TLIBS)
+coretestprogs: $(TESTPROGS)
+
+testprogs: coretestprogs srcck1$(BEXE) fuzzcheck$(TEXE) sessionfuzz$(TEXE)
+
# A very detailed test running most or all test cases
fulltest: $(TESTPROGS) fuzztest
./testfixture$(TEXE) $(TOP)/test/all.test $(TESTOPTS)
@@ -1228,7 +1262,7 @@ sqlite3_analyzer.c: sqlite3.c $(TOP)/src/tclsqlite.c $(TOP)/tool/spaceanal.tcl $
sqlite3_analyzer$(TEXE): sqlite3_analyzer.c
$(LTLINK) sqlite3_analyzer.c -o $@ $(LIBTCL) $(TLIBS)
-sqltclsh.c: sqlite3.c $(TOP)/src/tclsqlite.c $(TOP)/tool/sqltclsh.tcl $(TOP)/ext/misc/appendvfs.c $(TOP)/tool/mkccode.tcl $(TOP)/tool/sqltclsh.c.in
+sqltclsh.c: sqlite3.c $(TOP)/src/tclsqlite.c $(TOP)/tool/sqltclsh.tcl $(TOP)/ext/misc/appendvfs.c $(TOP)/tool/mkccode.tcl $(TOP)/tool/sqltclsh.c.in
$(TCLSH_CMD) $(TOP)/tool/mkccode.tcl $(TOP)/tool/sqltclsh.c.in >sqltclsh.c
sqltclsh$(TEXE): sqltclsh.c
@@ -1275,6 +1309,9 @@ showshm$(TEXE): $(TOP)/tool/showshm.c
changeset$(TEXE): $(TOP)/ext/session/changeset.c sqlite3.lo
$(LTLINK) -o $@ $(TOP)/ext/session/changeset.c sqlite3.lo $(TLIBS)
+changesetfuzz$(TEXE): $(TOP)/ext/session/changesetfuzz.c sqlite3.lo
+ $(LTLINK) -o $@ $(TOP)/ext/session/changesetfuzz.c sqlite3.lo $(TLIBS)
+
rollback-test$(TEXE): $(TOP)/tool/rollback-test.c sqlite3.lo
$(LTLINK) -o $@ $(TOP)/tool/rollback-test.c sqlite3.lo $(TLIBS)
@@ -1295,7 +1332,7 @@ KV_OPT += -DSQLITE_DIRECT_OVERFLOW_READ
kvtest$(TEXE): $(TOP)/test/kvtest.c sqlite3.c
$(LTLINK) $(KV_OPT) -o $@ $(TOP)/test/kvtest.c sqlite3.c $(TLIBS)
-rbu$(EXE): $(TOP)/ext/rbu/rbu.c $(TOP)/ext/rbu/sqlite3rbu.c sqlite3.lo
+rbu$(EXE): $(TOP)/ext/rbu/rbu.c $(TOP)/ext/rbu/sqlite3rbu.c sqlite3.lo
$(LTLINK) -I. -o $@ $(TOP)/ext/rbu/rbu.c sqlite3.lo $(TLIBS)
loadfts$(EXE): $(TOP)/tool/loadfts.c libsqlite3.la
@@ -1323,7 +1360,7 @@ snapshot-tarball: sqlite3.c
# 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
# target is invoked by the releasetest.tcl script.
-#
+#
THREADTEST3_SRC = $(TOP)/test/threadtest3.c \
$(TOP)/test/tt3_checkpoint.c \
$(TOP)/test/tt3_index.c \
@@ -1337,7 +1374,7 @@ threadtest3$(TEXE): sqlite3.lo $(THREADTEST3_SRC)
threadtest: threadtest3$(TEXE)
./threadtest3$(TEXE)
-releasetest:
+releasetest:
$(TCLSH_CMD) $(TOP)/test/releasetest.tcl
# Standard install and cleanup targets
@@ -1345,7 +1382,7 @@ releasetest:
lib_install: libsqlite3.la
$(INSTALL) -d $(DESTDIR)$(libdir)
$(LTINSTALL) libsqlite3.la $(DESTDIR)$(libdir)
-
+
install: sqlite3$(TEXE) lib_install sqlite3.h sqlite3.pc ${HAVE_TCL:1=tcl_install}
$(INSTALL) -d $(DESTDIR)$(bindir)
$(LTINSTALL) sqlite3$(TEXE) $(DESTDIR)$(bindir)
@@ -1363,7 +1400,7 @@ tcl_install: lib_install libtclsqlite3.la pkgIndex.tcl
rm -f $(DESTDIR)$(TCLLIBDIR)/libtclsqlite3.la $(DESTDIR)$(TCLLIBDIR)/libtclsqlite3.a
$(INSTALL) -m 0644 pkgIndex.tcl $(DESTDIR)$(TCLLIBDIR)
-clean:
+clean:
rm -f *.lo *.la *.o sqlite3$(TEXE) libsqlite3.la
rm -f sqlite3.h opcodes.*
rm -rf .libs .deps
diff --git a/Makefile.msc b/Makefile.msc
index 4c6cdfb..e3feffa 100644
--- a/Makefile.msc
+++ b/Makefile.msc
@@ -345,6 +345,7 @@ OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_STMTVTAB=1
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_DBPAGE_VTAB=1
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_DBSTAT_VTAB=1
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_INTROSPECTION_PRAGMAS=1
+OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_DESERIALIZE=1
!ENDIF
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_COLUMN_METADATA=1
!ENDIF
@@ -1515,6 +1516,7 @@ TESTEXT = \
$(TOP)\ext\misc\closure.c \
$(TOP)\ext\misc\csv.c \
$(TOP)\ext\misc\eval.c \
+ $(TOP)\ext\misc\explain.c \
$(TOP)\ext\misc\fileio.c \
$(TOP)\ext\misc\fuzzer.c \
$(TOP)\ext\fts5\fts5_tcl.c \
@@ -1622,7 +1624,8 @@ FUZZDATA = \
$(TOP)\test\fuzzdata3.db \
$(TOP)\test\fuzzdata4.db \
$(TOP)\test\fuzzdata5.db \
- $(TOP)\test\fuzzdata6.db
+ $(TOP)\test\fuzzdata6.db \
+ $(TOP)\test\fuzzdata7.db
# <>
# Additional compiler options for the shell. These are only effective
@@ -1632,6 +1635,7 @@ FUZZDATA = \
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_FTS4=1
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_EXPLAIN_COMMENTS=1
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_OFFSET_SQL_FUNC=1
+SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_DESERIALIZE=1
!ENDIF
# <>
@@ -2334,6 +2338,10 @@ extensiontest: testfixture.exe testloadext.dll
@set PATH=$(LIBTCLPATH);$(PATH)
.\testfixture.exe $(TOP)\test\loadext.test $(TESTOPTS)
+coretestprogs: $(TESTPROGS)
+
+testprogs: coretestprogs srcck1.exe fuzzcheck.exe sessionfuzz.exe
+
fulltest: $(TESTPROGS) fuzztest
@set PATH=$(LIBTCLPATH);$(PATH)
.\testfixture.exe $(TOP)\test\all.test $(TESTOPTS)
@@ -2441,6 +2449,11 @@ changeset.exe: $(TOP)\ext\session\changeset.c $(SQLITE3C) $(SQLITE3H)
-DSQLITE_ENABLE_SESSION=1 -DSQLITE_ENABLE_PREUPDATE_HOOK=1 \
$(TOP)\ext\session\changeset.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS)
+changesetfuzz.exe: $(TOP)\ext\session\changesetfuzz.c $(SQLITE3C) $(SQLITE3H)
+ $(LTLINK) $(NO_WARN) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION \
+ -DSQLITE_ENABLE_SESSION=1 -DSQLITE_ENABLE_PREUPDATE_HOOK=1 \
+ $(TOP)\ext\session\changesetfuzz.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS)
+
fts3view.exe: $(TOP)\ext\fts3\tool\fts3view.c $(SQLITE3C) $(SQLITE3H)
$(LTLINK) $(NO_WARN) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION \
$(TOP)\ext\fts3\tool\fts3view.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS)
diff --git a/VERSION b/VERSION
index 427f346..419ede3 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-3.25.2
+3.26.0
diff --git a/configure b/configure
index 038abd4..51653aa 100755
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for sqlite 3.25.2.
+# Generated by GNU Autoconf 2.69 for sqlite 3.26.0.
#
#
# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
@@ -726,8 +726,8 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='sqlite'
PACKAGE_TARNAME='sqlite'
-PACKAGE_VERSION='3.25.2'
-PACKAGE_STRING='sqlite 3.25.2'
+PACKAGE_VERSION='3.26.0'
+PACKAGE_STRING='sqlite 3.26.0'
PACKAGE_BUGREPORT=''
PACKAGE_URL=''
@@ -1466,7 +1466,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
-\`configure' configures sqlite 3.25.2 to adapt to many kinds of systems.
+\`configure' configures sqlite 3.26.0 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1531,7 +1531,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
- short | recursive ) echo "Configuration of sqlite 3.25.2:";;
+ short | recursive ) echo "Configuration of sqlite 3.26.0:";;
esac
cat <<\_ACEOF
@@ -1657,7 +1657,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
-sqlite configure 3.25.2
+sqlite configure 3.26.0
generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc.
@@ -2076,7 +2076,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
-It was created by sqlite $as_me 3.25.2, which was
+It was created by sqlite $as_me 3.26.0, which was
generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@
@@ -12232,7 +12232,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
-This file was extended by sqlite $as_me 3.25.2, which was
+This file was extended by sqlite $as_me 3.26.0, which was
generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -12298,7 +12298,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
-sqlite config.status 3.25.2
+sqlite config.status 3.26.0
configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\"
diff --git a/doc/lemon.html b/doc/lemon.html
index 4f0849e..056ae5f 100644
--- a/doc/lemon.html
+++ b/doc/lemon.html
@@ -777,6 +777,9 @@ For example:
This might be needed, for example, if some of the C actions in the
grammar call functions that are prototyped in unistd.h.
+Use the %code directive to add code to
+the end of the generated parser.
+
The %left directive
diff --git a/ext/expert/sqlite3expert.c b/ext/expert/sqlite3expert.c
index 695aaec..e88fb7e 100644
--- a/ext/expert/sqlite3expert.c
+++ b/ext/expert/sqlite3expert.c
@@ -644,6 +644,7 @@ static int idxRegisterVtab(sqlite3expert *p){
0, /* xSavepoint */
0, /* xRelease */
0, /* xRollbackTo */
+ 0, /* xShadowName */
};
return sqlite3_create_module(p->dbv, "expert", &expertModule, (void*)p);
diff --git a/ext/fts3/fts3.c b/ext/fts3/fts3.c
index d0e6d9b..f6fb931 100644
--- a/ext/fts3/fts3.c
+++ b/ext/fts3/fts3.c
@@ -1821,7 +1821,7 @@ static int fts3ScanInteriorNode(
const char *zCsr = zNode; /* Cursor to iterate through node */
const char *zEnd = &zCsr[nNode];/* End of interior node buffer */
char *zBuffer = 0; /* Buffer to load terms into */
- int nAlloc = 0; /* Size of allocated buffer */
+ i64 nAlloc = 0; /* Size of allocated buffer */
int isFirstTerm = 1; /* True when processing first term on page */
sqlite3_int64 iChild; /* Block id of child node to descend to */
@@ -1859,14 +1859,14 @@ static int fts3ScanInteriorNode(
zCsr += fts3GetVarint32(zCsr, &nSuffix);
assert( nPrefix>=0 && nSuffix>=0 );
- if( &zCsr[nSuffix]>zEnd ){
+ if( nPrefix>zCsr-zNode || nSuffix>zEnd-zCsr ){
rc = FTS_CORRUPT_VTAB;
goto finish_scan;
}
- if( nPrefix+nSuffix>nAlloc ){
+ if( (i64)nPrefix+nSuffix>nAlloc ){
char *zNew;
- nAlloc = (nPrefix+nSuffix) * 2;
- zNew = (char *)sqlite3_realloc(zBuffer, nAlloc);
+ nAlloc = ((i64)nPrefix+nSuffix) * 2;
+ zNew = (char *)sqlite3_realloc64(zBuffer, nAlloc);
if( !zNew ){
rc = SQLITE_NOMEM;
goto finish_scan;
@@ -3846,8 +3846,23 @@ static int fts3RollbackToMethod(sqlite3_vtab *pVtab, int iSavepoint){
return SQLITE_OK;
}
+/*
+** Return true if zName is the extension on one of the shadow tables used
+** by this module.
+*/
+static int fts3ShadowName(const char *zName){
+ static const char *azName[] = {
+ "content", "docsize", "segdir", "segments", "stat",
+ };
+ unsigned int i;
+ for(i=0; i&pReader->aNode[pReader->nNode]
+ if( nSuffix<=0
+ || (&pReader->aNode[pReader->nNode] - pNext)pReader->nTermAlloc
){
return FTS_CORRUPT_VTAB;
}
- if( nPrefix+nSuffix>pReader->nTermAlloc ){
- int nNew = (nPrefix+nSuffix)*2;
- char *zNew = sqlite3_realloc(pReader->zTerm, nNew);
+ /* Both nPrefix and nSuffix were read by fts3GetVarint32() and so are
+ ** between 0 and 0x7FFFFFFF. But the sum of the two may cause integer
+ ** overflow - hence the (i64) casts. */
+ if( (i64)nPrefix+nSuffix>(i64)pReader->nTermAlloc ){
+ i64 nNew = ((i64)nPrefix+nSuffix)*2;
+ char *zNew = sqlite3_realloc64(pReader->zTerm, nNew);
if( !zNew ){
return SQLITE_NOMEM;
}
@@ -1404,7 +1408,7 @@ static int fts3SegReaderNext(
** b-tree node. And that the final byte of the doclist is 0x00. If either
** of these statements is untrue, then the data structure is corrupt.
*/
- if( &pReader->aDoclist[pReader->nDoclist]>&pReader->aNode[pReader->nNode]
+ if( (&pReader->aNode[pReader->nNode] - pReader->aDoclist)nDoclist
|| (pReader->nPopulate==0 && pReader->aDoclist[pReader->nDoclist-1])
){
return FTS_CORRUPT_VTAB;
@@ -3730,6 +3734,9 @@ static int nodeReaderNext(NodeReader *p){
}
p->iOff += fts3GetVarint32(&p->aNode[p->iOff], &nSuffix);
+ if( nPrefix>p->iOff || nSuffix>p->nNode-p->iOff ){
+ return SQLITE_CORRUPT_VTAB;
+ }
blobGrowBuffer(&p->term, nPrefix+nSuffix, &rc);
if( rc==SQLITE_OK ){
memcpy(&p->term.a[nPrefix], &p->aNode[p->iOff], nSuffix);
@@ -3737,6 +3744,9 @@ static int nodeReaderNext(NodeReader *p){
p->iOff += nSuffix;
if( p->iChild==0 ){
p->iOff += fts3GetVarint32(&p->aNode[p->iOff], &p->nDoclist);
+ if( (p->nNode-p->iOff)nDoclist ){
+ return SQLITE_CORRUPT_VTAB;
+ }
p->aDoclist = &p->aNode[p->iOff];
p->iOff += p->nDoclist;
}
@@ -3744,7 +3754,6 @@ static int nodeReaderNext(NodeReader *p){
}
assert( p->iOff<=p->nNode );
-
return rc;
}
diff --git a/ext/fts5/fts5_index.c b/ext/fts5/fts5_index.c
index 394280b..0a6d8d2 100644
--- a/ext/fts5/fts5_index.c
+++ b/ext/fts5/fts5_index.c
@@ -5402,7 +5402,7 @@ int sqlite3Fts5IndexQuery(
fts5CloseReader(p);
}
- *ppIter = &pRet->base;
+ *ppIter = (Fts5IndexIter*)pRet;
sqlite3Fts5BufferFree(&buf);
}
return fts5IndexReturn(p);
diff --git a/ext/fts5/fts5_main.c b/ext/fts5/fts5_main.c
index e9ec2de..e5ff393 100644
--- a/ext/fts5/fts5_main.c
+++ b/ext/fts5/fts5_main.c
@@ -2645,9 +2645,24 @@ static void fts5SourceIdFunc(
sqlite3_result_text(pCtx, "--FTS5-SOURCE-ID--", -1, SQLITE_TRANSIENT);
}
+/*
+** Return true if zName is the extension on one of the shadow tables used
+** by this module.
+*/
+static int fts5ShadowName(const char *zName){
+ static const char *azName[] = {
+ "config", "content", "data", "docsize", "idx"
+ };
+ unsigned int i;
+ for(i=0; iiInstPos;
int *po = &pCsr->iInstOff;
+ assert( sqlite3Fts5IterEof(pIter)==0 );
+ assert( pCsr->bEof==0 );
while( eDetail==FTS5_DETAIL_NONE
|| sqlite3Fts5PoslistNext64(pIter->pData, pIter->nData, po, pp)
){
@@ -440,7 +442,7 @@ static int fts5VocabInstanceNext(Fts5VocabCursor *pCsr){
rc = sqlite3Fts5IterNextScan(pCsr->pIter);
if( rc==SQLITE_OK ){
rc = fts5VocabInstanceNewTerm(pCsr);
- if( eDetail==FTS5_DETAIL_NONE ) break;
+ if( pCsr->bEof || eDetail==FTS5_DETAIL_NONE ) break;
}
if( rc ){
pCsr->bEof = 1;
@@ -755,10 +757,9 @@ int sqlite3Fts5VocabInit(Fts5Global *pGlobal, sqlite3 *db){
/* xSavepoint */ 0,
/* xRelease */ 0,
/* xRollbackTo */ 0,
+ /* xShadowName */ 0
};
void *p = (void*)pGlobal;
return sqlite3_create_module_v2(db, "fts5vocab", &fts5Vocab, p, 0);
}
-
-
diff --git a/ext/fts5/test/fts5aa.test b/ext/fts5/test/fts5aa.test
index 6fa3ad8..b6a2499 100644
--- a/ext/fts5/test/fts5aa.test
+++ b/ext/fts5/test/fts5aa.test
@@ -409,6 +409,7 @@ do_test 14.3 {
do_execsql_test 15.0 {
INSERT INTO t1(t1) VALUES('integrity-check');
}
+sqlite3_db_config db DEFENSIVE 0
do_execsql_test 15.1 {
UPDATE t1_content SET c1 = 'xyz xyz xyz xyz xyz abc' WHERE rowid = 1;
}
diff --git a/ext/fts5/test/fts5connect.test b/ext/fts5/test/fts5connect.test
index c615d4c..4607734 100644
--- a/ext/fts5/test/fts5connect.test
+++ b/ext/fts5/test/fts5connect.test
@@ -244,4 +244,3 @@ foreach {tn sql res} {
}
finish_test
-
diff --git a/ext/fts5/test/fts5corrupt.test b/ext/fts5/test/fts5corrupt.test
index 1462912..5f13513 100644
--- a/ext/fts5/test/fts5corrupt.test
+++ b/ext/fts5/test/fts5corrupt.test
@@ -41,6 +41,7 @@ db_save
do_execsql_test 1.2 { INSERT INTO t1(t1) VALUES('integrity-check') }
set segid [lindex [fts5_level_segids t1] 0]
+sqlite3_db_config db DEFENSIVE 0
do_test 1.3 {
execsql {
DELETE FROM t1_data WHERE rowid = fts5_rowid('segment', $segid, 4);
@@ -50,6 +51,7 @@ do_test 1.3 {
do_test 1.4 {
db_restore_and_reopen
+ sqlite3_db_config db DEFENSIVE 0
execsql {
UPDATE t1_data set block = X'00000000' || substr(block, 5) WHERE
rowid = fts5_rowid('segment', $segid, 4);
@@ -89,7 +91,7 @@ do_execsql_test 3.0 {
do_execsql_test 3.1 {
SELECT * FROM t3 WHERE t3 MATCH 'o'
} {{one o} {three o} {five o}}
-
+sqlite3_db_config db DEFENSIVE 0
do_catchsql_test 3.1 {
DELETE FROM t3_content WHERE rowid = 3;
SELECT * FROM t3 WHERE t3 MATCH 'o';
diff --git a/ext/fts5/test/fts5corrupt2.test b/ext/fts5/test/fts5corrupt2.test
index 74721e5..a815320 100644
--- a/ext/fts5/test/fts5corrupt2.test
+++ b/ext/fts5/test/fts5corrupt2.test
@@ -99,6 +99,7 @@ foreach {tno stmt} {
set lrowid [db one {SELECT max(rowid) FROM t1_data WHERE (rowid & $mask)=0}]
set nbyte [db one {SELECT length(block) FROM t1_data WHERE rowid=$lrowid}]
set all [db eval {SELECT rowid FROM t1}]
+sqlite3_db_config db DEFENSIVE 0
for {set i [expr $nbyte-2]} {$i>=0} {incr i -1} {
do_execsql_test 2.$i.1 {
BEGIN;
@@ -248,6 +249,7 @@ foreach {tn hdr} {
#--------------------------------------------------------------------
reset_db
+sqlite3_db_config db DEFENSIVE 0
do_execsql_test 6.1 {
CREATE VIRTUAL TABLE x5 USING fts5(tt);
INSERT INTO x5 VALUES('a');
diff --git a/ext/fts5/test/fts5corrupt3.test b/ext/fts5/test/fts5corrupt3.test
index 72e9ab1..ec823b3 100644
--- a/ext/fts5/test/fts5corrupt3.test
+++ b/ext/fts5/test/fts5corrupt3.test
@@ -51,6 +51,7 @@ do_test 1.1 {
set {} {}
} {}
+sqlite3_db_config db DEFENSIVE 0
for {set i 0} {$i < $L} {incr i} {
do_test 1.2.$i {
catchsql {
@@ -86,6 +87,7 @@ do_execsql_test 2.2 {
#
reset_db
do_test 3.0 { create_t1 } {}
+sqlite3_db_config db DEFENSIVE 0
do_execsql_test 3.1 {
SELECT count(*) FROM t1_data;
@@ -158,6 +160,7 @@ do_3_test 3.10
# Test that segments that end unexpectedly are identified as corruption.
#
reset_db
+sqlite3_db_config db DEFENSIVE 0
do_test 4.0 {
execsql {
CREATE VIRTUAL TABLE t1 USING fts5(x);
@@ -182,6 +185,7 @@ for {set i 1} {1} {incr i} {
db close
sqlite3 db test.db
+ sqlite3_db_config db DEFENSIVE 0
db eval {
BEGIN;
@@ -257,6 +261,7 @@ foreach rowid [db eval {SELECT rowid FROM x1_data WHERE rowid>100}] {
#------------------------------------------------------------------------
#
reset_db
+sqlite3_db_config db DEFENSIVE 0
do_execsql_test 6.1.0 {
CREATE VIRTUAL TABLE t1 USING fts5(a);
INSERT INTO t1 VALUES('bbbbb ccccc');
@@ -273,6 +278,7 @@ do_catchsql_test 6.1.2 {
#-------
reset_db
+sqlite3_db_config db DEFENSIVE 0
do_execsql_test 6.2.0 {
CREATE VIRTUAL TABLE t1 USING fts5(a);
INSERT INTO t1(t1, rank) VALUES('pgsz', 32);
@@ -288,6 +294,7 @@ do_catchsql_test 6.2.2 {
#-------
reset_db
+sqlite3_db_config db DEFENSIVE 0
do_execsql_test 6.3.0 {
CREATE VIRTUAL TABLE t1 USING fts5(a);
INSERT INTO t1 VALUES('abc abcdef abcdefghi');
@@ -362,6 +369,7 @@ do_test 7.0 {
}
} {}
+sqlite3_db_config db DEFENSIVE 0
do_test 7.1 {
foreach i [db eval { SELECT rowid FROM t5_data WHERE rowid>100 }] {
db eval BEGIN
@@ -383,6 +391,7 @@ do_execsql_test 8.1 {
INSERT INTO t1 VALUES('one', 'two');
}
+sqlite3_db_config db DEFENSIVE 0
do_test 9.1.1 {
set blob "12345678" ;# cookie
append blob "0105" ;# 1 level, total of 5 segments
diff --git a/ext/fts5/test/fts5first.test b/ext/fts5/test/fts5first.test
index b2cac1f..357672d 100644
--- a/ext/fts5/test/fts5first.test
+++ b/ext/fts5/test/fts5first.test
@@ -93,4 +93,3 @@ do_catchsql_test 3.3 {
SELECT * FROM x2('^a');
} {1 {fts5: phrase queries are not supported (detail!=full)}}
finish_test
-
diff --git a/ext/fts5/test/fts5integrity.test b/ext/fts5/test/fts5integrity.test
index a38b164..25c7277 100644
--- a/ext/fts5/test/fts5integrity.test
+++ b/ext/fts5/test/fts5integrity.test
@@ -71,6 +71,7 @@ do_execsql_test 4.1 {
INSERT INTO aa(aa) VALUES('integrity-check');
}
+sqlite3_db_config db DEFENSIVE 0
do_catchsql_test 4.2 {
BEGIN;
UPDATE aa_docsize SET sz = X'44' WHERE rowid = 3;
diff --git a/ext/fts5/test/fts5rank.test b/ext/fts5/test/fts5rank.test
index 0a986b5..e8f5473 100644
--- a/ext/fts5/test/fts5rank.test
+++ b/ext/fts5/test/fts5rank.test
@@ -163,4 +163,3 @@ do_execsql_test 5.1 {
} {30 31 32 33 34 35 36 37 38 39 40}
finish_test
-
diff --git a/ext/fts5/test/fts5rebuild.test b/ext/fts5/test/fts5rebuild.test
index 0191831..ae881c0 100644
--- a/ext/fts5/test/fts5rebuild.test
+++ b/ext/fts5/test/fts5rebuild.test
@@ -39,6 +39,7 @@ do_execsql_test 1.4 {
INSERT INTO f1(f1) VALUES('integrity-check');
} {}
+sqlite3_db_config db DEFENSIVE 0
do_execsql_test 1.5 {
DELETE FROM f1_data;
} {}
diff --git a/ext/fts5/test/fts5rowid.test b/ext/fts5/test/fts5rowid.test
index e7fd1bc..8935ecf 100644
--- a/ext/fts5/test/fts5rowid.test
+++ b/ext/fts5/test/fts5rowid.test
@@ -70,6 +70,7 @@ set res [db one {SELECT count(*) FROM x1_data}]
do_execsql_test 2.3 {
SELECT count(fts5_decode(rowid, block)) FROM x1_data;
} $res
+sqlite3_db_config db DEFENSIVE 0
do_execsql_test 2.4 {
UPDATE x1_data SET block = X'';
SELECT count(fts5_decode(rowid, block)) FROM x1_data;
diff --git a/ext/fts5/test/fts5version.test b/ext/fts5/test/fts5version.test
index 58cd348..60ec81c 100644
--- a/ext/fts5/test/fts5version.test
+++ b/ext/fts5/test/fts5version.test
@@ -36,9 +36,10 @@ do_execsql_test 1.3 {
SELECT rowid FROM t1 WHERE t1 MATCH 'a';
} {1}
+sqlite3_db_config db DEFENSIVE 0
do_execsql_test 1.4 {
UPDATE t1_config set v=5 WHERE k='version';
-}
+}
do_test 1.5 {
db close
@@ -53,6 +54,7 @@ do_test 1.6 {
} {1 {invalid fts5 file format (found 5, expected 4) - run 'rebuild'}}
do_test 1.7 {
+ sqlite3_db_config db DEFENSIVE 0
execsql { DELETE FROM t1_config WHERE k='version' }
db close
sqlite3 db test.db
diff --git a/ext/fts5/test/fts5vocab.test b/ext/fts5/test/fts5vocab.test
index 8c40316..d3c8b76 100644
--- a/ext/fts5/test/fts5vocab.test
+++ b/ext/fts5/test/fts5vocab.test
@@ -420,6 +420,7 @@ if {[detail_is_none]} { set resc [row_to_col $resr] }
do_execsql_test 8.1.1 { SELECT * FROM x1_r; } $resr
do_execsql_test 8.1.2 { SELECT * FROM x1_c } $resc
+sqlite3_db_config db DEFENSIVE 0
do_execsql_test 8.2 {
PRAGMA writable_schema = 1;
UPDATE sqlite_master
@@ -481,4 +482,3 @@ do_test 9.6 {
finish_test
-
diff --git a/ext/fts5/test/fts5vocab2.test b/ext/fts5/test/fts5vocab2.test
index 4a0a1f4..8edea54 100644
--- a/ext/fts5/test/fts5vocab2.test
+++ b/ext/fts5/test/fts5vocab2.test
@@ -13,7 +13,7 @@
#
source [file join [file dirname [info script]] fts5_common.tcl]
-set testprefix fts5vocab
+set testprefix fts5vocab2
# If SQLITE_ENABLE_FTS5 is defined, omit this file.
ifcapable !fts5 {
@@ -206,4 +206,3 @@ do_execsql_test 3.5 {
}
finish_test
-
diff --git a/ext/misc/amatch.c b/ext/misc/amatch.c
index 914e263..142e354 100644
--- a/ext/misc/amatch.c
+++ b/ext/misc/amatch.c
@@ -1473,7 +1473,8 @@ static sqlite3_module amatchModule = {
0, /* xRename */
0, /* xSavepoint */
0, /* xRelease */
- 0 /* xRollbackTo */
+ 0, /* xRollbackTo */
+ 0 /* xShadowName */
};
#endif /* SQLITE_OMIT_VIRTUALTABLE */
diff --git a/ext/misc/btreeinfo.c b/ext/misc/btreeinfo.c
index 131b210..3d818f2 100644
--- a/ext/misc/btreeinfo.c
+++ b/ext/misc/btreeinfo.c
@@ -411,6 +411,7 @@ int sqlite3BinfoRegister(sqlite3 *db){
0, /* xSavepoint */
0, /* xRelease */
0, /* xRollbackTo */
+ 0 /* xShadowName */
};
return sqlite3_create_module(db, "sqlite_btreeinfo", &binfo_module, 0);
}
diff --git a/ext/misc/closure.c b/ext/misc/closure.c
index 74bffc7..03f13c0 100644
--- a/ext/misc/closure.c
+++ b/ext/misc/closure.c
@@ -938,7 +938,8 @@ static sqlite3_module closureModule = {
0, /* xRename */
0, /* xSavepoint */
0, /* xRelease */
- 0 /* xRollbackTo */
+ 0, /* xRollbackTo */
+ 0 /* xShadowName */
};
#endif /* SQLITE_OMIT_VIRTUALTABLE */
diff --git a/ext/misc/completion.c b/ext/misc/completion.c
index 4a4b918..72ad23d 100644
--- a/ext/misc/completion.c
+++ b/ext/misc/completion.c
@@ -468,7 +468,8 @@ static sqlite3_module completionModule = {
0, /* xRename */
0, /* xSavepoint */
0, /* xRelease */
- 0 /* xRollbackTo */
+ 0, /* xRollbackTo */
+ 0 /* xShadowName */
};
#endif /* SQLITE_OMIT_VIRTUALTABLE */
diff --git a/ext/misc/csv.c b/ext/misc/csv.c
index ec90f96..8cca8ae 100644
--- a/ext/misc/csv.c
+++ b/ext/misc/csv.c
@@ -19,9 +19,9 @@
** CREATE VIRTUAL TABLE temp.csv USING csv(filename=FILENAME);
** SELECT * FROM csv;
**
-** The columns are named "c1", "c2", "c3", ... by default. But the
-** application can define its own CREATE TABLE statement as an additional
-** parameter. For example:
+** The columns are named "c1", "c2", "c3", ... by default. Or the
+** application can define its own CREATE TABLE statement using the
+** schema= parameter, like this:
**
** CREATE VIRTUAL TABLE temp.csv2 USING csv(
** filename = "../http.log",
@@ -32,9 +32,9 @@
** the data= parameter.
**
** If the columns=N parameter is supplied, then the CSV file is assumed to have
-** N columns. If the columns parameter is omitted, the CSV file is opened
-** as soon as the virtual table is constructed and the first row of the CSV
-** is read in order to count the tables.
+** N columns. If both the columns= and schema= parameters are omitted, then
+** the number and names of the columns is determined by the first line of
+** the CSV input.
**
** Some extra debugging features (used for testing virtual tables) are available
** if this module is compiled with -DSQLITE_TEST.
@@ -436,6 +436,34 @@ static int csv_boolean(const char *z){
return -1;
}
+/* Check to see if the string is of the form: "TAG = BOOLEAN" or just "TAG".
+** If it is, set *pValue to be the value of the boolean ("true" if there is
+** not "= BOOLEAN" component) and return non-zero. If the input string
+** does not begin with TAG, return zero.
+*/
+static int csv_boolean_parameter(
+ const char *zTag, /* Tag we are looking for */
+ int nTag, /* Size of the tag in bytes */
+ const char *z, /* Input parameter */
+ int *pValue /* Write boolean value here */
+){
+ int b;
+ z = csv_skip_whitespace(z);
+ if( strncmp(zTag, z, nTag)!=0 ) return 0;
+ z = csv_skip_whitespace(z + nTag);
+ if( z[0]==0 ){
+ *pValue = 1;
+ return 1;
+ }
+ if( z[0]!='=' ) return 0;
+ z = csv_skip_whitespace(z+1);
+ b = csv_boolean(z);
+ if( b>=0 ){
+ *pValue = b;
+ return 1;
+ }
+ return 0;
+}
/*
** Parameters:
@@ -469,6 +497,7 @@ static int csvtabConnect(
#ifdef SQLITE_TEST
int tstFlags = 0; /* Value for testflags=N parameter */
#endif
+ int b; /* Value of a boolean parameter */
int nCol = -99; /* Value of the columns= parameter */
CsvReader sRdr; /* A CSV file reader used to store an error
** message and/or to count the number of columns */
@@ -493,21 +522,12 @@ static int csvtabConnect(
if( j=0 ){
csv_errmsg(&sRdr, "more than one 'header' parameter");
goto csvtab_connect_error;
}
- x = csv_boolean(zValue);
- if( x==1 ){
- bHeader = 1;
- }else if( x==0 ){
- bHeader = 0;
- }else{
- csv_errmsg(&sRdr, "unrecognized argument to 'header': %s", zValue);
- goto csvtab_connect_error;
- }
+ bHeader = b;
}else
#ifdef SQLITE_TEST
if( (zValue = csv_parameter("testflags",9,z))!=0 ){
@@ -521,53 +541,94 @@ static int csvtabConnect(
}
nCol = atoi(zValue);
if( nCol<=0 ){
- csv_errmsg(&sRdr, "must have at least one column");
+ csv_errmsg(&sRdr, "column= value must be positive");
goto csvtab_connect_error;
}
}else
{
- csv_errmsg(&sRdr, "unrecognized parameter '%s'", z);
+ csv_errmsg(&sRdr, "bad parameter: '%s'", z);
goto csvtab_connect_error;
}
}
if( (CSV_FILENAME==0)==(CSV_DATA==0) ){
- csv_errmsg(&sRdr, "must either filename= or data= but not both");
+ csv_errmsg(&sRdr, "must specify either filename= or data= but not both");
goto csvtab_connect_error;
}
- if( nCol<=0 && csv_reader_open(&sRdr, CSV_FILENAME, CSV_DATA) ){
+
+ if( (nCol<=0 || bHeader==1)
+ && csv_reader_open(&sRdr, CSV_FILENAME, CSV_DATA)
+ ){
goto csvtab_connect_error;
}
pNew = sqlite3_malloc( sizeof(*pNew) );
*ppVtab = (sqlite3_vtab*)pNew;
if( pNew==0 ) goto csvtab_connect_oom;
memset(pNew, 0, sizeof(*pNew));
- if( nCol>0 ){
+ if( CSV_SCHEMA==0 ){
+ sqlite3_str *pStr = sqlite3_str_new(0);
+ char *zSep = "";
+ int iCol = 0;
+ sqlite3_str_appendf(pStr, "CREATE TABLE x(");
+ if( nCol<0 && bHeader<1 ){
+ nCol = 0;
+ do{
+ csv_read_one_field(&sRdr);
+ nCol++;
+ }while( sRdr.cTerm==',' );
+ }
+ if( nCol>0 && bHeader<1 ){
+ for(iCol=0; iCol0 && iColnCol = nCol;
- }else{
+ sqlite3_str_appendf(pStr, ")");
+ CSV_SCHEMA = sqlite3_str_finish(pStr);
+ if( CSV_SCHEMA==0 ) goto csvtab_connect_oom;
+ }else if( nCol<0 ){
do{
csv_read_one_field(&sRdr);
pNew->nCol++;
}while( sRdr.cTerm==',' );
+ }else{
+ pNew->nCol = nCol;
}
pNew->zFilename = CSV_FILENAME; CSV_FILENAME = 0;
pNew->zData = CSV_DATA; CSV_DATA = 0;
#ifdef SQLITE_TEST
pNew->tstFlags = tstFlags;
#endif
- pNew->iStart = bHeader==1 ? ftell(sRdr.in) : 0;
- csv_reader_reset(&sRdr);
- if( CSV_SCHEMA==0 ){
- char *zSep = "";
- CSV_SCHEMA = sqlite3_mprintf("CREATE TABLE x(");
- if( CSV_SCHEMA==0 ) goto csvtab_connect_oom;
- for(i=0; inCol; i++){
- CSV_SCHEMA = sqlite3_mprintf("%z%sc%d TEXT",CSV_SCHEMA, zSep, i);
- zSep = ",";
- }
- CSV_SCHEMA = sqlite3_mprintf("%z);", CSV_SCHEMA);
+ if( bHeader!=1 ){
+ pNew->iStart = 0;
+ }else if( pNew->zData ){
+ pNew->iStart = (int)sRdr.iIn;
+ }else{
+ pNew->iStart = ftell(sRdr.in);
}
+ csv_reader_reset(&sRdr);
rc = sqlite3_declare_vtab(db, CSV_SCHEMA);
- if( rc ) goto csvtab_connect_error;
+ if( rc ){
+ csv_errmsg(&sRdr, "bad schema: '%s' - %s", CSV_SCHEMA, sqlite3_errmsg(db));
+ goto csvtab_connect_error;
+ }
for(i=0; i
+#include
+
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+
+/* explain_vtab is a subclass of sqlite3_vtab which will
+** serve as the underlying representation of a explain virtual table
+*/
+typedef struct explain_vtab explain_vtab;
+struct explain_vtab {
+ sqlite3_vtab base; /* Base class - must be first */
+ sqlite3 *db; /* Database connection for this explain vtab */
+};
+
+/* explain_cursor is a subclass of sqlite3_vtab_cursor which will
+** serve as the underlying representation of a cursor that scans
+** over rows of the result from an EXPLAIN operation.
+*/
+typedef struct explain_cursor explain_cursor;
+struct explain_cursor {
+ sqlite3_vtab_cursor base; /* Base class - must be first */
+ sqlite3 *db; /* Database connection for this cursor */
+ char *zSql; /* Value for the EXPLN_COLUMN_SQL column */
+ sqlite3_stmt *pExplain; /* Statement being explained */
+ int rc; /* Result of last sqlite3_step() on pExplain */
+};
+
+/*
+** The explainConnect() method is invoked to create a new
+** explain_vtab that describes the explain virtual table.
+**
+** Think of this routine as the constructor for explain_vtab objects.
+**
+** All this routine needs to do is:
+**
+** (1) Allocate the explain_vtab object and initialize all fields.
+**
+** (2) Tell SQLite (via the sqlite3_declare_vtab() interface) what the
+** result set of queries against explain will look like.
+*/
+static int explainConnect(
+ sqlite3 *db,
+ void *pAux,
+ int argc, const char *const*argv,
+ sqlite3_vtab **ppVtab,
+ char **pzErr
+){
+ explain_vtab *pNew;
+ int rc;
+
+/* Column numbers */
+#define EXPLN_COLUMN_ADDR 0 /* Instruction address */
+#define EXPLN_COLUMN_OPCODE 1 /* Opcode */
+#define EXPLN_COLUMN_P1 2 /* Operand 1 */
+#define EXPLN_COLUMN_P2 3 /* Operand 2 */
+#define EXPLN_COLUMN_P3 4 /* Operand 3 */
+#define EXPLN_COLUMN_P4 5 /* Operand 4 */
+#define EXPLN_COLUMN_P5 6 /* Operand 5 */
+#define EXPLN_COLUMN_COMMENT 7 /* Comment */
+#define EXPLN_COLUMN_SQL 8 /* SQL that is being explained */
+
+
+ rc = sqlite3_declare_vtab(db,
+ "CREATE TABLE x(addr,opcode,p1,p2,p3,p4,p5,comment,sql HIDDEN)");
+ if( rc==SQLITE_OK ){
+ pNew = sqlite3_malloc( sizeof(*pNew) );
+ *ppVtab = (sqlite3_vtab*)pNew;
+ if( pNew==0 ) return SQLITE_NOMEM;
+ memset(pNew, 0, sizeof(*pNew));
+ pNew->db = db;
+ }
+ return rc;
+}
+
+/*
+** This method is the destructor for explain_cursor objects.
+*/
+static int explainDisconnect(sqlite3_vtab *pVtab){
+ sqlite3_free(pVtab);
+ return SQLITE_OK;
+}
+
+/*
+** Constructor for a new explain_cursor object.
+*/
+static int explainOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
+ explain_cursor *pCur;
+ pCur = sqlite3_malloc( sizeof(*pCur) );
+ if( pCur==0 ) return SQLITE_NOMEM;
+ memset(pCur, 0, sizeof(*pCur));
+ pCur->db = ((explain_vtab*)p)->db;
+ *ppCursor = &pCur->base;
+ return SQLITE_OK;
+}
+
+/*
+** Destructor for a explain_cursor.
+*/
+static int explainClose(sqlite3_vtab_cursor *cur){
+ explain_cursor *pCur = (explain_cursor*)cur;
+ sqlite3_finalize(pCur->pExplain);
+ sqlite3_free(pCur->zSql);
+ sqlite3_free(pCur);
+ return SQLITE_OK;
+}
+
+
+/*
+** Advance a explain_cursor to its next row of output.
+*/
+static int explainNext(sqlite3_vtab_cursor *cur){
+ explain_cursor *pCur = (explain_cursor*)cur;
+ pCur->rc = sqlite3_step(pCur->pExplain);
+ if( pCur->rc!=SQLITE_DONE && pCur->rc!=SQLITE_ROW ) return pCur->rc;
+ return SQLITE_OK;
+}
+
+/*
+** Return values of columns for the row at which the explain_cursor
+** is currently pointing.
+*/
+static int explainColumn(
+ sqlite3_vtab_cursor *cur, /* The cursor */
+ sqlite3_context *ctx, /* First argument to sqlite3_result_...() */
+ int i /* Which column to return */
+){
+ explain_cursor *pCur = (explain_cursor*)cur;
+ if( i==EXPLN_COLUMN_SQL ){
+ sqlite3_result_text(ctx, pCur->zSql, -1, SQLITE_TRANSIENT);
+ }else{
+ sqlite3_result_value(ctx, sqlite3_column_value(pCur->pExplain, i));
+ }
+ return SQLITE_OK;
+}
+
+/*
+** Return the rowid for the current row. In this implementation, the
+** rowid is the same as the output value.
+*/
+static int explainRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
+ explain_cursor *pCur = (explain_cursor*)cur;
+ *pRowid = sqlite3_column_int64(pCur->pExplain, 0);
+ return SQLITE_OK;
+}
+
+/*
+** Return TRUE if the cursor has been moved off of the last
+** row of output.
+*/
+static int explainEof(sqlite3_vtab_cursor *cur){
+ explain_cursor *pCur = (explain_cursor*)cur;
+ return pCur->rc!=SQLITE_ROW;
+}
+
+/*
+** This method is called to "rewind" the explain_cursor object back
+** to the first row of output. This method is always called at least
+** once prior to any call to explainColumn() or explainRowid() or
+** explainEof().
+**
+** The argv[0] is the SQL statement that is to be explained.
+*/
+static int explainFilter(
+ sqlite3_vtab_cursor *pVtabCursor,
+ int idxNum, const char *idxStr,
+ int argc, sqlite3_value **argv
+){
+ explain_cursor *pCur = (explain_cursor *)pVtabCursor;
+ char *zSql = 0;
+ int rc;
+ sqlite3_finalize(pCur->pExplain);
+ pCur->pExplain = 0;
+ if( sqlite3_value_type(argv[0])!=SQLITE_TEXT ){
+ pCur->rc = SQLITE_DONE;
+ return SQLITE_OK;
+ }
+ sqlite3_free(pCur->zSql);
+ pCur->zSql = sqlite3_mprintf("%s", sqlite3_value_text(argv[0]));
+ if( pCur->zSql ){
+ zSql = sqlite3_mprintf("EXPLAIN %s", pCur->zSql);
+ }
+ if( zSql==0 ){
+ rc = SQLITE_NOMEM;
+ }else{
+ rc = sqlite3_prepare_v2(pCur->db, zSql, -1, &pCur->pExplain, 0);
+ sqlite3_free(zSql);
+ }
+ if( rc ){
+ sqlite3_finalize(pCur->pExplain);
+ pCur->pExplain = 0;
+ sqlite3_free(pCur->zSql);
+ pCur->zSql = 0;
+ }else{
+ pCur->rc = sqlite3_step(pCur->pExplain);
+ rc = (pCur->rc==SQLITE_DONE || pCur->rc==SQLITE_ROW) ? SQLITE_OK : pCur->rc;
+ }
+ return rc;
+}
+
+/*
+** SQLite will invoke this method one or more times while planning a query
+** that uses the explain virtual table. This routine needs to create
+** a query plan for each invocation and compute an estimated cost for that
+** plan.
+*/
+static int explainBestIndex(
+ sqlite3_vtab *tab,
+ sqlite3_index_info *pIdxInfo
+){
+ int i; /* Loop counter */
+ int idx = -1; /* Index of a usable == constraint against SQL */
+ int unusable = 0; /* True if there are unusable constraints on SQL */
+
+ pIdxInfo->estimatedRows = 500;
+ for(i=0; inConstraint; i++){
+ struct sqlite3_index_constraint *p = &pIdxInfo->aConstraint[i];
+ if( p->iColumn!=EXPLN_COLUMN_SQL ) continue;
+ if( !p->usable ){
+ unusable = 1;
+ }else if( p->op==SQLITE_INDEX_CONSTRAINT_EQ ){
+ idx = i;
+ }
+ }
+ if( idx>=0 ){
+ /* There exists a usable == constraint against the SQL column */
+ pIdxInfo->estimatedCost = 10.0;
+ pIdxInfo->idxNum = 1;
+ pIdxInfo->aConstraintUsage[idx].argvIndex = 1;
+ pIdxInfo->aConstraintUsage[idx].omit = 1;
+ }else if( unusable ){
+ /* There are unusable constraints against the SQL column. Do not allow
+ ** this plan to continue forward. */
+ return SQLITE_CONSTRAINT;
+ }
+ return SQLITE_OK;
+}
+
+/*
+** This following structure defines all the methods for the
+** explain virtual table.
+*/
+static sqlite3_module explainModule = {
+ 0, /* iVersion */
+ 0, /* xCreate */
+ explainConnect, /* xConnect */
+ explainBestIndex, /* xBestIndex */
+ explainDisconnect, /* xDisconnect */
+ 0, /* xDestroy */
+ explainOpen, /* xOpen - open a cursor */
+ explainClose, /* xClose - close a cursor */
+ explainFilter, /* xFilter - configure scan constraints */
+ explainNext, /* xNext - advance a cursor */
+ explainEof, /* xEof - check for end of scan */
+ explainColumn, /* xColumn - read data */
+ explainRowid, /* xRowid - read data */
+ 0, /* xUpdate */
+ 0, /* xBegin */
+ 0, /* xSync */
+ 0, /* xCommit */
+ 0, /* xRollback */
+ 0, /* xFindMethod */
+ 0, /* xRename */
+ 0, /* xSavepoint */
+ 0, /* xRelease */
+ 0, /* xRollbackTo */
+ 0, /* xShadowName */
+};
+
+#endif /* SQLITE_OMIT_VIRTUALTABLE */
+
+int sqlite3ExplainVtabInit(sqlite3 *db){
+ int rc = SQLITE_OK;
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ rc = sqlite3_create_module(db, "explain", &explainModule, 0);
+#endif
+ return rc;
+}
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+int sqlite3_explain_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ int rc = SQLITE_OK;
+ SQLITE_EXTENSION_INIT2(pApi);
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ rc = sqlite3ExplainVtabInit(db);
+#endif
+ return rc;
+}
diff --git a/ext/misc/fileio.c b/ext/misc/fileio.c
index 816a353..3a4fa18 100644
--- a/ext/misc/fileio.c
+++ b/ext/misc/fileio.c
@@ -106,7 +106,18 @@ SQLITE_EXTENSION_INIT1
#include
+/*
+** Structure of the fsdir() table-valued function
+*/
+ /* 0 1 2 3 4 5 */
#define FSDIR_SCHEMA "(name,mode,mtime,data,path HIDDEN,dir HIDDEN)"
+#define FSDIR_COLUMN_NAME 0 /* Name of the file */
+#define FSDIR_COLUMN_MODE 1 /* Access mode */
+#define FSDIR_COLUMN_MTIME 2 /* Last modification time */
+#define FSDIR_COLUMN_DATA 3 /* File content */
+#define FSDIR_COLUMN_PATH 4 /* Path to top of search */
+#define FSDIR_COLUMN_DIR 5 /* Path is relative to this directory */
+
/*
** Set the result stored by context ctx to a blob containing the
@@ -695,20 +706,20 @@ static int fsdirColumn(
){
fsdir_cursor *pCur = (fsdir_cursor*)cur;
switch( i ){
- case 0: { /* name */
+ case FSDIR_COLUMN_NAME: {
sqlite3_result_text(ctx, &pCur->zPath[pCur->nBase], -1, SQLITE_TRANSIENT);
break;
}
- case 1: /* mode */
+ case FSDIR_COLUMN_MODE:
sqlite3_result_int64(ctx, pCur->sStat.st_mode);
break;
- case 2: /* mtime */
+ case FSDIR_COLUMN_MTIME:
sqlite3_result_int64(ctx, pCur->sStat.st_mtime);
break;
- case 3: { /* data */
+ case FSDIR_COLUMN_DATA: {
mode_t m = pCur->sStat.st_mode;
if( S_ISDIR(m) ){
sqlite3_result_null(ctx);
@@ -738,6 +749,12 @@ static int fsdirColumn(
readFileContents(ctx, pCur->zPath);
}
}
+ case FSDIR_COLUMN_PATH:
+ default: {
+ /* The FSDIR_COLUMN_PATH and FSDIR_COLUMN_DIR are input parameters.
+ ** always return their values as NULL */
+ break;
+ }
}
return SQLITE_OK;
}
@@ -764,6 +781,9 @@ static int fsdirEof(sqlite3_vtab_cursor *cur){
/*
** xFilter callback.
+**
+** idxNum==1 PATH parameter only
+** idxNum==2 Both PATH and DIR supplied
*/
static int fsdirFilter(
sqlite3_vtab_cursor *cur,
@@ -816,40 +836,63 @@ static int fsdirFilter(
** In this implementation idxNum is used to represent the
** query plan. idxStr is unused.
**
-** The query plan is represented by bits in idxNum:
+** The query plan is represented by values of idxNum:
**
-** (1) start = $value -- constraint exists
-** (2) stop = $value -- constraint exists
-** (4) step = $value -- constraint exists
-** (8) output in descending order
+** (1) The path value is supplied by argv[0]
+** (2) Path is in argv[0] and dir is in argv[1]
*/
static int fsdirBestIndex(
sqlite3_vtab *tab,
sqlite3_index_info *pIdxInfo
){
int i; /* Loop over constraints */
- int idx4 = -1;
- int idx5 = -1;
+ int idxPath = -1; /* Index in pIdxInfo->aConstraint of PATH= */
+ int idxDir = -1; /* Index in pIdxInfo->aConstraint of DIR= */
+ int seenPath = 0; /* True if an unusable PATH= constraint is seen */
+ int seenDir = 0; /* True if an unusable DIR= constraint is seen */
const struct sqlite3_index_constraint *pConstraint;
(void)tab;
pConstraint = pIdxInfo->aConstraint;
for(i=0; inConstraint; i++, pConstraint++){
- if( pConstraint->usable==0 ) continue;
if( pConstraint->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue;
- if( pConstraint->iColumn==4 ) idx4 = i;
- if( pConstraint->iColumn==5 ) idx5 = i;
+ switch( pConstraint->iColumn ){
+ case FSDIR_COLUMN_PATH: {
+ if( pConstraint->usable ){
+ idxPath = i;
+ seenPath = 0;
+ }else if( idxPath<0 ){
+ seenPath = 1;
+ }
+ break;
+ }
+ case FSDIR_COLUMN_DIR: {
+ if( pConstraint->usable ){
+ idxDir = i;
+ seenDir = 0;
+ }else if( idxDir<0 ){
+ seenDir = 1;
+ }
+ break;
+ }
+ }
+ }
+ if( seenPath || seenDir ){
+ /* If input parameters are unusable, disallow this plan */
+ return SQLITE_CONSTRAINT;
}
- if( idx4<0 ){
+ if( idxPath<0 ){
pIdxInfo->idxNum = 0;
- pIdxInfo->estimatedCost = (double)(((sqlite3_int64)1) << 50);
+ /* The pIdxInfo->estimatedCost should have been initialized to a huge
+ ** number. Leave it unchanged. */
+ pIdxInfo->estimatedRows = 0x7fffffff;
}else{
- pIdxInfo->aConstraintUsage[idx4].omit = 1;
- pIdxInfo->aConstraintUsage[idx4].argvIndex = 1;
- if( idx5>=0 ){
- pIdxInfo->aConstraintUsage[idx5].omit = 1;
- pIdxInfo->aConstraintUsage[idx5].argvIndex = 2;
+ pIdxInfo->aConstraintUsage[idxPath].omit = 1;
+ pIdxInfo->aConstraintUsage[idxPath].argvIndex = 1;
+ if( idxDir>=0 ){
+ pIdxInfo->aConstraintUsage[idxDir].omit = 1;
+ pIdxInfo->aConstraintUsage[idxDir].argvIndex = 2;
pIdxInfo->idxNum = 2;
pIdxInfo->estimatedCost = 10.0;
}else{
@@ -888,7 +931,8 @@ static int fsdirRegister(sqlite3 *db){
0, /* xRename */
0, /* xSavepoint */
0, /* xRelease */
- 0 /* xRollbackTo */
+ 0, /* xRollbackTo */
+ 0, /* xShadowName */
};
int rc = sqlite3_create_module(db, "fsdir", &fsdirModule, 0);
diff --git a/ext/misc/json1.c b/ext/misc/json1.c
index 85b1143..a5b4549 100644
--- a/ext/misc/json1.c
+++ b/ext/misc/json1.c
@@ -1994,6 +1994,9 @@ static int jsonEachConnect(
#define JEACH_PARENT 5
#define JEACH_FULLKEY 6
#define JEACH_PATH 7
+/* The xBestIndex method assumes that the JSON and ROOT columns are
+** the last two columns in the table. Should this ever changes, be
+** sure to update the xBestIndex method. */
#define JEACH_JSON 8
#define JEACH_ROOT 9
@@ -2251,35 +2254,54 @@ static int jsonEachBestIndex(
sqlite3_vtab *tab,
sqlite3_index_info *pIdxInfo
){
- int i;
- int jsonIdx = -1;
- int rootIdx = -1;
+ int i; /* Loop counter or computed array index */
+ int aIdx[2]; /* Index of constraints for JSON and ROOT */
+ int unusableMask = 0; /* Mask of unusable JSON and ROOT constraints */
+ int idxMask = 0; /* Mask of usable == constraints JSON and ROOT */
const struct sqlite3_index_constraint *pConstraint;
+ /* This implementation assumes that JSON and ROOT are the last two
+ ** columns in the table */
+ assert( JEACH_ROOT == JEACH_JSON+1 );
UNUSED_PARAM(tab);
+ aIdx[0] = aIdx[1] = -1;
pConstraint = pIdxInfo->aConstraint;
for(i=0; inConstraint; i++, pConstraint++){
- if( pConstraint->usable==0 ) continue;
- if( pConstraint->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue;
- switch( pConstraint->iColumn ){
- case JEACH_JSON: jsonIdx = i; break;
- case JEACH_ROOT: rootIdx = i; break;
- default: /* no-op */ break;
+ int iCol;
+ int iMask;
+ if( pConstraint->iColumn < JEACH_JSON ) continue;
+ iCol = pConstraint->iColumn - JEACH_JSON;
+ assert( iCol==0 || iCol==1 );
+ iMask = 1 << iCol;
+ if( pConstraint->usable==0 ){
+ unusableMask |= iMask;
+ }else if( pConstraint->op==SQLITE_INDEX_CONSTRAINT_EQ ){
+ aIdx[iCol] = i;
+ idxMask |= iMask;
}
}
- if( jsonIdx<0 ){
+ if( (unusableMask & ~idxMask)!=0 ){
+ /* If there are any unusable constraints on JSON or ROOT, then reject
+ ** this entire plan */
+ return SQLITE_CONSTRAINT;
+ }
+ if( aIdx[0]<0 ){
+ /* No JSON input. Leave estimatedCost at the huge value that it was
+ ** initialized to to discourage the query planner from selecting this
+ ** plan. */
pIdxInfo->idxNum = 0;
- pIdxInfo->estimatedCost = 1e99;
}else{
pIdxInfo->estimatedCost = 1.0;
- pIdxInfo->aConstraintUsage[jsonIdx].argvIndex = 1;
- pIdxInfo->aConstraintUsage[jsonIdx].omit = 1;
- if( rootIdx<0 ){
- pIdxInfo->idxNum = 1;
+ i = aIdx[0];
+ pIdxInfo->aConstraintUsage[i].argvIndex = 1;
+ pIdxInfo->aConstraintUsage[i].omit = 1;
+ if( aIdx[1]<0 ){
+ pIdxInfo->idxNum = 1; /* Only JSON supplied. Plan 1 */
}else{
- pIdxInfo->aConstraintUsage[rootIdx].argvIndex = 2;
- pIdxInfo->aConstraintUsage[rootIdx].omit = 1;
- pIdxInfo->idxNum = 3;
+ i = aIdx[1];
+ pIdxInfo->aConstraintUsage[i].argvIndex = 2;
+ pIdxInfo->aConstraintUsage[i].omit = 1;
+ pIdxInfo->idxNum = 3; /* Both JSON and ROOT are supplied. Plan 3 */
}
}
return SQLITE_OK;
@@ -2388,7 +2410,8 @@ static sqlite3_module jsonEachModule = {
0, /* xRename */
0, /* xSavepoint */
0, /* xRelease */
- 0 /* xRollbackTo */
+ 0, /* xRollbackTo */
+ 0 /* xShadowName */
};
/* The methods of the json_tree virtual table. */
@@ -2415,7 +2438,8 @@ static sqlite3_module jsonTreeModule = {
0, /* xRename */
0, /* xSavepoint */
0, /* xRelease */
- 0 /* xRollbackTo */
+ 0, /* xRollbackTo */
+ 0 /* xShadowName */
};
#endif /* SQLITE_OMIT_VIRTUALTABLE */
diff --git a/ext/misc/memstat.c b/ext/misc/memstat.c
new file mode 100644
index 0000000..dcd5742
--- /dev/null
+++ b/ext/misc/memstat.c
@@ -0,0 +1,428 @@
+/*
+** 2018-09-27
+**
+** 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 demonstrates an eponymous virtual table that returns information
+** from sqlite3_status64() and sqlite3_db_status().
+**
+** Usage example:
+**
+** .load ./memstat
+** .mode quote
+** .header on
+** SELECT * FROM memstat;
+*/
+#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_MEMSTATVTAB)
+#if !defined(SQLITEINT_H)
+#include "sqlite3ext.h"
+#endif
+SQLITE_EXTENSION_INIT1
+#include
+#include
+
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+
+/* memstat_vtab is a subclass of sqlite3_vtab which will
+** serve as the underlying representation of a memstat virtual table
+*/
+typedef struct memstat_vtab memstat_vtab;
+struct memstat_vtab {
+ sqlite3_vtab base; /* Base class - must be first */
+ sqlite3 *db; /* Database connection for this memstat vtab */
+};
+
+/* memstat_cursor is a subclass of sqlite3_vtab_cursor which will
+** serve as the underlying representation of a cursor that scans
+** over rows of the result
+*/
+typedef struct memstat_cursor memstat_cursor;
+struct memstat_cursor {
+ sqlite3_vtab_cursor base; /* Base class - must be first */
+ sqlite3 *db; /* Database connection for this cursor */
+ int iRowid; /* Current row in aMemstatColumn[] */
+ int iDb; /* Which schema we are looking at */
+ int nDb; /* Number of schemas */
+ char **azDb; /* Names of all schemas */
+ sqlite3_int64 aVal[2]; /* Result values */
+};
+
+/*
+** The memstatConnect() method is invoked to create a new
+** memstat_vtab that describes the memstat virtual table.
+**
+** Think of this routine as the constructor for memstat_vtab objects.
+**
+** All this routine needs to do is:
+**
+** (1) Allocate the memstat_vtab object and initialize all fields.
+**
+** (2) Tell SQLite (via the sqlite3_declare_vtab() interface) what the
+** result set of queries against memstat will look like.
+*/
+static int memstatConnect(
+ sqlite3 *db,
+ void *pAux,
+ int argc, const char *const*argv,
+ sqlite3_vtab **ppVtab,
+ char **pzErr
+){
+ memstat_vtab *pNew;
+ int rc;
+
+/* Column numbers */
+#define MSV_COLUMN_NAME 0 /* Name of quantity being measured */
+#define MSV_COLUMN_SCHEMA 1 /* schema name */
+#define MSV_COLUMN_VALUE 2 /* Current value */
+#define MSV_COLUMN_HIWTR 3 /* Highwater mark */
+
+ rc = sqlite3_declare_vtab(db,"CREATE TABLE x(name,schema,value,hiwtr)");
+ if( rc==SQLITE_OK ){
+ pNew = sqlite3_malloc( sizeof(*pNew) );
+ *ppVtab = (sqlite3_vtab*)pNew;
+ if( pNew==0 ) return SQLITE_NOMEM;
+ memset(pNew, 0, sizeof(*pNew));
+ pNew->db = db;
+ }
+ return rc;
+}
+
+/*
+** This method is the destructor for memstat_cursor objects.
+*/
+static int memstatDisconnect(sqlite3_vtab *pVtab){
+ sqlite3_free(pVtab);
+ return SQLITE_OK;
+}
+
+/*
+** Constructor for a new memstat_cursor object.
+*/
+static int memstatOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
+ memstat_cursor *pCur;
+ pCur = sqlite3_malloc( sizeof(*pCur) );
+ if( pCur==0 ) return SQLITE_NOMEM;
+ memset(pCur, 0, sizeof(*pCur));
+ pCur->db = ((memstat_vtab*)p)->db;
+ *ppCursor = &pCur->base;
+ return SQLITE_OK;
+}
+
+/*
+** Clear all the schema names from a cursor
+*/
+static void memstatClearSchema(memstat_cursor *pCur){
+ int i;
+ if( pCur->azDb==0 ) return;
+ for(i=0; inDb; i++){
+ sqlite3_free(pCur->azDb[i]);
+ }
+ sqlite3_free(pCur->azDb);
+ pCur->azDb = 0;
+ pCur->nDb = 0;
+}
+
+/*
+** Fill in the azDb[] array for the cursor.
+*/
+static int memstatFindSchemas(memstat_cursor *pCur){
+ sqlite3_stmt *pStmt = 0;
+ int rc;
+ if( pCur->nDb ) return SQLITE_OK;
+ rc = sqlite3_prepare_v2(pCur->db, "PRAGMA database_list", -1, &pStmt, 0);
+ if( rc ){
+ sqlite3_finalize(pStmt);
+ return rc;
+ }
+ while( sqlite3_step(pStmt)==SQLITE_ROW ){
+ char **az, *z;
+ az = sqlite3_realloc(pCur->azDb, sizeof(char*)*(pCur->nDb+1));
+ if( az==0 ){
+ memstatClearSchema(pCur);
+ return SQLITE_NOMEM;
+ }
+ pCur->azDb = az;
+ z = sqlite3_mprintf("%s", sqlite3_column_text(pStmt, 1));
+ if( z==0 ){
+ memstatClearSchema(pCur);
+ return SQLITE_NOMEM;
+ }
+ pCur->azDb[pCur->nDb] = z;
+ pCur->nDb++;
+ }
+ sqlite3_finalize(pStmt);
+ return SQLITE_OK;
+}
+
+
+/*
+** Destructor for a memstat_cursor.
+*/
+static int memstatClose(sqlite3_vtab_cursor *cur){
+ memstat_cursor *pCur = (memstat_cursor*)cur;
+ memstatClearSchema(pCur);
+ sqlite3_free(cur);
+ return SQLITE_OK;
+}
+
+
+/*
+** Allowed values for aMemstatColumn[].eType
+*/
+#define MSV_GSTAT 0 /* sqlite3_status64() information */
+#define MSV_DB 1 /* sqlite3_db_status() information */
+#define MSV_ZIPVFS 2 /* ZIPVFS file-control with 64-bit return */
+
+/*
+** An array of quantities that can be measured and reported by
+** this virtual table
+*/
+static const struct MemstatColumns {
+ const char *zName; /* Symbolic name */
+ unsigned char eType; /* Type of interface */
+ unsigned char mNull; /* Bitmask of which columns are NULL */
+ /* 2: dbname, 4: current, 8: hiwtr */
+ int eOp; /* Opcode */
+} aMemstatColumn[] = {
+ {"MEMORY_USED", MSV_GSTAT, 2, SQLITE_STATUS_MEMORY_USED },
+ {"MALLOC_SIZE", MSV_GSTAT, 6, SQLITE_STATUS_MALLOC_SIZE },
+ {"MALLOC_COUNT", MSV_GSTAT, 2, SQLITE_STATUS_MALLOC_COUNT },
+ {"PAGECACHE_USED", MSV_GSTAT, 2, SQLITE_STATUS_PAGECACHE_USED },
+ {"PAGECACHE_OVERFLOW", MSV_GSTAT, 2, SQLITE_STATUS_PAGECACHE_OVERFLOW },
+ {"PAGECACHE_SIZE", MSV_GSTAT, 6, SQLITE_STATUS_PAGECACHE_SIZE },
+ {"PARSER_STACK", MSV_GSTAT, 6, SQLITE_STATUS_PARSER_STACK },
+ {"DB_LOOKASIDE_USED", MSV_DB, 2, SQLITE_DBSTATUS_LOOKASIDE_USED },
+ {"DB_LOOKASIDE_HIT", MSV_DB, 6, SQLITE_DBSTATUS_LOOKASIDE_HIT },
+ {"DB_LOOKASIDE_MISS_SIZE", MSV_DB, 6, SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE},
+ {"DB_LOOKASIDE_MISS_FULL", MSV_DB, 6, SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL},
+ {"DB_CACHE_USED", MSV_DB, 10, SQLITE_DBSTATUS_CACHE_USED },
+#if SQLITE_VERSION_NUMBER >= 3140000
+ {"DB_CACHE_USED_SHARED", MSV_DB, 10, SQLITE_DBSTATUS_CACHE_USED_SHARED },
+#endif
+ {"DB_SCHEMA_USED", MSV_DB, 10, SQLITE_DBSTATUS_SCHEMA_USED },
+ {"DB_STMT_USED", MSV_DB, 10, SQLITE_DBSTATUS_STMT_USED },
+ {"DB_CACHE_HIT", MSV_DB, 10, SQLITE_DBSTATUS_CACHE_HIT },
+ {"DB_CACHE_MISS", MSV_DB, 10, SQLITE_DBSTATUS_CACHE_MISS },
+ {"DB_CACHE_WRITE", MSV_DB, 10, SQLITE_DBSTATUS_CACHE_WRITE },
+#if SQLITE_VERSION_NUMBER >= 3230000
+ {"DB_CACHE_SPILL", MSV_DB, 10, SQLITE_DBSTATUS_CACHE_SPILL },
+#endif
+ {"DB_DEFERRED_FKS", MSV_DB, 10, SQLITE_DBSTATUS_DEFERRED_FKS },
+#ifdef SQLITE_ENABLE_ZIPVFS
+ {"ZIPVFS_CACHE_USED", MSV_ZIPVFS, 8, 231454 },
+ {"ZIPVFS_CACHE_HIT", MSV_ZIPVFS, 8, 231455 },
+ {"ZIPVFS_CACHE_MISS", MSV_ZIPVFS, 8, 231456 },
+ {"ZIPVFS_CACHE_WRITE", MSV_ZIPVFS, 8, 231457 },
+ {"ZIPVFS_DIRECT_READ", MSV_ZIPVFS, 8, 231458 },
+ {"ZIPVFS_DIRECT_BYTES", MSV_ZIPVFS, 8, 231459 },
+#endif /* SQLITE_ENABLE_ZIPVFS */
+};
+#define MSV_NROW (sizeof(aMemstatColumn)/sizeof(aMemstatColumn[0]))
+
+/*
+** Advance a memstat_cursor to its next row of output.
+*/
+static int memstatNext(sqlite3_vtab_cursor *cur){
+ memstat_cursor *pCur = (memstat_cursor*)cur;
+ int i;
+ assert( pCur->iRowid<=MSV_NROW );
+ while(1){
+ i = (int)pCur->iRowid - 1;
+ if( i<0 || (aMemstatColumn[i].mNull & 2)!=0 || (++pCur->iDb)>=pCur->nDb ){
+ pCur->iRowid++;
+ if( pCur->iRowid>MSV_NROW ) return SQLITE_OK; /* End of the table */
+ pCur->iDb = 0;
+ i++;
+ }
+ pCur->aVal[0] = 0;
+ pCur->aVal[1] = 0;
+ switch( aMemstatColumn[i].eType ){
+ case MSV_GSTAT: {
+ if( sqlite3_libversion_number()>=3010000 ){
+ sqlite3_status64(aMemstatColumn[i].eOp,
+ &pCur->aVal[0], &pCur->aVal[1],0);
+ }else{
+ int xCur, xHiwtr;
+ sqlite3_status(aMemstatColumn[i].eOp, &xCur, &xHiwtr, 0);
+ pCur->aVal[0] = xCur;
+ pCur->aVal[1] = xHiwtr;
+ }
+ break;
+ }
+ case MSV_DB: {
+ int xCur, xHiwtr;
+ sqlite3_db_status(pCur->db, aMemstatColumn[i].eOp, &xCur, &xHiwtr, 0);
+ pCur->aVal[0] = xCur;
+ pCur->aVal[1] = xHiwtr;
+ break;
+ }
+ case MSV_ZIPVFS: {
+ int rc;
+ rc = sqlite3_file_control(pCur->db, pCur->azDb[pCur->iDb],
+ aMemstatColumn[i].eOp, (void*)&pCur->aVal[0]);
+ if( rc!=SQLITE_OK ) continue;
+ break;
+ }
+ }
+ break;
+ }
+ return SQLITE_OK;
+}
+
+
+/*
+** Return values of columns for the row at which the memstat_cursor
+** is currently pointing.
+*/
+static int memstatColumn(
+ sqlite3_vtab_cursor *cur, /* The cursor */
+ sqlite3_context *ctx, /* First argument to sqlite3_result_...() */
+ int iCol /* Which column to return */
+){
+ memstat_cursor *pCur = (memstat_cursor*)cur;
+ int i;
+ assert( pCur->iRowid>0 && pCur->iRowid<=MSV_NROW );
+ i = (int)pCur->iRowid - 1;
+ if( (aMemstatColumn[i].mNull & (1<azDb[pCur->iDb], -1, 0);
+ break;
+ }
+ case MSV_COLUMN_VALUE: {
+ sqlite3_result_int64(ctx, pCur->aVal[0]);
+ break;
+ }
+ case MSV_COLUMN_HIWTR: {
+ sqlite3_result_int64(ctx, pCur->aVal[1]);
+ break;
+ }
+ }
+ return SQLITE_OK;
+}
+
+/*
+** Return the rowid for the current row. In this implementation, the
+** rowid is the same as the output value.
+*/
+static int memstatRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
+ memstat_cursor *pCur = (memstat_cursor*)cur;
+ *pRowid = pCur->iRowid*1000 + pCur->iDb;
+ return SQLITE_OK;
+}
+
+/*
+** Return TRUE if the cursor has been moved off of the last
+** row of output.
+*/
+static int memstatEof(sqlite3_vtab_cursor *cur){
+ memstat_cursor *pCur = (memstat_cursor*)cur;
+ return pCur->iRowid>MSV_NROW;
+}
+
+/*
+** This method is called to "rewind" the memstat_cursor object back
+** to the first row of output. This method is always called at least
+** once prior to any call to memstatColumn() or memstatRowid() or
+** memstatEof().
+*/
+static int memstatFilter(
+ sqlite3_vtab_cursor *pVtabCursor,
+ int idxNum, const char *idxStr,
+ int argc, sqlite3_value **argv
+){
+ memstat_cursor *pCur = (memstat_cursor *)pVtabCursor;
+ int rc = memstatFindSchemas(pCur);
+ if( rc ) return rc;
+ pCur->iRowid = 0;
+ pCur->iDb = 0;
+ return memstatNext(pVtabCursor);
+}
+
+/*
+** SQLite will invoke this method one or more times while planning a query
+** that uses the memstat virtual table. This routine needs to create
+** a query plan for each invocation and compute an estimated cost for that
+** plan.
+*/
+static int memstatBestIndex(
+ sqlite3_vtab *tab,
+ sqlite3_index_info *pIdxInfo
+){
+ pIdxInfo->estimatedCost = (double)500;
+ pIdxInfo->estimatedRows = 500;
+ return SQLITE_OK;
+}
+
+/*
+** This following structure defines all the methods for the
+** memstat virtual table.
+*/
+static sqlite3_module memstatModule = {
+ 0, /* iVersion */
+ 0, /* xCreate */
+ memstatConnect, /* xConnect */
+ memstatBestIndex, /* xBestIndex */
+ memstatDisconnect, /* xDisconnect */
+ 0, /* xDestroy */
+ memstatOpen, /* xOpen - open a cursor */
+ memstatClose, /* xClose - close a cursor */
+ memstatFilter, /* xFilter - configure scan constraints */
+ memstatNext, /* xNext - advance a cursor */
+ memstatEof, /* xEof - check for end of scan */
+ memstatColumn, /* xColumn - read data */
+ memstatRowid, /* xRowid - read data */
+ 0, /* xUpdate */
+ 0, /* xBegin */
+ 0, /* xSync */
+ 0, /* xCommit */
+ 0, /* xRollback */
+ 0, /* xFindMethod */
+ 0, /* xRename */
+ 0, /* xSavepoint */
+ 0, /* xRelease */
+ 0, /* xRollbackTo */
+ 0, /* xShadowName */
+};
+
+#endif /* SQLITE_OMIT_VIRTUALTABLE */
+
+int sqlite3MemstatVtabInit(sqlite3 *db){
+ int rc = SQLITE_OK;
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ rc = sqlite3_create_module(db, "sqlite_memstat", &memstatModule, 0);
+#endif
+ return rc;
+}
+
+#ifndef SQLITE_CORE
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+int sqlite3_memstat_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ int rc = SQLITE_OK;
+ SQLITE_EXTENSION_INIT2(pApi);
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ rc = sqlite3MemstatVtabInit(db);
+#endif
+ return rc;
+}
+#endif /* SQLITE_CORE */
+#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_MEMSTATVTAB) */
diff --git a/ext/misc/series.c b/ext/misc/series.c
index 3df0a37..86309dd 100644
--- a/ext/misc/series.c
+++ b/ext/misc/series.c
@@ -313,44 +313,45 @@ static int seriesBestIndex(
sqlite3_vtab *tab,
sqlite3_index_info *pIdxInfo
){
- int i; /* Loop over constraints */
+ int i, j; /* Loop over constraints */
int idxNum = 0; /* The query plan bitmask */
- int startIdx = -1; /* Index of the start= constraint, or -1 if none */
- int stopIdx = -1; /* Index of the stop= constraint, or -1 if none */
- int stepIdx = -1; /* Index of the step= constraint, or -1 if none */
+ int unusableMask = 0; /* Mask of unusable constraints */
int nArg = 0; /* Number of arguments that seriesFilter() expects */
-
+ int aIdx[3]; /* Constraints on start, stop, and step */
const struct sqlite3_index_constraint *pConstraint;
+
+ /* This implementation assumes that the start, stop, and step columns
+ ** are the last three columns in the virtual table. */
+ assert( SERIES_COLUMN_STOP == SERIES_COLUMN_START+1 );
+ assert( SERIES_COLUMN_STEP == SERIES_COLUMN_START+2 );
+ aIdx[0] = aIdx[1] = aIdx[2] = -1;
pConstraint = pIdxInfo->aConstraint;
for(i=0; inConstraint; i++, pConstraint++){
- if( pConstraint->usable==0 ) continue;
- if( pConstraint->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue;
- switch( pConstraint->iColumn ){
- case SERIES_COLUMN_START:
- startIdx = i;
- idxNum |= 1;
- break;
- case SERIES_COLUMN_STOP:
- stopIdx = i;
- idxNum |= 2;
- break;
- case SERIES_COLUMN_STEP:
- stepIdx = i;
- idxNum |= 4;
- break;
+ int iCol; /* 0 for start, 1 for stop, 2 for step */
+ int iMask; /* bitmask for those column */
+ if( pConstraint->iColumniColumn - SERIES_COLUMN_START;
+ assert( iCol>=0 && iCol<=2 );
+ iMask = 1 << iCol;
+ if( pConstraint->usable==0 ){
+ unusableMask |= iMask;
+ continue;
+ }else if( pConstraint->op==SQLITE_INDEX_CONSTRAINT_EQ ){
+ idxNum |= iMask;
+ aIdx[iCol] = i;
}
}
- if( startIdx>=0 ){
- pIdxInfo->aConstraintUsage[startIdx].argvIndex = ++nArg;
- pIdxInfo->aConstraintUsage[startIdx].omit= !SQLITE_SERIES_CONSTRAINT_VERIFY;
+ for(i=0; i<3; i++){
+ if( (j = aIdx[i])>=0 ){
+ pIdxInfo->aConstraintUsage[j].argvIndex = ++nArg;
+ pIdxInfo->aConstraintUsage[j].omit = !SQLITE_SERIES_CONSTRAINT_VERIFY;
+ }
}
- if( stopIdx>=0 ){
- pIdxInfo->aConstraintUsage[stopIdx].argvIndex = ++nArg;
- pIdxInfo->aConstraintUsage[stopIdx].omit = !SQLITE_SERIES_CONSTRAINT_VERIFY;
- }
- if( stepIdx>=0 ){
- pIdxInfo->aConstraintUsage[stepIdx].argvIndex = ++nArg;
- pIdxInfo->aConstraintUsage[stepIdx].omit = !SQLITE_SERIES_CONSTRAINT_VERIFY;
+ if( (unusableMask & ~idxNum)!=0 ){
+ /* The start, stop, and step columns are inputs. Therefore if there
+ ** are unusable constraints on any of start, stop, or step then
+ ** this plan is unusable */
+ return SQLITE_CONSTRAINT;
}
if( (idxNum & 3)==3 ){
/* Both start= and stop= boundaries are available. This is the
@@ -365,7 +366,6 @@ static int seriesBestIndex(
/* If either boundary is missing, we have to generate a huge span
** of numbers. Make this case very expensive so that the query
** planner will work hard to avoid it. */
- pIdxInfo->estimatedCost = (double)2147483647;
pIdxInfo->estimatedRows = 2147483647;
}
pIdxInfo->idxNum = idxNum;
diff --git a/ext/misc/sha1.c b/ext/misc/sha1.c
index e2843bd..886b1db 100644
--- a/ext/misc/sha1.c
+++ b/ext/misc/sha1.c
@@ -10,7 +10,7 @@
**
******************************************************************************
**
-** This SQLite extension implements a functions that compute SHA1 hashes.
+** This SQLite extension implements functions that compute SHA1 hashes.
** Two SQL functions are implemented:
**
** sha1(X)
diff --git a/ext/misc/shathree.c b/ext/misc/shathree.c
index e5c9540..e35fa49 100644
--- a/ext/misc/shathree.c
+++ b/ext/misc/shathree.c
@@ -10,7 +10,7 @@
**
******************************************************************************
**
-** This SQLite extension implements a functions that compute SHA1 hashes.
+** This SQLite extension implements functions that compute SHA3 hashes.
** Two SQL functions are implemented:
**
** sha3(X,SIZE)
diff --git a/ext/misc/spellfix.c b/ext/misc/spellfix.c
index faceea1..81bef13 100644
--- a/ext/misc/spellfix.c
+++ b/ext/misc/spellfix.c
@@ -1295,6 +1295,9 @@ typedef struct Transliteration Transliteration;
struct Transliteration {
unsigned short int cFrom;
unsigned char cTo0, cTo1, cTo2, cTo3;
+#ifdef SQLITE_SPELLFIX_5BYTE_MAPPINGS
+ unsigned char cTo4;
+#endif
};
/*
@@ -1708,7 +1711,11 @@ static const Transliteration *spellfixFindTranslit(int c, int *pxTop){
** should be freed by the caller.
*/
static unsigned char *transliterate(const unsigned char *zIn, int nIn){
+#ifdef SQLITE_SPELLFIX_5BYTE_MAPPINGS
+ unsigned char *zOut = sqlite3_malloc64( nIn*5 + 1 );
+#else
unsigned char *zOut = sqlite3_malloc64( nIn*4 + 1 );
+#endif
int c, sz, nOut;
if( zOut==0 ) return 0;
nOut = 0;
@@ -1732,6 +1739,11 @@ static unsigned char *transliterate(const unsigned char *zIn, int nIn){
zOut[nOut++] = tbl[x].cTo2;
if( tbl[x].cTo3 ){
zOut[nOut++] = tbl[x].cTo3;
+#ifdef SQLITE_SPELLFIX_5BYTE_MAPPINGS
+ if( tbl[x].cTo4 ){
+ zOut[nOut++] = tbl[x].cTo4;
+ }
+#endif /* SQLITE_SPELLFIX_5BYTE_MAPPINGS */
}
}
}
diff --git a/ext/misc/stmt.c b/ext/misc/stmt.c
index dbaa0bd..d2b33e7 100644
--- a/ext/misc/stmt.c
+++ b/ext/misc/stmt.c
@@ -266,6 +266,7 @@ static sqlite3_module stmtModule = {
0, /* xSavepoint */
0, /* xRelease */
0, /* xRollbackTo */
+ 0, /* xShadowName */
};
#endif /* SQLITE_OMIT_VIRTUALTABLE */
diff --git a/ext/misc/templatevtab.c b/ext/misc/templatevtab.c
index 95b5f60..d7efa2b 100644
--- a/ext/misc/templatevtab.c
+++ b/ext/misc/templatevtab.c
@@ -248,7 +248,8 @@ static sqlite3_module templatevtabModule = {
/* xRename */ 0,
/* xSavepoint */ 0,
/* xRelease */ 0,
- /* xRollbackTo */ 0
+ /* xRollbackTo */ 0,
+ /* xShadowName */ 0
};
diff --git a/ext/misc/unionvtab.c b/ext/misc/unionvtab.c
index 94a5c8f..2d2053c 100644
--- a/ext/misc/unionvtab.c
+++ b/ext/misc/unionvtab.c
@@ -1350,7 +1350,8 @@ static int createUnionVtab(sqlite3 *db){
0, /* xRename */
0, /* xSavepoint */
0, /* xRelease */
- 0 /* xRollbackTo */
+ 0, /* xRollbackTo */
+ 0 /* xShadowName */
};
int rc;
diff --git a/ext/misc/vtablog.c b/ext/misc/vtablog.c
index 9e03fd4..424b345 100644
--- a/ext/misc/vtablog.c
+++ b/ext/misc/vtablog.c
@@ -492,6 +492,7 @@ static sqlite3_module vtablogModule = {
0, /* xSavepoint */
0, /* xRelease */
0, /* xRollbackTo */
+ 0, /* xShadowName */
};
#ifdef _WIN32
diff --git a/ext/misc/zipfile.c b/ext/misc/zipfile.c
index 9f2258e..e57dc38 100644
--- a/ext/misc/zipfile.c
+++ b/ext/misc/zipfile.c
@@ -1296,25 +1296,26 @@ static int zipfileBestIndex(
sqlite3_index_info *pIdxInfo
){
int i;
+ int idx = -1;
+ int unusable = 0;
for(i=0; inConstraint; i++){
const struct sqlite3_index_constraint *pCons = &pIdxInfo->aConstraint[i];
- if( pCons->usable==0 ) continue;
- if( pCons->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue;
if( pCons->iColumn!=ZIPFILE_F_COLUMN_IDX ) continue;
- break;
+ if( pCons->usable==0 ){
+ unusable = 1;
+ }else if( pCons->op==SQLITE_INDEX_CONSTRAINT_EQ ){
+ idx = i;
+ }
}
-
- if( inConstraint ){
- pIdxInfo->aConstraintUsage[i].argvIndex = 1;
- pIdxInfo->aConstraintUsage[i].omit = 1;
+ if( idx>=0 ){
+ pIdxInfo->aConstraintUsage[idx].argvIndex = 1;
+ pIdxInfo->aConstraintUsage[idx].omit = 1;
pIdxInfo->estimatedCost = 1000.0;
pIdxInfo->idxNum = 1;
- }else{
- pIdxInfo->estimatedCost = (double)(((sqlite3_int64)1) << 50);
- pIdxInfo->idxNum = 0;
+ }else if( unusable ){
+ return SQLITE_CONSTRAINT;
}
-
return SQLITE_OK;
}
diff --git a/ext/rbu/rbu1.test b/ext/rbu/rbu1.test
index 1d16c1c..7ec075b 100644
--- a/ext/rbu/rbu1.test
+++ b/ext/rbu/rbu1.test
@@ -670,4 +670,3 @@ foreach {tn3 create_vfs destroy_vfs} {
finish_test
-
diff --git a/ext/rbu/rbu10.test b/ext/rbu/rbu10.test
index 4b398b6..a7c63cf 100644
--- a/ext/rbu/rbu10.test
+++ b/ext/rbu/rbu10.test
@@ -185,4 +185,3 @@ do_test 4.3 {
finish_test
-
diff --git a/ext/rbu/rbu11.test b/ext/rbu/rbu11.test
index fdc701a..5a4219b 100644
--- a/ext/rbu/rbu11.test
+++ b/ext/rbu/rbu11.test
@@ -195,4 +195,3 @@ do_test 4.7.2 {
} {1 {SQLITE_ERROR - rbu_state mismatch error}}
finish_test
-
diff --git a/ext/rbu/rbu12.test b/ext/rbu/rbu12.test
index a83d089..7816bfe 100644
--- a/ext/rbu/rbu12.test
+++ b/ext/rbu/rbu12.test
@@ -232,4 +232,3 @@ do_multiclient_test tn {
}
finish_test
-
diff --git a/ext/rbu/rbu13.test b/ext/rbu/rbu13.test
index ad67a98..624c587 100644
--- a/ext/rbu/rbu13.test
+++ b/ext/rbu/rbu13.test
@@ -62,4 +62,3 @@ do_execsql_test 1.4 {
finish_test
-
diff --git a/ext/rbu/rbu14.test b/ext/rbu/rbu14.test
index d4f97ac..07f6784 100644
--- a/ext/rbu/rbu14.test
+++ b/ext/rbu/rbu14.test
@@ -92,4 +92,3 @@ foreach {tn schema} {
finish_test
-
diff --git a/ext/rbu/rbu3.test b/ext/rbu/rbu3.test
index 995b312..da87561 100644
--- a/ext/rbu/rbu3.test
+++ b/ext/rbu/rbu3.test
@@ -203,5 +203,3 @@ do_test 5.3 {
do_test 6.1 { sqlite3rbu_internal_test } {}
finish_test
-
-
diff --git a/ext/rbu/rbu5.test b/ext/rbu/rbu5.test
index 8e4ae8c..3696dfb 100644
--- a/ext/rbu/rbu5.test
+++ b/ext/rbu/rbu5.test
@@ -300,7 +300,3 @@ foreach {tn idx} {
finish_test
-
-
-
-
diff --git a/ext/rbu/rbu6.test b/ext/rbu/rbu6.test
index f057215..bb5b17f 100644
--- a/ext/rbu/rbu6.test
+++ b/ext/rbu/rbu6.test
@@ -100,4 +100,3 @@ for {set nStep 8} {$nStep < 20} {incr nStep} {
finish_test
-
diff --git a/ext/rbu/rbu7.test b/ext/rbu/rbu7.test
index f773c9e..1e3bc17 100644
--- a/ext/rbu/rbu7.test
+++ b/ext/rbu/rbu7.test
@@ -106,5 +106,3 @@ foreach {tn tbl} {
}
finish_test
-
-
diff --git a/ext/rbu/rbu8.test b/ext/rbu/rbu8.test
index 75edd4e..c0ccd8c 100644
--- a/ext/rbu/rbu8.test
+++ b/ext/rbu/rbu8.test
@@ -72,4 +72,3 @@ integrity_check 1.3.3
finish_test
-
diff --git a/ext/rbu/rbu9.test b/ext/rbu/rbu9.test
index 3ce649d..0efdc1d 100644
--- a/ext/rbu/rbu9.test
+++ b/ext/rbu/rbu9.test
@@ -125,4 +125,3 @@ foreach {tn idx} {
finish_test
-
diff --git a/ext/rbu/rbuA.test b/ext/rbu/rbuA.test
index 286194c..642caca 100644
--- a/ext/rbu/rbuA.test
+++ b/ext/rbu/rbuA.test
@@ -80,4 +80,3 @@ do_test 2.2 {
finish_test
-
diff --git a/ext/rbu/rbuB.test b/ext/rbu/rbuB.test
index c007fb7..ece51c3 100644
--- a/ext/rbu/rbuB.test
+++ b/ext/rbu/rbuB.test
@@ -59,4 +59,3 @@ sqlite3_shutdown
test_sqlite3_log
sqlite3_initialize
finish_test
-
diff --git a/ext/rbu/rbuC.test b/ext/rbu/rbuC.test
index 89fd015..ff3d4d5 100644
--- a/ext/rbu/rbuC.test
+++ b/ext/rbu/rbuC.test
@@ -139,4 +139,3 @@ foreach {tn schema} {
finish_test
-
diff --git a/ext/rbu/rbucollate.test b/ext/rbu/rbucollate.test
index 3b3b022..ccc0976 100644
--- a/ext/rbu/rbucollate.test
+++ b/ext/rbu/rbucollate.test
@@ -60,4 +60,3 @@ do_test 1.2 {
#forcedelete testrbu.db
finish_test
-
diff --git a/ext/rbu/rbucrash.test b/ext/rbu/rbucrash.test
index f422181..34ac2c8 100644
--- a/ext/rbu/rbucrash.test
+++ b/ext/rbu/rbucrash.test
@@ -145,4 +145,3 @@ for {set nPre 0} {$nPre < $rbu_num_steps} {incr nPre} {
}
finish_test
-
diff --git a/ext/rbu/rbucrash2.test b/ext/rbu/rbucrash2.test
index 5f2ba60..9ff6eba 100644
--- a/ext/rbu/rbucrash2.test
+++ b/ext/rbu/rbucrash2.test
@@ -103,4 +103,3 @@ for {set x 1} {$x < 2} {incr x} {
}
finish_test
-
diff --git a/ext/rbu/rbudiff.test b/ext/rbu/rbudiff.test
index 6f6af82..965ce29 100644
--- a/ext/rbu/rbudiff.test
+++ b/ext/rbu/rbudiff.test
@@ -300,4 +300,3 @@ tablE t1 USING FTs5(c);
finish_test
-
diff --git a/ext/rbu/rbudor.test b/ext/rbu/rbudor.test
index dcee7ac..df4d934 100644
--- a/ext/rbu/rbudor.test
+++ b/ext/rbu/rbudor.test
@@ -56,4 +56,3 @@ do_execsql_test 1.4 {
} [list 1 $bigA 2 $bigB]
finish_test
-
diff --git a/ext/rbu/rbufault.test b/ext/rbu/rbufault.test
index 3e78b6e..247a991 100644
--- a/ext/rbu/rbufault.test
+++ b/ext/rbu/rbufault.test
@@ -234,4 +234,3 @@ foreach {tn2 setup sql expect} {
}
finish_test
-
diff --git a/ext/rbu/rbufault2.test b/ext/rbu/rbufault2.test
index ec89397..5b006f7 100644
--- a/ext/rbu/rbufault2.test
+++ b/ext/rbu/rbufault2.test
@@ -55,4 +55,3 @@ do_faultsim_test 1 -faults oom* -prep {
finish_test
-
diff --git a/ext/rbu/rbufault3.test b/ext/rbu/rbufault3.test
index 4fd202d..5d44885 100644
--- a/ext/rbu/rbufault3.test
+++ b/ext/rbu/rbufault3.test
@@ -95,4 +95,3 @@ foreach {fault errlist} {
}
finish_test
-
diff --git a/ext/rbu/rbufault4.test b/ext/rbu/rbufault4.test
index fe6cc90..551b8b2 100644
--- a/ext/rbu/rbufault4.test
+++ b/ext/rbu/rbufault4.test
@@ -63,4 +63,3 @@ for {set tn 1} {1} {incr tn} {
finish_test
-
diff --git a/ext/rbu/rbufts.test b/ext/rbu/rbufts.test
index c2821a9..95d4e75 100644
--- a/ext/rbu/rbufts.test
+++ b/ext/rbu/rbufts.test
@@ -131,4 +131,3 @@ do_test 3.3 {
finish_test
-
diff --git a/ext/rbu/rbumulti.test b/ext/rbu/rbumulti.test
index 59c6538..5579a5f 100644
--- a/ext/rbu/rbumulti.test
+++ b/ext/rbu/rbumulti.test
@@ -172,4 +172,3 @@ for {set i 0} {$i<=3} {incr i} {
finish_test
-
diff --git a/ext/rbu/rbuprogress.test b/ext/rbu/rbuprogress.test
index 078b3b0..db479e3 100644
--- a/ext/rbu/rbuprogress.test
+++ b/ext/rbu/rbuprogress.test
@@ -416,4 +416,3 @@ foreach {bReopen} { 0 1 } {
finish_test
-
diff --git a/ext/rbu/rburesume.test b/ext/rbu/rburesume.test
index d03894e..a2cf9bc 100644
--- a/ext/rbu/rburesume.test
+++ b/ext/rbu/rburesume.test
@@ -251,4 +251,3 @@ for {set n 1} {$n < 5000} {incr n} {
}
finish_test
-
diff --git a/ext/rbu/rbusave.test b/ext/rbu/rbusave.test
index 1bb71a8..210d7b5 100644
--- a/ext/rbu/rbusave.test
+++ b/ext/rbu/rbusave.test
@@ -102,4 +102,3 @@ do_execsql_test 1.5 {
} {1 one 1 3 3 3 4 4 4 1 one 1 3 3 3 4 4 4}
finish_test
-
diff --git a/ext/rbu/rbusplit.test b/ext/rbu/rbusplit.test
index 678f388..34fef38 100644
--- a/ext/rbu/rbusplit.test
+++ b/ext/rbu/rbusplit.test
@@ -92,4 +92,3 @@ foreach {tn cmd} {
}
finish_test
-
diff --git a/ext/rbu/rbutemplimit.test b/ext/rbu/rbutemplimit.test
index 274f870..9397b56 100644
--- a/ext/rbu/rbutemplimit.test
+++ b/ext/rbu/rbutemplimit.test
@@ -126,4 +126,3 @@ do_test 1.6.1 {
do_test 1.6.2 { info commands rbu } {}
finish_test
-
diff --git a/ext/rbu/rbuvacuum.test b/ext/rbu/rbuvacuum.test
index dba0ef3..1785f52 100644
--- a/ext/rbu/rbuvacuum.test
+++ b/ext/rbu/rbuvacuum.test
@@ -397,4 +397,3 @@ do_test 3.5 {
catch { db close }
finish_test
-
diff --git a/ext/rbu/rbuvacuum2.test b/ext/rbu/rbuvacuum2.test
index 0a1fe3d..4713580 100644
--- a/ext/rbu/rbuvacuum2.test
+++ b/ext/rbu/rbuvacuum2.test
@@ -232,4 +232,3 @@ do_test 6.3 {
} {ok}
finish_test
-
diff --git a/ext/rbu/sqlite3rbu.c b/ext/rbu/sqlite3rbu.c
index 065b13c..cd2f96c 100644
--- a/ext/rbu/sqlite3rbu.c
+++ b/ext/rbu/sqlite3rbu.c
@@ -405,7 +405,8 @@ struct rbu_vfs {
sqlite3_vfs *pRealVfs; /* Underlying VFS */
sqlite3_mutex *mutex; /* Mutex to protect pMain */
sqlite3rbu *pRbu; /* Owner RBU object */
- rbu_file *pMain; /* Linked list of main db files */
+ rbu_file *pMain; /* List of main db files */
+ rbu_file *pMainRbu; /* List of main db files with pRbu!=0 */
};
/*
@@ -434,6 +435,7 @@ struct rbu_file {
const char *zWal; /* Wal filename for this main db file */
rbu_file *pWalFd; /* Wal file descriptor for this main db */
rbu_file *pMainNext; /* Next MAIN_DB file */
+ rbu_file *pMainRbuNext; /* Next MAIN_DB file with pRbu!=0 */
};
/*
@@ -4030,6 +4032,69 @@ static int rbuUpdateTempSize(rbu_file *pFd, sqlite3_int64 nNew){
return SQLITE_OK;
}
+/*
+** Add an item to the main-db lists, if it is not already present.
+**
+** There are two main-db lists. One for all file descriptors, and one
+** for all file descriptors with rbu_file.pDb!=0. If the argument has
+** rbu_file.pDb!=0, then it is assumed to already be present on the
+** main list and is only added to the pDb!=0 list.
+*/
+static void rbuMainlistAdd(rbu_file *p){
+ rbu_vfs *pRbuVfs = p->pRbuVfs;
+ rbu_file *pIter;
+ assert( (p->openFlags & SQLITE_OPEN_MAIN_DB) );
+ sqlite3_mutex_enter(pRbuVfs->mutex);
+ if( p->pRbu==0 ){
+ for(pIter=pRbuVfs->pMain; pIter; pIter=pIter->pMainNext);
+ p->pMainNext = pRbuVfs->pMain;
+ pRbuVfs->pMain = p;
+ }else{
+ for(pIter=pRbuVfs->pMainRbu; pIter && pIter!=p; pIter=pIter->pMainRbuNext){}
+ if( pIter==0 ){
+ p->pMainRbuNext = pRbuVfs->pMainRbu;
+ pRbuVfs->pMainRbu = p;
+ }
+ }
+ sqlite3_mutex_leave(pRbuVfs->mutex);
+}
+
+/*
+** Remove an item from the main-db lists.
+*/
+static void rbuMainlistRemove(rbu_file *p){
+ rbu_file **pp;
+ sqlite3_mutex_enter(p->pRbuVfs->mutex);
+ for(pp=&p->pRbuVfs->pMain; *pp && *pp!=p; pp=&((*pp)->pMainNext)){}
+ if( *pp ) *pp = p->pMainNext;
+ p->pMainNext = 0;
+ for(pp=&p->pRbuVfs->pMainRbu; *pp && *pp!=p; pp=&((*pp)->pMainRbuNext)){}
+ if( *pp ) *pp = p->pMainRbuNext;
+ p->pMainRbuNext = 0;
+ sqlite3_mutex_leave(p->pRbuVfs->mutex);
+}
+
+/*
+** Given that zWal points to a buffer containing a wal file name passed to
+** either the xOpen() or xAccess() VFS method, search the main-db list for
+** a file-handle opened by the same database connection on the corresponding
+** database file.
+**
+** If parameter bRbu is true, only search for file-descriptors with
+** rbu_file.pDb!=0.
+*/
+static rbu_file *rbuFindMaindb(rbu_vfs *pRbuVfs, const char *zWal, int bRbu){
+ rbu_file *pDb;
+ sqlite3_mutex_enter(pRbuVfs->mutex);
+ if( bRbu ){
+ for(pDb=pRbuVfs->pMainRbu; pDb && pDb->zWal!=zWal; pDb=pDb->pMainRbuNext){}
+ }else{
+ for(pDb=pRbuVfs->pMain; pDb && pDb->zWal!=zWal; pDb=pDb->pMainNext){}
+ }
+ sqlite3_mutex_leave(pRbuVfs->mutex);
+ return pDb;
+}
+
/*
** Close an rbu file.
*/
@@ -4047,17 +4112,14 @@ static int rbuVfsClose(sqlite3_file *pFile){
sqlite3_free(p->zDel);
if( p->openFlags & SQLITE_OPEN_MAIN_DB ){
- rbu_file **pp;
- sqlite3_mutex_enter(p->pRbuVfs->mutex);
- for(pp=&p->pRbuVfs->pMain; *pp!=p; pp=&((*pp)->pMainNext));
- *pp = p->pMainNext;
- sqlite3_mutex_leave(p->pRbuVfs->mutex);
+ rbuMainlistRemove(p);
rbuUnlockShm(p);
p->pReal->pMethods->xShmUnmap(p->pReal, 0);
}
else if( (p->openFlags & SQLITE_OPEN_DELETEONCLOSE) && p->pRbu ){
rbuUpdateTempSize(p, 0);
}
+ assert( p->pMainNext==0 && p->pRbuVfs->pMain!=p );
/* Close the underlying file handle */
rc = p->pReal->pMethods->xClose(p->pReal);
@@ -4316,6 +4378,9 @@ static int rbuVfsFileControl(sqlite3_file *pFile, int op, void *pArg){
}else if( rc==SQLITE_NOTFOUND ){
pRbu->pTargetFd = p;
p->pRbu = pRbu;
+ if( p->openFlags & SQLITE_OPEN_MAIN_DB ){
+ rbuMainlistAdd(p);
+ }
if( p->pWalFd ) p->pWalFd->pRbu = pRbu;
rc = SQLITE_OK;
}
@@ -4477,20 +4542,6 @@ static int rbuVfsShmUnmap(sqlite3_file *pFile, int delFlag){
return rc;
}
-/*
-** Given that zWal points to a buffer containing a wal file name passed to
-** either the xOpen() or xAccess() VFS method, return a pointer to the
-** file-handle opened by the same database connection on the corresponding
-** database file.
-*/
-static rbu_file *rbuFindMaindb(rbu_vfs *pRbuVfs, const char *zWal){
- rbu_file *pDb;
- sqlite3_mutex_enter(pRbuVfs->mutex);
- for(pDb=pRbuVfs->pMain; pDb && pDb->zWal!=zWal; pDb=pDb->pMainNext){}
- sqlite3_mutex_leave(pRbuVfs->mutex);
- return pDb;
-}
-
/*
** A main database named zName has just been opened. The following
** function returns a pointer to a buffer owned by SQLite that contains
@@ -4569,7 +4620,7 @@ static int rbuVfsOpen(
pFd->zWal = rbuMainToWal(zName, flags);
}
else if( flags & SQLITE_OPEN_WAL ){
- rbu_file *pDb = rbuFindMaindb(pRbuVfs, zName);
+ rbu_file *pDb = rbuFindMaindb(pRbuVfs, zName, 0);
if( pDb ){
if( pDb->pRbu && pDb->pRbu->eStage==RBU_STAGE_OAL ){
/* This call is to open a *-wal file. Intead, open the *-oal. This
@@ -4621,10 +4672,7 @@ static int rbuVfsOpen(
** mutex protected linked list of all such files. */
pFile->pMethods = &rbuvfs_io_methods;
if( flags & SQLITE_OPEN_MAIN_DB ){
- sqlite3_mutex_enter(pRbuVfs->mutex);
- pFd->pMainNext = pRbuVfs->pMain;
- pRbuVfs->pMain = pFd;
- sqlite3_mutex_leave(pRbuVfs->mutex);
+ rbuMainlistAdd(pFd);
}
}else{
sqlite3_free(pFd->zDel);
@@ -4672,7 +4720,7 @@ static int rbuVfsAccess(
** file opened instead.
*/
if( rc==SQLITE_OK && flags==SQLITE_ACCESS_EXISTS ){
- rbu_file *pDb = rbuFindMaindb(pRbuVfs, zPath);
+ rbu_file *pDb = rbuFindMaindb(pRbuVfs, zPath, 1);
if( pDb && pDb->pRbu && pDb->pRbu->eStage==RBU_STAGE_OAL ){
if( *pResOut ){
rc = SQLITE_CANTOPEN;
diff --git a/ext/repair/test/checkindex01.test b/ext/repair/test/checkindex01.test
index 2593039..97973ae 100644
--- a/ext/repair/test/checkindex01.test
+++ b/ext/repair/test/checkindex01.test
@@ -347,5 +347,3 @@ do_index_check_test 7.3 t7i3 {
do_index_check_test 7.4 t7i4 {
{} 1,1 {} 3,3
}
-
-
diff --git a/ext/rtree/geopoly.c b/ext/rtree/geopoly.c
index a34ca12..f6a31f5 100644
--- a/ext/rtree/geopoly.c
+++ b/ext/rtree/geopoly.c
@@ -106,14 +106,24 @@ typedef float GeoCoord;
**
** encoding (1 byte) 0=big-endian, 1=little-endian
** nvertex (3 bytes) Number of vertexes as a big-endian integer
+**
+** Enough space is allocated for 4 coordinates, to work around over-zealous
+** warnings coming from some compiler (notably, clang). In reality, the size
+** of each GeoPoly memory allocate is adjusted as necessary so that the
+** GeoPoly.a[] array at the end is the appropriate size.
*/
typedef struct GeoPoly GeoPoly;
struct GeoPoly {
int nVertex; /* Number of vertexes */
unsigned char hdr[4]; /* Header for on-disk representation */
- GeoCoord a[2]; /* 2*nVertex values. X (longitude) first, then Y */
+ GeoCoord a[8]; /* 2*nVertex values. X (longitude) first, then Y */
};
+/* The size of a memory allocation needed for a GeoPoly object sufficient
+** to hold N coordinate pairs.
+*/
+#define GEOPOLY_SZ(N) (sizeof(GeoPoly) + sizeof(GeoCoord)*2*((N)-4))
+
/*
** State of a parse of a GeoJSON input.
*/
@@ -138,7 +148,7 @@ static void geopolySwab32(unsigned char *a){
/* Skip whitespace. Return the next non-whitespace character. */
static char geopolySkipSpace(GeoParse *p){
- while( p->z[0] && safe_isspace(p->z[0]) ) p->z++;
+ while( safe_isspace(p->z[0]) ) p->z++;
return p->z[0];
}
@@ -158,7 +168,7 @@ static int geopolyParseNumber(GeoParse *p, GeoCoord *pVal){
if( c=='0' && z[j+1]>='0' && z[j+1]<='9' ) return 0;
for(;; j++){
c = z[j];
- if( c>='0' && c<='9' ) continue;
+ if( safe_isdigit(c) ) continue;
if( c=='.' ){
if( z[j-1]=='-' ) return 0;
if( seenDP ) return 0;
@@ -180,7 +190,17 @@ static int geopolyParseNumber(GeoParse *p, GeoCoord *pVal){
break;
}
if( z[j-1]<'0' ) return 0;
- if( pVal ) *pVal = (GeoCoord)atof((const char*)p->z);
+ if( pVal ){
+#ifdef SQLITE_AMALGAMATION
+ /* The sqlite3AtoF() routine is much much faster than atof(), if it
+ ** is available */
+ double r;
+ (void)sqlite3AtoF((const char*)p->z, &r, j, SQLITE_UTF8);
+ *pVal = r;
+#else
+ *pVal = (GeoCoord)atof((const char*)p->z);
+#endif
+ }
p->z += j;
return 1;
}
@@ -238,12 +258,10 @@ static GeoPoly *geopolyParseJson(const unsigned char *z, int *pRc){
&& s.a[1]==s.a[s.nVertex*2-1]
&& (s.z++, geopolySkipSpace(&s)==0)
){
- int nByte;
GeoPoly *pOut;
int x = 1;
s.nVertex--; /* Remove the redundant vertex at the end */
- nByte = sizeof(GeoPoly) * s.nVertex*2*sizeof(GeoCoord);
- pOut = sqlite3_malloc64( nByte );
+ pOut = sqlite3_malloc64( GEOPOLY_SZ(s.nVertex) );
x = 1;
if( pOut==0 ) goto parse_json_err;
pOut->nVertex = s.nVertex;
@@ -446,6 +464,27 @@ static void geopolyXformFunc(
}
}
+/*
+** Compute the area enclosed by the polygon.
+**
+** This routine can also be used to detect polygons that rotate in
+** the wrong direction. Polygons are suppose to be counter-clockwise (CCW).
+** This routine returns a negative value for clockwise (CW) polygons.
+*/
+static double geopolyArea(GeoPoly *p){
+ double rArea = 0.0;
+ int ii;
+ for(ii=0; iinVertex-1; ii++){
+ rArea += (p->a[ii*2] - p->a[ii*2+2]) /* (x0 - x1) */
+ * (p->a[ii*2+1] + p->a[ii*2+3]) /* (y0 + y1) */
+ * 0.5;
+ }
+ rArea += (p->a[ii*2] - p->a[0]) /* (xN - x0) */
+ * (p->a[ii*2+1] + p->a[1]) /* (yN + y0) */
+ * 0.5;
+ return rArea;
+}
+
/*
** Implementation of the geopoly_area(X) function.
**
@@ -461,21 +500,106 @@ static void geopolyAreaFunc(
){
GeoPoly *p = geopolyFuncParam(context, argv[0], 0);
if( p ){
- double rArea = 0.0;
- int ii;
- for(ii=0; iinVertex-1; ii++){
- rArea += (p->a[ii*2] - p->a[ii*2+2]) /* (x0 - x1) */
- * (p->a[ii*2+1] + p->a[ii*2+3]) /* (y0 + y1) */
- * 0.5;
- }
- rArea += (p->a[ii*2] - p->a[0]) /* (xN - x0) */
- * (p->a[ii*2+1] + p->a[1]) /* (yN + y0) */
- * 0.5;
- sqlite3_result_double(context, rArea);
+ sqlite3_result_double(context, geopolyArea(p));
sqlite3_free(p);
}
}
+/*
+** Implementation of the geopoly_ccw(X) function.
+**
+** If the rotation of polygon X is clockwise (incorrect) instead of
+** counter-clockwise (the correct winding order according to RFC7946)
+** then reverse the order of the vertexes in polygon X.
+**
+** In other words, this routine returns a CCW polygon regardless of the
+** winding order of its input.
+**
+** Use this routine to sanitize historical inputs that that sometimes
+** contain polygons that wind in the wrong direction.
+*/
+static void geopolyCcwFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ GeoPoly *p = geopolyFuncParam(context, argv[0], 0);
+ if( p ){
+ if( geopolyArea(p)<0.0 ){
+ int ii, jj;
+ for(ii=2, jj=p->nVertex*2 - 2; iia[ii];
+ p->a[ii] = p->a[jj];
+ p->a[jj] = t;
+ t = p->a[ii+1];
+ p->a[ii+1] = p->a[jj+1];
+ p->a[jj+1] = t;
+ }
+ }
+ sqlite3_result_blob(context, p->hdr,
+ 4+8*p->nVertex, SQLITE_TRANSIENT);
+ sqlite3_free(p);
+ }
+}
+
+#define GEOPOLY_PI 3.1415926535897932385
+
+/* Fast approximation for sine(X) for X between -0.5*pi and 2*pi
+*/
+static double geopolySine(double r){
+ assert( r>=-0.5*GEOPOLY_PI && r<=2.0*GEOPOLY_PI );
+ if( r>=1.5*GEOPOLY_PI ){
+ r -= 2.0*GEOPOLY_PI;
+ }
+ if( r>=0.5*GEOPOLY_PI ){
+ return -geopolySine(r-GEOPOLY_PI);
+ }else{
+ double r2 = r*r;
+ double r3 = r2*r;
+ double r5 = r3*r2;
+ return 0.9996949*r - 0.1656700*r3 + 0.0075134*r5;
+ }
+}
+
+/*
+** Function: geopoly_regular(X,Y,R,N)
+**
+** Construct a simple, convex, regular polygon centered at X, Y
+** with circumradius R and with N sides.
+*/
+static void geopolyRegularFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ double x = sqlite3_value_double(argv[0]);
+ double y = sqlite3_value_double(argv[1]);
+ double r = sqlite3_value_double(argv[2]);
+ int n = sqlite3_value_int(argv[3]);
+ int i;
+ GeoPoly *p;
+
+ if( n<3 || r<=0.0 ) return;
+ if( n>1000 ) n = 1000;
+ p = sqlite3_malloc64( sizeof(*p) + (n-1)*2*sizeof(GeoCoord) );
+ if( p==0 ){
+ sqlite3_result_error_nomem(context);
+ return;
+ }
+ i = 1;
+ p->hdr[0] = *(unsigned char*)&i;
+ p->hdr[1] = 0;
+ p->hdr[2] = (n>>8)&0xff;
+ p->hdr[3] = n&0xff;
+ for(i=0; ia[i*2] = x - r*geopolySine(rAngle-0.5*GEOPOLY_PI);
+ p->a[i*2+1] = y + r*geopolySine(rAngle);
+ }
+ sqlite3_result_blob(context, p->hdr, 4+8*n, SQLITE_TRANSIENT);
+ sqlite3_free(p);
+}
+
/*
** If pPoly is a polygon, compute its bounding box. Then:
**
@@ -520,7 +644,7 @@ static GeoPoly *geopolyBBox(
if( pRc ) *pRc = SQLITE_OK;
if( aCoord==0 ){
geopolyBboxFill:
- pOut = sqlite3_realloc(p, sizeof(GeoPoly)+sizeof(GeoCoord)*6);
+ pOut = sqlite3_realloc(p, GEOPOLY_SZ(4));
if( pOut==0 ){
sqlite3_free(p);
if( context ) sqlite3_result_error_nomem(context);
@@ -1548,7 +1672,16 @@ static int geopolyUpdate(
if( sqlite3_value_nochange(aData[2]) ){
sqlite3_bind_null(pUp, 2);
}else{
- sqlite3_bind_value(pUp, 2, aData[2]);
+ GeoPoly *p = 0;
+ if( sqlite3_value_type(aData[2])==SQLITE_TEXT
+ && (p = geopolyFuncParam(0, aData[2], &rc))!=0
+ && rc==SQLITE_OK
+ ){
+ sqlite3_bind_blob(pUp, 2, p->hdr, 4+8*p->nVertex, SQLITE_TRANSIENT);
+ }else{
+ sqlite3_bind_value(pUp, 2, aData[2]);
+ }
+ sqlite3_free(p);
nChange = 1;
}
for(jj=1; jjnAux; jj++){
@@ -1592,7 +1725,7 @@ static int geopolyFindFunction(
static sqlite3_module geopolyModule = {
- 2, /* iVersion */
+ 3, /* iVersion */
geopolyCreate, /* xCreate - create a table */
geopolyConnect, /* xConnect - connect to an existing table */
geopolyBestIndex, /* xBestIndex - Determine search strategy */
@@ -1615,25 +1748,29 @@ static sqlite3_module geopolyModule = {
rtreeSavepoint, /* xSavepoint */
0, /* xRelease */
0, /* xRollbackTo */
+ rtreeShadowName /* xShadowName */
};
static int sqlite3_geopoly_init(sqlite3 *db){
int rc = SQLITE_OK;
static const struct {
void (*xFunc)(sqlite3_context*,int,sqlite3_value**);
- int nArg;
+ signed char nArg;
+ unsigned char bPure;
const char *zName;
} aFunc[] = {
- { geopolyAreaFunc, 1, "geopoly_area" },
- { geopolyBlobFunc, 1, "geopoly_blob" },
- { geopolyJsonFunc, 1, "geopoly_json" },
- { geopolySvgFunc, -1, "geopoly_svg" },
- { geopolyWithinFunc, 2, "geopoly_within" },
- { geopolyContainsPointFunc, 3, "geopoly_contains_point" },
- { geopolyOverlapFunc, 2, "geopoly_overlap" },
- { geopolyDebugFunc, 1, "geopoly_debug" },
- { geopolyBBoxFunc, 1, "geopoly_bbox" },
- { geopolyXformFunc, 7, "geopoly_xform" },
+ { geopolyAreaFunc, 1, 1, "geopoly_area" },
+ { geopolyBlobFunc, 1, 1, "geopoly_blob" },
+ { geopolyJsonFunc, 1, 1, "geopoly_json" },
+ { geopolySvgFunc, -1, 1, "geopoly_svg" },
+ { geopolyWithinFunc, 2, 1, "geopoly_within" },
+ { geopolyContainsPointFunc, 3, 1, "geopoly_contains_point" },
+ { geopolyOverlapFunc, 2, 1, "geopoly_overlap" },
+ { geopolyDebugFunc, 1, 0, "geopoly_debug" },
+ { geopolyBBoxFunc, 1, 1, "geopoly_bbox" },
+ { geopolyXformFunc, 7, 1, "geopoly_xform" },
+ { geopolyRegularFunc, 4, 1, "geopoly_regular" },
+ { geopolyCcwFunc, 1, 1, "geopoly_ccw" },
};
static const struct {
void (*xStep)(sqlite3_context*,int,sqlite3_value**);
@@ -1644,8 +1781,9 @@ static int sqlite3_geopoly_init(sqlite3 *db){
};
int i;
for(i=0; i'
+.print 'Regular Polygons
'
+.print ''
+
.print '