aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordan <dan@noemail.net>2020-07-13 18:04:27 +0000
committerdan <dan@noemail.net>2020-07-13 18:04:27 +0000
commita7f82d9f47ca75a2f47dc14f8a8deb6730d718d0 (patch)
treee2000d1d8b1b14297c1a8790c65dd90c4a20e2b9
parent7465787b97a0a09841e343630a07ba80f1399e4a (diff)
parent5b107654e965973e68c88f90a09a3cc53bac9d8b (diff)
downloadsqlite-a7f82d9f47ca75a2f47dc14f8a8deb6730d718d0.tar.gz
sqlite-a7f82d9f47ca75a2f47dc14f8a8deb6730d718d0.zip
Merge latest trunk changes with this branch.
FossilOrigin-Name: 5ee3c27e20d12a126fb773b428bb864102b949a5b26a8d5c523753dcedf4be10
-rw-r--r--Makefile.in33
-rw-r--r--Makefile.msc60
-rw-r--r--VERSION2
-rw-r--r--autoconf/Makefile.am2
-rw-r--r--autoconf/Makefile.msc2
-rwxr-xr-xconfigure22
-rw-r--r--configure.ac4
-rw-r--r--doc/lemon.html39
-rw-r--r--doc/wal-lock.md88
-rw-r--r--ext/async/sqlite3async.c1
-rw-r--r--ext/async/sqlite3async.h1
-rw-r--r--ext/expert/sqlite3expert.c29
-rw-r--r--ext/fts3/README.content2
-rw-r--r--ext/fts3/fts3.c31
-rw-r--r--ext/fts3/fts3_snippet.c2
-rw-r--r--ext/fts3/fts3_write.c34
-rw-r--r--ext/fts3/tool/fts3view.c4
-rw-r--r--ext/fts5/fts5_index.c4
-rw-r--r--ext/fts5/test/fts5corrupt3.test215
-rw-r--r--ext/icu/README.txt3
-rw-r--r--ext/icu/sqliteicu.h1
-rw-r--r--ext/lsm1/lsm-test/lsmtest1.c2
-rw-r--r--ext/lsm1/lsm-test/lsmtest8.c2
-rw-r--r--ext/lsm1/lsm-test/lsmtest9.c3
-rw-r--r--ext/lsm1/lsm-test/lsmtest_bt.c4
-rw-r--r--ext/lsm1/lsm-test/lsmtest_tdb.c2
-rw-r--r--ext/lsm1/lsm-test/lsmtest_tdb2.cc1
-rw-r--r--ext/lsm1/lsm-test/lsmtest_tdb4.c2
-rw-r--r--ext/lsm1/lsm_unix.c9
-rw-r--r--ext/misc/btreeinfo.c12
-rw-r--r--ext/misc/cksumvfs.c797
-rw-r--r--ext/misc/completion.c4
-rw-r--r--ext/misc/dbdump.c14
-rw-r--r--ext/misc/decimal.c619
-rw-r--r--ext/misc/explain.c2
-rw-r--r--ext/misc/ieee754.c182
-rw-r--r--ext/misc/json1.c1
-rw-r--r--ext/misc/mmapwarm.c2
-rw-r--r--ext/misc/scrub.c4
-rw-r--r--ext/misc/sqlar.c1
-rw-r--r--ext/misc/stmt.c3
-rw-r--r--ext/misc/uint.c1
-rw-r--r--ext/misc/vfsstat.c2
-rw-r--r--ext/rbu/sqlite3rbu.c36
-rw-r--r--ext/repair/checkindex.c2
-rw-r--r--ext/rtree/geopoly.c2
-rw-r--r--ext/session/session_common.tcl4
-rw-r--r--ext/session/sessioninvert.test24
-rw-r--r--ext/session/sqlite3session.c6
-rw-r--r--main.mk29
-rw-r--r--manifest368
-rw-r--r--manifest.uuid2
-rw-r--r--src/alter.c71
-rw-r--r--src/analyze.c239
-rw-r--r--src/backup.c2
-rw-r--r--src/btree.c116
-rw-r--r--src/btree.h4
-rw-r--r--src/btreeInt.h6
-rw-r--r--src/build.c236
-rw-r--r--src/ctime.c6
-rw-r--r--src/date.c6
-rw-r--r--src/dbstat.c4
-rw-r--r--src/delete.c3
-rw-r--r--src/expr.c157
-rw-r--r--src/func.c7
-rw-r--r--src/global.c5
-rw-r--r--src/insert.c4
-rw-r--r--src/loadext.c10
-rw-r--r--src/main.c203
-rw-r--r--src/malloc.c12
-rw-r--r--src/mem3.c148
-rw-r--r--src/memdb.c13
-rw-r--r--src/mutex_unix.c2
-rw-r--r--src/mutex_w32.c2
-rw-r--r--src/notify.c16
-rw-r--r--src/os.c8
-rw-r--r--src/os_unix.c58
-rw-r--r--src/os_win.c41
-rw-r--r--src/pager.c379
-rw-r--r--src/pager.h25
-rw-r--r--src/parse.y57
-rw-r--r--src/pragma.c43
-rw-r--r--src/pragma.h96
-rw-r--r--src/prepare.c40
-rw-r--r--src/printf.c20
-rw-r--r--src/resolve.c14
-rw-r--r--src/select.c278
-rw-r--r--src/shell.c.in642
-rw-r--r--src/sqlite.h.in88
-rw-r--r--src/sqliteInt.h87
-rw-r--r--src/table.c4
-rw-r--r--src/tclsqlite.c13
-rw-r--r--src/test1.c6
-rw-r--r--src/test4.c4
-rw-r--r--src/test8.c2
-rw-r--r--src/test_multiplex.c2
-rw-r--r--src/test_mutex.c2
-rw-r--r--src/test_osinst.c4
-rw-r--r--src/test_schema.c6
-rw-r--r--src/test_sqllog.c16
-rw-r--r--src/treeview.c8
-rw-r--r--src/trigger.c15
-rw-r--r--src/update.c14
-rw-r--r--src/utf.c20
-rw-r--r--src/util.c3
-rw-r--r--src/vacuum.c16
-rw-r--r--src/vdbe.c91
-rw-r--r--src/vdbe.h3
-rw-r--r--src/vdbeInt.h14
-rw-r--r--src/vdbeapi.c39
-rw-r--r--src/vdbeaux.c465
-rw-r--r--src/vdbevtab.c424
-rw-r--r--src/vtab.c18
-rw-r--r--src/wal.c418
-rw-r--r--src/wal.h5
-rw-r--r--src/walker.c37
-rw-r--r--src/where.c2
-rw-r--r--src/window.c50
-rw-r--r--test/aggnested.test47
-rw-r--r--test/alter.test1
-rw-r--r--test/alter3.test1
-rw-r--r--test/alter4.test2
-rw-r--r--test/altertab.test18
-rw-r--r--test/atrc.c2
-rw-r--r--test/busy2.test132
-rw-r--r--test/corruptL.test109
-rw-r--r--test/cost.test4
-rw-r--r--test/count.test38
-rw-r--r--test/cursorhint.test8
-rw-r--r--test/dbfuzz2.c2
-rw-r--r--test/decimal.test142
-rw-r--r--test/distinct.test4
-rw-r--r--test/e_expr.test50
-rw-r--r--test/e_fkey.test4
-rw-r--r--test/filter1.test18
-rw-r--r--test/fkey2.test3
-rw-r--r--test/fkey5.test55
-rw-r--r--test/fordelete.test2
-rw-r--r--test/fts3corrupt2.test2
-rw-r--r--test/fts3corrupt4.test435
-rw-r--r--test/fts3corrupt6.test60
-rw-r--r--test/fts3matchinfo2.test35
-rw-r--r--test/fts3snippet.test13
-rw-r--r--test/fts3snippet2.test60
-rw-r--r--test/fuzzdata8.dbbin1476608 -> 1526784 bytes
-rw-r--r--test/gencol1.test26
-rw-r--r--test/ieee754.test4
-rw-r--r--test/index7.test12
-rw-r--r--test/indexedby.test26
-rw-r--r--test/istrue.test29
-rw-r--r--test/kvtest.c2
-rw-r--r--test/mutex1.test10
-rw-r--r--test/optfuzz-db01.c1
-rw-r--r--test/permutations.test6
-rw-r--r--test/printf.test15
-rw-r--r--test/select3.test9
-rw-r--r--test/selectA.test21
-rw-r--r--test/shell1.test16
-rw-r--r--test/speedtest1.c282
-rw-r--r--test/stat.test30
-rw-r--r--test/tkt-3fe897352e.test8
-rw-r--r--test/tt3_stress.c8
-rw-r--r--test/wal.test1
-rw-r--r--test/walsetlk.test198
-rw-r--r--test/where.test8
-rw-r--r--test/where9.test14
-rw-r--r--test/whereG.test11
-rw-r--r--test/win32longpath.test31
-rw-r--r--test/window1.test338
-rw-r--r--test/window9.test4
-rw-r--r--test/without_rowid3.test21
-rw-r--r--tool/dbhash.c6
-rw-r--r--tool/fast_vacuum.c18
-rw-r--r--tool/index_usage.c10
-rw-r--r--tool/lemon.c143
-rw-r--r--tool/mkautoconfamal.sh5
-rw-r--r--tool/mkpragmatab.tcl5
-rw-r--r--tool/mksqlite3c.tcl3
-rw-r--r--tool/mksqlite3h.tcl2
-rw-r--r--tool/offsets.c2
-rw-r--r--tool/showdb.c4
-rw-r--r--tool/showlocks.c63
-rw-r--r--tool/spaceanal.tcl18
-rw-r--r--tool/speed-check.sh4
-rw-r--r--tool/sqldiff.c32
-rw-r--r--vsixtest/App.xaml.cpp2
186 files changed, 7991 insertions, 2274 deletions
diff --git a/Makefile.in b/Makefile.in
index 01e3bed6e..3fc984cff 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -190,7 +190,8 @@ LIBOBJS0 = alter.lo analyze.lo attach.lo auth.lo \
table.lo threads.lo tokenize.lo treeview.lo trigger.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 \
+ vdbetrace.lo vdbevtab.lo \
+ wal.lo walker.lo where.lo wherecode.lo whereexpr.lo \
window.lo utf.lo vtab.lo
# Object files for the amalgamation.
@@ -296,6 +297,7 @@ SRC = \
$(TOP)/src/vdbemem.c \
$(TOP)/src/vdbesort.c \
$(TOP)/src/vdbetrace.c \
+ $(TOP)/src/vdbevtab.c \
$(TOP)/src/vdbeInt.h \
$(TOP)/src/vtab.c \
$(TOP)/src/vxworks.h \
@@ -441,6 +443,7 @@ TESTSRC += \
$(TOP)/ext/misc/carray.c \
$(TOP)/ext/misc/closure.c \
$(TOP)/ext/misc/csv.c \
+ $(TOP)/ext/misc/decimal.c \
$(TOP)/ext/misc/eval.c \
$(TOP)/ext/misc/explain.c \
$(TOP)/ext/misc/fileio.c \
@@ -502,6 +505,7 @@ TESTSRC2 = \
$(TOP)/src/vdbe.c \
$(TOP)/src/vdbemem.c \
$(TOP)/src/vdbetrace.c \
+ $(TOP)/src/vdbevtab.c \
$(TOP)/src/where.c \
$(TOP)/src/wherecode.c \
$(TOP)/src/whereexpr.c \
@@ -607,6 +611,7 @@ SHELL_OPT += -DSQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
SHELL_OPT += -DSQLITE_ENABLE_STMTVTAB
SHELL_OPT += -DSQLITE_ENABLE_DBPAGE_VTAB
SHELL_OPT += -DSQLITE_ENABLE_DBSTAT_VTAB
+SHELL_OPT += -DSQLITE_ENABLE_BYTECODE_VTAB
SHELL_OPT += -DSQLITE_ENABLE_OFFSET_SQL_FUNC
SHELL_OPT += -DSQLITE_ENABLE_DESERIALIZE
FUZZERSHELL_OPT = -DSQLITE_ENABLE_JSON1
@@ -615,10 +620,12 @@ FUZZCHECK_OPT += -DSQLITE_MAX_MEMORY=50000000
FUZZCHECK_OPT += -DSQLITE_PRINTF_PRECISION_LIMIT=1000
FUZZCHECK_OPT += -DSQLITE_ENABLE_DESERIALIZE
FUZZCHECK_OPT += -DSQLITE_ENABLE_FTS4
+FUZZCHECK_OPT += -DSQLITE_ENABLE_FTS3_PARENTHESIS
#FUZZCHECK_OPT += -DSQLITE_ENABLE_FTS5
FUZZCHECK_OPT += -DSQLITE_ENABLE_RTREE
FUZZCHECK_OPT += -DSQLITE_ENABLE_GEOPOLY
FUZZCHECK_OPT += -DSQLITE_ENABLE_DBSTAT_VTAB
+FUZZCHECK_OPT += -DSQLITE_ENABLE_BYTECODE_VTAB
FUZZCHECK_SRC = $(TOP)/test/fuzzcheck.c $(TOP)/test/ossfuzz.c
DBFUZZ_OPT =
@@ -688,6 +695,7 @@ DBFUZZ2_OPTS = \
-DSQLITE_ENABLE_DESERIALIZE \
-DSQLITE_DEBUG \
-DSQLITE_ENABLE_DBSTAT_VTAB \
+ -DSQLITE_ENABLE_BYTECODE_VTAB \
-DSQLITE_ENABLE_RTREE \
-DSQLITE_ENABLE_FTS4 \
-DSQLITE_ENABLE_FTS5
@@ -1004,6 +1012,9 @@ vdbesort.lo: $(TOP)/src/vdbesort.c $(HDR)
vdbetrace.lo: $(TOP)/src/vdbetrace.c $(HDR)
$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/vdbetrace.c
+vdbevtab.lo: $(TOP)/src/vdbevtab.c $(HDR)
+ $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/vdbevtab.c
+
vtab.lo: $(TOP)/src/vtab.c $(HDR)
$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/vtab.c
@@ -1057,6 +1068,12 @@ parse.c: $(TOP)/src/parse.y lemon$(BEXE)
sqlite3.h: $(TOP)/src/sqlite.h.in $(TOP)/manifest mksourceid$(BEXE) $(TOP)/VERSION
$(TCLSH_CMD) $(TOP)/tool/mksqlite3h.tcl $(TOP) >sqlite3.h
+sqlite3rc.h: $(TOP)/src/sqlite3.rc $(TOP)/VERSION
+ echo '#ifndef SQLITE_RESOURCE_VERSION' >$@
+ echo -n '#define SQLITE_RESOURCE_VERSION ' >>$@
+ cat $(TOP)/VERSION | $(TCLSH_CMD) $(TOP)/tool/replace.tcl exact . , >>$@
+ echo '#endif' >>sqlite3rc.h
+
keywordhash.h: $(TOP)/tool/mkkeywordhash.c
$(BCC) -o mkkeywordhash$(BEXE) $(OPT_FEATURE_FLAGS) $(OPTS) $(TOP)/tool/mkkeywordhash.c
./mkkeywordhash$(BEXE) >keywordhash.h
@@ -1065,9 +1082,11 @@ keywordhash.h: $(TOP)/tool/mkkeywordhash.c
SHELL_SRC = \
$(TOP)/src/shell.c.in \
$(TOP)/ext/misc/appendvfs.c \
- $(TOP)/ext/misc/shathree.c \
- $(TOP)/ext/misc/fileio.c \
$(TOP)/ext/misc/completion.c \
+ $(TOP)/ext/misc/decimal.c \
+ $(TOP)/ext/misc/fileio.c \
+ $(TOP)/ext/misc/ieee754.c \
+ $(TOP)/ext/misc/shathree.c \
$(TOP)/ext/misc/sqlar.c \
$(TOP)/ext/misc/uint.c \
$(TOP)/ext/expert/sqlite3expert.c \
@@ -1211,6 +1230,7 @@ TESTFIXTURE_FLAGS += -DSQLITE_SERIES_CONSTRAINT_VERIFY=1
TESTFIXTURE_FLAGS += -DSQLITE_DEFAULT_PAGE_SIZE=1024
TESTFIXTURE_FLAGS += -DSQLITE_ENABLE_STMTVTAB
TESTFIXTURE_FLAGS += -DSQLITE_ENABLE_DBPAGE_VTAB
+TESTFIXTURE_FLAGS += -DSQLITE_ENABLE_BYTECODE_VTAB
TESTFIXTURE_FLAGS += -DSQLITE_ENABLE_DESERIALIZE
TESTFIXTURE_SRC0 = $(TESTSRC2) libsqlite3.la
@@ -1275,6 +1295,9 @@ valgrindtest: $(TESTPROGS) valgrindfuzz
smoketest: $(TESTPROGS) fuzzcheck$(TEXE)
./testfixture$(TEXE) $(TOP)/test/main.test $(TESTOPTS)
+shelltest: $(TESTPROGS)
+ ./testfixture$(TEXT) $(TOP)/test/permutations.test shell
+
sqlite3_analyzer.c: sqlite3.c $(TOP)/src/tclsqlite.c $(TOP)/tool/spaceanal.tcl $(TOP)/tool/mkccode.tcl $(TOP)/tool/sqlite3_analyzer.c.in
$(TCLSH_CMD) $(TOP)/tool/mkccode.tcl $(TOP)/tool/sqlite3_analyzer.c.in >sqlite3_analyzer.c
@@ -1377,10 +1400,10 @@ checksymbols: sqlite3.o
# a tarball named for the version number. Ex: sqlite-autoconf-3110000.tar.gz.
# The snapshot-tarball target builds a tarball named by the SHA1 hash
#
-amalgamation-tarball: sqlite3.c
+amalgamation-tarball: sqlite3.c sqlite3rc.h
TOP=$(TOP) sh $(TOP)/tool/mkautoconfamal.sh --normal
-snapshot-tarball: sqlite3.c
+snapshot-tarball: sqlite3.c sqlite3rc.h
TOP=$(TOP) sh $(TOP)/tool/mkautoconfamal.sh --snapshot
# The next two rules are used to support the "threadtest" target. Building
diff --git a/Makefile.msc b/Makefile.msc
index 90944e845..47857d9d8 100644
--- a/Makefile.msc
+++ b/Makefile.msc
@@ -234,6 +234,15 @@ OSTRACE = 0
DEBUG = 0
!ENDIF
+# <<mark>>
+# Disable use of the --linemacros argument to the mksqlite3c.tcl tool, which
+# is used to build the amalgamation.
+#
+!IFNDEF NO_LINEMACROS
+NO_LINEMACROS = 0
+!ENDIF
+# <</mark>>
+
# Enable use of available compiler optimizations? Normally, this should be
# non-zero. Setting this to zero, thus disabling all compiler optimizations,
# can be useful for testing.
@@ -357,6 +366,7 @@ OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_JSON1=1
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_ENABLE_BYTECODE_VTAB=1
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_DESERIALIZE=1
!ENDIF
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_COLUMN_METADATA=1
@@ -775,7 +785,7 @@ MKSQLITE3C_TOOL = $(TOP)\tool\mksqlite3c.tcl
!ENDIF
!IFNDEF MKSQLITE3C_ARGS
-!IF $(DEBUG)>1
+!IF $(DEBUG)>1 && $(NO_LINEMACROS)==0
MKSQLITE3C_ARGS = --linemacros
!ELSE
MKSQLITE3C_ARGS =
@@ -1246,7 +1256,8 @@ LIBOBJS0 = vdbe.lo parse.lo alter.lo analyze.lo attach.lo auth.lo \
table.lo threads.lo tokenize.lo treeview.lo trigger.lo \
update.lo upsert.lo util.lo vacuum.lo \
vdbeapi.lo vdbeaux.lo vdbeblob.lo vdbemem.lo vdbesort.lo \
- vdbetrace.lo wal.lo walker.lo where.lo wherecode.lo whereexpr.lo \
+ vdbetrace.lo vdbevtab.lo wal.lo walker.lo where.lo wherecode.lo \
+ whereexpr.lo \
window.lo utf.lo vtab.lo
# <</mark>>
@@ -1353,6 +1364,7 @@ SRC01 = \
$(TOP)\src\vdbemem.c \
$(TOP)\src\vdbesort.c \
$(TOP)\src\vdbetrace.c \
+ $(TOP)\src\vdbevtab.c \
$(TOP)\src\vtab.c \
$(TOP)\src\wal.c \
$(TOP)\src\walker.c \
@@ -1483,7 +1495,7 @@ SRC12 =
# All source code files.
#
-SRC = $(SRC00) $(SRC01) $(SRC03) $(SRC04) $(SRC05) $(SRC06) $(SRC07) $(SRC08) $(SRC09) $(SRC10) $(SRC11)
+SRC = $(SRC00) $(SRC01) $(SRC03) $(SRC04) $(SRC05) $(SRC06) $(SRC07) $(SRC08) $(SRC09) $(SRC10) $(SRC11) $(SRC12)
# Source code to the test files.
#
@@ -1548,6 +1560,7 @@ TESTEXT = \
$(TOP)\ext\misc\carray.c \
$(TOP)\ext\misc\closure.c \
$(TOP)\ext\misc\csv.c \
+ $(TOP)\ext\misc\decimal.c \
$(TOP)\ext\misc\eval.c \
$(TOP)\ext\misc\explain.c \
$(TOP)\ext\misc\fileio.c \
@@ -1684,6 +1697,7 @@ FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_FTS4
FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_RTREE
FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_GEOPOLY
FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_DBSTAT_VTAB
+FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_BYTECODE_VTAB
FUZZCHECK_SRC = $(TOP)\test\fuzzcheck.c $(TOP)\test\ossfuzz.c
OSSSHELL_SRC = $(TOP)\test\ossshell.c $(TOP)\test\ossfuzz.c
@@ -1833,15 +1847,16 @@ mptest: mptester.exe
for %i in ($(SRC11)) do copy /Y %i tsrc
for %i in ($(SRC12)) do copy /Y %i tsrc
copy /Y fts5.c tsrc
+ copy /B tsrc\fts5.c +,,
copy /Y fts5.h tsrc
+ copy /B tsrc\fts5.h +,,
del /Q tsrc\sqlite.h.in tsrc\parse.y 2>NUL
$(TCLSH_CMD) $(TOP)\tool\vdbe-compress.tcl $(OPTS) < tsrc\vdbe.c > vdbe.new
move vdbe.new tsrc\vdbe.c
echo > .target_source
-sqlite3.c: .target_source sqlite3ext.h $(MKSQLITE3C_TOOL)
+sqlite3.c: .target_source sqlite3ext.h sqlite3session.h $(MKSQLITE3C_TOOL)
$(TCLSH_CMD) $(MKSQLITE3C_TOOL) $(MKSQLITE3C_ARGS)
- copy $(TOP)\ext\session\sqlite3session.h .
sqlite3-all.c: sqlite3.c $(TOP)\tool\split-sqlite3c.tcl
$(TCLSH_CMD) $(TOP)\tool\split-sqlite3c.tcl
@@ -1856,7 +1871,8 @@ sqlite3.lo: $(SQLITE3C)
# Rules to build the LEMON compiler generator
#
lempar.c: $(TOP)\tool\lempar.c
- copy $(TOP)\tool\lempar.c .
+ copy /Y $(TOP)\tool\lempar.c .
+ copy /B lempar.c +,,
lemon.exe: $(TOP)\tool\lemon.c lempar.c
$(BCC) $(NO_WARN) -Daccess=_access \
@@ -2109,6 +2125,9 @@ vdbesort.lo: $(TOP)\src\vdbesort.c $(HDR)
vdbetrace.lo: $(TOP)\src\vdbetrace.c $(HDR)
$(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\vdbetrace.c
+vdbevtab.lo: $(TOP)\src\vdbevtab.c $(HDR)
+ $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\vdbevtab.c
+
vtab.lo: $(TOP)\src\vtab.c $(HDR)
$(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\vtab.c
@@ -2153,7 +2172,8 @@ parse.h: parse.c
parse.c: $(TOP)\src\parse.y lemon.exe
del /Q parse.y parse.h parse.h.temp 2>NUL
- copy $(TOP)\src\parse.y .
+ copy /Y $(TOP)\src\parse.y .
+ copy /B parse.y +,,
.\lemon.exe $(REQ_FEATURE_FLAGS) $(OPT_FEATURE_FLAGS) $(EXT_FEATURE_FLAGS) $(OPTS) -S parse.y
$(SQLITE3H): $(TOP)\src\sqlite.h.in $(TOP)\manifest mksourceid.exe $(TOP)\VERSION
@@ -2166,8 +2186,13 @@ sqlite3ext.h: .target_source
copy /Y sqlite3ext.h tsrc\sqlite3ext.h
!ELSE
copy /Y tsrc\sqlite3ext.h sqlite3ext.h
+ copy /B sqlite3ext.h +,,
!ENDIF
+sqlite3session.h: $(TOP)\ext\session\sqlite3session.h
+ copy /Y $(TOP)\ext\session\sqlite3session.h .
+ copy /B sqlite3session.h +,,
+
mkkeywordhash.exe: $(TOP)\tool\mkkeywordhash.c
$(BCC) $(NO_WARN) -Fe$@ $(REQ_FEATURE_FLAGS) $(OPT_FEATURE_FLAGS) $(EXT_FEATURE_FLAGS) $(OPTS) \
$(TOP)\tool\mkkeywordhash.c /link $(LDFLAGS) $(NLTLINKOPTS) $(NLTLIBPATHS)
@@ -2179,10 +2204,12 @@ keywordhash.h: $(TOP)\tool\mkkeywordhash.c mkkeywordhash.exe
SHELL_SRC = \
$(TOP)\src\shell.c.in \
$(TOP)\ext\misc\appendvfs.c \
- $(TOP)\ext\misc\shathree.c \
- $(TOP)\ext\misc\fileio.c \
$(TOP)\ext\misc\completion.c \
- $(TOP)\ext\misc\uint.c \
+ $(TOP)\ext\misc\decimal.c \
+ $(TOP)\ext\misc\fileio.c \
+ $(TOP)\ext\misc\ieee754.c \
+ $(TOP)\ext\misc\shathree.c \
+ $(TOP)\ext\misc\uint.c \
$(TOP)\ext\expert\sqlite3expert.c \
$(TOP)\ext\expert\sqlite3expert.h \
$(TOP)\ext\misc\memtrace.c \
@@ -2313,7 +2340,8 @@ LSM1_SRC = \
$(TOP)\ext\lsm1\lsm_win32.c
fts5parse.c: $(TOP)\ext\fts5\fts5parse.y lemon.exe
- copy $(TOP)\ext\fts5\fts5parse.y .
+ copy /Y $(TOP)\ext\fts5\fts5parse.y .
+ copy /B fts5parse.y +,,
del /Q fts5parse.h 2>NUL
.\lemon.exe $(REQ_FEATURE_FLAGS) $(OPT_FEATURE_FLAGS) $(EXT_FEATURE_FLAGS) $(OPTS) -S fts5parse.y
@@ -2321,11 +2349,13 @@ fts5parse.h: fts5parse.c
fts5.c: $(FTS5_SRC)
$(TCLSH_CMD) $(TOP)\ext\fts5\tool\mkfts5c.tcl
- copy $(TOP)\ext\fts5\fts5.h .
+ copy /Y $(TOP)\ext\fts5\fts5.h .
+ copy /B fts5.h +,,
lsm1.c: $(LSM1_SRC)
$(TCLSH_CMD) $(TOP)\ext\lsm1\tool\mklsm1c.tcl
- copy $(TOP)\ext\lsm1\lsm.h .
+ copy /Y $(TOP)\ext\lsm1\lsm.h .
+ copy /B lsm.h +,,
fts5.lo: fts5.c $(HDR) $(EXTHDR)
$(LTCOMPILE) $(CORE_COMPILE_OPTS) $(NO_WARN) -DSQLITE_CORE -c fts5.c
@@ -2353,6 +2383,7 @@ TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_SERIES_CONSTRAINT_VERIFY=1
TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_DEFAULT_PAGE_SIZE=1024
TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_ENABLE_STMTVTAB=1
TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_ENABLE_DBPAGE_VTAB=1
+TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_ENABLE_BYTECODE_VTAB=1
TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_ENABLE_JSON1=1
TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_ENABLE_DESERIALIZE=1
TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) $(TEST_CCONV_OPTS)
@@ -2435,6 +2466,9 @@ smoketest: $(TESTPROGS)
@set PATH=$(LIBTCLPATH);$(PATH)
.\testfixture.exe $(TOP)\test\main.test $(TESTOPTS)
+shelltest: $(TESTPROGS)
+ .\testfixture.exe $(TOP)\test\permutations.test shell
+
sqlite3_analyzer.c: $(SQLITE3C) $(SQLITE3H) $(TOP)\src\tclsqlite.c $(TOP)\tool\spaceanal.tcl $(TOP)\tool\mkccode.tcl $(TOP)\tool\sqlite3_analyzer.c.in $(SQLITE_TCL_DEP)
$(TCLSH_CMD) $(TOP)\tool\mkccode.tcl $(TOP)\tool\sqlite3_analyzer.c.in > $@
diff --git a/VERSION b/VERSION
index cac6068cf..949654dc3 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-3.32.0
+3.33.0
diff --git a/autoconf/Makefile.am b/autoconf/Makefile.am
index 20af7433b..694419b27 100644
--- a/autoconf/Makefile.am
+++ b/autoconf/Makefile.am
@@ -13,7 +13,7 @@ sqlite3_CFLAGS = $(AM_CFLAGS) -DSQLITE_ENABLE_EXPLAIN_COMMENTS -DSQLITE_ENABLE_D
include_HEADERS = sqlite3.h sqlite3ext.h
-EXTRA_DIST = sqlite3.1 tea Makefile.msc sqlite3.rc README.txt Replace.cs Makefile.fallback
+EXTRA_DIST = sqlite3.1 tea Makefile.msc sqlite3.rc sqlite3rc.h README.txt Replace.cs Makefile.fallback
pkgconfigdir = ${libdir}/pkgconfig
pkgconfig_DATA = sqlite3.pc
diff --git a/autoconf/Makefile.msc b/autoconf/Makefile.msc
index 37a3c1b18..746162a00 100644
--- a/autoconf/Makefile.msc
+++ b/autoconf/Makefile.msc
@@ -196,6 +196,7 @@ OSTRACE = 0
DEBUG = 0
!ENDIF
+
# Enable use of available compiler optimizations? Normally, this should be
# non-zero. Setting this to zero, thus disabling all compiler optimizations,
# can be useful for testing.
@@ -288,6 +289,7 @@ OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_JSON1=1
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_ENABLE_BYTECODE_VTAB=1
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_DESERIALIZE=1
!ENDIF
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_COLUMN_METADATA=1
diff --git a/configure b/configure
index e44efa938..9ba67e99e 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.32.0.
+# Generated by GNU Autoconf 2.69 for sqlite 3.33.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.32.0'
-PACKAGE_STRING='sqlite 3.32.0'
+PACKAGE_VERSION='3.33.0'
+PACKAGE_STRING='sqlite 3.33.0'
PACKAGE_BUGREPORT=''
PACKAGE_URL=''
@@ -1467,7 +1467,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.32.0 to adapt to many kinds of systems.
+\`configure' configures sqlite 3.33.0 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1532,7 +1532,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
- short | recursive ) echo "Configuration of sqlite 3.32.0:";;
+ short | recursive ) echo "Configuration of sqlite 3.33.0:";;
esac
cat <<\_ACEOF
@@ -1659,7 +1659,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
-sqlite configure 3.32.0
+sqlite configure 3.33.0
generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc.
@@ -2078,7 +2078,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.32.0, which was
+It was created by sqlite $as_me 3.33.0, which was
generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@
@@ -11268,7 +11268,7 @@ if test "${enable_amalgamation+set}" = set; then :
enableval=$enable_amalgamation;
fi
-if test "${enable_amalgamation}" == "no" ; then
+if test "${enable_amalgamation}" = "no" ; then
USE_AMALGAMATION=0
fi
@@ -11619,7 +11619,7 @@ if test "${enable_update_limit+set}" = set; then :
enableval=$enable_update_limit;
fi
-if test "${enable_udlimit}" = "yes" ; then
+if test "${enable_update_limit}" = "yes" ; then
OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_UPDATE_DELETE_LIMIT"
fi
@@ -12243,7 +12243,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.32.0, which was
+This file was extended by sqlite $as_me 3.33.0, which was
generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -12309,7 +12309,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.32.0
+sqlite config.status 3.33.0
configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\"
diff --git a/configure.ac b/configure.ac
index ef70a4f0d..6c1fdb6b2 100644
--- a/configure.ac
+++ b/configure.ac
@@ -569,7 +569,7 @@ AC_SUBST(TARGET_DEBUG)
# See whether we should use the amalgamation to build
AC_ARG_ENABLE(amalgamation, AC_HELP_STRING([--disable-amalgamation],
[Disable the amalgamation and instead build all files separately]))
-if test "${enable_amalgamation}" == "no" ; then
+if test "${enable_amalgamation}" = "no" ; then
USE_AMALGAMATION=0
fi
AC_SUBST(USE_AMALGAMATION)
@@ -651,7 +651,7 @@ fi
# statements.
AC_ARG_ENABLE(update-limit, AC_HELP_STRING([--enable-update-limit],
[Enable the UPDATE/DELETE LIMIT clause]))
-if test "${enable_udlimit}" = "yes" ; then
+if test "${enable_update_limit}" = "yes" ; then
OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_UPDATE_DELETE_LIMIT"
fi
diff --git a/doc/lemon.html b/doc/lemon.html
index 17988deef..714cbfa5b 100644
--- a/doc/lemon.html
+++ b/doc/lemon.html
@@ -104,9 +104,13 @@ Write all output files into <i>directory</i>. Normally, output files
are written into the directory that contains the input grammar file.
<li><b>-D<i>name</i></b>
Define C preprocessor macro <i>name</i>. This macro is usable by
-"<tt><a href='#pifdef'>%ifdef</a></tt>" and
-"<tt><a href='#pifdef'>%ifndef</a></tt>" lines
+"<tt><a href='#pifdef'>%ifdef</a></tt>",
+"<tt><a href='#pifdef'>%ifndef</a></tt>", and
+"<tt><a href="#pifdef">%if</a></tt> lines
in the grammar file.
+<li><b>-E</b>
+Run the "%if" preprocessor step only and print the revised grammar
+file.
<li><b>-g</b>
Do not generate a parser. Instead write the input grammar to standard
output with all comments, actions, and other extraneous text removed.
@@ -555,9 +559,11 @@ other than that, the order of directives in Lemon is arbitrary.</p>
<li><tt><a href='#default_destructor'>%default_destructor</a></tt>
<li><tt><a href='#default_type'>%default_type</a></tt>
<li><tt><a href='#destructor'>%destructor</a></tt>
+<li><tt><a href='#pifdef'>%else</a></tt>
<li><tt><a href='#pifdef'>%endif</a></tt>
<li><tt><a href='#extraarg'>%extra_argument</a></tt>
<li><tt><a href='#pfallback'>%fallback</a></tt>
+<li><tt><a href='#pifdef'>%if</a></tt>
<li><tt><a href='#pifdef'>%ifdef</a></tt>
<li><tt><a href='#pifdef'>%ifndef</a></tt>
<li><tt><a href='#pinclude'>%include</a></tt>
@@ -737,10 +743,11 @@ arguments are tokens which fall back to the token identified by the first
argument.</p>
<a name='pifdef'></a>
-<h4>The <tt>%ifdef</tt>, <tt>%ifndef</tt>, and <tt>%endif</tt> directives</h4>
+<h4>The <tt>%if</tt> directive and its friends</h4>
-<p>The <tt>%ifdef</tt>, <tt>%ifndef</tt>, and <tt>%endif</tt> directives
-are similar to #ifdef, #ifndef, and #endif in the C-preprocessor,
+<p>The <tt>%if</tt>, <tt>%ifdef</tt>, <tt>%ifndef</tt>, <tt>%else</tt>,
+and <tt>%endif</tt> directives
+are similar to #if, #ifdef, #ifndef, #else, and #endif in the C-preprocessor,
just not as general.
Each of these directives must begin at the left margin. No whitespace
is allowed between the "%" and the directive name.</p>
@@ -749,12 +756,22 @@ is allowed between the "%" and the directive name.</p>
"<tt>%endif</tt>" is
ignored unless the "-DMACRO" command-line option is used. Grammar text
betwen "<tt>%ifndef MACRO</tt>" and the next nested "<tt>%endif</tt>" is
-included except when the "-DMACRO" command-line option is used.</p>
-
-<p>Note that the argument to <tt>%ifdef</tt> and <tt>%ifndef</tt> must
-be a single preprocessor symbol name, not a general expression.
-There is no "<tt>%else</tt>" directive.</p>
-
+included except when the "-DMACRO" command-line option is used.<p>
+
+<p>The text in between "<tt>%if</tt> <i>CONDITIONAL</i>" and its
+corresponding <tt>%endif</tt> is included only if <i>CONDITIONAL</i>
+is true. The CONDITION is one or more macro names, optionally connected
+using the "||" and "&amp;&amp;" binary operators, the "!" unary operator,
+and grouped using balanced parentheses. Each term is true if the
+corresponding macro exists, and false if it does not exist.</p>
+
+<p>An optional "<tt>%else</tt>" directive can occur anywhere in between a
+<tt>%ifdef</tt>, <tt>%ifndef</tt>, or <tt>%if</tt> directive and
+its corresponding <tt>%endif</tt>.</p>
+
+<p>Note that the argument to <tt>%ifdef</tt> and <tt>%ifndef</tt> is
+intended to be a single preprocessor symbol name, not a general expression.
+Use the "<tt>%if</tt>" directive for general expressions.</p>
<a name='pinclude'></a>
<h4>The <tt>%include</tt> directive</h4>
diff --git a/doc/wal-lock.md b/doc/wal-lock.md
new file mode 100644
index 000000000..d74bb88b6
--- /dev/null
+++ b/doc/wal-lock.md
@@ -0,0 +1,88 @@
+# Wal-Mode Blocking Locks
+
+On some Unix-like systems, SQLite may be configured to use POSIX blocking locks
+by:
+
+ * building the library with SQLITE\_ENABLE\_SETLK\_TIMEOUT defined, and
+ * configuring a timeout in ms using the sqlite3\_busy\_timeout() API.
+
+Blocking locks may be advantageous as (a) waiting database clients do not
+need to continuously poll the database lock, and (b) using blocking locks
+facilitates transfer of OS priority between processes when a high priority
+process is blocked by a lower priority one.
+
+Only read/write clients use blocking locks. Clients that have read-only access
+to the \*-shm file nevery use blocking locks.
+
+Threads or processes that access a single database at a time never deadlock as
+a result of blocking database locks. But it is of course possible for threads
+that lock multiple databases simultaneously to do so. In most cases the OS will
+detect the deadlock and return an error.
+
+## Wal Recovery
+
+Wal database "recovery" is a process required when the number of connected
+database clients changes from zero to one. In this case, a client is
+considered to connect to the database when it first reads data from it.
+Before recovery commences, an exclusive WRITER lock is taken.
+
+Without blocking locks, if two clients attempt recovery simultaneously, one
+fails to obtain the WRITER lock and either invokes the busy-handler callback or
+returns SQLITE\_BUSY to the user. With blocking locks configured, the second
+client blocks on the WRITER lock.
+
+## Database Readers
+
+Usually, read-only are not blocked by any other database clients, so they
+have no need of blocking locks.
+
+If a read-only transaction is being opened on a snapshot, the CHECKPOINTER
+lock is required briefly as part of opening the transaction (to check that a
+checkpointer is not currently overwriting the snapshot being opened). A
+blocking lock is used to obtain the CHECKPOINTER lock in this case. A snapshot
+opener may therefore block on and transfer priority to a checkpointer in some
+cases.
+
+## Database Writers
+
+A database writer must obtain the exclusive WRITER lock. It uses a blocking
+lock to do so if any of the following are true:
+
+ * the transaction is an implicit one consisting of a single DML or DDL
+ statement, or
+ * the transaction is opened using BEGIN IMMEDIATE or BEGIN EXCLUSIVE, or
+ * the first SQL statement executed following the BEGIN command is a DML or
+ DDL statement (not a read-only statement like a SELECT).
+
+In other words, in all cases except when an open read-transaction is upgraded
+to a write-transaction. In that case a non-blocking lock is used.
+
+## Database Checkpointers
+
+Database checkpointers takes the following locks, in order:
+
+ * The exclusive CHECKPOINTER lock.
+ * The exclusive WRITER lock (FULL, RESTART and TRUNCATE only).
+ * Exclusive lock on read-mark slots 1-N. These are immediately released after being taken.
+ * Exclusive lock on read-mark 0.
+ * Exclusive lock on read-mark slots 1-N again. These are immediately released
+ after being taken (RESTART and TRUNCATE only).
+
+All of the above use blocking locks.
+
+## Summary
+
+With blocking locks configured, the only cases in which clients should see an
+SQLITE\_BUSY error are:
+
+ * if the OS does not grant a blocking lock before the configured timeout
+ expires, and
+ * when an open read-transaction is upgraded to a write-transaction.
+
+In all other cases the blocking locks implementation should prevent clients
+from having to handle SQLITE\_BUSY errors and facilitate appropriate transfer
+of priorities between competing clients.
+
+Clients that lock multiple databases simultaneously must be wary of deadlock.
+
+
diff --git a/ext/async/sqlite3async.c b/ext/async/sqlite3async.c
index b6f4a4bd3..eed7c8d73 100644
--- a/ext/async/sqlite3async.c
+++ b/ext/async/sqlite3async.c
@@ -1704,4 +1704,3 @@ int sqlite3async_control(int op, ...){
}
#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ASYNCIO) */
-
diff --git a/ext/async/sqlite3async.h b/ext/async/sqlite3async.h
index 5b20d7189..13b23bc6a 100644
--- a/ext/async/sqlite3async.h
+++ b/ext/async/sqlite3async.h
@@ -220,4 +220,3 @@ int sqlite3async_control(int op, ...);
} /* End of the 'extern "C"' block */
#endif
#endif /* ifndef __SQLITEASYNC_H_ */
-
diff --git a/ext/expert/sqlite3expert.c b/ext/expert/sqlite3expert.c
index e88fb7e78..1dd070089 100644
--- a/ext/expert/sqlite3expert.c
+++ b/ext/expert/sqlite3expert.c
@@ -1128,14 +1128,19 @@ int idxFindIndexes(
/* int iParent = sqlite3_column_int(pExplain, 1); */
/* int iNotUsed = sqlite3_column_int(pExplain, 2); */
const char *zDetail = (const char*)sqlite3_column_text(pExplain, 3);
- int nDetail = STRLEN(zDetail);
+ int nDetail;
int i;
+ if( !zDetail ) continue;
+ nDetail = STRLEN(zDetail);
+
for(i=0; i<nDetail; i++){
const char *zIdx = 0;
- if( memcmp(&zDetail[i], " USING INDEX ", 13)==0 ){
+ if( i+13<nDetail && memcmp(&zDetail[i], " USING INDEX ", 13)==0 ){
zIdx = &zDetail[i+13];
- }else if( memcmp(&zDetail[i], " USING COVERING INDEX ", 22)==0 ){
+ }else if( i+22<nDetail
+ && memcmp(&zDetail[i], " USING COVERING INDEX ", 22)==0
+ ){
zIdx = &zDetail[i+22];
}
if( zIdx ){
@@ -1218,7 +1223,7 @@ static int idxProcessOneTrigger(
IdxTable *pTab = pWrite->pTab;
const char *zTab = pTab->zName;
const char *zSql =
- "SELECT 'CREATE TEMP' || substr(sql, 7) FROM sqlite_master "
+ "SELECT 'CREATE TEMP' || substr(sql, 7) FROM sqlite_schema "
"WHERE tbl_name = %Q AND type IN ('table', 'trigger') "
"ORDER BY type;";
sqlite3_stmt *pSelect = 0;
@@ -1318,12 +1323,12 @@ static int idxCreateVtabSchema(sqlite3expert *p, char **pzErrmsg){
** 2) Create the equivalent virtual table in dbv.
*/
rc = idxPrepareStmt(p->db, &pSchema, pzErrmsg,
- "SELECT type, name, sql, 1 FROM sqlite_master "
+ "SELECT type, name, sql, 1 FROM sqlite_schema "
"WHERE type IN ('table','view') AND name NOT LIKE 'sqlite_%%' "
" UNION ALL "
- "SELECT type, name, sql, 2 FROM sqlite_master "
+ "SELECT type, name, sql, 2 FROM sqlite_schema "
"WHERE type = 'trigger'"
- " AND tbl_name IN(SELECT name FROM sqlite_master WHERE type = 'view') "
+ " AND tbl_name IN(SELECT name FROM sqlite_schema WHERE type = 'view') "
"ORDER BY 4, 1"
);
while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSchema) ){
@@ -1493,7 +1498,7 @@ static int idxLargestIndex(sqlite3 *db, int *pnMax, char **pzErr){
int rc = SQLITE_OK;
const char *zMax =
"SELECT max(i.seqno) FROM "
- " sqlite_master AS s, "
+ " sqlite_schema AS s, "
" pragma_index_list(s.name) AS l, "
" pragma_index_info(l.name) AS i "
"WHERE s.type = 'table'";
@@ -1646,7 +1651,7 @@ static int idxPopulateStat1(sqlite3expert *p, char **pzErr){
const char *zAllIndex =
"SELECT s.rowid, s.name, l.name FROM "
- " sqlite_master AS s, "
+ " sqlite_schema AS s, "
" pragma_index_list(s.name) AS l "
"WHERE s.type = 'table'";
const char *zIndexXInfo =
@@ -1720,7 +1725,7 @@ static int idxPopulateStat1(sqlite3expert *p, char **pzErr){
sqlite3_free(pCtx);
if( rc==SQLITE_OK ){
- rc = sqlite3_exec(p->dbm, "ANALYZE sqlite_master", 0, 0, 0);
+ rc = sqlite3_exec(p->dbm, "ANALYZE sqlite_schema", 0, 0, 0);
}
sqlite3_exec(p->db, "DROP TABLE IF EXISTS temp."UNIQUE_TABLE_NAME,0,0,0);
@@ -1759,7 +1764,7 @@ sqlite3expert *sqlite3_expert_new(sqlite3 *db, char **pzErrmsg){
if( rc==SQLITE_OK ){
sqlite3_stmt *pSql;
rc = idxPrintfPrepareStmt(pNew->db, &pSql, pzErrmsg,
- "SELECT sql FROM sqlite_master WHERE name NOT LIKE 'sqlite_%%'"
+ "SELECT sql FROM sqlite_schema WHERE name NOT LIKE 'sqlite_%%'"
" AND sql NOT LIKE 'CREATE VIRTUAL %%'"
);
while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSql) ){
@@ -1950,4 +1955,4 @@ void sqlite3_expert_destroy(sqlite3expert *p){
}
}
-#endif /* ifndef SQLITE_OMIT_VIRTUAL_TABLE */
+#endif /* ifndef SQLITE_OMIT_VIRTUALTABLE */
diff --git a/ext/fts3/README.content b/ext/fts3/README.content
index ab986754d..b6a75399b 100644
--- a/ext/fts3/README.content
+++ b/ext/fts3/README.content
@@ -174,5 +174,3 @@ EXTERNAL CONTENT FTS4 TABLES
only be useful if the full-text index has somehow become corrupt. It is an
error to attempt to rebuild the full-text index maintained by a contentless
FTS4 table.
-
-
diff --git a/ext/fts3/fts3.c b/ext/fts3/fts3.c
index 841d7448f..892fc36d3 100644
--- a/ext/fts3/fts3.c
+++ b/ext/fts3/fts3.c
@@ -2068,7 +2068,7 @@ static void fts3PutDeltaVarint(
sqlite3_int64 *piPrev, /* IN/OUT: Previous value written to list */
sqlite3_int64 iVal /* Write this value to the list */
){
- assert( iVal-*piPrev > 0 || (*piPrev==0 && iVal==0) );
+ assert_fts3_nc( iVal-*piPrev > 0 || (*piPrev==0 && iVal==0) );
*pp += sqlite3Fts3PutVarint(*pp, iVal-*piPrev);
*piPrev = iVal;
}
@@ -2185,7 +2185,9 @@ static void fts3ReadNextPos(
sqlite3_int64 *pi /* IN/OUT: Value read from position-list */
){
if( (**pp)&0xFE ){
- fts3GetDeltaVarint(pp, pi);
+ int iVal;
+ *pp += fts3GetVarint32((*pp), &iVal);
+ *pi += iVal;
*pi -= 2;
}else{
*pi = POSITION_LIST_END;
@@ -2265,6 +2267,9 @@ static int fts3PoslistMerge(
*/
fts3GetDeltaVarint(&p1, &i1);
fts3GetDeltaVarint(&p2, &i2);
+ if( i1<2 || i2<2 ){
+ break;
+ }
do {
fts3PutDeltaVarint(&p, &iPrev, (i1<i2) ? i1 : i2);
iPrev -= 2;
@@ -2333,7 +2338,7 @@ static int fts3PoslistPhraseMerge(
/* Never set both isSaveLeft and isExact for the same invocation. */
assert( isSaveLeft==0 || isExact==0 );
- assert( p!=0 && *p1!=0 && *p2!=0 );
+ assert_fts3_nc( p!=0 && *p1!=0 && *p2!=0 );
if( *p1==POS_COLUMN ){
p1++;
p1 += fts3GetVarint32(p1, &iCol1);
@@ -4518,7 +4523,7 @@ void sqlite3Fts3DoclistNext(
assert( nDoclist>0 );
assert( *pbEof==0 );
- assert( p || *piDocid==0 );
+ assert_fts3_nc( p || *piDocid==0 );
assert( !p || (p>=aDoclist && p<=&aDoclist[nDoclist]) );
if( p==0 ){
@@ -5168,7 +5173,7 @@ static void fts3EvalInvalidatePoslist(Fts3Phrase *pPhrase){
**
** Parameter nNear is passed the NEAR distance of the expression (5 in
** the example above). When this function is called, *paPoslist points to
-** the position list, and *pnToken is the number of phrase tokens in, the
+** the position list, and *pnToken is the number of phrase tokens in the
** phrase on the other side of the NEAR operator to pPhrase. For example,
** if pPhrase refers to the "def ghi" phrase, then *paPoslist points to
** the position list associated with phrase "abc".
@@ -5203,10 +5208,12 @@ static int fts3EvalNearTrim(
);
if( res ){
nNew = (int)(pOut - pPhrase->doclist.pList) - 1;
- assert( pPhrase->doclist.pList[nNew]=='\0' );
- assert( nNew<=pPhrase->doclist.nList && nNew>0 );
- memset(&pPhrase->doclist.pList[nNew], 0, pPhrase->doclist.nList - nNew);
- pPhrase->doclist.nList = nNew;
+ if( nNew>=0 ){
+ assert( pPhrase->doclist.pList[nNew]=='\0' );
+ assert( nNew<=pPhrase->doclist.nList && nNew>0 );
+ memset(&pPhrase->doclist.pList[nNew], 0, pPhrase->doclist.nList - nNew);
+ pPhrase->doclist.nList = nNew;
+ }
*paPoslist = pPhrase->doclist.pList;
*pnToken = pPhrase->nToken;
}
@@ -5315,6 +5322,7 @@ static void fts3EvalNextRow(
fts3EvalNextRow(pCsr, pLeft, pRc);
}
}
+ pRight->bEof = pLeft->bEof = 1;
}
}
break;
@@ -5557,7 +5565,10 @@ static int fts3EvalTestExpr(
}else
#endif
{
- bHit = (pExpr->bEof==0 && pExpr->iDocid==pCsr->iPrevId);
+ bHit = (
+ pExpr->bEof==0 && pExpr->iDocid==pCsr->iPrevId
+ && pExpr->pPhrase->doclist.nList>0
+ );
}
break;
}
diff --git a/ext/fts3/fts3_snippet.c b/ext/fts3/fts3_snippet.c
index 2b20ba10a..ebc771fd6 100644
--- a/ext/fts3/fts3_snippet.c
+++ b/ext/fts3/fts3_snippet.c
@@ -876,7 +876,7 @@ static int fts3ExprLHits(
iStart = pExpr->iPhrase * ((p->nCol + 31) / 32);
}
- while( 1 ){
+ if( pIter ) while( 1 ){
int nHit = fts3ColumnlistCount(&pIter);
if( (pPhrase->iColumn>=pTab->nColumn || pPhrase->iColumn==iCol) ){
if( p->flag==FTS3_MATCHINFO_LHITS ){
diff --git a/ext/fts3/fts3_write.c b/ext/fts3/fts3_write.c
index b9acc47dc..092cad9ac 100644
--- a/ext/fts3/fts3_write.c
+++ b/ext/fts3/fts3_write.c
@@ -341,7 +341,9 @@ static int fts3SqlStmt(
** created by merging the oldest :2 segments from absolute level :1. See
** function sqlite3Fts3Incrmerge() for details. */
/* 29 */ "SELECT 2 * total(1 + leaves_end_block - start_block) "
- " FROM %Q.'%q_segdir' WHERE level = ? AND idx < ?",
+ " FROM (SELECT * FROM %Q.'%q_segdir' "
+ " WHERE level = ? ORDER BY idx ASC LIMIT ?"
+ " )",
/* SQL_DELETE_SEGDIR_ENTRY
** Delete the %_segdir entry on absolute level :1 with index :2. */
@@ -2853,6 +2855,19 @@ int sqlite3Fts3MsrIncrRestart(Fts3MultiSegReader *pCsr){
return SQLITE_OK;
}
+static int fts3GrowSegReaderBuffer(Fts3MultiSegReader *pCsr, int nReq){
+ if( nReq>pCsr->nBuffer ){
+ char *aNew;
+ pCsr->nBuffer = nReq*2;
+ aNew = sqlite3_realloc(pCsr->aBuffer, pCsr->nBuffer);
+ if( !aNew ){
+ return SQLITE_NOMEM;
+ }
+ pCsr->aBuffer = aNew;
+ }
+ return SQLITE_OK;
+}
+
int sqlite3Fts3SegReaderStep(
Fts3Table *p, /* Virtual table handle */
@@ -2987,15 +3002,9 @@ int sqlite3Fts3SegReaderStep(
}
nByte = sqlite3Fts3VarintLen(iDelta) + (isRequirePos?nList+1:0);
- if( nDoclist+nByte>pCsr->nBuffer ){
- char *aNew;
- pCsr->nBuffer = (nDoclist+nByte)*2;
- aNew = sqlite3_realloc(pCsr->aBuffer, pCsr->nBuffer);
- if( !aNew ){
- return SQLITE_NOMEM;
- }
- pCsr->aBuffer = aNew;
- }
+
+ rc = fts3GrowSegReaderBuffer(pCsr, nByte+nDoclist);
+ if( rc ) return rc;
if( isFirst ){
char *a = &pCsr->aBuffer[nDoclist];
@@ -3020,6 +3029,9 @@ int sqlite3Fts3SegReaderStep(
fts3SegReaderSort(apSegment, nMerge, j, xCmp);
}
if( nDoclist>0 ){
+ rc = fts3GrowSegReaderBuffer(pCsr, nDoclist+FTS3_NODE_PADDING);
+ if( rc ) return rc;
+ memset(&pCsr->aBuffer[nDoclist], 0, FTS3_NODE_PADDING);
pCsr->aDoclist = pCsr->aBuffer;
pCsr->nDoclist = nDoclist;
rc = SQLITE_ROW;
@@ -4288,7 +4300,7 @@ static int fts3IncrmergeLoad(
int i;
int nHeight = (int)aRoot[0];
NodeWriter *pNode;
- if( nHeight<1 || nHeight>FTS_MAX_APPENDABLE_HEIGHT ){
+ if( nHeight<1 || nHeight>=FTS_MAX_APPENDABLE_HEIGHT ){
sqlite3_reset(pSelect);
return FTS_CORRUPT_VTAB;
}
diff --git a/ext/fts3/tool/fts3view.c b/ext/fts3/tool/fts3view.c
index 37f9b7396..9558cde0d 100644
--- a/ext/fts3/tool/fts3view.c
+++ b/ext/fts3/tool/fts3view.c
@@ -93,7 +93,7 @@ static int runSql(sqlite3 *db, const char *zFormat, ...){
static void showSchema(sqlite3 *db, const char *zTab){
sqlite3_stmt *pStmt;
pStmt = prepare(db,
- "SELECT sql FROM sqlite_master"
+ "SELECT sql FROM sqlite_schema"
" WHERE name LIKE '%q%%'"
" ORDER BY 1",
zTab);
@@ -831,7 +831,7 @@ int main(int argc, char **argv){
sqlite3_stmt *pStmt;
int cnt = 0;
pStmt = prepare(db, "SELECT b.sql"
- " FROM sqlite_master a, sqlite_master b"
+ " FROM sqlite_schema a, sqlite_schema b"
" WHERE a.name GLOB '*_segdir'"
" AND b.name=substr(a.name,1,length(a.name)-7)"
" ORDER BY 1");
diff --git a/ext/fts5/fts5_index.c b/ext/fts5/fts5_index.c
index f33617465..5e1155c2a 100644
--- a/ext/fts5/fts5_index.c
+++ b/ext/fts5/fts5_index.c
@@ -2321,11 +2321,11 @@ static void fts5LeafSeek(
}
search_success:
- pIter->iLeafOffset = iOff + nNew;
- if( pIter->iLeafOffset>n || nNew<1 ){
+ if( (i64)iOff+nNew>n || nNew<1 ){
p->rc = FTS5_CORRUPT;
return;
}
+ pIter->iLeafOffset = iOff + nNew;
pIter->iTermLeafOffset = pIter->iLeafOffset;
pIter->iTermLeafPgno = pIter->iLeafPgno;
diff --git a/ext/fts5/test/fts5corrupt3.test b/ext/fts5/test/fts5corrupt3.test
index 4e0ae64a9..25aa094e9 100644
--- a/ext/fts5/test/fts5corrupt3.test
+++ b/ext/fts5/test/fts5corrupt3.test
@@ -10108,6 +10108,221 @@ do_catchsql_test 68.1 {
INSERT INTO t1(t1) SELECT x FROM t2;
} {1 {database disk image is malformed}}
+#-------------------------------------------------------------------------
+reset_db
+do_test 69.0 {
+ sqlite3 db {}
+ db deserialize [decode_hexdb {
+.open --hexdb
+| size 32768 pagesize 4096 filename crash-31c462b8b665d0.db
+| page 1 offset 0
+| 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3.
+| 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 08 .....@ ........
+| 32: 00 00 00 02 00 00 00 00 00 00 00 00 00 00 00 00 ................
+| 96: 00 00 00 00 0d 0f c7 00 07 0d 92 00 0f 8d 0f 36 ...............6
+| 112: 0e cb 0e 6b 0e 0e 0d b6 0d 92 00 00 00 00 00 00 ...k............
+| 3472: 00 00 22 08 06 17 11 11 01 31 74 61 62 6c 65 74 .........1tablet
+| 3488: 32 74 32 08 43 52 45 41 54 45 20 54 41 42 4c 45 2t2.CREATE TABLE
+| 3504: 20 74 32 28 78 29 56 07 06 17 1f 1f 01 7d 74 61 t2(x)V.......ta
+| 3520: 62 6c 65 74 31 5f 63 6f 6e 66 69 67 74 31 5f 63 blet1_configt1_c
+| 3536: 6f 6e 66 69 67 07 43 52 45 41 54 45 20 54 41 42 onfig.CREATE TAB
+| 3552: 4c 45 20 27 74 31 5f 63 6f 6e 66 69 67 27 28 6b LE 't1_config'(k
+| 3568: 20 50 52 49 4d 41 52 59 20 4b 45 59 2c 20 76 29 PRIMARY KEY, v)
+| 3584: 20 57 49 54 48 4f 55 54 20 52 4f 57 49 44 5b 06 WITHOUT ROWID[.
+| 3600: 07 17 21 21 01 81 01 74 61 62 6c 65 74 31 5f 64 ..!!...tablet1_d
+| 3616: 6f 63 73 69 7a 65 74 31 5f 64 6f 63 73 69 7a 65 ocsizet1_docsize
+| 3632: 06 43 52 45 41 54 45 20 54 41 42 4c 45 20 27 74 .CREATE TABLE 't
+| 3648: 31 5f 64 6f 63 73 69 7a 65 27 28 69 64 20 49 4e 1_docsize'(id IN
+| 3664: 54 45 47 45 52 20 50 52 49 4d 41 52 59 20 4b 45 TEGER PRIMARY KE
+| 3680: 59 2c 20 73 7a 20 42 4c 4f 42 29 5e 05 07 17 21 Y, sz BLOB)^...!
+| 3696: 21 01 81 07 74 61 62 6c 65 74 31 5f 63 6f 6e 74 !...tablet1_cont
+| 3712: 65 6e 74 74 31 5f 63 6f 6e 74 65 6e 74 05 43 52 entt1_content.CR
+| 3728: 45 41 54 45 20 54 41 42 4c 45 20 27 74 31 5f 63 EATE TABLE 't1_c
+| 3744: 6f 6e 74 65 6e 74 27 28 69 64 20 49 4e 54 45 47 ontent'(id INTEG
+| 3760: 45 52 20 50 52 49 4d 41 52 59 20 4b 45 59 2c 20 ER PRIMARY KEY,
+| 3776: 63 39 2c 20 63 31 2c 20 63 32 29 69 04 07 17 19 c9, c1, c2)i....
+| 3792: 19 01 81 2d 74 61 62 6c 65 74 31 5f 69 64 78 74 ...-tablet1_idxt
+| 3808: 31 5f 69 64 78 04 43 52 45 41 54 45 20 54 41 42 1_idx.CREATE TAB
+| 3824: 4c 45 20 27 74 31 5f 69 64 78 27 28 73 65 67 69 LE 't1_idx'(segi
+| 3840: 64 2c 20 74 65 72 6d 2c 20 70 67 6e 6f 2c 20 50 d, term, pgno, P
+| 3856: 52 49 4d 41 52 59 20 4b 45 59 28 73 65 67 69 64 RIMARY KEY(segid
+| 3872: 2c 20 74 65 72 6d 29 29 20 57 49 54 48 4f 55 54 , term)) WITHOUT
+| 3888: 20 52 4f 57 49 44 55 03 07 17 1b 1b 01 81 01 74 ROWIDU........t
+| 3904: 61 62 6c 65 74 31 5f 64 61 74 61 74 31 5f 64 61 ablet1_datat1_da
+| 3920: 74 61 03 43 52 45 41 54 45 20 54 41 42 4c 45 20 ta.CREATE TABLE
+| 3936: 27 74 31 5f 64 61 74 61 27 28 69 64 20 49 4e 54 't1_data'(id INT
+| 3952: 45 47 45 52 20 50 52 49 4d 41 52 59 20 4b 45 59 EGER PRIMARY KEY
+| 3968: 2c 20 62 6c 6f 63 6b 20 42 4c 4f 42 29 38 02 06 , block BLOB)8..
+| 3984: 17 11 11 08 5f 74 61 62 6c 65 74 31 74 31 43 52 ...._tablet1t1CR
+| 4000: 45 41 54 45 20 56 49 52 54 55 41 4c 20 54 41 42 EATE VIRTUAL TAB
+| 4016: 4c 45 20 74 31 20 55 53 49 4e 47 20 66 74 73 35 LE t1 USING fts5
+| 4032: 28 61 2c 62 2c 63 29 00 00 00 00 00 00 00 00 00 (a,b,c).........
+| page 3 offset 8192
+| 0: 0d 00 00 00 03 0c 94 00 0f e6 0f ef 0c 94 00 00 ................
+| 3216: 00 00 00 00 86 4a 84 80 80 80 80 01 04 00 8d 18 .....J..........
+| 3232: 00 00 03 2b 02 30 30 01 02 06 01 02 06 01 02 06 ...+.00.........
+| 3248: 1f 02 03 01 02 03 01 02 03 01 08 32 30 31 36 30 ...........20160
+| 3264: 36 30 39 01 02 07 01 02 07 01 02 07 01 01 34 01 609...........4.
+| 3280: 02 05 01 02 05 01 02 05 01 01 35 01 02 04 01 02 ..........5.....
+| 3296: 04 01 02 04 02 07 30 30 30 30 30 30 30 1c 02 04 ......0000000...
+| 3312: 01 02 04 01 02 04 01 06 62 69 6e 61 72 79 03 06 ........binary..
+| 3328: 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 ................
+| 3344: 02 02 03 06 00 02 02 03 06 01 02 02 03 06 01 02 ................
+| 3360: 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 ................
+| 3376: 03 06 01 02 02 03 06 01 02 02 01 08 63 6f 6d 70 ............comp
+| 3392: 69 6c 65 72 01 02 02 01 02 02 01 02 02 01 06 64 iler...........d
+| 3408: 62 73 74 61 74 07 02 03 01 02 03 01 02 03 02 04 bstat...........
+| 3424: 65 62 75 67 04 02 02 01 02 02 01 02 02 01 06 65 ebug...........e
+| 3440: 6e 61 62 6c 65 07 02 02 01 02 02 01 02 02 01 02 nable...........
+| 3456: 02 01 02 02 01 02 02 01 02 02 01 02 02 01 02 02 ................
+| 3472: 01 02 02 01 02 02 01 02 02 01 02 02 01 02 02 01 ................
+| 3488: 01 02 01 02 02 01 02 02 01 02 02 01 02 02 01 02 ................
+| 3504: 02 01 02 02 02 08 78 74 65 6e 73 69 6f 6e 1f 02 ......xtension..
+| 3520: 04 01 02 04 01 02 04 01 04 66 74 73 34 1a 02 03 .........fts4...
+| 3536: 01 02 03 01 02 03 04 01 35 0d 02 03 01 02 03 01 ........5.......
+| 3552: 02 03 01 03 67 63 63 01 aa 03 01 02 03 01 02 03 ....gcc.........
+| 3568: 02 06 65 6f 70 6f 6c 79 10 02 03 02 02 03 01 02 ..eopoly........
+| 3584: 03 01 05 6a 73 6f 6e 31 13 02 03 01 02 03 01 02 ...json1........
+| 3600: 03 01 04 6c 6f 61 64 1f 02 03 01 02 03 01 02 03 ...load.........
+| 3616: 01 03 6d 61 78 1c 02 02 01 02 02 01 02 02 02 05 ..max...........
+| 3632: 65 6d 6f 72 79 1c 02 03 01 02 03 01 02 03 04 04 emory...........
+| 3648: 73 79 73 35 16 02 03 01 02 03 01 02 03 01 06 6e sys5...........n
+| 3664: 6f 63 61 73 65 02 06 01 02 02 03 06 01 02 02 03 ocase...........
+| 3680: 06 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 ................
+| 3696: 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 ................
+| 3712: 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 ................
+| 3728: 02 01 04 6f 6d 69 74 1f 02 02 01 02 02 01 02 01 ...omit.........
+| 3744: ff ff ff ff ff ff ff ff f0 00 00 00 00 00 01 02 ................
+| 3760: 58 81 96 4d 01 06 01 02 02 03 06 01 02 02 03 06 X..M............
+| 3776: 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 ................
+| 3792: 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 ................
+| 3808: 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 ................
+| 3824: 01 0a 74 68 72 65 61 64 73 61 66 65 22 02 02 01 ..threadsafe....
+| 3840: 02 02 01 02 02 01 04 76 74 61 62 07 02 04 01 02 .......vtab.....
+| 3856: 04 01 02 04 01 01 78 01 06 01 01 02 01 06 01 01 ......x.........
+| 3872: 02 01 06 01 1e 02 01 06 01 01 02 01 06 01 01 02 ................
+| 3888: 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 ................
+| 3904: 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 ................
+| 3920: 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 ................
+| 3936: 00 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 ................
+| 3952: 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 ................
+| 3968: 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 ................
+| 3984: 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 ................
+| 4000: 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 ................
+| 4016: 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 ................
+| 4032: 02 01 06 01 01 02 01 06 01 01 02 04 15 13 0c 0c ................
+| 4048: 12 44 13 11 0f 47 13 0f 0b 0e 11 10 0f 0e 10 0f .D...G..........
+| 4064: 44 0f 10 40 15 0f 07 01 03 00 14 24 5a 24 24 0f D..@.......$Z$$.
+| 4080: 0a 03 00 24 00 00 00 00 01 01 01 00 01 01 01 01 ...$............
+| page 4 offset 12288
+| 0: 0a 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+| 4080: 00 00 00 00 00 00 00 00 00 00 05 04 09 0c 01 02 ................
+| page 5 offset 16384
+| 0: 0d 00 00 00 24 0c 0a 00 0f d8 0f af 0f 86 0f 74 ....$..........t
+| 16: 0f 61 0f 4e 0f 2f 0f 0f 0e ef 0e d7 0e be 0e a5 .a.N./..........
+| 32: 0e 8d 0e 74 0e 5b 0e 40 0e 24 0e 08 0d ef 0d d5 ...t.[.@.$......
+| 48: 0d bb 0d a0 0d 84 0d 68 0d 4f 0d 00 00 00 00 00 .......h.O......
+| 3072: 00 00 00 00 00 00 00 00 00 00 18 24 05 00 25 0f ...........$..%.
+| 3088: 19 54 48 52 45 41 44 53 41 46 45 3d 30 58 42 49 .THREADSAFE=0XBI
+| 3104: 4e 41 52 59 18 23 05 00 25 0f 19 54 48 52 45 41 NARY.#..%..THREA
+| 3120: 44 53 41 46 45 3d 30 58 4e 4f 43 41 53 45 17 22 DSAFE=0XNOCASE..
+| 3136: 05 00 25 0f 17 54 48 52 45 41 44 53 41 46 45 3d ..%..THREADSAFE=
+| 3152: 30 58 52 54 52 49 4d 1f 21 05 00 33 0f 19 4f 4d 0XRTRIM.!..3..OM
+| 3168: 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 53 49 4f IT LOAD EXTENSIO
+| 3184: 4e 58 42 49 4e 41 52 59 1f 20 05 00 33 d3 19 4f NXBINARY. ..3..O
+| 3200: 4d 49 54 28 2c 4f 41 44 b2 04 55 85 44 54 e5 34 MIT(,OAD..U.DT.4
+| 3216: 94 f4 e5 84 e4 f4 34 15 34 51 e1 f0 50 03 30 f1 ......4.4Q..P.0.
+| 3232: 74 f4 d4 95 42 04 c4 f4 14 42 04 55 85 44 54 e5 t...B....B.U.DT.
+| 3248: 34 94 f4 e5 85 25 45 24 94 d1 f1 e0 50 03 30 f1 4....%E$....P.0.
+| 3264: 94 d4 15 82 04 d4 54 d4 f5 25 93 d3 53 03 03 03 ......T..%..S...
+| 3280: 03 03 03 05 84 24 94 e4 15 25 91 f1 d0 50 03 30 .....$...%...P.0
+| 3296: f1 94 d4 15 82 04 d4 54 d4 f5 25 93 d3 53 03 03 .......T..%..S..
+| 3312: 03 03 03 03 05 84 e4 f4 34 15 34 51 e1 c0 50 03 ........4.4Q..P.
+| 3328: 30 f1 74 d4 15 82 04 d4 54 d4 f5 25 93 d3 53 03 0.t.....T..%..S.
+| 3344: 03 03 03 03 03 05 85 25 45 24 94 d1 81 b0 50 02 .......%E$....P.
+| 3360: 50 f1 94 54 e4 14 24 c4 52 05 25 45 24 54 55 84 P..T..$.R.%E$TU.
+| 3376: 24 94 e4 15 25 91 81 a0 50 02 50 f1 94 54 e4 14 $...%...P.P..T..
+| 3392: 24 c4 52 05 25 45 24 54 55 84 e4 f4 34 15 34 51 $.R.%E$TU...4.4Q
+| 3408: 71 90 50 02 50 f1 74 54 e4 14 24 c4 52 05 25 45 q.P.P.tT..$.R.%E
+| 3424: 24 54 55 85 25 45 24 94 d1 a1 80 50 02 90 f1 94 $TU.%E$....P....
+| 3440: 54 e4 14 24 c4 52 04 d4 54 d5 35 95 33 55 84 24 T..$.R..T.5.3U.$
+| 3456: 94 e4 15 25 91 a1 70 50 02 90 f1 94 54 e4 14 24 ...%..pP....T..$
+| 3472: c4 52 04 d4 54 d5 35 95 33 55 84 e4 f4 34 15 34 .R..T.5.3U...4.4
+| 3488: 51 91 60 50 02 90 f1 74 54 e4 14 24 c4 52 04 d4 Q.`P...tT..$.R..
+| 3504: 54 d5 35 95 33 55 85 25 45 24 94 d1 81 50 50 02 T.5.3U.%E$...PP.
+| 3520: 50 f1 94 54 e4 14 24 c4 52 04 a5 34 f4 e3 15 84 P..T..$.R..4....
+| 3536: 24 94 e4 15 25 91 81 40 50 02 50 f1 94 54 e4 14 $...%..@P.P..T..
+| 3552: 24 c4 52 04 a5 34 f4 e3 15 84 e4 f4 34 15 34 51 $.R..4......4.4Q
+| 3568: 71 30 50 02 4f f1 74 54 e4 14 24 c4 52 04 a5 34 q0P.O.tT..$.R..4
+| 3584: f4 e3 15 85 25 45 24 94 d1 a1 20 50 02 90 f1 94 ....%E$... P....
+| 3600: 54 e4 14 24 c4 52 04 74 54 f5 04 f4 c5 95 84 24 T..$.R.tT......$
+| 3616: 94 e4 15 25 91 a1 10 50 02 90 f1 94 54 e4 14 24 ...%...P....T..$
+| 3632: c4 52 04 74 54 f5 04 f4 c5 95 84 e4 f4 34 15 34 .R.tT........4.4
+| 3648: 51 91 00 50 02 90 f1 74 54 e4 14 24 c4 51 f4 74 Q..P...tT..$.Q.t
+| 3664: 54 f5 04 f4 c5 95 85 25 45 24 94 d1 70 f0 50 02 T......%E$..p.P.
+| 3680: 30 f1 94 54 e4 14 24 c5 20 46 54 53 35 58 42 49 0..T..$. FTS5XBI
+| 3696: 4e 41 52 59 17 0e 05 00 23 0f 19 45 4e 41 42 4c NARY....#..ENABL
+| 3712: 45 20 46 54 53 35 58 4f 4f 43 41 53 45 16 0d 05 E FTS5XOOCASE...
+| 3728: 00 23 0f 17 45 4e 41 42 4c 45 20 46 54 53 35 58 .#..ENABLE FTS5X
+| 3744: 52 54 52 49 4d 17 0c 05 00 23 0f 19 45 4e 41 42 RTRIM....#..ENAB
+| 3760: 4c 45 20 46 54 53 34 58 42 49 4e 41 52 59 97 0b LE FTS4XBINARY..
+| 3776: 05 00 23 0f 19 45 4e 41 42 4c 45 20 46 54 53 34 ..#..ENABLE FTS4
+| 3792: 58 4e 4f 43 41 53 45 16 0a 05 00 23 0f 17 45 4e XNOCASE....#..EN
+| 3808: 41 42 4c 45 20 46 54 53 34 58 52 54 52 49 4d 1e ABLE FTS4XRTRIM.
+| 3824: 09 05 00 3e 5f 19 45 4e 41 42 4c 45 20 44 42 53 ...>_.ENABLE DBS
+| 3840: 44 41 54 20 56 54 41 42 58 42 49 4e 41 52 59 1e DAT VTABXBINARY.
+| 3856: 08 05 00 31 0f 19 45 4e 41 42 4c 45 20 44 42 53 ...1..ENABLE DBS
+| 3872: 54 41 54 20 56 54 41 42 58 4e 4f 43 4d e3 45 1d TAT VTABXNOCM.E.
+| 3888: 07 05 00 31 0f 17 45 4e 41 42 4c 45 20 44 42 53 ...1..ENABLE DBS
+| 3904: 54 41 54 20 56 54 41 42 58 52 54 52 49 4d 11 06 TAT VTABXRTRIM..
+| 3920: 05 00 17 0f 19 44 45 42 55 47 58 42 49 4e 41 52 .....DEBUGXBINAR
+| 3936: 59 11 05 05 00 17 0f 19 44 45 42 55 47 58 4e 4f Y.......DEBUGXNO
+| 3952: 43 41 53 45 10 02 02 50 08 5f 17 44 45 42 55 47 CASE...P._.DEBUG
+| 3968: 58 52 54 52 49 4d 27 03 05 00 44 0f 19 43 4f 4d XRTRIM'...D..COM
+| 3984: 50 49 4c 45 52 3d 67 63 63 2d 35 2e 34 2e 30 20 PILER=gcc-5.4.0
+| 4000: 32 30 31 36 30 36 30 39 58 42 49 4e 41 52 59 27 20160609XBINARY'
+| 4016: 02 05 00 43 0f 19 43 4f 4d 50 49 4c 45 52 3d 67 ...C..COMPILER=g
+| 4032: 63 63 2d 35 2e 34 2e 30 20 32 30 31 36 30 36 30 cc-5.4.0 2016060
+| 4048: 39 58 4e 4f 43 41 53 45 26 01 05 00 43 c9 17 43 9XNOCASE&...C..C
+| 4064: 4f 4d 50 49 4c 47 02 3d 67 63 63 2d 35 2e 34 2e OMPILG.=gcc-5.4.
+| 4080: 30 20 32 30 31 36 30 36 30 39 58 52 54 52 49 4d 0 20160609XRTRIM
+| page 6 offset 20480
+| 0: 0d 00 00 00 24 0e e0 00 0f f8 0f f0 0f e8 0f e0 ....$...........
+| 16: 0f d8 0f d0 0f c8 0f c0 0f b8 0f b0 0f a8 0f a0 ................
+| 32: 0f 98 0f 90 0f 88 0f 80 0f 78 0f 70 0f 68 0f 60 .........x.p.h.`
+| 48: 0f 58 0f 50 0f 48 0f 40 0f 38 00 00 00 00 00 00 .X.P.H.@.8......
+| 3808: 06 24 03 00 12 02 01 01 06 23 03 00 12 02 01 01 .$.......#......
+| 3824: 06 22 03 00 12 02 01 01 06 21 03 00 12 03 01 01 .........!......
+| 3840: 06 20 03 00 12 03 01 01 06 1f 03 00 12 03 01 01 . ..............
+| 3856: 06 1e 03 00 12 03 01 01 06 1d 03 00 12 03 01 01 ................
+| 3872: 06 1c 03 00 12 03 01 01 06 1b 03 00 12 02 01 01 ................
+| 3888: 06 1a 03 00 12 02 01 01 06 19 03 00 12 02 01 01 ................
+| 3904: 06 18 03 00 12 02 01 01 06 17 03 00 12 02 01 01 ................
+| 3920: 06 16 03 00 12 02 01 01 06 15 03 00 12 02 01 01 ................
+| 3936: 06 14 03 00 12 02 01 01 06 13 03 00 12 02 01 01 ................
+| 3952: 06 12 03 00 12 02 01 01 06 11 03 00 12 02 01 01 ................
+| 3968: 06 10 03 00 12 02 01 01 06 1f 03 00 12 02 01 01 ................
+| 3984: 06 0e 03 00 12 02 01 01 06 0d 03 00 12 02 01 01 ................
+| 4000: 06 0c 03 00 12 02 01 01 06 0b 03 00 12 02 01 01 ................
+| 4016: 06 0a 03 00 12 02 01 01 06 09 03 00 12 03 01 01 ................
+| 4032: 06 08 03 00 12 03 01 01 06 07 03 00 12 03 01 01 ................
+| 4048: 06 06 03 00 12 01 01 01 06 05 03 00 12 01 01 01 ................
+| 4064: 06 04 03 00 12 01 01 01 06 03 03 00 12 06 01 01 ................
+| 4080: 06 02 03 00 12 06 01 01 06 01 03 00 12 06 01 01 ................
+| page 7 offset 24576
+| 0: 0a 00 00 00 01 0f f4 00 0f f4 00 00 00 00 00 00 ................
+| 4080: 00 00 00 00 0b 03 1b 01 76 65 72 73 69 6f 6e 04 ........version.
+| page 8 offset 28672
+| 0: 0d 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+| 4048: 00 00 00 00 00 00 11 03 02 2b 69 6e 74 65 67 72 .........+integr
+| 4064: 69 74 79 2d 63 68 65 63 6b 09 00 00 00 00 00 00 ity-check.......
+| end crash-31c462b8b665d0.db
+}]} {}
+
+
+do_catchsql_test 69.2 {
+ SELECT * FROM t1 WHERE a MATCH 'fx*'
+} {1 {database disk image is malformed}}
sqlite3_fts5_may_be_corrupt 0
finish_test
diff --git a/ext/icu/README.txt b/ext/icu/README.txt
index af75d22e6..be443f54e 100644
--- a/ext/icu/README.txt
+++ b/ext/icu/README.txt
@@ -116,7 +116,8 @@ SQLite. Documentation follows.
and use it as a dynamically loadable SQLite extension. To do this
using gcc on *nix:
- gcc -shared icu.c `icu-config --ldflags` -o libSqliteIcu.so
+ gcc -fPIC -shared icu.c `pkg-config --libs --cflags icu-uc icu-io` \
+ -o libSqliteIcu.so
You may need to add "-I" flags so that gcc can find sqlite3ext.h
and sqlite3.h. The resulting shared lib, libSqliteIcu.so, may be
diff --git a/ext/icu/sqliteicu.h b/ext/icu/sqliteicu.h
index 69b42f982..24a4d623b 100644
--- a/ext/icu/sqliteicu.h
+++ b/ext/icu/sqliteicu.h
@@ -24,4 +24,3 @@ int sqlite3IcuInit(sqlite3 *db);
#ifdef __cplusplus
} /* extern "C" */
#endif /* __cplusplus */
-
diff --git a/ext/lsm1/lsm-test/lsmtest1.c b/ext/lsm1/lsm-test/lsmtest1.c
index dcbc71842..1ce2cc058 100644
--- a/ext/lsm1/lsm-test/lsmtest1.c
+++ b/ext/lsm1/lsm-test/lsmtest1.c
@@ -654,5 +654,3 @@ void test_data_3(
testFree(zName);
}
}
-
-
diff --git a/ext/lsm1/lsm-test/lsmtest8.c b/ext/lsm1/lsm-test/lsmtest8.c
index f734ac6ab..7efa0dfa6 100644
--- a/ext/lsm1/lsm-test/lsmtest8.c
+++ b/ext/lsm1/lsm-test/lsmtest8.c
@@ -322,5 +322,3 @@ void do_writer_crash_test(const char *zPattern, int *pRc){
}
}
-
-
diff --git a/ext/lsm1/lsm-test/lsmtest9.c b/ext/lsm1/lsm-test/lsmtest9.c
index 144cae720..b01de0d4e 100644
--- a/ext/lsm1/lsm-test/lsmtest9.c
+++ b/ext/lsm1/lsm-test/lsmtest9.c
@@ -138,6 +138,3 @@ void test_data_4(
testFree(zName);
}
}
-
-
-
diff --git a/ext/lsm1/lsm-test/lsmtest_bt.c b/ext/lsm1/lsm-test/lsmtest_bt.c
index 5135dd055..8a4f54a8c 100644
--- a/ext/lsm1/lsm-test/lsmtest_bt.c
+++ b/ext/lsm1/lsm-test/lsmtest_bt.c
@@ -69,7 +69,3 @@ int do_bt(int nArg, char **azArg){
sqlite4_buffer_clear(&buf.output);
return 0;
}
-
-
-
-
diff --git a/ext/lsm1/lsm-test/lsmtest_tdb.c b/ext/lsm1/lsm-test/lsmtest_tdb.c
index 9c4f9df8a..8f63f64ac 100644
--- a/ext/lsm1/lsm-test/lsmtest_tdb.c
+++ b/ext/lsm1/lsm-test/lsmtest_tdb.c
@@ -553,7 +553,7 @@ static int sql_begin(TestDb *pTestDb, int iLevel){
/* If there are no transactions at all open, open a read transaction. */
if( pDb->nOpenTrans==0 ){
int rc = sqlite3_exec(pDb->db,
- "BEGIN; SELECT * FROM sqlite_master LIMIT 1;" , 0, 0, 0
+ "BEGIN; SELECT * FROM sqlite_schema LIMIT 1;" , 0, 0, 0
);
if( rc!=0 ) return rc;
pDb->nOpenTrans = 1;
diff --git a/ext/lsm1/lsm-test/lsmtest_tdb2.cc b/ext/lsm1/lsm-test/lsmtest_tdb2.cc
index 307c2b5f0..86ebb4958 100644
--- a/ext/lsm1/lsm-test/lsmtest_tdb2.cc
+++ b/ext/lsm1/lsm-test/lsmtest_tdb2.cc
@@ -367,4 +367,3 @@ int test_mdb_scan(
}
#endif /* HAVE_MDB */
-
diff --git a/ext/lsm1/lsm-test/lsmtest_tdb4.c b/ext/lsm1/lsm-test/lsmtest_tdb4.c
index c45b0529a..1f9292852 100644
--- a/ext/lsm1/lsm-test/lsmtest_tdb4.c
+++ b/ext/lsm1/lsm-test/lsmtest_tdb4.c
@@ -978,5 +978,3 @@ static int bgc_detach(BtDb *pDb){
/*
** End of background checkpointer.
*************************************************************************/
-
-
diff --git a/ext/lsm1/lsm_unix.c b/ext/lsm1/lsm_unix.c
index 22240771e..88952d15f 100644
--- a/ext/lsm1/lsm_unix.c
+++ b/ext/lsm1/lsm_unix.c
@@ -228,6 +228,10 @@ static int lsmPosixOsRemap(
}
p->pMap = mmap(0, iSz, PROT_READ|PROT_WRITE, MAP_SHARED, p->fd, 0);
+ if( p->pMap==MAP_FAILED ){
+ p->pMap = 0;
+ return LSM_IOERR_BKPT;
+ }
p->nMap = iSz;
}
@@ -413,7 +417,10 @@ static int lsmPosixOsShmMap(lsm_file *pFile, int iChunk, int sz, void **ppShm){
p->apShm[iChunk] = mmap(0, LSM_SHM_CHUNK_SIZE,
PROT_READ|PROT_WRITE, MAP_SHARED, p->shmfd, iChunk*LSM_SHM_CHUNK_SIZE
);
- if( p->apShm[iChunk]==0 ) return LSM_IOERR_BKPT;
+ if( p->apShm[iChunk]==MAP_FAILED ){
+ p->apShm[iChunk] = 0;
+ return LSM_IOERR_BKPT;
+ }
}
*ppShm = p->apShm[iChunk];
diff --git a/ext/misc/btreeinfo.c b/ext/misc/btreeinfo.c
index 0624fc177..22f826813 100644
--- a/ext/misc/btreeinfo.c
+++ b/ext/misc/btreeinfo.c
@@ -21,7 +21,7 @@
** name TEXT, -- Name of table or index for this btree.
** tbl_name TEXT, -- Associated table
** rootpage INT, -- The root page of the btree
-** sql TEXT, -- SQL for this btree - from sqlite_master
+** sql TEXT, -- SQL for this btree - from sqlite_schema
** hasRowid BOOLEAN, -- True if the btree has a rowid
** nEntry INT, -- Estimated number of entries
** nPage INT, -- Estimated number of pages
@@ -30,9 +30,9 @@
** zSchema TEXT HIDDEN -- The schema to which this btree belongs
** );
**
-** The first 5 fields are taken directly from the sqlite_master table.
+** The first 5 fields are taken directly from the sqlite_schema table.
** Considering only the first 5 fields, the only difference between
-** this virtual table and the sqlite_master table is that this virtual
+** this virtual table and the sqlite_schema table is that this virtual
** table omits all entries that have a 0 or NULL rowid - in other words
** it omits triggers and views.
**
@@ -88,7 +88,7 @@ typedef struct BinfoCursor BinfoCursor;
/* A cursor for the sqlite_btreeinfo table */
struct BinfoCursor {
sqlite3_vtab_cursor base; /* Base class. Must be first */
- sqlite3_stmt *pStmt; /* Query against sqlite_master */
+ sqlite3_stmt *pStmt; /* Query against sqlite_schema */
int rc; /* Result of previous sqlite_step() call */
int hasRowid; /* hasRowid value. Negative if unknown. */
sqlite3_int64 nEntry; /* nEntry value */
@@ -242,10 +242,10 @@ static int binfoFilter(
pCsr->zSchema = sqlite3_mprintf("main");
}
zSql = sqlite3_mprintf(
- "SELECT 0, 'table','sqlite_master','sqlite_master',1,NULL "
+ "SELECT 0, 'table','sqlite_schema','sqlite_schema',1,NULL "
"UNION ALL "
"SELECT rowid, type, name, tbl_name, rootpage, sql"
- " FROM \"%w\".sqlite_master WHERE rootpage>=1",
+ " FROM \"%w\".sqlite_schema WHERE rootpage>=1",
pCsr->zSchema);
sqlite3_finalize(pCsr->pStmt);
pCsr->pStmt = 0;
diff --git a/ext/misc/cksumvfs.c b/ext/misc/cksumvfs.c
new file mode 100644
index 000000000..80ace2ac8
--- /dev/null
+++ b/ext/misc/cksumvfs.c
@@ -0,0 +1,797 @@
+/*
+** 2020-04-20
+**
+** The author disclaims copyright to this source code. In place of
+** a legal notice, here is a blessing:
+**
+** May you do good and not evil.
+** May you find forgiveness for yourself and forgive others.
+** May you share freely, never taking more than you give.
+**
+******************************************************************************
+**
+** This file implements a VFS shim that writes a checksum on each page
+** of an SQLite database file. When reading pages, the checksum is verified
+** and an error is raised if the checksum is incorrect.
+**
+** COMPILING
+**
+** This extension requires SQLite 3.32.0 or later. It uses the
+** sqlite3_database_file_object() interface which was added in
+** version 3.32.0, so it will not link with an earlier version of
+** SQLite.
+**
+** To build this extension as a separately loaded shared library or
+** DLL, use compiler command-lines similar to the following:
+**
+** (linux) gcc -fPIC -shared cksumvfs.c -o cksumvfs.so
+** (mac) clang -fPIC -dynamiclib cksumvfs.c -o cksumvfs.dylib
+** (windows) cl cksumvfs.c -link -dll -out:cksumvfs.dll
+**
+** You may want to add additional compiler options, of course,
+** according to the needs of your project.
+**
+** If you want to statically link this extension with your product,
+** then compile it like any other C-language module but add the
+** "-DSQLITE_CKSUMVFS_STATIC" option so that this module knows that
+** it is being statically linked rather than dynamically linked
+**
+** LOADING
+**
+** To load this extension as a shared library, you first have to
+** bring up a dummy SQLite database connection to use as the argument
+** to the sqlite3_load_extension() API call. Then you invoke the
+** sqlite3_load_extension() API and shutdown the dummy database
+** connection. All subsequent database connections that are opened
+** will include this extension. For example:
+**
+** sqlite3 *db;
+** sqlite3_open(":memory:", &db);
+** sqlite3_load_extention(db, "./cksumvfs");
+** sqlite3_close(db);
+**
+** If this extension is compiled with -DSQLITE_CKSUMVFS_STATIC and
+** statically linked against the application, initialize it using
+** a single API call as follows:
+**
+** sqlite3_cksumvfs_init();
+**
+** Cksumvfs is a VFS Shim. When loaded, "cksmvfs" becomes the new
+** default VFS and it uses the prior default VFS as the next VFS
+** down in the stack. This is normally what you want. However, it
+** complex situations where multiple VFS shims are being loaded,
+** it might be important to ensure that cksumvfs is loaded in the
+** correct order so that it sequences itself into the default VFS
+** Shim stack in the right order.
+**
+** USING
+**
+** Open database connections using the sqlite3_open() or
+** sqlite3_open_v2() interfaces, as normal. Ordinary database files
+** (without a checksum) will operate normally. Databases with
+** checksums will return an SQLITE_IOERR_DATA error if a page is
+** encountered that contains an invalid checksum.
+**
+** Checksumming only works on databases that have a reserve-bytes
+** value of exactly 8. The default value for reserve-bytes is 0.
+** Hence, newly created database files will omit the checksum by
+** default. To create a database that includes a checksum, change
+** the reserve-bytes value to 8 by runing:
+**
+** int n = 8;
+** sqlite3_file_control(db, 0, SQLITE_FCNTL_RESERVED_BYTES, &n);
+**
+** If you do this immediately after creating a new database file,
+** before anything else has been written into the file, then that
+** might be all that you need to do. Otherwise, the API call
+** above should be followed by:
+**
+** sqlite3_exec(db, "VACUUM", 0, 0, 0);
+**
+** It never hurts to run the VACUUM, even if you don't need it.
+** If the database is in WAL mode, you should shutdown and
+** reopen all database connections before continuing.
+**
+** From the CLI, use the ".filectrl reserve_bytes 8" command,
+** followed by "VACUUM;".
+**
+** Note that SQLite allows the number of reserve-bytes to be
+** increased but not decreased. So if a database file already
+** has a reserve-bytes value greater than 8, there is no way to
+** activate checksumming on that database, other than to dump
+** and restore the database file. Note also that other extensions
+** might also make use of the reserve-bytes. Checksumming will
+** be incompatible with those other extensions.
+**
+** VERIFICATION OF CHECKSUMS
+**
+** If any checksum is incorrect, the "PRAGMA quick_check" command
+** will find it. To verify that checksums are actually enabled
+** and running, use the following query:
+**
+** SELECT count(*), verify_checksum(data)
+** FROM sqlite_dbpage
+** GROUP BY 2;
+**
+** There are three possible outputs form the verify_checksum()
+** function: 1, 0, and NULL. 1 is returned if the checksum is
+** correct. 0 is returned if the checksum is incorrect. NULL
+** is returned if the page is unreadable. If checksumming is
+** enabled, the read will fail if the checksum is wrong, so the
+** usual result from verify_checksum() on a bad checksum is NULL.
+**
+** If everything is OK, the query above should return a single
+** row where the second column is 1. Any other result indicates
+** either that there is a checksum error, or checksum validation
+** is disabled.
+**
+** CONTROLLING CHECKSUM VERIFICATION
+**
+** The cksumvfs extension implements a new PRAGMA statement that can
+** be used to disable, re-enable, or query the status of checksum
+** verification:
+**
+** PRAGMA checksum_verification; -- query status
+** PRAGMA checksum_verification=OFF; -- disable verification
+** PRAGMA checksum_verification=ON; -- re-enable verification
+**
+** The "checksum_verification" pragma will return "1" (true) or "0"
+** (false) if checksum verification is enabled or disabled, respectively.
+** "Verification" in this context means the feature that causes
+** SQLITE_IOERR_DATA errors if a checksum mismatch is detected while
+** reading. Checksums are always kept up-to-date as long as the
+** reserve-bytes value of the database is 8, regardless of the setting
+** of this pragma. Checksum verification can be disabled (for example)
+** to do forensic analysis of a database that has previously reported
+** a checksum error.
+**
+** The "checksum_verification" pragma will always respond with "0" if
+** the database file does not have a reserve-bytes value of 8. The
+** pragma will return no rows at all if the cksumvfs extension is
+** not loaded.
+**
+** IMPLEMENTATION NOTES
+**
+** The checksum is stored in the last 8 bytes of each page. This
+** module only operates if the "bytes of reserved space on each page"
+** value at offset 20 the SQLite database header is exactly 8. If
+** the reserved-space value is not 8, this module is a no-op.
+*/
+#ifdef SQLITE_CKSUMVFS_STATIC
+# include "sqlite3.h"
+#else
+# include "sqlite3ext.h"
+ SQLITE_EXTENSION_INIT1
+#endif
+#include <string.h>
+#include <assert.h>
+
+
+/*
+** Forward declaration of objects used by this utility
+*/
+typedef struct sqlite3_vfs CksmVfs;
+typedef struct CksmFile CksmFile;
+
+/*
+** Useful datatype abbreviations
+*/
+#if !defined(SQLITE_CORE)
+ typedef unsigned char u8;
+ typedef unsigned int u32;
+#endif
+
+/* Access to a lower-level VFS that (might) implement dynamic loading,
+** access to randomness, etc.
+*/
+#define ORIGVFS(p) ((sqlite3_vfs*)((p)->pAppData))
+#define ORIGFILE(p) ((sqlite3_file*)(((CksmFile*)(p))+1))
+
+/* An open file */
+struct CksmFile {
+ sqlite3_file base; /* IO methods */
+ const char *zFName; /* Original name of the file */
+ char computeCksm; /* True to compute checksums.
+ ** Always true if reserve size is 8. */
+ char verifyCksm; /* True to verify checksums */
+ char isWal; /* True if processing a WAL file */
+ char inCkpt; /* Currently doing a checkpoint */
+ CksmFile *pPartner; /* Ptr from WAL to main-db, or from main-db to WAL */
+};
+
+/*
+** Methods for CksmFile
+*/
+static int cksmClose(sqlite3_file*);
+static int cksmRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst);
+static int cksmWrite(sqlite3_file*,const void*,int iAmt, sqlite3_int64 iOfst);
+static int cksmTruncate(sqlite3_file*, sqlite3_int64 size);
+static int cksmSync(sqlite3_file*, int flags);
+static int cksmFileSize(sqlite3_file*, sqlite3_int64 *pSize);
+static int cksmLock(sqlite3_file*, int);
+static int cksmUnlock(sqlite3_file*, int);
+static int cksmCheckReservedLock(sqlite3_file*, int *pResOut);
+static int cksmFileControl(sqlite3_file*, int op, void *pArg);
+static int cksmSectorSize(sqlite3_file*);
+static int cksmDeviceCharacteristics(sqlite3_file*);
+static int cksmShmMap(sqlite3_file*, int iPg, int pgsz, int, void volatile**);
+static int cksmShmLock(sqlite3_file*, int offset, int n, int flags);
+static void cksmShmBarrier(sqlite3_file*);
+static int cksmShmUnmap(sqlite3_file*, int deleteFlag);
+static int cksmFetch(sqlite3_file*, sqlite3_int64 iOfst, int iAmt, void **pp);
+static int cksmUnfetch(sqlite3_file*, sqlite3_int64 iOfst, void *p);
+
+/*
+** Methods for CksmVfs
+*/
+static int cksmOpen(sqlite3_vfs*, const char *, sqlite3_file*, int , int *);
+static int cksmDelete(sqlite3_vfs*, const char *zName, int syncDir);
+static int cksmAccess(sqlite3_vfs*, const char *zName, int flags, int *);
+static int cksmFullPathname(sqlite3_vfs*, const char *zName, int, char *zOut);
+static void *cksmDlOpen(sqlite3_vfs*, const char *zFilename);
+static void cksmDlError(sqlite3_vfs*, int nByte, char *zErrMsg);
+static void (*cksmDlSym(sqlite3_vfs *pVfs, void *p, const char*zSym))(void);
+static void cksmDlClose(sqlite3_vfs*, void*);
+static int cksmRandomness(sqlite3_vfs*, int nByte, char *zOut);
+static int cksmSleep(sqlite3_vfs*, int microseconds);
+static int cksmCurrentTime(sqlite3_vfs*, double*);
+static int cksmGetLastError(sqlite3_vfs*, int, char *);
+static int cksmCurrentTimeInt64(sqlite3_vfs*, sqlite3_int64*);
+static int cksmSetSystemCall(sqlite3_vfs*, const char*,sqlite3_syscall_ptr);
+static sqlite3_syscall_ptr cksmGetSystemCall(sqlite3_vfs*, const char *z);
+static const char *cksmNextSystemCall(sqlite3_vfs*, const char *zName);
+
+static sqlite3_vfs cksm_vfs = {
+ 3, /* iVersion (set when registered) */
+ 0, /* szOsFile (set when registered) */
+ 1024, /* mxPathname */
+ 0, /* pNext */
+ "cksmvfs", /* zName */
+ 0, /* pAppData (set when registered) */
+ cksmOpen, /* xOpen */
+ cksmDelete, /* xDelete */
+ cksmAccess, /* xAccess */
+ cksmFullPathname, /* xFullPathname */
+ cksmDlOpen, /* xDlOpen */
+ cksmDlError, /* xDlError */
+ cksmDlSym, /* xDlSym */
+ cksmDlClose, /* xDlClose */
+ cksmRandomness, /* xRandomness */
+ cksmSleep, /* xSleep */
+ cksmCurrentTime, /* xCurrentTime */
+ cksmGetLastError, /* xGetLastError */
+ cksmCurrentTimeInt64, /* xCurrentTimeInt64 */
+ cksmSetSystemCall, /* xSetSystemCall */
+ cksmGetSystemCall, /* xGetSystemCall */
+ cksmNextSystemCall /* xNextSystemCall */
+};
+
+static const sqlite3_io_methods cksm_io_methods = {
+ 3, /* iVersion */
+ cksmClose, /* xClose */
+ cksmRead, /* xRead */
+ cksmWrite, /* xWrite */
+ cksmTruncate, /* xTruncate */
+ cksmSync, /* xSync */
+ cksmFileSize, /* xFileSize */
+ cksmLock, /* xLock */
+ cksmUnlock, /* xUnlock */
+ cksmCheckReservedLock, /* xCheckReservedLock */
+ cksmFileControl, /* xFileControl */
+ cksmSectorSize, /* xSectorSize */
+ cksmDeviceCharacteristics, /* xDeviceCharacteristics */
+ cksmShmMap, /* xShmMap */
+ cksmShmLock, /* xShmLock */
+ cksmShmBarrier, /* xShmBarrier */
+ cksmShmUnmap, /* xShmUnmap */
+ cksmFetch, /* xFetch */
+ cksmUnfetch /* xUnfetch */
+};
+
+/* Do byte swapping on a unsigned 32-bit integer */
+#define BYTESWAP32(x) ( \
+ (((x)&0x000000FF)<<24) + (((x)&0x0000FF00)<<8) \
+ + (((x)&0x00FF0000)>>8) + (((x)&0xFF000000)>>24) \
+)
+
+/* Compute a checksum on a buffer */
+static void cksmCompute(
+ u8 *a, /* Content to be checksummed */
+ int nByte, /* Bytes of content in a[]. Must be a multiple of 8. */
+ u8 *aOut /* OUT: Final 8-byte checksum value output */
+){
+ u32 s1 = 0, s2 = 0;
+ u32 *aData = (u32*)a;
+ u32 *aEnd = (u32*)&a[nByte];
+ u32 x = 1;
+
+ assert( nByte>=8 );
+ assert( (nByte&0x00000007)==0 );
+ assert( nByte<=65536 );
+
+ if( 1 == *(u8*)&x ){
+ /* Little-endian */
+ do {
+ s1 += *aData++ + s2;
+ s2 += *aData++ + s1;
+ }while( aData<aEnd );
+ }else{
+ /* Big-endian */
+ do {
+ s1 += BYTESWAP32(aData[0]) + s2;
+ s2 += BYTESWAP32(aData[1]) + s1;
+ aData += 2;
+ }while( aData<aEnd );
+ s1 = BYTESWAP32(s1);
+ s2 = BYTESWAP32(s2);
+ }
+ memcpy(aOut, &s1, 4);
+ memcpy(aOut+4, &s2, 4);
+}
+
+/*
+** SQL function: verify_checksum(BLOB)
+**
+** Return 0 or 1 if the checksum is invalid or valid. Or return
+** NULL if the input is not a BLOB that is the right size for a
+** database page.
+*/
+static void cksmVerifyFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ int nByte;
+ u8 *data;
+ u8 cksum[8];
+ data = (u8*)sqlite3_value_blob(argv[0]);
+ if( data==0 ) return;
+ if( sqlite3_value_type(argv[0])!=SQLITE_BLOB ) return;
+ nByte = sqlite3_value_bytes(argv[0]);
+ if( nByte<512 || nByte>65536 || (nByte & (nByte-1))!=0 ) return;
+ cksmCompute(data, nByte-8, cksum);
+ sqlite3_result_int(context, memcmp(data+nByte-8,cksum,8)==0);
+}
+
+/*
+** Close a cksm-file.
+*/
+static int cksmClose(sqlite3_file *pFile){
+ CksmFile *p = (CksmFile *)pFile;
+ if( p->pPartner ){
+ assert( p->pPartner->pPartner==p );
+ p->pPartner->pPartner = 0;
+ p->pPartner = 0;
+ }
+ pFile = ORIGFILE(pFile);
+ return pFile->pMethods->xClose(pFile);
+}
+
+/*
+** Set the computeCkSm and verifyCksm flags, if they need to be
+** changed.
+*/
+static void cksmSetFlags(CksmFile *p, int hasCorrectReserveSize){
+ if( hasCorrectReserveSize!=p->computeCksm ){
+ p->computeCksm = p->verifyCksm = hasCorrectReserveSize;
+ if( p->pPartner ){
+ p->pPartner->verifyCksm = hasCorrectReserveSize;
+ p->pPartner->computeCksm = hasCorrectReserveSize;
+ }
+ }
+}
+
+/*
+** Read data from a cksm-file.
+*/
+static int cksmRead(
+ sqlite3_file *pFile,
+ void *zBuf,
+ int iAmt,
+ sqlite_int64 iOfst
+){
+ int rc;
+ CksmFile *p = (CksmFile *)pFile;
+ pFile = ORIGFILE(pFile);
+ rc = pFile->pMethods->xRead(pFile, zBuf, iAmt, iOfst);
+ if( rc==SQLITE_OK ){
+ if( iOfst==0 && iAmt>=100 && memcmp(zBuf,"SQLite format 3",16)==0 ){
+ u8 *d = (u8*)zBuf;
+ char hasCorrectReserveSize = (d[20]==8);
+ cksmSetFlags(p, hasCorrectReserveSize);
+ }
+ /* Verify the checksum if
+ ** (1) the size indicates that we are dealing with a complete
+ ** database page
+ ** (2) checksum verification is enabled
+ ** (3) we are not in the middle of checkpoint
+ */
+ if( iAmt>=512 /* (1) */
+ && p->verifyCksm /* (2) */
+ && !p->inCkpt /* (3) */
+ ){
+ u8 cksum[8];
+ cksmCompute((u8*)zBuf, iAmt-8, cksum);
+ if( memcmp((u8*)zBuf+iAmt-8, cksum, 8)!=0 ){
+ sqlite3_log(SQLITE_IOERR_DATA,
+ "checksum fault offset %lld of \"%s\"",
+ iOfst, p->zFName);
+ rc = SQLITE_IOERR_DATA;
+ }
+ }
+ }
+ return rc;
+}
+
+/*
+** Write data to a cksm-file.
+*/
+static int cksmWrite(
+ sqlite3_file *pFile,
+ const void *zBuf,
+ int iAmt,
+ sqlite_int64 iOfst
+){
+ CksmFile *p = (CksmFile *)pFile;
+ pFile = ORIGFILE(pFile);
+ if( iOfst==0 && iAmt>=100 && memcmp(zBuf,"SQLite format 3",16)==0 ){
+ u8 *d = (u8*)zBuf;
+ char hasCorrectReserveSize = (d[20]==8);
+ cksmSetFlags(p, hasCorrectReserveSize);
+ }
+ /* If the write size is appropriate for a database page and if
+ ** checksums where ever enabled, then it will be safe to compute
+ ** the checksums. The reserve byte size might have increased, but
+ ** it will never decrease. And because it cannot decrease, the
+ ** checksum will not overwrite anything.
+ */
+ if( iAmt>=512
+ && p->computeCksm
+ && !p->inCkpt
+ ){
+ cksmCompute((u8*)zBuf, iAmt-8, ((u8*)zBuf)+iAmt-8);
+ }
+ return pFile->pMethods->xWrite(pFile, zBuf, iAmt, iOfst);
+}
+
+/*
+** Truncate a cksm-file.
+*/
+static int cksmTruncate(sqlite3_file *pFile, sqlite_int64 size){
+ pFile = ORIGFILE(pFile);
+ return pFile->pMethods->xTruncate(pFile, size);
+}
+
+/*
+** Sync a cksm-file.
+*/
+static int cksmSync(sqlite3_file *pFile, int flags){
+ pFile = ORIGFILE(pFile);
+ return pFile->pMethods->xSync(pFile, flags);
+}
+
+/*
+** Return the current file-size of a cksm-file.
+*/
+static int cksmFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
+ CksmFile *p = (CksmFile *)pFile;
+ pFile = ORIGFILE(p);
+ return pFile->pMethods->xFileSize(pFile, pSize);
+}
+
+/*
+** Lock a cksm-file.
+*/
+static int cksmLock(sqlite3_file *pFile, int eLock){
+ pFile = ORIGFILE(pFile);
+ return pFile->pMethods->xLock(pFile, eLock);
+}
+
+/*
+** Unlock a cksm-file.
+*/
+static int cksmUnlock(sqlite3_file *pFile, int eLock){
+ pFile = ORIGFILE(pFile);
+ return pFile->pMethods->xUnlock(pFile, eLock);
+}
+
+/*
+** Check if another file-handle holds a RESERVED lock on a cksm-file.
+*/
+static int cksmCheckReservedLock(sqlite3_file *pFile, int *pResOut){
+ pFile = ORIGFILE(pFile);
+ return pFile->pMethods->xCheckReservedLock(pFile, pResOut);
+}
+
+/*
+** File control method. For custom operations on a cksm-file.
+*/
+static int cksmFileControl(sqlite3_file *pFile, int op, void *pArg){
+ int rc;
+ CksmFile *p = (CksmFile*)pFile;
+ pFile = ORIGFILE(pFile);
+ if( op==SQLITE_FCNTL_PRAGMA ){
+ char **azArg = (char**)pArg;
+ assert( azArg[1]!=0 );
+ if( sqlite3_stricmp(azArg[1],"checksum_verification")==0 ){
+ char *zArg = azArg[2];
+ if( zArg!=0 ){
+ if( (zArg[0]>='1' && zArg[0]<='9')
+ || sqlite3_strlike("enable%",zArg,0)==0
+ || sqlite3_stricmp("yes",zArg)==0
+ || sqlite3_stricmp("on",zArg)==0
+ ){
+ p->verifyCksm = p->computeCksm;
+ }else{
+ p->verifyCksm = 0;
+ }
+ if( p->pPartner ) p->pPartner->verifyCksm = p->verifyCksm;
+ }
+ azArg[0] = sqlite3_mprintf("%d",p->verifyCksm);
+ return SQLITE_OK;
+ }else if( p->computeCksm && azArg[2]!=0
+ && sqlite3_stricmp(azArg[1], "page_size")==0 ){
+ /* Do not allow page size changes on a checksum database */
+ return SQLITE_OK;
+ }
+ }else if( op==SQLITE_FCNTL_CKPT_START || op==SQLITE_FCNTL_CKPT_DONE ){
+ p->inCkpt = op==SQLITE_FCNTL_CKPT_START;
+ if( p->pPartner ) p->pPartner->inCkpt = p->inCkpt;
+ }
+ rc = pFile->pMethods->xFileControl(pFile, op, pArg);
+ if( rc==SQLITE_OK && op==SQLITE_FCNTL_VFSNAME ){
+ *(char**)pArg = sqlite3_mprintf("cksm/%z", *(char**)pArg);
+ }
+ return rc;
+}
+
+/*
+** Return the sector-size in bytes for a cksm-file.
+*/
+static int cksmSectorSize(sqlite3_file *pFile){
+ pFile = ORIGFILE(pFile);
+ return pFile->pMethods->xSectorSize(pFile);
+}
+
+/*
+** Return the device characteristic flags supported by a cksm-file.
+*/
+static int cksmDeviceCharacteristics(sqlite3_file *pFile){
+ pFile = ORIGFILE(pFile);
+ return pFile->pMethods->xDeviceCharacteristics(pFile);
+}
+
+/* Create a shared memory file mapping */
+static int cksmShmMap(
+ sqlite3_file *pFile,
+ int iPg,
+ int pgsz,
+ int bExtend,
+ void volatile **pp
+){
+ pFile = ORIGFILE(pFile);
+ return pFile->pMethods->xShmMap(pFile,iPg,pgsz,bExtend,pp);
+}
+
+/* Perform locking on a shared-memory segment */
+static int cksmShmLock(sqlite3_file *pFile, int offset, int n, int flags){
+ pFile = ORIGFILE(pFile);
+ return pFile->pMethods->xShmLock(pFile,offset,n,flags);
+}
+
+/* Memory barrier operation on shared memory */
+static void cksmShmBarrier(sqlite3_file *pFile){
+ pFile = ORIGFILE(pFile);
+ pFile->pMethods->xShmBarrier(pFile);
+}
+
+/* Unmap a shared memory segment */
+static int cksmShmUnmap(sqlite3_file *pFile, int deleteFlag){
+ pFile = ORIGFILE(pFile);
+ return pFile->pMethods->xShmUnmap(pFile,deleteFlag);
+}
+
+/* Fetch a page of a memory-mapped file */
+static int cksmFetch(
+ sqlite3_file *pFile,
+ sqlite3_int64 iOfst,
+ int iAmt,
+ void **pp
+){
+ CksmFile *p = (CksmFile *)pFile;
+ if( p->computeCksm ){
+ *pp = 0;
+ return SQLITE_OK;
+ }
+ pFile = ORIGFILE(pFile);
+ return pFile->pMethods->xFetch(pFile, iOfst, iAmt, pp);
+}
+
+/* Release a memory-mapped page */
+static int cksmUnfetch(sqlite3_file *pFile, sqlite3_int64 iOfst, void *pPage){
+ pFile = ORIGFILE(pFile);
+ return pFile->pMethods->xUnfetch(pFile, iOfst, pPage);
+}
+
+/*
+** Open a cksm file handle.
+*/
+static int cksmOpen(
+ sqlite3_vfs *pVfs,
+ const char *zName,
+ sqlite3_file *pFile,
+ int flags,
+ int *pOutFlags
+){
+ CksmFile *p;
+ sqlite3_file *pSubFile;
+ sqlite3_vfs *pSubVfs;
+ int rc;
+ pSubVfs = ORIGVFS(pVfs);
+ if( (flags & (SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_WAL))==0 ){
+ return pSubVfs->xOpen(pSubVfs, zName, pFile, flags, pOutFlags);
+ }
+ p = (CksmFile*)pFile;
+ memset(p, 0, sizeof(*p));
+ pSubFile = ORIGFILE(pFile);
+ p->base.pMethods = &cksm_io_methods;
+ rc = pSubVfs->xOpen(pSubVfs, zName, pSubFile, flags, pOutFlags);
+ if( rc ) goto cksm_open_done;
+ if( flags & SQLITE_OPEN_WAL ){
+ sqlite3_file *pDb = sqlite3_database_file_object(zName);
+ p->pPartner = (CksmFile*)pDb;
+ assert( p->pPartner->pPartner==0 );
+ p->pPartner->pPartner = p;
+ p->isWal = 1;
+ p->computeCksm = p->pPartner->computeCksm;
+ }else{
+ p->isWal = 0;
+ p->computeCksm = 0;
+ }
+ p->zFName = zName;
+cksm_open_done:
+ if( rc ) pFile->pMethods = 0;
+ return rc;
+}
+
+/*
+** All other VFS methods are pass-thrus.
+*/
+static int cksmDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
+ return ORIGVFS(pVfs)->xDelete(ORIGVFS(pVfs), zPath, dirSync);
+}
+static int cksmAccess(
+ sqlite3_vfs *pVfs,
+ const char *zPath,
+ int flags,
+ int *pResOut
+){
+ return ORIGVFS(pVfs)->xAccess(ORIGVFS(pVfs), zPath, flags, pResOut);
+}
+static int cksmFullPathname(
+ sqlite3_vfs *pVfs,
+ const char *zPath,
+ int nOut,
+ char *zOut
+){
+ return ORIGVFS(pVfs)->xFullPathname(ORIGVFS(pVfs),zPath,nOut,zOut);
+}
+static void *cksmDlOpen(sqlite3_vfs *pVfs, const char *zPath){
+ return ORIGVFS(pVfs)->xDlOpen(ORIGVFS(pVfs), zPath);
+}
+static void cksmDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){
+ ORIGVFS(pVfs)->xDlError(ORIGVFS(pVfs), nByte, zErrMsg);
+}
+static void (*cksmDlSym(sqlite3_vfs *pVfs, void *p, const char *zSym))(void){
+ return ORIGVFS(pVfs)->xDlSym(ORIGVFS(pVfs), p, zSym);
+}
+static void cksmDlClose(sqlite3_vfs *pVfs, void *pHandle){
+ ORIGVFS(pVfs)->xDlClose(ORIGVFS(pVfs), pHandle);
+}
+static int cksmRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
+ return ORIGVFS(pVfs)->xRandomness(ORIGVFS(pVfs), nByte, zBufOut);
+}
+static int cksmSleep(sqlite3_vfs *pVfs, int nMicro){
+ return ORIGVFS(pVfs)->xSleep(ORIGVFS(pVfs), nMicro);
+}
+static int cksmCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
+ return ORIGVFS(pVfs)->xCurrentTime(ORIGVFS(pVfs), pTimeOut);
+}
+static int cksmGetLastError(sqlite3_vfs *pVfs, int a, char *b){
+ return ORIGVFS(pVfs)->xGetLastError(ORIGVFS(pVfs), a, b);
+}
+static int cksmCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *p){
+ return ORIGVFS(pVfs)->xCurrentTimeInt64(ORIGVFS(pVfs), p);
+}
+static int cksmSetSystemCall(
+ sqlite3_vfs *pVfs,
+ const char *zName,
+ sqlite3_syscall_ptr pCall
+){
+ return ORIGVFS(pVfs)->xSetSystemCall(ORIGVFS(pVfs),zName,pCall);
+}
+static sqlite3_syscall_ptr cksmGetSystemCall(
+ sqlite3_vfs *pVfs,
+ const char *zName
+){
+ return ORIGVFS(pVfs)->xGetSystemCall(ORIGVFS(pVfs),zName);
+}
+static const char *cksmNextSystemCall(sqlite3_vfs *pVfs, const char *zName){
+ return ORIGVFS(pVfs)->xNextSystemCall(ORIGVFS(pVfs), zName);
+}
+
+/* Register the verify_checksum() SQL function.
+*/
+static int cksmRegisterFunc(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ int rc;
+ if( db==0 ) return SQLITE_OK;
+ rc = sqlite3_create_function(db, "verify_checksum", 1,
+ SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_DETERMINISTIC,
+ 0, cksmVerifyFunc, 0, 0);
+ return rc;
+}
+
+/*
+** Register the cksum VFS as the default VFS for the system.
+** Also make arrangements to automatically register the "verify_checksum()"
+** SQL function on each new database connection.
+*/
+static int cksmRegisterVfs(void){
+ int rc = SQLITE_OK;
+ sqlite3_vfs *pOrig;
+ if( sqlite3_vfs_find("cksmvfs")!=0 ) return SQLITE_OK;
+ pOrig = sqlite3_vfs_find(0);
+ cksm_vfs.iVersion = pOrig->iVersion;
+ cksm_vfs.pAppData = pOrig;
+ cksm_vfs.szOsFile = pOrig->szOsFile + sizeof(CksmFile);
+ rc = sqlite3_vfs_register(&cksm_vfs, 1);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_auto_extension((void(*)(void))cksmRegisterFunc);
+ }
+ return rc;
+}
+
+#if defined(SQLITE_CKSUMVFS_STATIC)
+/* This variant of the initializer runs when the extension is
+** statically linked.
+*/
+int sqlite3_register_cksumvfs(const char *NotUsed){
+ (void)NotUsed;
+ return cksmRegisterVfs();
+}
+#endif /* defined(SQLITE_CKSUMVFS_STATIC */
+
+#if !defined(SQLITE_CKSUMVFS_STATIC)
+/* This variant of the initializer function is used when the
+** extension is shared library to be loaded at run-time.
+*/
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+/*
+** This routine is called by sqlite3_load_extension() when the
+** extension is first loaded.
+***/
+int sqlite3_cksumvfs_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ int rc;
+ SQLITE_EXTENSION_INIT2(pApi);
+ (void)pzErrMsg; /* not used */
+ rc = cksmRegisterFunc(db, 0, 0);
+ if( rc==SQLITE_OK ){
+
+ }
+ if( rc==SQLITE_OK ){
+ rc = cksmRegisterVfs();
+ }
+ if( rc==SQLITE_OK ) rc = SQLITE_OK_LOAD_PERMANENTLY;
+ return rc;
+}
+#endif /* !defined(SQLITE_CKSUMVFS_STATIC) */
diff --git a/ext/misc/completion.c b/ext/misc/completion.c
index b624b6d47..d9e7b8597 100644
--- a/ext/misc/completion.c
+++ b/ext/misc/completion.c
@@ -226,7 +226,7 @@ static int completionNext(sqlite3_vtab_cursor *cur){
const char *zDb = (const char*)sqlite3_column_text(pS2, 1);
zSql = sqlite3_mprintf(
"%z%s"
- "SELECT name FROM \"%w\".sqlite_master",
+ "SELECT name FROM \"%w\".sqlite_schema",
zSql, zSep, zDb
);
if( zSql==0 ) return SQLITE_NOMEM;
@@ -250,7 +250,7 @@ static int completionNext(sqlite3_vtab_cursor *cur){
const char *zDb = (const char*)sqlite3_column_text(pS2, 1);
zSql = sqlite3_mprintf(
"%z%s"
- "SELECT pti.name FROM \"%w\".sqlite_master AS sm"
+ "SELECT pti.name FROM \"%w\".sqlite_schema AS sm"
" JOIN pragma_table_info(sm.name,%Q) AS pti"
" WHERE sm.type='table'",
zSql, zSep, zDb, zDb
diff --git a/ext/misc/dbdump.c b/ext/misc/dbdump.c
index 157e646bb..ecf7d810d 100644
--- a/ext/misc/dbdump.c
+++ b/ext/misc/dbdump.c
@@ -395,7 +395,7 @@ static int dump_callback(void *pArg, int nArg, char **azArg, char **azCol){
if( strcmp(zTable, "sqlite_sequence")==0 ){
p->xCallback("DELETE FROM sqlite_sequence;\n", p->pArg);
}else if( sqlite3_strglob("sqlite_stat?", zTable)==0 ){
- p->xCallback("ANALYZE sqlite_master;\n", p->pArg);
+ p->xCallback("ANALYZE sqlite_schema;\n", p->pArg);
}else if( strncmp(zTable, "sqlite_", 7)==0 ){
return 0;
}else if( strncmp(zSql, "CREATE VIRTUAL TABLE", 20)==0 ){
@@ -404,7 +404,7 @@ static int dump_callback(void *pArg, int nArg, char **azArg, char **azCol){
p->writableSchema = 1;
}
output_formatted(p,
- "INSERT INTO sqlite_master(type,name,tbl_name,rootpage,sql)"
+ "INSERT INTO sqlite_schema(type,name,tbl_name,rootpage,sql)"
"VALUES('table','%q','%q',0,'%q');",
zTable, zTable, zSql);
return 0;
@@ -646,27 +646,27 @@ int sqlite3_db_dump(
xCallback("PRAGMA foreign_keys=OFF;\nBEGIN TRANSACTION;\n", pArg);
if( zTable==0 ){
run_schema_dump_query(&x,
- "SELECT name, type, sql FROM \"%w\".sqlite_master "
+ "SELECT name, type, sql FROM \"%w\".sqlite_schema "
"WHERE sql NOT NULL AND type=='table' AND name!='sqlite_sequence'",
zSchema
);
run_schema_dump_query(&x,
- "SELECT name, type, sql FROM \"%w\".sqlite_master "
+ "SELECT name, type, sql FROM \"%w\".sqlite_schema "
"WHERE name=='sqlite_sequence'", zSchema
);
output_sql_from_query(&x,
- "SELECT sql FROM sqlite_master "
+ "SELECT sql FROM sqlite_schema "
"WHERE sql NOT NULL AND type IN ('index','trigger','view')", 0
);
}else{
run_schema_dump_query(&x,
- "SELECT name, type, sql FROM \"%w\".sqlite_master "
+ "SELECT name, type, sql FROM \"%w\".sqlite_schema "
"WHERE tbl_name=%Q COLLATE nocase AND type=='table'"
" AND sql NOT NULL",
zSchema, zTable
);
output_sql_from_query(&x,
- "SELECT sql FROM \"%w\".sqlite_master "
+ "SELECT sql FROM \"%w\".sqlite_schema "
"WHERE sql NOT NULL"
" AND type IN ('index','trigger','view')"
" AND tbl_name=%Q COLLATE nocase",
diff --git a/ext/misc/decimal.c b/ext/misc/decimal.c
new file mode 100644
index 000000000..e2c9d1ba8
--- /dev/null
+++ b/ext/misc/decimal.c
@@ -0,0 +1,619 @@
+/*
+** 2020-06-22
+**
+** 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.
+**
+******************************************************************************
+**
+** Routines to implement arbitrary-precision decimal math.
+**
+** The focus here is on simplicity and correctness, not performance.
+*/
+#include "sqlite3ext.h"
+SQLITE_EXTENSION_INIT1
+#include <assert.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+
+
+/* A decimal object */
+typedef struct Decimal Decimal;
+struct Decimal {
+ char sign; /* 0 for positive, 1 for negative */
+ char oom; /* True if an OOM is encountered */
+ char isNull; /* True if holds a NULL rather than a number */
+ char isInit; /* True upon initialization */
+ int nDigit; /* Total number of digits */
+ int nFrac; /* Number of digits to the right of the decimal point */
+ signed char *a; /* Array of digits. Most significant first. */
+};
+
+/*
+** Release memory held by a Decimal, but do not free the object itself.
+*/
+static void decimal_clear(Decimal *p){
+ sqlite3_free(p->a);
+}
+
+/*
+** Destroy a Decimal object
+*/
+static void decimal_free(Decimal *p){
+ if( p ){
+ decimal_clear(p);
+ sqlite3_free(p);
+ }
+}
+
+/*
+** Allocate a new Decimal object. Initialize it to the number given
+** by the input string.
+*/
+static Decimal *decimal_new(
+ sqlite3_context *pCtx,
+ sqlite3_value *pIn,
+ int nAlt,
+ const unsigned char *zAlt
+){
+ Decimal *p;
+ int n, i;
+ const unsigned char *zIn;
+ int iExp = 0;
+ p = sqlite3_malloc( sizeof(*p) );
+ if( p==0 ) goto new_no_mem;
+ p->sign = 0;
+ p->oom = 0;
+ p->isInit = 1;
+ p->isNull = 0;
+ p->nDigit = 0;
+ p->nFrac = 0;
+ if( zAlt ){
+ n = nAlt,
+ zIn = zAlt;
+ }else{
+ if( sqlite3_value_type(pIn)==SQLITE_NULL ){
+ p->a = 0;
+ p->isNull = 1;
+ return p;
+ }
+ n = sqlite3_value_bytes(pIn);
+ zIn = sqlite3_value_text(pIn);
+ }
+ p->a = sqlite3_malloc64( n+1 );
+ if( p->a==0 ) goto new_no_mem;
+ for(i=0; isspace(zIn[i]); i++){}
+ if( zIn[i]=='-' ){
+ p->sign = 1;
+ i++;
+ }else if( zIn[i]=='+' ){
+ i++;
+ }
+ while( i<n && zIn[i]=='0' ) i++;
+ while( i<n ){
+ char c = zIn[i];
+ if( c>='0' && c<='9' ){
+ p->a[p->nDigit++] = c - '0';
+ }else if( c=='.' ){
+ p->nFrac = p->nDigit + 1;
+ }else if( c=='e' || c=='E' ){
+ int j = i+1;
+ int neg = 0;
+ if( j>=n ) break;
+ if( zIn[j]=='-' ){
+ neg = 1;
+ j++;
+ }else if( zIn[j]=='+' ){
+ j++;
+ }
+ while( j<n && iExp<1000000 ){
+ if( zIn[j]>='0' && zIn[j]<='9' ){
+ iExp = iExp*10 + zIn[j] - '0';
+ }
+ j++;
+ }
+ if( neg ) iExp = -iExp;
+ break;
+ }
+ i++;
+ }
+ if( p->nFrac ){
+ p->nFrac = p->nDigit - (p->nFrac - 1);
+ }
+ if( iExp>0 ){
+ if( p->nFrac>0 ){
+ if( iExp<=p->nFrac ){
+ p->nFrac -= iExp;
+ iExp = 0;
+ }else{
+ iExp -= p->nFrac;
+ p->nFrac = 0;
+ }
+ }
+ if( iExp>0 ){
+ p->a = sqlite3_realloc64(p->a, p->nDigit + iExp + 1 );
+ if( p->a==0 ) goto new_no_mem;
+ memset(p->a+p->nDigit, 0, iExp);
+ p->nDigit += iExp;
+ }
+ }else if( iExp<0 ){
+ int nExtra;
+ iExp = -iExp;
+ nExtra = p->nDigit - p->nFrac - 1;
+ if( nExtra ){
+ if( nExtra>=iExp ){
+ p->nFrac += iExp;
+ iExp = 0;
+ }else{
+ iExp -= nExtra;
+ p->nFrac = p->nDigit - 1;
+ }
+ }
+ if( iExp>0 ){
+ p->a = sqlite3_realloc64(p->a, p->nDigit + iExp + 1 );
+ if( p->a==0 ) goto new_no_mem;
+ memmove(p->a+iExp, p->a, p->nDigit);
+ memset(p->a, 0, iExp);
+ p->nDigit += iExp;
+ p->nFrac += iExp;
+ }
+ }
+ return p;
+
+new_no_mem:
+ if( pCtx ) sqlite3_result_error_nomem(pCtx);
+ sqlite3_free(p);
+ return 0;
+}
+
+/*
+** Make the given Decimal the result.
+*/
+static void decimal_result(sqlite3_context *pCtx, Decimal *p){
+ char *z;
+ int i, j;
+ int n;
+ if( p==0 || p->oom ){
+ sqlite3_result_error_nomem(pCtx);
+ return;
+ }
+ if( p->isNull ){
+ sqlite3_result_null(pCtx);
+ return;
+ }
+ z = sqlite3_malloc( p->nDigit+4 );
+ if( z==0 ){
+ sqlite3_result_error_nomem(pCtx);
+ return;
+ }
+ i = 0;
+ if( p->nDigit==0 || (p->nDigit==1 && p->a[0]==0) ){
+ p->sign = 0;
+ }
+ if( p->sign ){
+ z[0] = '-';
+ i = 1;
+ }
+ n = p->nDigit - p->nFrac;
+ if( n<=0 ){
+ z[i++] = '0';
+ }
+ j = 0;
+ while( n>1 && p->a[j]==0 ){
+ j++;
+ n--;
+ }
+ while( n>0 ){
+ z[i++] = p->a[j] + '0';
+ j++;
+ n--;
+ }
+ if( p->nFrac ){
+ z[i++] = '.';
+ do{
+ z[i++] = p->a[j] + '0';
+ j++;
+ }while( j<p->nDigit );
+ }
+ z[i] = 0;
+ sqlite3_result_text(pCtx, z, i, sqlite3_free);
+}
+
+/*
+** SQL Function: decimal(X)
+**
+** Convert input X into decimal and then back into text
+*/
+static void decimalFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ Decimal *p = decimal_new(context, argv[0], 0, 0);
+ decimal_result(context, p);
+ decimal_free(p);
+}
+
+/*
+** Compare to Decimal objects. Return negative, 0, or positive if the
+** first object is less than, equal to, or greater than the second.
+**
+** Preconditions for this routine:
+**
+** pA!=0
+** pA->isNull==0
+** pB!=0
+** pB->isNull==0
+*/
+static int decimal_cmp(const Decimal *pA, const Decimal *pB){
+ int nASig, nBSig, rc, n;
+ if( pA->sign!=pB->sign ){
+ return pA->sign ? -1 : +1;
+ }
+ if( pA->sign ){
+ const Decimal *pTemp = pA;
+ pA = pB;
+ pB = pTemp;
+ }
+ nASig = pA->nDigit - pA->nFrac;
+ nBSig = pB->nDigit - pB->nFrac;
+ if( nASig!=nBSig ){
+ return nASig - nBSig;
+ }
+ n = pA->nDigit;
+ if( n>pB->nDigit ) n = pB->nDigit;
+ rc = memcmp(pA->a, pB->a, n);
+ if( rc==0 ){
+ rc = pA->nDigit - pB->nDigit;
+ }
+ return rc;
+}
+
+/*
+** SQL Function: decimal_cmp(X, Y)
+**
+** Return negative, zero, or positive if X is less then, equal to, or
+** greater than Y.
+*/
+static void decimalCmpFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ Decimal *pA = 0, *pB = 0;
+ int rc;
+
+ pA = decimal_new(context, argv[0], 0, 0);
+ if( pA==0 || pA->isNull ) goto cmp_done;
+ pB = decimal_new(context, argv[1], 0, 0);
+ if( pB==0 || pB->isNull ) goto cmp_done;
+ rc = decimal_cmp(pA, pB);
+ if( rc<0 ) rc = -1;
+ else if( rc>0 ) rc = +1;
+ sqlite3_result_int(context, rc);
+cmp_done:
+ decimal_free(pA);
+ decimal_free(pB);
+}
+
+/*
+** Expand the Decimal so that it has a least nDigit digits and nFrac
+** digits to the right of the decimal point.
+*/
+static void decimal_expand(Decimal *p, int nDigit, int nFrac){
+ int nAddSig;
+ int nAddFrac;
+ if( p==0 ) return;
+ nAddFrac = nFrac - p->nFrac;
+ nAddSig = (nDigit - p->nDigit) - nAddFrac;
+ if( nAddFrac==0 && nAddSig==0 ) return;
+ p->a = sqlite3_realloc64(p->a, nDigit+1);
+ if( p->a==0 ){
+ p->oom = 1;
+ return;
+ }
+ if( nAddSig ){
+ memmove(p->a+nAddSig, p->a, p->nDigit);
+ memset(p->a, 0, nAddSig);
+ p->nDigit += nAddSig;
+ }
+ if( nAddFrac ){
+ memset(p->a+p->nDigit, 0, nAddFrac);
+ p->nDigit += nAddFrac;
+ p->nFrac += nAddFrac;
+ }
+}
+
+/*
+** Add the value pB into pA.
+**
+** Both pA and pB might become denormalized by this routine.
+*/
+static void decimal_add(Decimal *pA, Decimal *pB){
+ int nSig, nFrac, nDigit;
+ int i, rc;
+ if( pA==0 ){
+ return;
+ }
+ if( pA->oom || pB==0 || pB->oom ){
+ pA->oom = 1;
+ return;
+ }
+ if( pA->isNull || pB->isNull ){
+ pA->isNull = 1;
+ return;
+ }
+ nSig = pA->nDigit - pA->nFrac;
+ if( nSig && pA->a[0]==0 ) nSig--;
+ if( nSig<pB->nDigit-pB->nFrac ){
+ nSig = pB->nDigit - pB->nFrac;
+ }
+ nFrac = pA->nFrac;
+ if( nFrac<pB->nFrac ) nFrac = pB->nFrac;
+ nDigit = nSig + nFrac + 1;
+ decimal_expand(pA, nDigit, nFrac);
+ decimal_expand(pB, nDigit, nFrac);
+ if( pA->oom || pB->oom ){
+ pA->oom = 1;
+ }else{
+ if( pA->sign==pB->sign ){
+ int carry = 0;
+ for(i=nDigit-1; i>=0; i--){
+ int x = pA->a[i] + pB->a[i] + carry;
+ if( x>=10 ){
+ carry = 1;
+ pA->a[i] = x - 10;
+ }else{
+ carry = 0;
+ pA->a[i] = x;
+ }
+ }
+ }else{
+ signed char *aA, *aB;
+ int borrow = 0;
+ rc = memcmp(pA->a, pB->a, nDigit);
+ if( rc<0 ){
+ aA = pB->a;
+ aB = pA->a;
+ pA->sign = !pA->sign;
+ }else{
+ aA = pA->a;
+ aB = pB->a;
+ }
+ for(i=nDigit-1; i>=0; i--){
+ int x = aA[i] - aB[i] - borrow;
+ if( x<0 ){
+ pA->a[i] = x+10;
+ borrow = 1;
+ }else{
+ pA->a[i] = x;
+ borrow = 0;
+ }
+ }
+ }
+ }
+}
+
+/*
+** Compare text in decimal order.
+*/
+static int decimalCollFunc(
+ void *notUsed,
+ int nKey1, const void *pKey1,
+ int nKey2, const void *pKey2
+){
+ const unsigned char *zA = (const unsigned char*)pKey1;
+ const unsigned char *zB = (const unsigned char*)pKey2;
+ Decimal *pA = decimal_new(0, 0, nKey1, zA);
+ Decimal *pB = decimal_new(0, 0, nKey2, zB);
+ int rc;
+ if( pA==0 || pB==0 ){
+ rc = 0;
+ }else{
+ rc = decimal_cmp(pA, pB);
+ }
+ decimal_free(pA);
+ decimal_free(pB);
+ return rc;
+}
+
+
+/*
+** SQL Function: decimal_add(X, Y)
+** decimal_sub(X, Y)
+**
+** Return the sum or difference of X and Y.
+*/
+static void decimalAddFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ Decimal *pA = decimal_new(context, argv[0], 0, 0);
+ Decimal *pB = decimal_new(context, argv[1], 0, 0);
+ decimal_add(pA, pB);
+ decimal_result(context, pA);
+ decimal_free(pA);
+ decimal_free(pB);
+}
+static void decimalSubFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ Decimal *pA = decimal_new(context, argv[0], 0, 0);
+ Decimal *pB = decimal_new(context, argv[1], 0, 0);
+ if( pB==0 ) return;
+ pB->sign = !pB->sign;
+ decimal_add(pA, pB);
+ decimal_result(context, pA);
+ decimal_free(pA);
+ decimal_free(pB);
+}
+
+/* Aggregate funcion: decimal_sum(X)
+**
+** Works like sum() except that it uses decimal arithmetic for unlimited
+** precision.
+*/
+static void decimalSumStep(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ Decimal *p;
+ Decimal *pArg;
+ p = sqlite3_aggregate_context(context, sizeof(*p));
+ if( p==0 ) return;
+ if( !p->isInit ){
+ p->isInit = 1;
+ p->a = sqlite3_malloc(2);
+ if( p->a==0 ){
+ p->oom = 1;
+ }else{
+ p->a[0] = 0;
+ }
+ p->nDigit = 1;
+ p->nFrac = 0;
+ }
+ if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return;
+ pArg = decimal_new(context, argv[0], 0, 0);
+ decimal_add(p, pArg);
+ decimal_free(pArg);
+}
+static void decimalSumInverse(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ Decimal *p;
+ Decimal *pArg;
+ p = sqlite3_aggregate_context(context, sizeof(*p));
+ if( p==0 ) return;
+ if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return;
+ pArg = decimal_new(context, argv[0], 0, 0);
+ if( pArg ) pArg->sign = !pArg->sign;
+ decimal_add(p, pArg);
+ decimal_free(pArg);
+}
+static void decimalSumValue(sqlite3_context *context){
+ Decimal *p = sqlite3_aggregate_context(context, 0);
+ if( p==0 ) return;
+ decimal_result(context, p);
+}
+static void decimalSumFinalize(sqlite3_context *context){
+ Decimal *p = sqlite3_aggregate_context(context, 0);
+ if( p==0 ) return;
+ decimal_result(context, p);
+ decimal_clear(p);
+}
+
+/*
+** SQL Function: decimal_mul(X, Y)
+**
+** Return the product of X and Y.
+**
+** All significant digits after the decimal point are retained.
+** Trailing zeros after the decimal point are omitted as long as
+** the number of digits after the decimal point is no less than
+** either the number of digits in either input.
+*/
+static void decimalMulFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ Decimal *pA = decimal_new(context, argv[0], 0, 0);
+ Decimal *pB = decimal_new(context, argv[1], 0, 0);
+ signed char *acc = 0;
+ int i, j, k;
+ int minFrac;
+ if( pA==0 || pA->oom || pA->isNull
+ || pB==0 || pB->oom || pB->isNull
+ ){
+ goto mul_end;
+ }
+ acc = sqlite3_malloc64( pA->nDigit + pB->nDigit + 2 );
+ if( acc==0 ){
+ sqlite3_result_error_nomem(context);
+ goto mul_end;
+ }
+ memset(acc, 0, pA->nDigit + pB->nDigit + 2);
+ minFrac = pA->nFrac;
+ if( pB->nFrac<minFrac ) minFrac = pB->nFrac;
+ for(i=pA->nDigit-1; i>=0; i--){
+ signed char f = pA->a[i];
+ int carry = 0, x;
+ for(j=pB->nDigit-1, k=i+j+3; j>=0; j--, k--){
+ x = acc[k] + f*pB->a[j] + carry;
+ acc[k] = x%10;
+ carry = x/10;
+ }
+ x = acc[k] + carry;
+ acc[k] = x%10;
+ acc[k-1] += x/10;
+ }
+ sqlite3_free(pA->a);
+ pA->a = acc;
+ acc = 0;
+ pA->nDigit += pB->nDigit + 2;
+ pA->nFrac += pB->nFrac;
+ pA->sign ^= pB->sign;
+ while( pA->nFrac>minFrac && pA->a[pA->nDigit-1]==0 ){
+ pA->nFrac--;
+ pA->nDigit--;
+ }
+ decimal_result(context, pA);
+
+mul_end:
+ sqlite3_free(acc);
+ decimal_free(pA);
+ decimal_free(pB);
+}
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+int sqlite3_decimal_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ int rc = SQLITE_OK;
+ SQLITE_EXTENSION_INIT2(pApi);
+ static const struct {
+ const char *zFuncName;
+ int nArg;
+ void (*xFunc)(sqlite3_context*,int,sqlite3_value**);
+ } aFunc[] = {
+ { "decimal", 1, decimalFunc },
+ { "decimal_cmp", 2, decimalCmpFunc },
+ { "decimal_add", 2, decimalAddFunc },
+ { "decimal_sub", 2, decimalSubFunc },
+ { "decimal_mul", 2, decimalMulFunc },
+ };
+ int i;
+ (void)pzErrMsg; /* Unused parameter */
+
+ for(i=0; i<sizeof(aFunc)/sizeof(aFunc[0]) && rc==SQLITE_OK; i++){
+ rc = sqlite3_create_function(db, aFunc[i].zFuncName, aFunc[i].nArg,
+ SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_DETERMINISTIC,
+ 0, aFunc[i].xFunc, 0, 0);
+ }
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_create_window_function(db, "decimal_sum", 1,
+ SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_DETERMINISTIC, 0,
+ decimalSumStep, decimalSumFinalize,
+ decimalSumValue, decimalSumInverse, 0);
+ }
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_create_collation(db, "decimal", SQLITE_UTF8,
+ 0, decimalCollFunc);
+ }
+ return rc;
+}
diff --git a/ext/misc/explain.c b/ext/misc/explain.c
index 7a2fc4776..009519457 100644
--- a/ext/misc/explain.c
+++ b/ext/misc/explain.c
@@ -16,7 +16,7 @@
** Usage example:
**
** .load ./explain
-** SELECT p2 FROM explain('SELECT * FROM sqlite_master')
+** SELECT p2 FROM explain('SELECT * FROM sqlite_schema')
** WHERE opcode='OpenRead';
**
** This module was originally written to help simplify SQLite testing,
diff --git a/ext/misc/ieee754.c b/ext/misc/ieee754.c
index a67c91878..cb274c3f7 100644
--- a/ext/misc/ieee754.c
+++ b/ext/misc/ieee754.c
@@ -26,10 +26,64 @@
**
** Examples:
**
-** ieee754(2.0) -> 'ieee754(2,0)'
-** ieee754(45.25) -> 'ieee754(181,-2)'
-** ieee754(2, 0) -> 2.0
-** ieee754(181, -2) -> 45.25
+** ieee754(2.0) -> 'ieee754(2,0)'
+** ieee754(45.25) -> 'ieee754(181,-2)'
+** ieee754(2, 0) -> 2.0
+** ieee754(181, -2) -> 45.25
+**
+** Two additional functions break apart the one-argument ieee754()
+** result into separate integer values:
+**
+** ieee754_mantissa(45.25) -> 181
+** ieee754_exponent(45.25) -> -2
+**
+** These functions convert binary64 numbers into blobs and back again.
+**
+** ieee754_from_blob(x'3ff0000000000000') -> 1.0
+** ieee754_to_blob(1.0) -> x'3ff0000000000000'
+**
+** In all single-argument functions, if the argument is an 8-byte blob
+** then that blob is interpreted as a big-endian binary64 value.
+**
+**
+** EXACT DECIMAL REPRESENTATION OF BINARY64 VALUES
+** -----------------------------------------------
+**
+** This extension in combination with the separate 'decimal' extension
+** can be used to compute the exact decimal representation of binary64
+** values. To begin, first compute a table of exponent values:
+**
+** CREATE TABLE pow2(x INTEGER PRIMARY KEY, v TEXT);
+** WITH RECURSIVE c(x,v) AS (
+** VALUES(0,'1')
+** UNION ALL
+** SELECT x+1, decimal_mul(v,'2') FROM c WHERE x+1<=971
+** ) INSERT INTO pow2(x,v) SELECT x, v FROM c;
+** WITH RECURSIVE c(x,v) AS (
+** VALUES(-1,'0.5')
+** UNION ALL
+** SELECT x-1, decimal_mul(v,'0.5') FROM c WHERE x-1>=-1075
+** ) INSERT INTO pow2(x,v) SELECT x, v FROM c;
+**
+** Then, to compute the exact decimal representation of a floating
+** point value (the value 47.49 is used in the example) do:
+**
+** WITH c(n) AS (VALUES(47.49))
+** ---------------^^^^^---- Replace with whatever you want
+** SELECT decimal_mul(ieee754_mantissa(c.n),pow2.v)
+** FROM pow2, c WHERE pow2.x=ieee754_exponent(c.n);
+**
+** Here is a query to show various boundry values for the binary64
+** number format:
+**
+** WITH c(name,bin) AS (VALUES
+** ('minimum positive value', x'0000000000000001'),
+** ('maximum subnormal value', x'000fffffffffffff'),
+** ('mininum positive nornal value', x'0010000000000000'),
+** ('maximum value', x'7fefffffffffffff'))
+** SELECT c.name, decimal_mul(ieee754_mantissa(c.bin),pow2.v)
+** FROM pow2, c WHERE pow2.x=ieee754_exponent(c.bin);
+**
*/
#include "sqlite3ext.h"
SQLITE_EXTENSION_INIT1
@@ -51,8 +105,19 @@ static void ieee754func(
int isNeg;
char zResult[100];
assert( sizeof(m)==sizeof(r) );
- if( sqlite3_value_type(argv[0])!=SQLITE_FLOAT ) return;
- r = sqlite3_value_double(argv[0]);
+ if( sqlite3_value_type(argv[0])==SQLITE_BLOB
+ && sqlite3_value_bytes(argv[0])==sizeof(r)
+ ){
+ const unsigned char *x = sqlite3_value_blob(argv[0]);
+ int i;
+ sqlite3_uint64 v = 0;
+ for(i=0; i<sizeof(r); i++){
+ v = (v<<8) | x[i];
+ }
+ memcpy(&r, &v, sizeof(r));
+ }else{
+ r = sqlite3_value_double(argv[0]);
+ }
if( r<0.0 ){
isNeg = 1;
r = -r;
@@ -66,17 +131,31 @@ static void ieee754func(
}else{
e = a>>52;
m = a & ((((sqlite3_int64)1)<<52)-1);
- m |= ((sqlite3_int64)1)<<52;
+ if( e==0 ){
+ m <<= 1;
+ }else{
+ m |= ((sqlite3_int64)1)<<52;
+ }
while( e<1075 && m>0 && (m&1)==0 ){
m >>= 1;
e++;
}
if( isNeg ) m = -m;
}
- sqlite3_snprintf(sizeof(zResult), zResult, "ieee754(%lld,%d)",
- m, e-1075);
- sqlite3_result_text(context, zResult, -1, SQLITE_TRANSIENT);
- }else if( argc==2 ){
+ switch( *(int*)sqlite3_user_data(context) ){
+ case 0:
+ sqlite3_snprintf(sizeof(zResult), zResult, "ieee754(%lld,%d)",
+ m, e-1075);
+ sqlite3_result_text(context, zResult, -1, SQLITE_TRANSIENT);
+ break;
+ case 1:
+ sqlite3_result_int64(context, m);
+ break;
+ case 2:
+ sqlite3_result_int(context, e-1075);
+ break;
+ }
+ }else{
sqlite3_int64 m, e, a;
double r;
int isNeg = 0;
@@ -86,7 +165,7 @@ static void ieee754func(
isNeg = 1;
m = -m;
if( m<0 ) return;
- }else if( m==0 && e>1000 && e<1000 ){
+ }else if( m==0 && e>-1000 && e<1000 ){
sqlite3_result_double(context, 0.0);
return;
}
@@ -99,8 +178,13 @@ static void ieee754func(
e--;
}
e += 1075;
- if( e<0 ) e = m = 0;
- if( e>0x7ff ) e = 0x7ff;
+ if( e<=0 ){
+ /* Subnormal */
+ m >>= 1-e;
+ e = 0;
+ }else if( e>0x7ff ){
+ e = 0x7ff;
+ }
a = m & ((((sqlite3_int64)1)<<52)-1);
a |= e<<52;
if( isNeg ) a |= ((sqlite3_uint64)1)<<63;
@@ -109,6 +193,49 @@ static void ieee754func(
}
}
+/*
+** Functions to convert between blobs and floats.
+*/
+static void ieee754func_from_blob(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ if( sqlite3_value_type(argv[0])==SQLITE_BLOB
+ && sqlite3_value_bytes(argv[0])==sizeof(double)
+ ){
+ double r;
+ const unsigned char *x = sqlite3_value_blob(argv[0]);
+ int i;
+ sqlite3_uint64 v = 0;
+ for(i=0; i<sizeof(r); i++){
+ v = (v<<8) | x[i];
+ }
+ memcpy(&r, &v, sizeof(r));
+ sqlite3_result_double(context, r);
+ }
+}
+static void ieee754func_to_blob(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ if( sqlite3_value_type(argv[0])==SQLITE_FLOAT
+ || sqlite3_value_type(argv[0])==SQLITE_INTEGER
+ ){
+ double r = sqlite3_value_double(argv[0]);
+ sqlite3_uint64 v;
+ unsigned char a[sizeof(r)];
+ int i;
+ memcpy(&v, &r, sizeof(r));
+ for(i=1; i<=sizeof(r); i++){
+ a[sizeof(r)-i] = v&0xff;
+ v >>= 8;
+ }
+ sqlite3_result_blob(context, a, sizeof(r), SQLITE_TRANSIENT);
+ }
+}
+
#ifdef _WIN32
__declspec(dllexport)
@@ -118,16 +245,29 @@ int sqlite3_ieee_init(
char **pzErrMsg,
const sqlite3_api_routines *pApi
){
+ static const struct {
+ char *zFName;
+ int nArg;
+ int iAux;
+ void (*xFunc)(sqlite3_context*,int,sqlite3_value**);
+ } aFunc[] = {
+ { "ieee754", 1, 0, ieee754func },
+ { "ieee754", 2, 0, ieee754func },
+ { "ieee754_mantissa", 1, 1, ieee754func },
+ { "ieee754_exponent", 1, 2, ieee754func },
+ { "ieee754_to_blob", 1, 0, ieee754func_to_blob },
+ { "ieee754_from_blob", 1, 0, ieee754func_from_blob },
+
+ };
+ int i;
int rc = SQLITE_OK;
SQLITE_EXTENSION_INIT2(pApi);
(void)pzErrMsg; /* Unused parameter */
- rc = sqlite3_create_function(db, "ieee754", 1,
- SQLITE_UTF8|SQLITE_INNOCUOUS, 0,
- ieee754func, 0, 0);
- if( rc==SQLITE_OK ){
- rc = sqlite3_create_function(db, "ieee754", 2,
- SQLITE_UTF8|SQLITE_INNOCUOUS, 0,
- ieee754func, 0, 0);
+ for(i=0; i<sizeof(aFunc)/sizeof(aFunc[0]) && rc==SQLITE_OK; i++){
+ rc = sqlite3_create_function(db, aFunc[i].zFName, aFunc[i].nArg,
+ SQLITE_UTF8|SQLITE_INNOCUOUS,
+ (void*)&aFunc[i].iAux,
+ aFunc[i].xFunc, 0, 0);
}
return rc;
}
diff --git a/ext/misc/json1.c b/ext/misc/json1.c
index d42cad17a..caf7a99d6 100644
--- a/ext/misc/json1.c
+++ b/ext/misc/json1.c
@@ -254,6 +254,7 @@ static int jsonGrow(JsonString *p, u32 N){
/* Append N bytes from zIn onto the end of the JsonString string.
*/
static void jsonAppendRaw(JsonString *p, const char *zIn, u32 N){
+ if( N==0 ) return;
if( (N+p->nUsed >= p->nAlloc) && jsonGrow(p,N)!=0 ) return;
memcpy(p->zBuf+p->nUsed, zIn, N);
p->nUsed += N;
diff --git a/ext/misc/mmapwarm.c b/ext/misc/mmapwarm.c
index 970a873f5..5afa47bf7 100644
--- a/ext/misc/mmapwarm.c
+++ b/ext/misc/mmapwarm.c
@@ -43,7 +43,7 @@ int sqlite3_mmap_warm(sqlite3 *db, const char *zDb){
if( 0==sqlite3_get_autocommit(db) ) return SQLITE_MISUSE;
/* Open a read-only transaction on the file in question */
- zSql = sqlite3_mprintf("BEGIN; SELECT * FROM %s%q%ssqlite_master",
+ zSql = sqlite3_mprintf("BEGIN; SELECT * FROM %s%q%ssqlite_schema",
(zDb ? "'" : ""), (zDb ? zDb : ""), (zDb ? "'." : "")
);
if( zSql==0 ) return SQLITE_NOMEM;
diff --git a/ext/misc/scrub.c b/ext/misc/scrub.c
index 4eb56b0fc..9fbf2aed4 100644
--- a/ext/misc/scrub.c
+++ b/ext/misc/scrub.c
@@ -166,7 +166,7 @@ static void scrubBackupOpenSrc(ScrubState *p){
sqlite3_errmsg(p->dbSrc));
return;
}
- p->rcErr = sqlite3_exec(p->dbSrc, "SELECT 1 FROM sqlite_master; BEGIN;",
+ p->rcErr = sqlite3_exec(p->dbSrc, "SELECT 1 FROM sqlite_schema; BEGIN;",
0, 0, 0);
if( p->rcErr ){
scrubBackupErr(p,
@@ -535,7 +535,7 @@ int sqlite3_scrub_backup(
/* Copy all of the btrees */
scrubBackupBtree(&s, 1, 0);
pStmt = scrubBackupPrepare(&s, s.dbSrc,
- "SELECT rootpage FROM sqlite_master WHERE coalesce(rootpage,0)>0");
+ "SELECT rootpage FROM sqlite_schema WHERE coalesce(rootpage,0)>0");
if( pStmt==0 ) goto scrub_abort;
while( sqlite3_step(pStmt)==SQLITE_ROW ){
i = (u32)sqlite3_column_int(pStmt, 0);
diff --git a/ext/misc/sqlar.c b/ext/misc/sqlar.c
index 8b90f9d1d..47cb68ff6 100644
--- a/ext/misc/sqlar.c
+++ b/ext/misc/sqlar.c
@@ -17,6 +17,7 @@
#include "sqlite3ext.h"
SQLITE_EXTENSION_INIT1
#include <zlib.h>
+#include <assert.h>
/*
** Implementation of the "sqlar_compress(X)" SQL function.
diff --git a/ext/misc/stmt.c b/ext/misc/stmt.c
index d2b33e741..876b0e5cb 100644
--- a/ext/misc/stmt.c
+++ b/ext/misc/stmt.c
@@ -168,7 +168,8 @@ static int stmtColumn(
sqlite3_result_int(ctx, sqlite3_stmt_busy(pCur->pStmt));
break;
}
- case STMT_COLUMN_MEM: {
+ default: {
+ assert( i==STMT_COLUMN_MEM );
i = SQLITE_STMTSTATUS_MEMUSED +
STMT_COLUMN_NSCAN - SQLITE_STMTSTATUS_FULLSCAN_STEP;
/* Fall thru */
diff --git a/ext/misc/uint.c b/ext/misc/uint.c
index 12982c2a2..286314fef 100644
--- a/ext/misc/uint.c
+++ b/ext/misc/uint.c
@@ -45,6 +45,7 @@ static int uintCollFunc(
const unsigned char *zA = (const unsigned char*)pKey1;
const unsigned char *zB = (const unsigned char*)pKey2;
int i=0, j=0, x;
+ (void)notUsed;
while( i<nKey1 && j<nKey2 ){
x = zA[i] - zB[j];
if( isdigit(zA[i]) ){
diff --git a/ext/misc/vfsstat.c b/ext/misc/vfsstat.c
index 7b5102a5a..186ed788f 100644
--- a/ext/misc/vfsstat.c
+++ b/ext/misc/vfsstat.c
@@ -811,7 +811,7 @@ int sqlite3_vfsstat_init(
if( rc==SQLITE_OK ){
rc = vstatRegister(db, pzErrMsg, pApi);
if( rc==SQLITE_OK ){
- rc = sqlite3_auto_extension(vstatRegister);
+ rc = sqlite3_auto_extension((void(*)(void))vstatRegister);
}
}
if( rc==SQLITE_OK ) rc = SQLITE_OK_LOAD_PERMANENTLY;
diff --git a/ext/rbu/sqlite3rbu.c b/ext/rbu/sqlite3rbu.c
index 8e82cd8b9..12a0a4660 100644
--- a/ext/rbu/sqlite3rbu.c
+++ b/ext/rbu/sqlite3rbu.c
@@ -975,7 +975,7 @@ static int rbuObjIterFirst(sqlite3rbu *p, RbuObjIter *pIter){
rc = prepareFreeAndCollectError(p->dbRbu, &pIter->pTblIter, &p->zErrmsg,
sqlite3_mprintf(
"SELECT rbu_target_name(name, type='view') AS target, name "
- "FROM sqlite_master "
+ "FROM sqlite_schema "
"WHERE type IN ('table', 'view') AND target IS NOT NULL "
" %s "
"ORDER BY name"
@@ -984,7 +984,7 @@ static int rbuObjIterFirst(sqlite3rbu *p, RbuObjIter *pIter){
if( rc==SQLITE_OK ){
rc = prepareAndCollectError(p->dbMain, &pIter->pIdxIter, &p->zErrmsg,
"SELECT name, rootpage, sql IS NULL OR substr(8, 6)=='UNIQUE' "
- " FROM main.sqlite_master "
+ " FROM main.sqlite_schema "
" WHERE type='index' AND tbl_name = ?"
);
}
@@ -1156,12 +1156,12 @@ static void rbuFinalize(sqlite3rbu *p, sqlite3_stmt *pStmt){
**
** ALGORITHM:
**
-** if( no entry exists in sqlite_master ){
+** if( no entry exists in sqlite_schema ){
** return RBU_PK_NOTABLE
** }else if( sql for the entry starts with "CREATE VIRTUAL" ){
** return RBU_PK_VTAB
** }else if( "PRAGMA index_list()" for the table contains a "pk" index ){
-** if( the index that is the pk exists in sqlite_master ){
+** if( the index that is the pk exists in sqlite_schema ){
** *piPK = rootpage of that index.
** return RBU_PK_EXTERNAL
** }else{
@@ -1181,9 +1181,9 @@ static void rbuTableType(
int *piPk
){
/*
- ** 0) SELECT count(*) FROM sqlite_master where name=%Q AND IsVirtual(%Q)
+ ** 0) SELECT count(*) FROM sqlite_schema where name=%Q AND IsVirtual(%Q)
** 1) PRAGMA index_list = ?
- ** 2) SELECT count(*) FROM sqlite_master where name=%Q
+ ** 2) SELECT count(*) FROM sqlite_schema where name=%Q
** 3) PRAGMA table_info = ?
*/
sqlite3_stmt *aStmt[4] = {0, 0, 0, 0};
@@ -1195,7 +1195,7 @@ static void rbuTableType(
p->rc = prepareFreeAndCollectError(p->dbMain, &aStmt[0], &p->zErrmsg,
sqlite3_mprintf(
"SELECT (sql LIKE 'create virtual%%'), rootpage"
- " FROM sqlite_master"
+ " FROM sqlite_schema"
" WHERE name=%Q", zTab
));
if( p->rc!=SQLITE_OK || sqlite3_step(aStmt[0])!=SQLITE_ROW ){
@@ -1218,7 +1218,7 @@ static void rbuTableType(
if( zOrig && zIdx && zOrig[0]=='p' ){
p->rc = prepareFreeAndCollectError(p->dbMain, &aStmt[2], &p->zErrmsg,
sqlite3_mprintf(
- "SELECT rootpage FROM sqlite_master WHERE name = %Q", zIdx
+ "SELECT rootpage FROM sqlite_schema WHERE name = %Q", zIdx
));
if( p->rc==SQLITE_OK ){
if( sqlite3_step(aStmt[2])==SQLITE_ROW ){
@@ -2038,7 +2038,7 @@ static void rbuCreateImposterTable2(sqlite3rbu *p, RbuObjIter *pIter){
** This is needed for the argument to "PRAGMA index_xinfo". Set
** zIdx to point to a nul-terminated string containing this name. */
p->rc = prepareAndCollectError(p->dbMain, &pQuery, &p->zErrmsg,
- "SELECT name FROM sqlite_master WHERE rootpage = ?"
+ "SELECT name FROM sqlite_schema WHERE rootpage = ?"
);
if( p->rc==SQLITE_OK ){
sqlite3_bind_int(pQuery, 1, tnum);
@@ -2211,7 +2211,7 @@ static char *rbuObjIterGetIndexWhere(sqlite3rbu *p, RbuObjIter *pIter){
if( rc==SQLITE_OK ){
rc = prepareAndCollectError(p->dbMain, &pStmt, &p->zErrmsg,
- "SELECT trim(sql) FROM sqlite_master WHERE type='index' AND name=?"
+ "SELECT trim(sql) FROM sqlite_schema WHERE type='index' AND name=?"
);
}
if( rc==SQLITE_OK ){
@@ -2793,7 +2793,7 @@ static void rbuOpenDatabase(sqlite3rbu *p, int *pbRetry){
int bOk = 0;
sqlite3_stmt *pCnt = 0;
p->rc = prepareAndCollectError(p->dbRbu, &pCnt, &p->zErrmsg,
- "SELECT count(*) FROM stat.sqlite_master"
+ "SELECT count(*) FROM stat.sqlite_schema"
);
if( p->rc==SQLITE_OK
&& sqlite3_step(pCnt)==SQLITE_ROW
@@ -2897,7 +2897,7 @@ static void rbuOpenDatabase(sqlite3rbu *p, int *pbRetry){
if( p->rc==SQLITE_OK ){
p->rc = sqlite3_file_control(p->dbMain, "main", SQLITE_FCNTL_RBU, (void*)p);
}
- rbuMPrintfExec(p, p->dbMain, "SELECT * FROM sqlite_master");
+ rbuMPrintfExec(p, p->dbMain, "SELECT * FROM sqlite_schema");
/* Mark the database file just opened as an RBU target database. If
** this call returns SQLITE_NOTFOUND, then the RBU vfs is not in use.
@@ -2990,7 +2990,7 @@ static void rbuSetupCheckpoint(sqlite3rbu *p, RbuState *pState){
if( pState==0 ){
p->eStage = 0;
if( p->rc==SQLITE_OK ){
- p->rc = sqlite3_exec(p->dbMain, "SELECT * FROM sqlite_master", 0, 0, 0);
+ p->rc = sqlite3_exec(p->dbMain, "SELECT * FROM sqlite_schema", 0, 0, 0);
}
}
@@ -3581,7 +3581,7 @@ static void rbuCreateTargetSchema(sqlite3rbu *p){
p->rc = sqlite3_exec(p->dbMain, "PRAGMA writable_schema=1", 0,0, &p->zErrmsg);
if( p->rc==SQLITE_OK ){
p->rc = prepareAndCollectError(p->dbRbu, &pSql, &p->zErrmsg,
- "SELECT sql FROM sqlite_master WHERE sql!='' AND rootpage!=0"
+ "SELECT sql FROM sqlite_schema WHERE sql!='' AND rootpage!=0"
" AND name!='sqlite_sequence' "
" ORDER BY type DESC"
);
@@ -3596,13 +3596,13 @@ static void rbuCreateTargetSchema(sqlite3rbu *p){
if( p->rc==SQLITE_OK ){
p->rc = prepareAndCollectError(p->dbRbu, &pSql, &p->zErrmsg,
- "SELECT * FROM sqlite_master WHERE rootpage=0 OR rootpage IS NULL"
+ "SELECT * FROM sqlite_schema WHERE rootpage=0 OR rootpage IS NULL"
);
}
if( p->rc==SQLITE_OK ){
p->rc = prepareAndCollectError(p->dbMain, &pInsert, &p->zErrmsg,
- "INSERT INTO sqlite_master VALUES(?,?,?,?,?)"
+ "INSERT INTO sqlite_schema VALUES(?,?,?,?,?)"
);
}
@@ -3865,7 +3865,7 @@ static void rbuIndexCntFunc(
assert( nVal==1 );
rc = prepareFreeAndCollectError(db, &pStmt, &zErrmsg,
- sqlite3_mprintf("SELECT count(*) FROM sqlite_master "
+ sqlite3_mprintf("SELECT count(*) FROM sqlite_schema "
"WHERE type='index' AND tbl_name = %Q", sqlite3_value_text(apVal[0]))
);
if( rc!=SQLITE_OK ){
@@ -3916,7 +3916,7 @@ static void rbuInitPhaseOneSteps(sqlite3rbu *p){
** occurs, nPhaseOneStep will be left set to -1. */
if( p->rc==SQLITE_OK ){
p->rc = prepareAndCollectError(p->dbRbu, &pStmt, &p->zErrmsg,
- "SELECT 1 FROM sqlite_master WHERE tbl_name = 'rbu_count'"
+ "SELECT 1 FROM sqlite_schema WHERE tbl_name = 'rbu_count'"
);
}
if( p->rc==SQLITE_OK ){
diff --git a/ext/repair/checkindex.c b/ext/repair/checkindex.c
index 58706c1aa..080a51530 100644
--- a/ext/repair/checkindex.c
+++ b/ext/repair/checkindex.c
@@ -473,7 +473,7 @@ static int cidxLookupIndex(
/* Find the table for this index. */
pFindTab = cidxPrepare(&rc, pCsr,
- "SELECT tbl_name, sql FROM sqlite_master WHERE name=%Q AND type='index'",
+ "SELECT tbl_name, sql FROM sqlite_schema WHERE name=%Q AND type='index'",
zIdx
);
if( rc==SQLITE_OK && sqlite3_step(pFindTab)==SQLITE_ROW ){
diff --git a/ext/rtree/geopoly.c b/ext/rtree/geopoly.c
index 14facad53..35294c8d8 100644
--- a/ext/rtree/geopoly.c
+++ b/ext/rtree/geopoly.c
@@ -683,6 +683,8 @@ static GeoPoly *geopolyBBox(
aCoord[2].f = mnY;
aCoord[3].f = mxY;
}
+ }else{
+ memset(aCoord, 0, sizeof(RtreeCoord)*4);
}
return pOut;
}
diff --git a/ext/session/session_common.tcl b/ext/session/session_common.tcl
index ceffdad4b..c52ac457c 100644
--- a/ext/session/session_common.tcl
+++ b/ext/session/session_common.tcl
@@ -172,8 +172,8 @@ proc compare_db {db1 db2} {
set data1 [$db1 eval $sql]
set data2 [$db2 eval $sql]
if {$data1 != $data2} {
- puts "$data1"
- puts "$data2"
+ puts "$db1: $data1"
+ puts "$db2: $data2"
error "table $tbl data mismatch"
}
}
diff --git a/ext/session/sessioninvert.test b/ext/session/sessioninvert.test
index 49205f6b2..b7c157d2e 100644
--- a/ext/session/sessioninvert.test
+++ b/ext/session/sessioninvert.test
@@ -155,5 +155,29 @@ do_test 3.2 {
compare_db db db2
} {}
+#-------------------------------------------------------------------------
+#
+reset_db
+do_execsql_test 4.0 {
+ CREATE TABLE t1(a INTEGER PRIMARY KEY, b UNIQUE);
+ INSERT INTO t1 VALUES(1, 'one');
+ INSERT INTO t1 VALUES(2, 'two');
+ INSERT INTO t1 VALUES(3, 'three');
+ INSERT INTO t1 VALUES(4, 'four');
+}
+
+do_invert_test 4.1 {
+ DELETE FROM t1;
+ INSERT INTO t1 VALUES(1, 'two');
+ INSERT INTO t1 VALUES(2, 'five');
+ INSERT INTO t1 VALUES(3, 'one');
+ INSERT INTO t1 VALUES(4, 'three');
+} {
+ {UPDATE t1 0 X. {i 1 t two} {{} {} t one}}
+ {UPDATE t1 0 X. {i 2 t five} {{} {} t two}}
+ {UPDATE t1 0 X. {i 3 t one} {{} {} t three}}
+ {UPDATE t1 0 X. {i 4 t three} {{} {} t four}}
+}
+
finish_test
diff --git a/ext/session/sqlite3session.c b/ext/session/sqlite3session.c
index 78cc5875c..cb350ab2d 100644
--- a/ext/session/sqlite3session.c
+++ b/ext/session/sqlite3session.c
@@ -3479,6 +3479,7 @@ struct SessionApplyCtx {
u8 *abPK; /* Boolean array - true if column is in PK */
int bStat1; /* True if table is sqlite_stat1 */
int bDeferConstraints; /* True to defer constraints */
+ int bInvertConstraints; /* Invert when iterating constraints buffer */
SessionBuffer constraints; /* Deferred constraints are stored here */
SessionBuffer rebase; /* Rebase information (if any) here */
u8 bRebaseStarted; /* If table header is already in rebase */
@@ -4251,7 +4252,9 @@ static int sessionRetryConstraints(
SessionBuffer cons = pApply->constraints;
memset(&pApply->constraints, 0, sizeof(SessionBuffer));
- rc = sessionChangesetStart(&pIter2, 0, 0, cons.nBuf, cons.aBuf, 0);
+ rc = sessionChangesetStart(
+ &pIter2, 0, 0, cons.nBuf, cons.aBuf, pApply->bInvertConstraints
+ );
if( rc==SQLITE_OK ){
size_t nByte = 2*pApply->nCol*sizeof(sqlite3_value*);
int rc2;
@@ -4318,6 +4321,7 @@ static int sessionChangesetApply(
pIter->in.bNoDiscard = 1;
memset(&sApply, 0, sizeof(sApply));
sApply.bRebase = (ppRebase && pnRebase);
+ sApply.bInvertConstraints = !!(flags & SQLITE_CHANGESETAPPLY_INVERT);
sqlite3_mutex_enter(sqlite3_db_mutex(db));
if( (flags & SQLITE_CHANGESETAPPLY_NOSAVEPOINT)==0 ){
rc = sqlite3_exec(db, "SAVEPOINT changeset_apply", 0, 0, 0);
diff --git a/main.mk b/main.mk
index bb51b4457..693887bd6 100644
--- a/main.mk
+++ b/main.mk
@@ -74,7 +74,8 @@ LIBOBJ+= vdbe.o parse.o \
table.o threads.o tokenize.o treeview.o trigger.o \
update.o upsert.o userauth.o util.o vacuum.o \
vdbeapi.o vdbeaux.o vdbeblob.o vdbemem.o vdbesort.o \
- vdbetrace.o wal.o walker.o where.o wherecode.o whereexpr.o \
+ vdbetrace.o vdbevtab.o \
+ wal.o walker.o where.o wherecode.o whereexpr.o \
utf.o vtab.o window.o
LIBOBJ += sqlite3session.o
@@ -173,6 +174,7 @@ SRC = \
$(TOP)/src/vdbemem.c \
$(TOP)/src/vdbesort.c \
$(TOP)/src/vdbetrace.c \
+ $(TOP)/src/vdbevtab.c \
$(TOP)/src/vdbeInt.h \
$(TOP)/src/vtab.c \
$(TOP)/src/vxworks.h \
@@ -361,6 +363,7 @@ TESTSRC += \
$(TOP)/ext/misc/carray.c \
$(TOP)/ext/misc/closure.c \
$(TOP)/ext/misc/csv.c \
+ $(TOP)/ext/misc/decimal.c \
$(TOP)/ext/misc/eval.c \
$(TOP)/ext/misc/explain.c \
$(TOP)/ext/misc/fileio.c \
@@ -421,6 +424,7 @@ TESTSRC2 = \
$(TOP)/src/vdbeaux.c \
$(TOP)/src/vdbe.c \
$(TOP)/src/vdbemem.c \
+ $(TOP)/src/vdbevtab.c \
$(TOP)/src/where.c \
$(TOP)/src/wherecode.c \
$(TOP)/src/whereexpr.c \
@@ -526,6 +530,7 @@ SHELL_OPT += -DSQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
SHELL_OPT += -DSQLITE_ENABLE_STMTVTAB
SHELL_OPT += -DSQLITE_ENABLE_DBPAGE_VTAB
SHELL_OPT += -DSQLITE_ENABLE_DBSTAT_VTAB
+SHELL_OPT += -DSQLITE_ENABLE_BYTECODE_VTAB
SHELL_OPT += -DSQLITE_ENABLE_OFFSET_SQL_FUNC
FUZZERSHELL_OPT = -DSQLITE_ENABLE_JSON1
FUZZCHECK_OPT = -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_MEMSYS5
@@ -536,6 +541,7 @@ FUZZCHECK_OPT += -DSQLITE_ENABLE_FTS4
FUZZCHECK_OPT += -DSQLITE_ENABLE_RTREE
FUZZCHECK_OPT += -DSQLITE_ENABLE_GEOPOLY
FUZZCHECK_OPT += -DSQLITE_ENABLE_DBSTAT_VTAB
+FUZZCHECK_OPT += -DSQLITE_ENABLE_BYTECODE_VTAB
DBFUZZ_OPT =
KV_OPT = -DSQLITE_THREADSAFE=0 -DSQLITE_DIRECT_OVERFLOW_READ
ST_OPT = -DSQLITE_THREADSAFE=0
@@ -586,6 +592,7 @@ DBFUZZ2_OPTS = \
-DSQLITE_ENABLE_DESERIALIZE \
-DSQLITE_DEBUG \
-DSQLITE_ENABLE_DBSTAT_VTAB \
+ -DSQLITE_ENABLE_BYTECODE_VTAB \
-DSQLITE_ENABLE_RTREE \
-DSQLITE_ENABLE_FTS4 \
-DSQLITE_ENABLE_FTS5
@@ -721,6 +728,12 @@ parse.c: $(TOP)/src/parse.y lemon
sqlite3.h: $(TOP)/src/sqlite.h.in $(TOP)/manifest mksourceid $(TOP)/VERSION $(TOP)/ext/rtree/sqlite3rtree.h
tclsh $(TOP)/tool/mksqlite3h.tcl $(TOP) >sqlite3.h
+sqlite3rc.h: $(TOP)/src/sqlite3.rc $(TOP)/VERSION
+ echo '#ifndef SQLITE_RESOURCE_VERSION' >$@
+ echo -n '#define SQLITE_RESOURCE_VERSION ' >>$@
+ cat $(TOP)/VERSION | tclsh $(TOP)/tool/replace.tcl exact . , >>$@
+ echo '#endif' >>sqlite3rc.h
+
keywordhash.h: $(TOP)/tool/mkkeywordhash.c
$(BCC) -o mkkeywordhash $(OPTS) $(TOP)/tool/mkkeywordhash.c
./mkkeywordhash >keywordhash.h
@@ -729,9 +742,11 @@ keywordhash.h: $(TOP)/tool/mkkeywordhash.c
SHELL_SRC = \
$(TOP)/src/shell.c.in \
$(TOP)/ext/misc/appendvfs.c \
- $(TOP)/ext/misc/shathree.c \
- $(TOP)/ext/misc/fileio.c \
$(TOP)/ext/misc/completion.c \
+ $(TOP)/ext/misc/decimal.c \
+ $(TOP)/ext/misc/fileio.c \
+ $(TOP)/ext/misc/ieee754.c \
+ $(TOP)/ext/misc/shathree.c \
$(TOP)/ext/misc/sqlar.c \
$(TOP)/ext/misc/uint.c \
$(TOP)/ext/expert/sqlite3expert.c \
@@ -895,6 +910,7 @@ TESTFIXTURE_FLAGS += -DSQLITE_SERIES_CONSTRAINT_VERIFY=1
TESTFIXTURE_FLAGS += -DSQLITE_DEFAULT_PAGE_SIZE=1024
TESTFIXTURE_FLAGS += -DSQLITE_ENABLE_STMTVTAB
TESTFIXTURE_FLAGS += -DSQLITE_ENABLE_DBPAGE_VTAB
+TESTFIXTURE_FLAGS += -DSQLITE_ENABLE_BYTECODE_VTAB
TESTFIXTURE_FLAGS += -DTCLSH_INIT_PROC=sqlite3TestInit
testfixture$(EXE): $(TESTSRC2) libsqlite3.a $(TESTSRC) $(TOP)/src/tclsqlite.c
@@ -968,6 +984,9 @@ valgrindtest: $(TESTPROGS) valgrindfuzz
smoketest: $(TESTPROGS) fuzzcheck$(EXE)
./testfixture$(EXE) $(TOP)/test/main.test $(TESTOPTS)
+shelltest: $(TESTPROGS)
+ ./testfixture$(EXT) $(TOP)/test/permutations.test shell
+
# 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.
@@ -1069,10 +1088,10 @@ checksymbols: sqlite3.o
# a tarball named for the version number. Ex: sqlite-autoconf-3110000.tar.gz.
# The snapshot-tarball target builds a tarball named by the SHA1 hash
#
-amalgamation-tarball: sqlite3.c
+amalgamation-tarball: sqlite3.c sqlite3rc.h
TOP=$(TOP) sh $(TOP)/tool/mkautoconfamal.sh --normal
-snapshot-tarball: sqlite3.c
+snapshot-tarball: sqlite3.c sqlite3rc.h
TOP=$(TOP) sh $(TOP)/tool/mkautoconfamal.sh --snapshot
diff --git a/manifest b/manifest
index 7e5a049d9..21b1b83d2 100644
--- a/manifest
+++ b/manifest
@@ -1,21 +1,21 @@
-C Fix\sproblems\swith\sUPDATE...FROM\sstatements\sthat\smodify\srowid\sor\sprimary-key\svalues.
-D 2020-05-01T18:43:49.018
+C Merge\slatest\strunk\schanges\swith\sthis\sbranch.
+D 2020-07-13T18:04:27.668
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
-F Makefile.in f6ab6e307d31e09d82aa4eca87ccb21ce66f486279e204b54b3149ff0d71616f
+F Makefile.in 19374a5db06c3199ec1bab71ab74a103d8abf21053c05e9389255dc58083f806
F Makefile.linux-gcc f609543700659711fbd230eced1f01353117621dccae7b9fb70daa64236c5241
-F Makefile.msc 46c338b1151fbeed42c82416c6bc4da7ff9a10f851bf379f8592280fd53d6efa
+F Makefile.msc 48f5a3fc32672c09ad73795749f6253e406a31526935fbbffd8f021108d54574
F README.md 1514a365ffca3c138e00c5cc839906108a01011a6b082bad19b09781e3aa498a
-F VERSION 980d78a2ce04a1fd0ebefbaabd665f7f9186563820629ee29c6e350e96f19b52
+F VERSION 5db2ee2cfcc790af73775fa485c13b2e8ccaa5936c6e1f47aedeba7056041ca5
F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50
F art/sqlite370.eps aa97a671332b432a54e1d74ff5e8775be34200c2
F art/sqlite370.ico af56c1d00fee7cd4753e8631ed60703ed0fc6e90
F art/sqlite370.jpg d512473dae7e378a67e28ff96a34da7cb331def2
F autoconf/INSTALL 83e4a25da9fd053c7b3665eaaaf7919707915903
-F autoconf/Makefile.am e14b629addaa1ce372b72043f28f40de2e32b7e211b6e0fc18dbb87989197e40
+F autoconf/Makefile.am a8d1d24affe52ebf8d7ddcf91aa973fa0316618ab95bb68c87cabf8faf527dc8
F autoconf/Makefile.fallback 22fe523eb36dfce31e0f6349f782eb084e86a5620b2b0b4f84a2d6133f53f5ac
-F autoconf/Makefile.msc 1d1e4af61289c62b94aa65a93afcd3dfa4b53e4195908980e0b138203e71e1c9
+F autoconf/Makefile.msc e0f1dafc48d000fd6ddfdb01815271528db55cbc7299ca888df5b93367f0d5a4
F autoconf/README.first 6c4f34fe115ff55d4e8dbfa3cecf04a0188292f7
F autoconf/README.txt 4f04b0819303aabaa35fff5f7b257fb0c1ef95f1
F autoconf/configure.ac 3cd933b959fe514eebd1ca1717dfddbf2c9b825b6bc2c5f744deaf5d63af9288
@@ -34,22 +34,23 @@ F autoconf/tea/win/rules.vc c511f222b80064096b705dbeb97060ee1d6b6d63
F config.guess 883205ddf25b46f10c181818bf42c09da9888884af96f79e1719264345053bd6
F config.h.in 6376abec766e9a0785178b1823b5a587e9f1ccbc
F config.sub c2d0260f17f3e4bc0b6808fccf1b291cb5e9126c14fc5890efc77b9fd0175559
-F configure 4bbb5f13998f2faf929b9ae708aea9fbcb08a46cb6dd3150e36c3f09c0a05a75 x
-F configure.ac 798a24cee2879325ca5b688a618199eb32cc77ed8136edbaa43d9137b470d54e
+F configure a97f98dfff699495aef66ae3d9c424345778a663f583e0d6e7522670518f87c1 x
+F configure.ac 40d01e89cb325c28b33f5957e61fede0bd17da2b5e37d9b223a90c8a318e88d4
F contrib/sqlitecon.tcl 210a913ad63f9f991070821e599d600bd913e0ad
F doc/F2FS.txt c1d4a0ae9711cfe0e1d8b019d154f1c29e0d3abfe820787ba1e9ed7691160fcd
-F doc/lemon.html 857495c0ce060a4e2f2ad7111135ad7e28041a32c10612279ab398eddf678f58
+F doc/lemon.html 1edc0f916e771212792d4d077aedc05168bf13fd65d64d41b2c13e46ac0063a8
F doc/pager-invariants.txt 27fed9a70ddad2088750c4a2b493b63853da2710
F doc/trusted-schema.md 33625008620e879c7bcfbbfa079587612c434fa094d338b08242288d358c3e8a
F doc/vfs-shm.txt e101f27ea02a8387ce46a05be2b1a902a021d37a
+F doc/wal-lock.md 781726aaba20bafeceb7ba9f91d5c98c6731691b30c954e37cf0b49a053d461d
F ext/README.md fd5f78013b0a2bc6f0067afb19e6ad040e89a10179b4f6f03eee58fac5f169bd
F ext/async/README.txt e12275968f6fde133a80e04387d0e839b0c51f91
-F ext/async/sqlite3async.c 0f3070cc3f5ede78f2b9361fb3b629ce200d7d74
-F ext/async/sqlite3async.h f489b080af7e72aec0e1ee6f1d98ab6cf2e4dcef
+F ext/async/sqlite3async.c 6f247666b495c477628dd19364d279c78ea48cd90c72d9f9b98ad1aff3294f94
+F ext/async/sqlite3async.h 46b47c79357b97ad85d20d2795942c0020dc20c532114a49808287f04aa5309a
F ext/expert/README.md b321c2762bb93c18ea102d5a5f7753a4b8bac646cb392b3b437f633caf2020c3
F ext/expert/expert.c d548d603a4cc9e61f446cc179c120c6713511c413f82a4a32b1e1e69d3f086a4
F ext/expert/expert1.test 2e10ff875c31c9e6fc5e324767624181273859771fe34c5daeeadf3f2974a4f7
-F ext/expert/sqlite3expert.c 3da865f2286433588260f41e796422c611bceaca3a0bbf9139a619cf7d062c19
+F ext/expert/sqlite3expert.c b5eae75862d34a204d16c45dcb813888b5f86bdc156c6136b0f79094c0da4f79
F ext/expert/sqlite3expert.h ca81efc2679a92373a13a3e76a6138d0310e32be53d6c3bfaedabd158ea8969b
F ext/expert/test_expert.c d56c194b769bdc90cf829a14c9ecbc1edca9c850b837a4d0b13be14095c32a72
F ext/fts1/README.txt 20ac73b006a70bcfd80069bdaf59214b6cf1db5e
@@ -78,11 +79,11 @@ F ext/fts2/fts2_tokenizer.c b529493d55e55497213c37e1f31680a77746be26
F ext/fts2/fts2_tokenizer.h 27a1a99ca2d615cf7e142839b8d79e8751b4529e
F ext/fts2/fts2_tokenizer1.c 07e223eecb483d448313b5f1553a4f299a7fb7a1
F ext/fts2/mkfts2amal.tcl 974d5d438cb3f7c4a652639262f82418c1e4cff0
-F ext/fts3/README.content fdc666a70d5257a64fee209f97cf89e0e6e32b51
+F ext/fts3/README.content b9078d0843a094d86af0d48dffbff13c906702b4c3558012e67b9c7cc3bf59ee
F ext/fts3/README.syntax a19711dc5458c20734b8e485e75fb1981ec2427a
F ext/fts3/README.tokenizers b92bdeb8b46503f0dd301d364efc5ef59ef9fa8e2758b8e742f39fa93a2e422d
F ext/fts3/README.txt 8c18f41574404623b76917b9da66fcb0ab38328d
-F ext/fts3/fts3.c de2cc136ccc6128e948ffd5d74636756014b2430d6237d7002c3bc3ceb1ae3ae
+F ext/fts3/fts3.c b8ed676b377b1f7f07596aa6272ea623acf087f529a3007b75d1f4908919e6b9
F ext/fts3/fts3.h 3a10a0af180d502cecc50df77b1b22df142817fe
F ext/fts3/fts3Int.h 2c59cc46aefde134c1782e89a6a5384710ddcd4e783071337aa5d43d07269be3
F ext/fts3/fts3_aux.c 96708c8b3a7d9b8ca1b68ea2b7e503e283f20e95f145becadedfad096dbd0f34
@@ -91,7 +92,7 @@ F ext/fts3/fts3_hash.c 8b6e31bfb0844c27dc6092c2620bdb1fca17ed613072db057d96952c6
F ext/fts3/fts3_hash.h 39cf6874dc239d6b4e30479b1975fe5b22a3caaf
F ext/fts3/fts3_icu.c 305ce7fb6036484085b5556a9c8e62acdc7763f0f4cdf5fd538212a9f3720116
F ext/fts3/fts3_porter.c 3565faf04b626cddf85f03825e86056a4562c009
-F ext/fts3/fts3_snippet.c 052b35ad746349ffb53820379bacdb23ff3ac60d3cc13d986e56d42822ef5a9a
+F ext/fts3/fts3_snippet.c 86e7e947a176f0f005720b3ca17631aca2fd2f9daa6729d4adbf2d16ab1b9613
F ext/fts3/fts3_term.c f45a1e7c6ef464abb1231245d123dae12266b69e05cc56e14045b76591ae92d1
F ext/fts3/fts3_test.c 73b16e229e517c1b1f0fb8e1046182a4e5dbc8dbe6eea8a5d4353fcce7dbbf39
F ext/fts3/fts3_tokenize_vtab.c cb792f59212f7799bf2891c7d4579bbf568f124ce8fbb0a9902aa5bd577e8b75
@@ -100,11 +101,11 @@ F ext/fts3/fts3_tokenizer.h 64c6ef6c5272c51ebe60fc607a896e84288fcbc3
F ext/fts3/fts3_tokenizer1.c 5c98225a53705e5ee34824087478cf477bdb7004
F ext/fts3/fts3_unicode.c 4b9af6151c29b35ed09574937083cece7c31e911f69615e168a39677569b684d
F ext/fts3/fts3_unicode2.c 416eb7e1e81142703520d284b768ca2751d40e31fa912cae24ba74860532bf0f
-F ext/fts3/fts3_write.c ed869b24d074f2498bdbef915d6db1f88c604ca5811502112061932a0bed5133
+F ext/fts3/fts3_write.c 723ed1b11ed46ad1b3a23c0d69fa39e77986783a82d5711bf87a5ce29e0a3b52
F ext/fts3/fts3speed.tcl b54caf6a18d38174f1a6e84219950d85e98bb1e9
F ext/fts3/mkfts3amal.tcl 252ecb7fe6467854f2aa237bf2c390b74e71f100
F ext/fts3/tool/fts3cov.sh c331d006359456cf6f8f953e37f2b9c7d568f3863f00bb5f7eb87fea4ac01b73
-F ext/fts3/tool/fts3view.c 202801a2056995b763864d60c2dee744d46f1677
+F ext/fts3/tool/fts3view.c 413c346399159df81f86c4928b7c4a455caab73bfbc8cd68f950f632e5751674
F ext/fts3/unicode/CaseFolding.txt 8c678ca52ecc95e16bc7afc2dbf6fc9ffa05db8c
F ext/fts3/unicode/UnicodeData.txt cd07314edb62d49fde34debdaf92fa2aa69011e7
F ext/fts3/unicode/mkunicode.tcl bf7fcaa6d68e6d38223467983785d054f1cff4d9e3905dd51f6ed8801bb590d5
@@ -117,7 +118,7 @@ F ext/fts5/fts5_buffer.c 5a5fe0159752c0fb0a5a93c722e9db2662822709490769d482b76a6
F ext/fts5/fts5_config.c b447948f35ad3354e8fe5e242e0a7e7b5b941555400b9404259944e3aa570037
F ext/fts5/fts5_expr.c 2be456484786333d559dc2987a00f2750981fab91d52db8452a8046278c5f22e
F ext/fts5/fts5_hash.c 1cc0095646f5f3b46721aa112fb4f9bf29ae175cb5338f89dcec66ed97acfe75
-F ext/fts5/fts5_index.c f25bec3c00bf050fa2d702d97b773d0706692661172026ddac8df1f164b8b198
+F ext/fts5/fts5_index.c de14c9a30f45e2b847ff9284b14776d9d07961e545e8f1546a6aa3f915af721f
F ext/fts5/fts5_main.c e881a2ea0bf01b3a3ff0bc1b31373c58fd54b6c9f3c43ea3d431bea4e5d4025e
F ext/fts5/fts5_storage.c 3ecda8edadc1f62a355d6789776be0da609f8658c50d72e422674093ab7e1528
F ext/fts5/fts5_tcl.c 39bcbae507f594aad778172fa914cad0f585bf92fd3b078c686e249282db0d95
@@ -158,7 +159,7 @@ F ext/fts5/test/fts5connect.test 08030168fc96fc278fa81f28654fb7e90566f33aff269c0
F ext/fts5/test/fts5content.test 213506436fb2c87567b8e31f6d43ab30aab99354cec74ed679f22aad0cdbf283
F ext/fts5/test/fts5corrupt.test 77ae6f41a7eba10620efb921cf7dbe218b0ef232b04519deb43581cb17a57ebe
F ext/fts5/test/fts5corrupt2.test 7453752ba12ce91690c469a6449d412561cc604b1dec994e16ab132952e7805f
-F ext/fts5/test/fts5corrupt3.test fab4ea761b2df254fb3909423989320772a3a757de4d151ddcfa2a40a3b93328
+F ext/fts5/test/fts5corrupt3.test 7afe0fea5b2160798fdc3306395048768c6fc13acefc0e7129d4075b6e1bb224
F ext/fts5/test/fts5corrupt4.test ea805c4d7c68b5f185b9db5d2060a7ae5875339738dd48203c92162f41e7ca91
F ext/fts5/test/fts5delete.test cbf87e3b8867c4d5cfcaed975c7475fd3f99d072bce2075fcedf43d1f82af775
F ext/fts5/test/fts5detail.test 31b240dbf6d44ac3507e2f8b65f29fdc12465ffd531212378c7ce1066766f54e
@@ -230,33 +231,33 @@ F ext/fts5/tool/fts5txt2db.tcl 526a9979c963f1c54fd50976a05a502e533a4c59
F ext/fts5/tool/loadfts5.tcl 95b03429ee6b138645703c6ca192c3ac96eaf093
F ext/fts5/tool/mkfts5c.tcl d1c2a9ab8e0ec690a52316f33dd9b1d379942f45
F ext/fts5/tool/showfts5.tcl d54da0e067306663e2d5d523965ca487698e722c
-F ext/icu/README.txt a295e91db742b153e8dce8f7efd31d28ad1eea4df31ef4daa3eedc85be2f5138
+F ext/icu/README.txt 1c48ffaf7f255bd73d00a35f68f6de357c2a6594f16cb00506a151be23694706
F ext/icu/icu.c 91c021c7e3e8bbba286960810fa303295c622e323567b2e6def4ce58e4466e60
-F ext/icu/sqliteicu.h 728867a802baa5a96de7495e9689a8e01715ef37
+F ext/icu/sqliteicu.h fa373836ed5a1ee7478bdf8a1650689294e41d0c89c1daab26e9ae78a32075a8
F ext/lsm1/Makefile a553b728bba6c11201b795188c5708915cc4290f02b7df6ba7e8c4c943fd5cd9
F ext/lsm1/Makefile.msc f8c878b467232226de288da320e1ac71c131f5ec91e08b21f502303347260013
F ext/lsm1/lsm-test/README 87ea529d2abe615e856d4714bfe8bb185e6c2771b8612aa6298588b7b43e6f86
F ext/lsm1/lsm-test/lsmtest.h cf58528ffe0cfe535e91b44584e2ec5fb1caacdabecef0d8dcf83bf83168bf28
-F ext/lsm1/lsm-test/lsmtest1.c ae6ba48a0851b39be69a7d0eb220bfb9521a526e926223d5014bd385df10abb3
+F ext/lsm1/lsm-test/lsmtest1.c 54374fe88cee888c52c31160013c26184288f47a45b23d4d85390aa539733aab
F ext/lsm1/lsm-test/lsmtest2.c 188b09aec776516aeedcfd13b9c6faf85ba16b3671a0897a2c740ee00a5dc4f8
F ext/lsm1/lsm-test/lsmtest3.c 9ab87528a36dbf4a61d7c8ad954f5ee368c0878c127b84b942b2e2abe522de26
F ext/lsm1/lsm-test/lsmtest4.c d258d6a245db5d8eaede096e2368d23f859c5e92c80ab9122463f708514fe10c
F ext/lsm1/lsm-test/lsmtest5.c 8d5242a0f870d65eeada191c8945781fed9cb8ece3886573790ebd373b62dac5
F ext/lsm1/lsm-test/lsmtest6.c 869cb4a172cd07d1a75b3aeaecd61d0a477787b3b8668bad0d3ff0f43b642b7c
F ext/lsm1/lsm-test/lsmtest7.c 7a917455a0f956a8ed3f44f5c9387ec0ea6627714874464cc3fa5c5a9cabb2f2
-F ext/lsm1/lsm-test/lsmtest8.c 589b68c44531a0f04d5e879bb1e211be5f7100f48eed7e8631e07ed5cbd68f94
-F ext/lsm1/lsm-test/lsmtest9.c dd1a0ebf41134933a744d1e00e60429a2a21fc50d587ae7dd6bdb6e96d805bdc
-F ext/lsm1/lsm-test/lsmtest_bt.c d70d9a9be5eef9360af1251dd083948d74fd30137a08f61bef995f7ac04e037f
+F ext/lsm1/lsm-test/lsmtest8.c 773f226163d0f0d62701e3764d0c35fd4365faca74098bd63648bc57d6f14402
+F ext/lsm1/lsm-test/lsmtest9.c 0a168757b757b106191acf43143dbbb5b2d76e57a3c8fd3018cecbaee1080aba
+F ext/lsm1/lsm-test/lsmtest_bt.c 79b24bfd37e05fd626c35ec23bc5bb62d8a403afd66c710335384884dc1366d7
F ext/lsm1/lsm-test/lsmtest_datasource.c 5d770be191d0ca51315926723009b2c25c0b4b8136840494ef710ac324aa916c
F ext/lsm1/lsm-test/lsmtest_func.c 159aa401bc8032bfa3d8cf2977bd687abebab880255895a5eb45770d626fa38d
F ext/lsm1/lsm-test/lsmtest_io.c cf11b27b129c6bd5818fa1d440176502dc27229f0db892b4479118d61993ea20
F ext/lsm1/lsm-test/lsmtest_main.c a9bc647738c0dcaebf205d6d194b3ce4a6ef3925801cd2d919f0a4ea33a15aeb
F ext/lsm1/lsm-test/lsmtest_mem.c 4e63c764345ab1df59d4f13a77980c6f3643798210b10d6cdbd785b4b888fda5
-F ext/lsm1/lsm-test/lsmtest_tdb.c 618a8619183fda4f5540fcde15f9068293c5e3180e1a246e34409b0c148758b3
+F ext/lsm1/lsm-test/lsmtest_tdb.c 754b1ca8e1cfa7b29cbe2e4ab500f7eee0059033741b8d83267afe6f495a536d
F ext/lsm1/lsm-test/lsmtest_tdb.h 8733eee249b12956a9df8322994b43d19bd8c02ad2e8b0bb5164db4d6ccc1735
-F ext/lsm1/lsm-test/lsmtest_tdb2.cc 99ea7f2dd9c7536c8fb9bdd329e4cfeb76899f3ddf6f48bdd3926e016922b715
+F ext/lsm1/lsm-test/lsmtest_tdb2.cc aebe50f2cb7a759214241938046fe5f00da66e4217637f946f436ca209776af9
F ext/lsm1/lsm-test/lsmtest_tdb3.c 7a7ccae189f5bb25bcd1ec3bbd740529706eded7f6729a5a0a9eeaeb57785320
-F ext/lsm1/lsm-test/lsmtest_tdb4.c 47e8bb5eba266472d690fb8264f1855ebdba0ae5a0e541e35fcda61ebf1d277f
+F ext/lsm1/lsm-test/lsmtest_tdb4.c cbe230727b9413d244062943371af1421ace472ccb023b75af6540e0fa52b1bb
F ext/lsm1/lsm-test/lsmtest_util.c 241622db5a332a09c8e6e7606b617d288a37b557f7d3bce0bb97809f67cc2806
F ext/lsm1/lsm-test/lsmtest_win32.c 0e0a224674c4d3170631c41b026b56c7e1672b151f5261e1b4cc19068641da2d
F ext/lsm1/lsm.h 0f6f64ff071471cb87bf98beb8386566f30ea001
@@ -271,7 +272,7 @@ F ext/lsm1/lsm_shared.c 76adfc1ed9ffebaf92746dde4b370ccc48143ca8b05b563816eadd2a
F ext/lsm1/lsm_sorted.c 6f7d8cf7a7d3d3f1ab5d9ba6347e8f39f3d73c00ec48afcd0c4bcbefd806f9b8
F ext/lsm1/lsm_str.c 65e361b488c87b10bf3e5c0070b14ffc602cf84f094880bece77bbf6678bca82
F ext/lsm1/lsm_tree.c 682679d7ef2b8b6f2fe77aeb532c8d29695bca671c220b0abac77069de5fb9fb
-F ext/lsm1/lsm_unix.c 57361bcf5b1a1a028f5d66571ee490e9064d2cfb145a2cc9e5ddade467bb551b
+F ext/lsm1/lsm_unix.c 11e0a5c19d754a4e1d93dfad06de8cc201f10f886b8e61a4c599ed34e334fc24
F ext/lsm1/lsm_varint.c 43f954af668a66c7928b81597c14d6ad4be9fedbc276bbd80f52fa28a02fdb62
F ext/lsm1/lsm_vtab.c 169bfe7ef8e6c9de9c77e17c4c50c9ae55fb0167d80be3d1be82c991184b6f35
F ext/lsm1/lsm_win32.c 0a4acbd7e8d136dd3a5753f0a9e7a9802263a9d96cef3278cf120bcaa724db7c
@@ -283,25 +284,27 @@ F ext/misc/amatch.c e3ad5532799cee9a97647f483f67f43b38796b84b5a8c60594fe782a4338
F ext/misc/anycollseq.c 5ffdfde9829eeac52219136ad6aa7cd9a4edb3b15f4f2532de52f4a22525eddb
F ext/misc/appendvfs.c 3777f22ec1057dc4e5fd89f2fbddcc7a29fbeef1ad038c736c54411bb1967af7
F ext/misc/blobio.c a867c4c4617f6ec223a307ebfe0eabb45e0992f74dd47722b96f3e631c0edb2a
-F ext/misc/btreeinfo.c 26004b7a6be320ec08fc20ca8d0f01fccb00a98cbe0f3197446794ff2a506aa3
+F ext/misc/btreeinfo.c d28ce349b40054eaa9473e835837bad7a71deec33ba13e39f963d50933bfa0f9
F ext/misc/carray.c 91e9a7f512fda934894bed30464552fffa7d3073b5be04189ae0bd0c59f26bfd
+F ext/misc/cksumvfs.c a3271f5cc3f87d80897cca76d54220380aeae3448efd23fefe47853443ef1185
F ext/misc/closure.c dbfd8543b2a017ae6b1a5843986b22ddf99ff126ec9634a2f4047cd14c85c243
-F ext/misc/completion.c a0efe03edfdc4f717c61e6c9b0bfe2708ff7878010dae3174980a68fdf76aabc
+F ext/misc/completion.c 6dafd7f4348eecc7be9e920d4b419d1fb2af75d938cd9c59a20cfe8beb2f22b9
F ext/misc/compress.c 3354c77a7c8e86e07d849916000cdac451ed96500bfb5bd83b20eb61eee012c9
F ext/misc/csv.c 3ed979c1eb35e35a98b30ef545a2facf62994594217681d9138b4b75faf6b0d7
F ext/misc/dbdata.c e316fba936571584e55abd5b974a32a191727a6b746053a0c9d439bd2cf93940
-F ext/misc/dbdump.c baf6e37447c9d6968417b1cd34cbedb0b0ab3f91b5329501d8a8d5be3287c336
+F ext/misc/dbdump.c b8592f6f2da292c62991a13864a60d6c573c47a9cc58362131b9e6a64f823e01
+F ext/misc/decimal.c c1897f624893d1c12e3c879d97ca7d1c4a36cae10d32afe632779de78c4aaa4f
F ext/misc/eval.c 04bc9aada78c888394204b4ed996ab834b99726fb59603b0ee3ed6e049755dc1
-F ext/misc/explain.c d5c12962d79913ef774b297006872af1fccda388f61a11d37758f9179a09551f
+F ext/misc/explain.c 0086fab288d4352ea638cf40ac382aad3b0dc5e845a1ea829a694c015fd970fe
F ext/misc/fileio.c 9b69e25da3b51d4a1d905a464ccb96709792ad627a742ba09215bc0d1447e7bd
F ext/misc/fossildelta.c 1240b2d3e52eab1d50c160c7fe1902a9bd210e052dc209200a750bbf885402d5
F ext/misc/fuzzer.c eae560134f66333e9e1ca4c8ffea75df42056e2ce8456734565dbe1c2a92bf3d
-F ext/misc/ieee754.c eaffd9b364d7c8371727e9c43fc8bec38cdacc4d11fc26beffaa3ca05a0ea9d6
-F ext/misc/json1.c 2d44e3fa37f958b42cbcd41651f9f0a0eaaf3bac3f1f4b8eb456431623cb3bd8
+F ext/misc/ieee754.c bb6bd8e9eeeda5a7ac82839fcab5c0b8156b0532165387cc5458a97f60047b5d
+F ext/misc/json1.c 3a42e3231d716516a8ae33b0a052d3ed5f52943e3d627b68744a427a6e552ae3
F ext/misc/memstat.c 3017a0832c645c0f8c773435620d663855f04690172316bd127270d1a7523d4d
F ext/misc/memtrace.c 7c0d115d2ef716ad0ba632c91e05bd119cb16c1aedf3bec9f06196ead2d5537b
F ext/misc/memvfs.c ab36f49e02ebcdf85a1e08dc4d8599ea8f343e073ac9e0bca18a98b7e1ec9567
-F ext/misc/mmapwarm.c 8c5fe90d807a23e44a8b93e96e8b812b19b300d5fd8c1d40a4fd1d8224e33f46
+F ext/misc/mmapwarm.c 347caa99915fb254e8949ec131667b7fae99e2a9ce91bd468efb6dc372d9b7a9
F ext/misc/nextchar.c 7877914c2a80c2f181dd04c3dbef550dfb54c93495dc03da2403b5dd58f34edd
F ext/misc/noop.c 81efe4cad9ec740e64388b14281cb983e6e2c223fed43eb77ab3e34946e0c1ab
F ext/misc/normalize.c b4290464f542bae7a97b43f15bd197949b833ffd668b7c313631bd5d4610212c
@@ -310,22 +313,22 @@ F ext/misc/prefixes.c 0f4f8cff5aebc00a7e3ac4021fd59cfe1a8e17c800ceaf592859ecb9cb
F ext/misc/regexp.c 246244c714267f303df76acf73dcf110cf2eaf076896aaaba8db6d6d21a129db
F ext/misc/remember.c add730f0f7e7436cd15ea3fd6a90fd83c3f706ab44169f7f048438b7d6baa69c
F ext/misc/rot13.c 51ac5f51e9d5fd811db58a9c23c628ad5f333c173f1fc53c8491a3603d38556c
-F ext/misc/scrub.c db9fff56fed322ca587d73727c6021b11ae79ce3f31b389e1d82891d144f22ad
+F ext/misc/scrub.c 2a44b0d44c69584c0580ad2553f6290a307a49df4668941d2812135bfb96a946
F ext/misc/series.c 4057dda3579b38ff88b2d3b13b4dd92dbd9d6f90dac2b55c19b0a8ed87ee4959
F ext/misc/sha1.c c8f2253c8792ffab9517695ea7d88c079f0395a5505eefef5c8198fe184ed5ac
F ext/misc/shathree.c 135b7c145db4a09b1650c3e7aff9cb538763a9a361e834c015dd1aaf8d5c9a00
F ext/misc/showauth.c 732578f0fe4ce42d577e1c86dc89dd14a006ab52
F ext/misc/spellfix.c 94df9bbfa514a563c1484f684a2df3d128a2f7209a84ca3ca100c68a0163e29f
-F ext/misc/sqlar.c c9e5d58544e1506135806a1e0f525f92d4bb6bb125348dce469d778fb334fbce
-F ext/misc/stmt.c 8a8dc4675042e4551e4afe99b8d0cc7a4a2fc1a8dacc0a9ce1b1bbff145da93d
+F ext/misc/sqlar.c 0ace5d3c10fe736dc584bf1159a36b8e2e60fab309d310cd8a0eecd9036621b6
+F ext/misc/stmt.c 35063044a388ead95557e4b84b89c1b93accc2f1c6ddea3f9710e8486a7af94a
F ext/misc/templatevtab.c 8a16a91a5ceaccfcbd6aaaa56d46828806e460dd194965b3f77bf38f14b942c4
F ext/misc/totype.c fa4aedeb07f66169005dffa8de3b0a2b621779fd44f85c103228a42afa71853b
-F ext/misc/uint.c 5870865fb5f6153db18db443f3ecdcdb17a06567ee47ecd9fd26e3ec7e5f6ce8
+F ext/misc/uint.c 053fed3bce2e89583afcd4bf804d75d659879bbcedac74d0fa9ed548839a030b
F ext/misc/unionvtab.c 36237f0607ca954ac13a4a0e2d2ac40c33bc6e032a5f55f431713061ef1625f9
F ext/misc/urifuncs.c f71360d14fa9e7626b563f1f781c6148109462741c5235ac63ae0f8917b9c751
F ext/misc/uuid.c 5bb2264c1b64d163efa46509544fd7500cb8769cb7c16dd52052da8d961505cf
F ext/misc/vfslog.c 3b25c2f56ba60788db247287be6ab024b53c4afffd412b4876db563389be0d35
-F ext/misc/vfsstat.c 77b5b4235c9f7f11eddf82487c0a422944ac2f132dafd5af3be7a68a057b1cdb
+F ext/misc/vfsstat.c 389ea13983d3af926504c314f06a83cc858d5adc24b40af74aaed1fece00c118
F ext/misc/vtablog.c 5538acd0c8ddaae372331bee11608d76973436b77d6a91e8635cfc9432fba5ae
F ext/misc/vtshim.c 1976e6dd68dd0d64508c91a6dfab8e75f8aaf6cd
F ext/misc/wholenumber.c 520f34c3099e5b7d546f13708607dc2fa173c46b68952eecf0d19cd675fec85e
@@ -371,12 +374,12 @@ F ext/rbu/rbuvacuum.test 55e101e90168c2b31df6c9638fe73dc7f7cc666b6142266d1563697
F ext/rbu/rbuvacuum2.test b8e5b51dc8b2c0153373d024c0936be3f66f9234acbd6d0baab0869d56b14e6b
F ext/rbu/rbuvacuum3.test 8addd82e4b83b4c93fa47428eae4fd0dbf410f8512c186f38e348feb49ba03dc
F ext/rbu/rbuvacuum4.test a78898e438a44803eb2bc897ba3323373c9f277418e2d6d76e90f2f1dbccfd10
-F ext/rbu/sqlite3rbu.c 77a47f3231f5f363b2c584dba3e310a7efdaf073ad8c18728ab846b38de2879c
+F ext/rbu/sqlite3rbu.c 05c457c27e9340c944f34e850871a915a6b5ee1d823f7a0bb2b482ac6b1e1464
F ext/rbu/sqlite3rbu.h 1dc88ab7bd32d0f15890ea08d23476c4198d3da3056985403991f8c9cd389812
F ext/rbu/test_rbu.c 03f6f177096a5f822d68d8e4069ad8907fe572c62ff2d19b141f59742821828a
F ext/repair/README.md 92f5e8aae749a4dae14f02eea8e1bb42d4db2b6ce5e83dbcdd6b1446997e0c15
F ext/repair/checkfreelist.c 0dbae18c1b552f58d64f8969e4fb1e7f11930c60a8c2a9a8d50b7f15bdfd54bd
-F ext/repair/checkindex.c 7d28c01a2e012ac64257d230fc452b2cafb78311a91a343633d01d95220f66f3
+F ext/repair/checkindex.c 4383e4469c21e5b9ae321d0d63cec53e981af9d7a6564be6374f0eeb93dfc890
F ext/repair/sqlite3_checker.c.in 4a5a3af3f450fe503e5a2985e98516dc2a6b9ad247449e284c1cf140fc91720f
F ext/repair/sqlite3_checker.tcl a9a2caa9660567257c177a91124d8c0dccdfa341e25c51e6da7f1fd9e601eafa
F ext/repair/test/README.md 34b2f542cf5be7bffe479242b33ee3492cea30711e447cc4a1a86cb5915f419e
@@ -384,7 +387,7 @@ F ext/repair/test/checkfreelist01.test 3e8aa6aeb4007680c94a8d07b41c339aa635cc782
F ext/repair/test/checkindex01.test b530f141413b587c9eb78ff734de6bb79bc3515c335096108c12c01bddbadcec
F ext/repair/test/test.tcl 686d76d888dffd021f64260abf29a55c57b2cedfa7fc69150b42b1d6119aac3c
F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761
-F ext/rtree/geopoly.c cac70b5502742bd0ba8877a1329a74e86a379c78567546a2a18cf5f9c3787f73
+F ext/rtree/geopoly.c f15cc6845d64a629035627d863cbe3eadc9cb30f9ca77bd823b0ca8a5a3f8b00
F ext/rtree/rtree.c 0ee39cc787b95aa03a012e09e6090b0fa452154fa812af9a379898560fd6c00f
F ext/rtree/rtree.h 4a690463901cb5e6127cf05eb8e642f127012fd5003830dbc974eca5802d9412
F ext/rtree/rtree1.test 00792b030a4e188ff1b22e8530e8aa0452bb5dd81c2b18cb004afc7dc63e040e
@@ -435,17 +438,17 @@ F ext/session/sessionE.test b2010949c9d7415306f64e3c2072ddabc4b8250c98478d3c0c4d
F ext/session/sessionF.test d37ed800881e742c208df443537bf29aa49fd56eac520d0f0c6df3e6320f3401
F ext/session/sessionG.test 3828b944cd1285f4379340fd36f8b64c464fc84df6ff3ccbc95578fd87140b9c
F ext/session/sessionH.test b17afdbd3b8f17e9bab91e235acf167cf35485db2ab2df0ea8893fbb914741a4
-F ext/session/session_common.tcl 29ec9910aca1e996ca1c8531b8cecabf96eb576aa53de65a8ff03d848b9a2a8b
+F ext/session/session_common.tcl f613174665456b2d916ae8df3e5735092a1c1712f36f46840172e9a01e8cc53e
F ext/session/session_speed_test.c dcf0ef58d76b70c8fbd9eab3be77cf9deb8bc1638fed8be518b62d6cbdef88b3
F ext/session/sessionat.test efe88965e74ff1bc2af9c310b28358c02d420c1fb2705cc7a28f0c1cc142c3ec
F ext/session/sessiondiff.test ad13dd65664bae26744e1f18eb3cbd5588349b7e9118851d8f9364248d67bcec
F ext/session/sessionfault.test da273f2712b6411e85e71465a1733b8501dbf6f7
F ext/session/sessionfault2.test dd593f80b6b4786f7adfe83c5939620bc505559770cc181332da26f29cddd7bb
-F ext/session/sessioninvert.test ae1a003a9ab1f8d64227dbb5c3a4c97e65b561b01e7b2953cf48683fb2724169
+F ext/session/sessioninvert.test 04075517a9497a80d39c495ba6b44f3982c7371129b89e2c52219819bc105a25
F ext/session/sessionrebase.test ccfa716b23bd1d3b03217ee58cfd90c78d4b99f53e6a9a2f05e82363b9142810
F ext/session/sessionstat1.test 218d351cf9fcd6648f125a26b607b140310160184723c2666091b54450a68fb5
F ext/session/sessionwor.test 67b5ab91d4f93ce65ff1f58240ac5ddf73f8670facc1ffa49cef56293d52818d
-F ext/session/sqlite3session.c e25b345896fa3646ff8b6c4058b3d9e365dc7eab4afe80b110808681098551c8
+F ext/session/sqlite3session.c fc8c6c13dc0456943ff24abf574ced10418eec66a548c97d3eafbebe9fc5e908
F ext/session/sqlite3session.h a2db5b72b938d12c727b4b4ec632254ca493670a9c0de597af3271a7f774fc57
F ext/session/test_session.c 98797aba475a799376c9a42214f2d1debf2d0c3cb657d9c8bbf4f70bf3fb4aec
F ext/userauth/sqlite3userauth.h 7f3ea8c4686db8e40b0a0e7a8e0b00fac13aa7a3
@@ -454,7 +457,7 @@ F ext/userauth/userauth.c 7f00cded7dcaa5d47f54539b290a43d2e59f4b1eb5f447545fa865
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60
-F main.mk f3a972451ed68fa1101d81606a2a1b0a2600b85547059fe89ccb2380b983e50c
+F main.mk b1cd0bc6aedad7ebb667b7f74f835f932f60ee33be2a5c3051fd93eb465f5c75
F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83
F mptest/config01.test 3c6adcbc50b991866855f1977ff172eb6d901271
F mptest/config02.test 4415dfe36c48785f751e16e32c20b077c28ae504
@@ -466,90 +469,90 @@ F spec.template 86a4a43b99ebb3e75e6b9a735d5fd293a24e90ca
F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
F sqlite3.1 fc7ad8990fc8409983309bb80de8c811a7506786
F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a
-F src/alter.c fa2c3be9b0ebecfafb7062072a0ae6eda126d3e5a9fd51b2eded5acd95dc783c
-F src/analyze.c 831bb090988477a00d3b4c000746e1b0454dcc93b10b793e6ebe1c47f25d193a
+F src/alter.c f6cf5c21f92ad59159a6c44214942efe1433389887851ca25ac0a4a658e0694b
+F src/analyze.c 2c77bcbb8651ccced4a8cdaf8d997663813b2967787070fa26d0360de2ee4367
F src/attach.c ff2daea0fe62080192e3f262670e4f61f5a86c1e7bea9cec34e960fe79852aa1
F src/auth.c a3d5bfdba83d25abed1013a8c7a5f204e2e29b0c25242a56bc02bb0c07bf1e06
-F src/backup.c 5e617c087f1c2d6005c2ec694ce80d6e16bc68d906e1b1c556d7c7c2228b636b
+F src/backup.c b1c90cd4110248c8e1273ff4578d3a84c0c34725e1b96dacd4a6294a908702de
F src/bitvec.c 17ea48eff8ba979f1f5b04cc484c7bb2be632f33
F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6
-F src/btree.c 02376eb7d49ccf31b53c2504f045ad74687c142a5c15ca837516e59e737867dc
-F src/btree.h 32672fa1aa74a7e9ab3aae822f94ffc8e732b1eb005988dc2283f91dc7573398
-F src/btreeInt.h 887cdd2ea7f4a65143074a8a7c8928b0546f8c18dda3c06a408ce7992cbab0c0
-F src/build.c d43ee335c3efc4005b4dcd07aecd1f9e231c10320fe8f65b0bf81f0b4b98eace
+F src/btree.c e8a64df5ebd1e9d5184ff89fc110e048cdf7b77cc300eb51c48969ef4e71c23b
+F src/btree.h f980f639ae89bd67284b1c260e91c97ce4fd50be687bed42a11f5ca42fda9323
+F src/btreeInt.h 19267385aa3bc00067d48e0e4ba83ae82dc08b0c15a3b3df20ea653cb462b5bf
+F src/build.c 0d340ea2a0ed8b6d2448c76b84e4d8b6e7ddfa1542b4e876aed989ce1eb248d9
F src/callback.c d0b853dd413255d2e337b34545e54d888ea02f20da5ad0e63585b389624c4a6c
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
-F src/ctime.c 6a77ec9e0eb87aea929e002c816298907e337094a7b556898ae2d1e6be209f90
-F src/date.c b29b349d277e3d579dcc295b24c0a2caed83fd8f090a9f7cbe6070c0fd662384
+F src/ctime.c e98518d2d3d4029a13c805e07313fb60c877be56db76e90dd5f3af73085d0ce6
+F src/date.c 9f1d31ef1bfdc732a83459e05770f6d5aeb57a7e323b48f1798cb870125601ef
F src/dbpage.c 8a01e865bf8bc6d7b1844b4314443a6436c07c3efe1d488ed89e81719047833a
-F src/dbstat.c 793deaf88a0904f88285d93d6713c636d55ede0ffd9f08d10f4ea825531d367f
-F src/delete.c 6a4cbe008e8885eac5a0e0f9228ad716db92e3f9f2f0cb91a8ae276658d1f909
-F src/expr.c d1e1d42cbdec08bb867a1ab43a59b401d82ff2bc88bdcb4af20e479a5facb6d8
+F src/dbstat.c 3aa79fc3aed7ce906e4ea6c10e85d657299e304f6049861fe300053ac57de36c
+F src/delete.c 410c771c25afc113c273d9efad6ab6881bda28c75a1838b9d2c52ba20d1dc704
+F src/expr.c 90039a043658ce78c3237ba5064c0934b7294120f6adc387f8d0fba306028154
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
F src/fkey.c 4b575423b0a5d4898b1a7868ce985cf1a8ad91c741c9abbb108ff02536d20f41
-F src/func.c f3dcdc0e95509864767c1f0991b19360f969e44177f4e058fd51da9a6154f47e
-F src/global.c 79a988b56b06ce2d08ebefe1d35da9aa25b3851faa47ea5233361c4827185a64
+F src/func.c 2333eb4277f55a5efdc12ef754e7d7ec9105d257b2fd00301d23ce1e8fa67dc0
+F src/global.c 0409ae635839e0bef26a69b68be64126ab6cba62ac19bd7694f1652e591c4c17
F src/hash.c 8d7dda241d0ebdafb6ffdeda3149a412d7df75102cecfc1021c98d6219823b19
F src/hash.h 9d56a9079d523b648774c1784b74b89bd93fac7b365210157482e4319a468f38
F src/hwtime.h cb1d7e3e1ed94b7aa6fde95ae2c2daccc3df826be26fc9ed7fd90d1750ae6144
F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
-F src/insert.c 8e4211d04eb460c0694d486c6ba1c068d468c6f653c3f237869a802ad82854de
+F src/insert.c c05a7c6f3dbb1a00360b51deac590d4977413078a98334e1650f43223a7d2fc6
F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa
-F src/loadext.c 421310045bd78afefb772294a99e50f37d87ae578786a6169074e6291e30d969
-F src/main.c 652a782cd7b6c6ddf7419fcaf06b8aa9440b7c815857241171c9bdf03ab6544c
-F src/malloc.c cabfef0d725e04c8abfe0231a556ed8b78bf329dcc3fddbf903f6cdcd53cf4e6
+F src/loadext.c 436af4968c6954d304fce9efa12719367bd8f37b19b93b71d6ad607e85adbb47
+F src/main.c 6eab8512369900c9ef8cd96de9ab549a39f21556c528c6b5083025a4ee441f51
+F src/malloc.c d0400b0366e1a3a2414ca4534b4a7406df34732835f37a15cb4642eb7df1a363
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
F src/mem1.c c12a42539b1ba105e3707d0e628ad70e611040d8f5e38cf942cee30c867083de
F src/mem2.c f1940d9e91948dd6a908fbb9ce3835c36b5d83c3
-F src/mem3.c 8768ac94694f31ffaf8b4d0ea5dc08af7010a35a
+F src/mem3.c 30301196cace2a085cbedee1326a49f4b26deff0af68774ca82c1f7c06fda4f6
F src/mem5.c 9bf955937b07f8c32541c8a9991f33ce3173d944
-F src/memdb.c 02a5fcec19b9d40dd449ca802dc1b2e8f93f255fbf2a886277a3c3800d8d35db
+F src/memdb.c 9480d2b7aacf7018fec8c58e5b04f8a2160a31de52f9902f36b9b17433558ced
F src/memjournal.c 7561c01c90958f3ba9bc6cb2d857123d932bdfa5539ea34427a0957b2e35154d
F src/msvc.h 3a15918220367a8876be3fa4f2abe423a861491e84b864fb2b7426bf022a28f8
F src/mutex.c 5e3409715552348732e97b9194abe92fdfcd934cfb681df4ba0ab87ac6c18d25
F src/mutex.h a7b2293c48db5f27007c3bdb21d438873637d12658f5a0bf8ad025bb96803c4a
F src/mutex_noop.c 9d4309c075ba9cc7249e19412d3d62f7f94839c4
-F src/mutex_unix.c aaf9ebc3f89df28483c52208497a99a02cc3650011422fc9d4c57e4392f7fe58
-F src/mutex_w32.c 7670d770c94bbfe8289bec9d7f1394c5a00a57c37f892aab6b6612d085255235
-F src/notify.c 9711a7575036f0d3040ba61bc6e217f13a9888e7
-F src/os.c 669cc3839cc35d20f81faf0be1ab6d4581cea35e9d8f3a9d48a98d6571f7c285
+F src/mutex_unix.c dd2b3f1cc1863079bc1349ac0fec395a500090c4fe4e11ab775310a49f2f956d
+F src/mutex_w32.c caa50e1c0258ac4443f52e00fe8aaea73b6d0728bd8856bedfff822cae418541
+F src/notify.c 89a97dc854c3aa62ad5f384ef50c5a4a11d70fcc69f86de3e991573421130ed6
+F src/os.c 80e4cf3e5da06be03ca641661e331ce60eeeeabf0d7354dbb1c0e166d0eedbbe
F src/os.h 48388821692e87da174ea198bf96b1b2d9d83be5dfc908f673ee21fafbe0d432
F src/os_common.h b2f4707a603e36811d9b1a13278bffd757857b85
F src/os_setup.h 0dbaea40a7d36bf311613d31342e0b99e2536586
-F src/os_unix.c 7ef8b60222558a373d89c18d0c3bc44365b45273a528183d40bec5bb76ce23fc
-F src/os_win.c 035a813cbd17f355bdcad7ab894af214a9c13a1db8aeac902365350b98cd45a7
+F src/os_unix.c e72b7148cda15bcb76840e2b17307021484b5c27ce109ecac8a476798e355f7e
+F src/os_win.c 81890779a52278267658e97d93f75ad8511c298b0e81f4df9a8ac0b286040c6e
F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
-F src/pager.c 52cee2f72710be47b5b13ff66b339ca3855e5bc48e92a94114d2affedc70041f
-F src/pager.h 3b33619a90180e0874c7eca31d6f6ceb464d9322c6fb4e9a7bbb318c8a17bdb3
-F src/parse.y 5f2150bb4974e440924dfcc2e33cea7cf1895492b917464572efd258b0eab267
+F src/pager.c c8f76f8e7b5ed9c4e2c70c65c63cfc183cbf087c566aa29c1ecea98f566ce540
+F src/pager.h 88dd4f06d69ed9e1d44d0d84176841913ccd4d0b05679302f4f83a385f7d2004
+F src/parse.y 37558683598e698b7fac29ea5d05642185f9abc815469c2fb5bc1164ed63fe73
F src/pcache.c 385ff064bca69789d199a98e2169445dc16e4291fa807babd61d4890c3b34177
F src/pcache.h 4f87acd914cef5016fae3030343540d75f5b85a1877eed1a2a19b9f284248586
F src/pcache1.c 6596e10baf3d8f84cc1585d226cf1ab26564a5f5caf85a15757a281ff977d51a
-F src/pragma.c 5fd004b89c77319008ddff6d65dcc83ccca9584d3048f4f66b108b5906a20dba
-F src/pragma.h 9473160d220416456b40f27323bb4b316d4e4e08ffbf8bf88c5f7045d49c38e5
-F src/prepare.c 8d4d6c8aa6afefc48027c54b41cdf134b4d6bc2fc4badbe483ad7fd9e1728a28
-F src/printf.c 9be6945837c839ba57837b4bc3af349eba630920fa5532aa518816defe42a7d4
+F src/pragma.c ae499b5ab8f4e833f67e28bf2322500e9aa612aadf12581d1324333f848d8b51
+F src/pragma.h 8dc78ab7e9ec6ce3ded8332810a2066f1ef6267e2e03cd7356ee00276125c6cf
+F src/prepare.c c471c2f7999c802ed6b3f034f52afba2049ab97b1481f9936c33ef4e77aedbfe
+F src/printf.c 94b5419ad0a17269f76a9e968ca19cf9fa37617abed2e246fc48844e511b6bc6
F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384
-F src/resolve.c 05471a183504f72aedf249851d94ad6feeac4d02be044fefdb4b42a8a6e13e42
+F src/resolve.c dcc9a5cbd7ec626c73e2e7a7dab49c0264b04ba8dcf3ff4b4aa9d36acd34c934
F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92
-F src/select.c 51882f7b24503163414ddcdc33705ea4f74707da70d7d0545e52aa8dff9f8983
-F src/shell.c.in 1fc834b80c72dd37587ea87a4f4167cf5e6d98d12d143184ed2e732f529c0950
-F src/sqlite.h.in fd6fcfe173accab8d9cb9a843856d9e9fb475f893b60a455e01d8739b5076f0e
+F src/select.c 01d1daa982f5c4874f46d360592db2135d679384ef3b20d3f474834b5126e508
+F src/shell.c.in 81fa23ac1a3d6ac9ed13e9ae711a3d8806396ca7cc12c5d6a2e2536f70b0c7ad
+F src/sqlite.h.in d2c03414a8ee5d4a6855c04dd7cd5998e45139b0fe66b65bae86d4223edd091f
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
F src/sqlite3ext.h 2d1af80082edffd71c6f96f70ad1ce6a4fb46615ad10291fc77fe0dea9ff0197
-F src/sqliteInt.h cea0d39df23798779db3cd0a2aa9cecc769ba9b13f58d5958e4a9e9325fa1b58
+F src/sqliteInt.h e0049e2f4dc46460538b74e200ac341a11f4cf92e19159c8c9a766731ade65fe
F src/sqliteLimit.h 95cb8479ca459496d9c1c6a9f76b38aee12203a56ce1092fe13e50ae2454c032
F src/status.c 9ff2210207c6c3b4d9631a8241a7d45ab1b26a0e9c84cb07a9b5ce2de9a3b278
-F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34
-F src/tclsqlite.c d0aa320416efe88c4dbb0156ed6c494f2f9958871a940e46984ee57b3e7fcc50
-F src/test1.c 5e8b8cc54e8c88906ea8a084387aa79bad245e539f4cee73149e5c0527e1db16
+F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
+F src/tclsqlite.c 986b6391f02cd9b53c1d688be55899f6ffddeb8e8014cd83c1b73ff912579a71
+F src/test1.c fe56c4bcaa2685ca9aa25d817a0ee9345e189aff4a5a71a3d8ba946c7776feb8
F src/test2.c 3efb99ab7f1fc8d154933e02ae1378bac9637da5
F src/test3.c 61798bb0d38b915067a8c8e03f5a534b431181f802659a6616f9b4ff7d872644
-F src/test4.c 405834f6a93ec395cc4c9bb8ecebf7c3d8079e7ca16ae65e82d01afd229694bb
+F src/test4.c 7c4420e01c577b5c4add2cb03119743b1a357543d347773b9e717195ea967159
F src/test5.c 328aae2c010c57a9829d255dc099d6899311672d
F src/test6.c e8d839fbc552ce044bec8234561a2d5b8819b48e29548ad0ba400471697946a8
F src/test7.c 5612e9aecf934d6df7bba6ce861fdf5ba5456010
-F src/test8.c 3f7d0cc4e12e06832ba3db4455cb16867ccadafa602eb6ff5fcf097bffce56ed
+F src/test8.c 7fb971777c2c79c734bb52757191d68d4af659b8de9b4a071be3f527a9d19a02
F src/test9.c 12e5ba554d2d1cbe0158f6ab3f7ffcd7a86ee4e5
F src/test_async.c 195ab49da082053fdb0f949c114b806a49ca770a
F src/test_autoext.c 915d245e736652a219a907909bb6710f0d587871
@@ -571,18 +574,18 @@ F src/test_journal.c a0b9709b2f12b1ec819eea8a1176f283bca6d688a6d4a502bd6fd79786f
F src/test_loadext.c 337056bae59f80b9eb00ba82088b39d0f4fe6dfd
F src/test_malloc.c dec0aa821b230773aeb3dd11d652c1193f7cedb18a20b25659bc672288115242
F src/test_md5.c 7268e1e8c399d4a5e181b64ac20e1e6f3bc4dd9fc87abac02db145a3d951fa8c
-F src/test_multiplex.c 46e278397bef99b10530c1a695b4f6f23823fde6d6589b182f14e9bd43440b57
+F src/test_multiplex.c d0ee44ec77687b35e83fd6b9fca4c5860f603b1b407fd375be62437b79af5ae3
F src/test_multiplex.h 5436d03f2d0501d04f3ed50a75819e190495b635
-F src/test_mutex.c 7f4337ba23ee6b1d2ec81c189653608cb069926a
+F src/test_mutex.c abf486e91bd65e2448027d4bb505e7cce6ba110e1afb9bd348d1996961cadf0d
F src/test_onefile.c f31e52e891c5fef6709b9fcef54ce660648a34172423a9cbdf4cbce3ba0049f4
-F src/test_osinst.c 98ef31ff03d55497829ca0f6c74a9f4e1aa48690
+F src/test_osinst.c d341f9d7613e007c8c3f7eba6cd307230047506aa8f97858c1fd21f5069616bd
F src/test_pcache.c a5cd24730cb43c5b18629043314548c9169abb00
F src/test_quota.c 6cb9297115b551f433a9ad1741817a9831abed99
F src/test_quota.h 2a8ad1952d1d2ca9af0ce0465e56e6c023b5e15d
F src/test_rtree.c 671f3fae50ff116ef2e32a3bf1fe21b5615b4b7b
-F src/test_schema.c f575932cb6274d12147a77e13ea4b49d52408513
+F src/test_schema.c f5d6067dfc2f2845c4dd56df63e66ee826fb23877855c785f75cc2ca83fd0c1b
F src/test_server.c a2615049954cbb9cfb4a62e18e2f0616e4dc38fe
-F src/test_sqllog.c 11e6ce7575f489155c604ac4b439f2ac1d3d5aef
+F src/test_sqllog.c 540feaea7280cd5f926168aee9deb1065ae136d0bbbe7361e2ef3541783e187a
F src/test_superlock.c 4839644b9201da822f181c5bc406c0b2385f672e
F src/test_syscall.c 1073306ba2e9bfc886771871a13d3de281ed3939
F src/test_tclsh.c eeafce33ad2136d57e5dec10f1e9a4347447eb72ffd504a1c7b9c6bfe2e71578
@@ -597,50 +600,51 @@ F src/test_window.c cdae419fdcea5bad6dcd9368c685abdad6deb59e9fc8b84b153de513d394
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c
F src/tokenize.c eee7bae3ec0bc4abee951554bf46a8ba567c0f7752ac90c820ed8afff4c612dc
-F src/treeview.c 82c6391a3ba76215d4185fd4719a56ec4caf186a40c8a7b6e6ba4ae4467c2742
-F src/trigger.c 4ada1037cc99777f647a882cdacbd1a4deb6567b69daf02946286401b88cdc04
-F src/update.c 9777ad958b979488ed2e04a7d226048179078916e32437bd633eb4cae191f1a9
+F src/treeview.c 4b92992176fb2caefbe06ba5bd06e0e0ebcde3d5564758da672631f17aa51cda
+F src/trigger.c 58721162a3ee608ae0d824b0eededbf9b7ebc038dd49aff879b05d44ad16ef10
+F src/update.c b0d5b464383ce014bc6e6f1d9193234ef146bd62b27812d836cd10333834a56f
F src/upsert.c 2920de71b20f04fe25eb00b655d086f0ba60ea133c59d7fa3325c49838818e78
-F src/utf.c 95fb6e03a5ca679045c5adccd05380f0addccabef5911abddcb06af069500ab7
-F src/util.c 3b6cedf7a0c69bd6e1acce832873952d416212d6293b18d03064e07d7a9b5118
-F src/vacuum.c f25d3b39681595e321a8a4e7fca3e5971cb14a401213d0742c9bf7d4ce8c2a1a
-F src/vdbe.c 972999395eee88702091fb5d50cf4effd07889c371807d222a7f517388e6378e
-F src/vdbe.h 51282fbe819ee0e8eeeaab176240860d334c20a12b14f3b363e7f1a4e05d60b9
-F src/vdbeInt.h 0b728ee662862a38b1912af741e2ac64f524de3c77aa86cf4306c42bdcd9de59
-F src/vdbeapi.c d176ee7251d5344de7bb2a0d2dd0fe536834e5843d9bc2389e0f5cdcd5374141
-F src/vdbeaux.c 8349559e72bf0cfa2258b1159b004ec4d1717a054d2e1829c8cc897c32da8752
+F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0
+F src/util.c c0bacc165f46169d2b720c37c8719165e383211698fad1de39dd16a8c161815a
+F src/vacuum.c 1c4f8e2f39d950037f4cf946b6858c993d3a54c3101f78e05c76460a073afcf0
+F src/vdbe.c 981666c49d33039df6dc9fccd40191575586ac4866255b2f57819cc5eb99f572
+F src/vdbe.h 07b8c636a87df8b6e58f29d6badd7f10d5844353deff1d7c88ed1c2bfe3bbd35
+F src/vdbeInt.h 571413068b5ac07e2ed8ca7a02fa529622fd5455ae6981498376e5e492d2e5ef
+F src/vdbeapi.c c1a9004ac554d8d48794d2ce5f80397f8e419fd28643a543cc1e004c7713c3ef
+F src/vdbeaux.c c0cd3429d4a542c749df9df4b93fb864d148fce071080f10893d20ca8604ac65
F src/vdbeblob.c 253ed82894924c362a7fa3079551d3554cd1cdace39aa833da77d3bc67e7c1b1
F src/vdbemem.c 39b942ecca179f4f30a32b54579a85d74ccaefa5af2a0ad2700abe5ef0768b22
F src/vdbesort.c 2be76d26998ce2b3324cdcc9f6443728e54b6c7677c553ad909c7d7cfab587df
F src/vdbetrace.c fa3bf238002f0bbbdfb66cc8afb0cea284ff9f148d6439bc1f6f2b4c3b7143f0
-F src/vtab.c 7b704a90515a239c6cdba6a66b1bb3a385e62326cceb5ecb05ec7a091d6b8515
+F src/vdbevtab.c ee5b4c902fdda2230f9503ac7b84c6d614c91e8f6f4dc1633e2e8dfef8ffb144
+F src/vtab.c 5f5fc793092f53bbdfde296c50f563fb7bda58cf48e9cf6a8bdfbc5abd409845
F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
-F src/wal.c ea8dad28bb0e2b85ac1ab7618968687ff5fd522af8a1a38d6960ec176ebc8ee6
-F src/wal.h 606292549f5a7be50b6227bd685fa76e3a4affad71bb8ac5ce4cb5c79f6a176a
-F src/walker.c 7c429c694abd12413a5c17aec9f47cfe9eba6807e6b0a32df883e8e3a14835ed
-F src/where.c 9546c82056e8cdb27291f98cf1adca5d271240b399bb97b32f77fc2bea6146c9
+F src/wal.c 231044ecf7d5d78bc705af9dcec6c10ec59e891366362b6be54bb6a0bc7c17db
+F src/wal.h c3aa7825bfa2fe0d85bef2db94655f99870a285778baa36307c0a16da32b226a
+F src/walker.c 3df26a33dc4f54e8771600fb7fdebe1ece0896c2ad68c30ab40b017aa4395049
+F src/where.c 7bcc07ff56d03d73308245135d96de46d2faeaee628bd4badf0bae60ae6a31fe
F src/whereInt.h 6b874aa15f94e43a2cec1080be64d955b04deeafeac90ffb5d6975c0d511be3c
F src/wherecode.c 7b939de85d65cc4b4bfa197513136b9e0ae03167e3b82842ca5a0ba1055ba65d
F src/whereexpr.c 264d58971eaf8256eb5b0917bcd7fc7a1f1109fdda183a8382308a1b18a2dce7
-F src/window.c ba1ffb78d73c5831433681aab7ee634230ee32f14ad508efa585044662141d5a
+F src/window.c 0dec178bfa541c757d15a2be78f34aea36393a0966600366810e5f8739ccf370
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
F test/affinity2.test ce1aafc86e110685b324e9a763eab4f2a73f737842ec3b687bd965867de90627
F test/affinity3.test 6a101af2fc945ce2912f6fe54dd646018551710d
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
-F test/aggnested.test 12106f0748e8e9bfc1a8e6840e203e051eae06a26ed13fc9fd5db108a8d6db54
+F test/aggnested.test 2f65ec8132e0ca896de550b9908094d49ad65a99116a9d79deeb6017604ad4f6
F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87
F test/all.test 2ecb8bbd52416642e41c9081182a8df05d42c75637afd4488aace78cc4b69e13
-F test/alter.test 77f0092d137dd9470fc683b64ed92868e188462e713e52f48deae8902ea60b96
+F test/alter.test 25e109787dc5e631e117eb6e1c57f96a572bb51228db3b4f8b5f41d665e2ccaa
F test/alter2.test a966ccfcddf9ce0a4e0e6ff1aca9e6e7948e0e242cd7e43fc091948521807687
-F test/alter3.test 9351a9f0c59ff9dddecccaaa2f777ffee5369870c63d30d3a74add815254ec0f
-F test/alter4.test 74b22251c5e9c48093cfc4921ed9c11b59df84634aeeb00e501773320beb8424
+F test/alter3.test e487958dec7932453e0b83baf21d6b1e71d5e7d9a55bc20eadfa62a51ddffc29
+F test/alter4.test dfd6086faf461b27ca2d2999848dcd207edf23352fc1592d0005c0844f3f08cf
F test/alterauth.test 63442ba61ceb0c1eeb63aac1f4f5cebfa509d352276059d27106ae256bafc959
F test/alterauth2.test c0a1ddf5b93d93cb0d15ba7acaf0c5c6fb515bbe861ede75b2d3fabad33b6499
F test/altercol.test 1d6a6fe698b81e626baea4881f5717f9bc53d7d07f1cd23ee7ad1b931f117ddf
F test/alterlegacy.test 82022721ce0de29cedc9a7af63bc9fcc078b0ee000f8283b4b6ea9c3eab2f44b
F test/altermalloc.test 167a47de41b5c638f5f5c6efb59784002b196fff70f98d9b4ed3cd74a3fb80c9
F test/altermalloc2.test fa7b1c1139ea39b8dec407cf1feb032ca8e0076bd429574969b619175ad0174b
-F test/altertab.test 523ba6368e0da19f462f7c05563c569675736d946724cac1c4ae848f76783434
+F test/altertab.test b8b2104212e8ea87c75c3cbe3cb78ed7236a6c828ee2e59ed09d3dbe9812d002
F test/altertab2.test b0d62f323ca5dab42b0bc028c52e310ebdd13e655e8fac070fe622bad7852c2b
F test/altertab3.test 155b8dc225ce484454a7fb4c8ba745680b6fa0fc3e08919cbbc19f9309d128ff
F test/amatch1.test b5ae7065f042b7f4c1c922933f4700add50cdb9f
@@ -666,7 +670,7 @@ F test/async5.test 383ab533fdb9f7ad228cc99ee66e1acb34cc0dc0
F test/atof1.test 1ccfc96a6888566597b83d882c81b3c04258dc39317e8c1cec89ba481eaa2fba
F test/atomic.test 065a453dde33c77ff586d91ccaa6ed419829d492dbb1a5694b8a09f3f9d7d061
F test/atomic2.test b6863b4aa552543874f80b42fb3063f1c8c2e3d8e56b6562f00a3cc347b5c1da
-F test/atrc.c ec92d56d8fbed9eb3e11aaf1ab98cf7dd59e69dae31f128013f1d97e54e7dfed
+F test/atrc.c c388fac43dbba05c804432a7135ae688b32e8f25818e9994ffba4b64cf60c27c
F test/attach.test d42862c72fef3d54367d962d41dcfb5363442a4a1bd898c22ae950cea1aa0dd3
F test/attach2.test 256bd240da1835fb8408dd59fb7ef71f8358c7a756c46662434d11d07ba3a0ce
F test/attach3.test c59d92791070c59272e00183b7353eeb94915976
@@ -724,6 +728,7 @@ F test/btree01.test e08b3613540145b353f20c81cb18ead54ff12e0f
F test/btree02.test 7555a5440453d900410160a52554fe6478af4faf53098f7235f1f443d5a1d6cc
F test/btreefault.test c2bcb542685eea44621275cfedbd8a13f65201e3
F test/busy.test 510dc6daaad18bcbbc085bcc6217d6dc418def5e73f72ce1475eea0cb7834727
+F test/busy2.test 415364312743992641f9bf679c84918327296067f85a5d00012b339dc35acbd7
F test/cache.test 13bc046b26210471ca6f2889aceb1ea52dc717de
F test/cacheflush.test af25bb1509df04c1da10e38d8f322d66eceedf61
F test/cachespill.test 895997f84a25b323b166aecb69baab2d6380ea98f9e0bcc688c4493c535cfab9
@@ -778,10 +783,10 @@ F test/corruptH.test 79801d97ec5c2f9f3c87739aa1ec2eb786f96454
F test/corruptI.test a17bbf54fdde78d43cf3cc34b0057719fd4a173a3d824285b67dc5257c064c7b
F test/corruptJ.test 4d5ccc4bf959464229a836d60142831ef76a5aa4
F test/corruptK.test 5b4212fe346699831c5ad559a62c54e11c0611bdde1ea8423a091f9c01aa32af
-F test/corruptL.test 13ef74a93223af25015d223add0df4c2d375f0b958b546a2a72033f2fdab7a70
+F test/corruptL.test 01cfda6b28f463d1713ac72a101e65549250568129ce5317ec6729729ecaf477
F test/corruptM.test 7d574320e08c1b36caa3e47262061f186367d593a7e305d35f15289cc2c3e067
-F test/cost.test 51f4fcaae6e78ad5a57096831259ed6c760e2ac6876836e91c00030fad385b34
-F test/count.test cb2e0f934c6eb33670044520748d2ecccd46259c
+F test/cost.test 1d156ce9858780a966c062694687afe0343a0ed12d081d071fb57027e726bafc
+F test/count.test e0699a15712bc2a4679d60e408921c2cce7f6365a30340e790c98e0f334a9c77
F test/countofview.test e17d6e6688cf74f22783c9ec6e788c0790ee4fbbaee713affd00b1ac0bb39b86
F test/coveridxscan.test 5ec98719a2e2914e8908dc75f7247d9b54a26df04625f846ac7900d5483f7296
F test/crash.test fb9dc4a02dcba30d4aa5c2c226f98b220b2b959f
@@ -798,7 +803,7 @@ F test/createtab.test 85cdfdae5c3de331cd888d6c66e1aba575b47c2e3c3cc4a1d6f5414069
F test/cse.test 00b3aea44b16828833c94fbe92475fd6977583fcb064ae0bc590986812b38d0c
F test/csv01.test c9c3af0d58c34e9ac970c5875a77939edb958762c8aafb95409e19a3f088b6cd
F test/ctime.test 78749e6c9a5f0010d67985be80788f841e3cd2da18114e2ed6010399a7d807f3
-F test/cursorhint.test 7bc346788390475e77a345da2b92270d04d35856
+F test/cursorhint.test 0175e4404181ace3ceca8b114eb0a98eae600d565aa4e2705abbe6614c7fe201
F test/cursorhint2.test 6f3aa9cb19e7418967a10ec6905209bcbb5968054da855fc36c8beee9ae9c42f
F test/dataversion1.test 6e5e86ac681f0782e766ebcb56c019ae001522d114e0e111e5ebf68ccf2a7bb8
F test/date.test 9b73bbeb1b82d9c1f44dec5cf563bf7da58d2373
@@ -807,10 +812,11 @@ F test/dbdata.test 042f49acff3438f940eeba5868d3af080ae64ddf26ae78f80c92bec3ca7d8
F test/dbfuzz.c 73047c920d6210e5912c87cdffd9a1c281d4252e
F test/dbfuzz001.test 42aad1dcef6219fbee86a9b7d08832c9bbb2e41508f6f128ae91745927276292
F test/dbfuzz2-seed1.db e6225c6f3d7b63f9c5b6867146a5f329d997ab105bee64644dc2b3a2f2aebaee
-F test/dbfuzz2.c c2c9cb40082a77b7e95ffb8b2da1e93322efadfb1c8c1e0001c95a0af1e156c2
+F test/dbfuzz2.c 40cc4600947f30600f0ab365a2714ec76a899c9adb2c0ccd63ba583b2f71390e
F test/dbpage.test 650234ba683b9d82b899c6c51439819787e7609f17a0cc40e0080a7b6443bc38
F test/dbstatus.test 4a4221a883025ffd39696b3d1b3910b928fb097d77e671351acb35f3aed42759
F test/dbstatus2.test f5fe0afed3fa45e57cfa70d1147606c20d2ba23feac78e9a172f2fe8ab5b78ef
+F test/decimal.test 12739a01bdba4c4d79f95b323e6b67b9fad1ab6ffb56116bd2b9c81a5b19e1d9
F test/default.test 9687cfb16717e4b8238c191697c98be88c0b16e568dd5368cd9284154097ef50
F test/delete.test 31832b0c45ecb51a54348c68db173be462985901e6ed7f403d6d7a8f70ab4ef0
F test/delete2.test 3a03f2cca1f9a67ec469915cb8babd6485db43fa
@@ -821,7 +827,7 @@ F test/descidx1.test edc8adee58d491b06c7157c50364eaf1c3605c9c19f8093cb1ea2b6184f
F test/descidx2.test a0ba347037ff3b811f4c6ceca5fd0f9d5d72e74e59f2d9de346a9d2f6ad78298
F test/descidx3.test 953c831df7ea219c73826dfbf2f6ee02d95040725aa88ccb4fa43d1a1999b926
F test/diskfull.test 106391384780753ea6896b7b4f005d10e9866b6e
-F test/distinct.test 8b6c652f0b2d477f0830884736f2a1cd2e8f7fc10a04aa6d571a401fa13ed88b
+F test/distinct.test e7d0cf371944dd0cbedff86420744e2f1ea2b528156451c97eb6ff41a99b9236
F test/distinct2.test 11b0594c932098e969d084ba45ab81d5040f4d4e766db65d49146705a305ed98
F test/distinctagg.test 1a6ef9c87a58669438fc771450d7a72577417376
F test/e_blobbytes.test 439a945953b35cb6948a552edaec4dc31fd70a05
@@ -833,8 +839,8 @@ F test/e_createtable.test ea27082d6f84df61e1d9e383f3fd79220418856a4a8afc41af75d4
F test/e_delete.test ab39084f26ae1f033c940b70ebdbbd523dc4962e
F test/e_droptrigger.test 3cd080807622c13e5bbb61fc9a57bd7754da2412
F test/e_dropview.test 74e405df7fa0f762e0c9445b166fe03955856532e2bb234c372f7c51228d75e7
-F test/e_expr.test 328d2d7c84f8e53e942a13eac771b337bcdfcf4c3569324001868b5639f3c857
-F test/e_fkey.test 2febb2084aef9b0186782421c07bc9d377abf067c9cb4efd49d9647ae31f5afe
+F test/e_expr.test 62000e6675d5bcf4b09276fe011a27779629ff8f6678ba5937fb6f1b78d645ff
+F test/e_fkey.test b497feb7c436693e16a36cdaba8d81ffe12f23659d139ee71dfa57c0c52d1e5b
F test/e_fts3.test 17ba7c373aba4d4f5696ba147ee23fd1a1ef70782af050e03e262ca187c5ee07
F test/e_insert.test f02f7f17852b2163732c6611d193f84fc67bc641fb4882c77a464076e5eba80e
F test/e_reindex.test 2b0e29344497d9a8a999453a003cb476b6b1d2eef2d6c120f83c2d3a429f3164
@@ -868,20 +874,20 @@ F test/extraquick.test cb254400bd42bfb777ff675356aabf3287978f79
F test/fallocate.test 37a62e396a68eeede8f8d2ecf23573a80faceb630788d314d0a073d862616717
F test/filectrl.test 6e871c2d35dead1d9a88e176e8d2ca094fec6bb3
F test/filefmt.test f393e80c4b8d493b7a7f8f3809a8425bbf4292af1f5140f01cb1427798a2bbd4
-F test/filter1.test 8a6f047a000ef391db2ca17b6beecc0006f4e0f9ca8bbe272b2443c7316e66b1
+F test/filter1.test 6c483ecf7886c8843a8612c021aa23f33c581f584151f251842b3a3592c95ac8
F test/filter2.tcl 44e525497ce07382915f01bd29ffd0fa49dab3adb87253b5e5103ba8f93393e8
F test/filter2.test 485cf95d1f6d6ceee5632201ca52a71868599836f430cdee42e5f7f14666e30a
F test/filterfault.test c08fb491d698e8df6c122c98f7db1c65ffcfcad2c1ab0e07fa8a5be1b34eaa8b
F test/fkey1.test d11dbb8a93ead9b5c46ae5d02da016d61245d47662fb2d844c99214f6163f768
-F test/fkey2.test 65c86b11127c11f80c0f450b3480321e0f087edea3031b9daa1978e3c020c91b
+F test/fkey2.test b1b6a8c5556dc0ccf31291b1fed8aa57e404b38f3236110e19ab4dc6aa93edf2
F test/fkey3.test 76d475c80b84ee7a5d062e56ccb6ea68882e2b49
F test/fkey4.test 86446017011273aad8f9a99c1a65019e7bd9ca9d
-F test/fkey5.test 24dd28eb3d9f1b5a174f47e9899ace5facb08373a4223593c8c631e6cf9f7d5a
+F test/fkey5.test 321fd41e8754389526b2b8e8769348dc9ff23a65d4d48b19c27df17459e82ec5
F test/fkey6.test d078a1e323a740062bed38df32b8a736fd320dc0
F test/fkey7.test 64fb28da03da5dfe3cdef5967aa7e832c2507bf7fb8f0780cacbca1f2338d031
F test/fkey8.test 48ef829d63f5f7b37aabd4df9363ac05f65539d1da8c4a44251631769d920579
F test/fkey_malloc.test 594a7ea1fbab553c036c70813cd8bd9407d63749
-F test/fordelete.test eb93a2f34137bb87bdab88fcab06c0bd92719aff
+F test/fordelete.test ba98f14446b310f9c9d935b97ec748753d0144a28b356ba30d1f4f6958fdde5c
F test/format4.test eeae341953db8b6bda7f549044797c3278a6cc345d11ada81471671b654f8ef4
F test/fts-9fd058691.test 78b887e30ae6816df0e1fed6259de4b5a64ad33c
F test/fts1a.test 46090311f85da51bb33bd5ce84f7948359c6d8d7
@@ -944,10 +950,11 @@ F test/fts3c.test fc723a9cf10b397fdfc2b32e73c53c8b1ec02958
F test/fts3comp1.test a0f5b16a2df44dd0b15751787130af2183167c0c
F test/fts3conf.test c84bbaec81281c1788aa545ac6e78a6bd6cde2bdbbce2da261690e3659f5a76b
F test/fts3corrupt.test 79a32ffdcd5254e2f7fa121d9656e61949ad049c3c6554229911b7ceac37c9c6
-F test/fts3corrupt2.test bf55c3fa0b0dc8ea1c0fe5543623bd27714585da6a129038fd6999fe3b0d25f3
+F test/fts3corrupt2.test e318f0676e5e78d5a4b702637e2bb25265954c08a1b1e4aaf93c7880bb0c67d0
F test/fts3corrupt3.test 0d5b69a0998b4adf868cc301fc78f3d0707745f1d984ce044c205cdb764b491f
-F test/fts3corrupt4.test 6a1331bb51dc27acc063d26e0f1b610863b56a833ee54fa32767d17cf96bda4a
+F test/fts3corrupt4.test b77dcdfa207c11d7966e71837c518cb0639c78fd109dec89c65d45a3bfd36701
F test/fts3corrupt5.test 0549f85ec4bd22e992f645f13c59b99d652f2f5e643dac75568bfd23a6db7ed5
+F test/fts3corrupt6.test b6c55218b704b0cef224b284c756f9c55d0afd0b3c3837618bffeaa8c31e0d8e
F test/fts3cov.test 7eacdbefd756cfa4dc2241974e3db2834e9b372ca215880e00032222f32194cf
F test/fts3d.test 2bd8c97bcb9975f2334147173b4872505b6a41359a4f9068960a36afe07a679f
F test/fts3defer.test f4c20e4c7153d20a98ee49ee5f3faef624fefc9a067f8d8d629db380c4d9f1de
@@ -967,6 +974,7 @@ F test/fts3fuzz001.test e3c7b0ce9b04cc02281dcc96812a277f02df03cd7dc082055d87e11e
F test/fts3join.test 949b4f5ae3ae9cc2423cb865d711e32476bdb205ab2be923fdf48246e4a44166
F test/fts3malloc.test b0e4c133b8d61d4f6d112d8110f8320e9e453ef6
F test/fts3matchinfo.test aa66cc50615578b30f6df9984819ae5b702511cf8a94251ec7c594096a703a4a
+F test/fts3matchinfo2.test 00144e841704b8debfcdf6097969cd9f2a1cf759e2203cda42583648f2e6bf58
F test/fts3misc.test 9ec15e7c0b5831a6353bd4c46bf3acdf1360eda5d9f396f667db4d05bcf92ecf
F test/fts3near.test 7e3354d46f155a822b59c0e957fd2a70c1d7e905
F test/fts3offsets.test b85fd382abdc78ebce721d8117bd552dfb75094c
@@ -976,7 +984,8 @@ F test/fts3query.test ca033ff2ebcc22c69d89032fb0bc1850997d31e7e60ecd26440796ba16
F test/fts3rank.test cd99bc83a3c923c8d52afd90d86979cf05fc41849f892faeac3988055ef37b99
F test/fts3rnd.test 1320d8826a845e38a96e769562bf83d7a92a15d0
F test/fts3shared.test 57e26a801f21027b7530da77db54286a6fe4997e
-F test/fts3snippet.test d9b9f4b717584040fb56df1dacab53acd474958e9c1d00b073d10726695cea0c
+F test/fts3snippet.test 0887196d67cffbe365edde535b95ecc642a532ce8551ccd9a73aab5999c3ffae
+F test/fts3snippet2.test 2dabb5889eda4c9980aad325e688b470781f97ce7c0fca0db125616fae0a2cdd
F test/fts3sort.test ed34c716a11cc2009a35210e84ad5f9c102362ca
F test/fts3tok1.test a663f4cac22a9505400bc22aacb818d7055240409c28729669ea7d4cc2120d15
F test/fts3tok_err.test 52273cd193b9036282f7bacb43da78c6be87418d
@@ -1026,12 +1035,12 @@ F test/fuzzdata4.db b502c7d5498261715812dd8b3c2005bad08b3a26e6489414bd13926cd3e4
F test/fuzzdata5.db e35f64af17ec48926481cfaf3b3855e436bd40d1cfe2d59a9474cb4b748a52a5
F test/fuzzdata6.db 92a80e4afc172c24f662a10a612d188fb272de4a9bd19e017927c95f737de6d7
F test/fuzzdata7.db 0166b56fd7a6b9636a1d60ef0a060f86ddaecf99400a666bb6e5bbd7199ad1f2
-F test/fuzzdata8.db fb701c5653f0a75a58e2ee0f8baf5b207faa7702dda88c913ebbe2abb3b33de3
+F test/fuzzdata8.db ef83ab1c8d130daabef304cb440bae2215208120de741b8476de66e16237808d
F test/fuzzer1.test 3d4c4b7e547aba5e5511a2991e3e3d07166cfbb8
F test/fuzzer2.test a85ef814ce071293bce1ad8dffa217cbbaad4c14
F test/fuzzerfault.test 8792cd77fd5bce765b05d0c8e01b9edcf8af8536
F test/gcfault.test dd28c228a38976d6336a3fc42d7e5f1ad060cb8c
-F test/gencol1.test e89eafdf03245e2609ddf6e9b0add37a17ce229095836c409131764c3a5282a5
+F test/gencol1.test b05e6c5edb9b10d48efb634ed07342441bddc89d225043e17095c36e567521a0
F test/genesis.tcl 1e2e2e8e5cc4058549a154ff1892fe5c9de19f98
F test/having.test e4098a4b8962f9596035c3b87a8928a10648acc509f1bb8d6f96413bbf79a1b3
F test/hexlit.test 4a6a5f46e3c65c4bf1fa06f5dd5a9507a5627751
@@ -1039,7 +1048,7 @@ F test/hidden.test 23c1393a79e846d68fd902d72c85d5e5dcf98711
F test/hook.test 1604b3b2f5931430087540404555c1b6be3618600b81558657c66b533ed70b13
F test/hook2.test b9ff3b8c6519fb67f33192f1afe86e7782ee4ac8
F test/icu.test 716a6b89fbabe5cc63e0cd4c260befb08fd7b9d761f04d43669233292f0753b1
-F test/ieee754.test 806fc0ce7f305f57e3331eaceeddcfec9339e607
+F test/ieee754.test b0945d12be7d255f3dfa18e2511b17ca37e0edd2b803231c52d05b86c04ab26e
F test/imposter1.test c3f1db2d3db2c24611a6596a3fc0ffc14f1466c8
F test/in.test ae4ba0fe3232fdd84ef1090a68c5cd6ccd93f1f8774d5c967dd0c1b301492eed
F test/in2.test 5d4c61d17493c832f7d2d32bef785119e87bde75
@@ -1064,10 +1073,10 @@ F test/index3.test 51685f39345462b84fcf77eb8537af847fdf438cc96b05c45d6aaca4e473a
F test/index4.test ab92e736d5946840236cd61ac3191f91a7856bf6
F test/index5.test 8621491915800ec274609e42e02a97d67e9b13e7
F test/index6.test f172653b35b20233e59200e8b92a76db61bf7285437bf777b93b306ba26a47e7
-F test/index7.test 1d764c0cca45f5a76150b08e127ccc8d52492cfa788b5fafed4be784a351b020
+F test/index7.test b8a0ba2110fd517bb48c4e76d26d60f1ab2ed9e257b18d71f820d7e71e9f8570
F test/index8.test bc2e3db70e8e62459aaa1bd7e4a9b39664f8f9d7
F test/index9.test 0aa3e509dddf81f93380396e40e9bb386904c1054924ba8fa9bcdfe85a8e7721
-F test/indexedby.test a52c8c6abfae4fbfb51d99440de4ca1840dbacc606b05e29328a2a8ba7cd914e
+F test/indexedby.test f54aac21c06948872010a956fd02de5178c362c7785a9887cf0b8616be17883b
F test/indexexpr1.test 284e119999d132cc8bf37735a928c9859b28e8e295d02b7a6a4f93977c7f9ba5
F test/indexexpr2.test dba11dbb0a58fcba4cd694f46b4004976123b81b0501f525d43c9be59f0207b1
F test/indexfault.test 98d78a8ff1f5335628b62f886a1cb7c7dac1ef6d48fa39c51ec871c87dce9811
@@ -1092,7 +1101,7 @@ F test/ioerr3.test d3cec5e1a11ad6d27527d0d38573fbff14c71bdd
F test/ioerr4.test f130fe9e71008577b342b8874d52984bd04ede2c
F test/ioerr5.test 2edfa4fb0f896f733071303b42224df8bedd9da4
F test/ioerr6.test a395a6ab144b26a9e3e21059a1ab6a7149cca65b
-F test/istrue.test 75327829744e65cc8700e69340b8e6c192e10e39dfae7ccb0e970d3c4f49090a
+F test/istrue.test 06f92ea38750fa74df7dbbe6920205251c2310861fbbe23a3adfa918a2e2ba74
F test/join.test bca044589e94bb466e4c1e91fb6fecdc3f3326ca6b3f590f555f1958156eb321
F test/join2.test 7d24d095ab88d3910228d53a3b548b7baf2e0e7d8aac6731a273e300e1b34b61
F test/join3.test 6f0c774ff1ba0489e6c88a3e77b9d3528fb4fda0
@@ -1111,7 +1120,7 @@ F test/json103.test aff6b7a4c17d5a20b487a7bc1a274bfdc63b829413bdfb83bedac42ec7f6
F test/json104.test 317f4ec4b2d87afbba4d2460cf5be297aea76f2285eb618d276dbcd40a50950f
F test/json105.test 45f7d6a9a54c85f8a9589b68d3e7a1f42d02f2359911a8cdbad1f9988f571173
F test/keyword1.test 37ef6bba5d2ed5b07ecdd6810571de2956599dff
-F test/kvtest.c 94da54bb66aae7a54e47cf7e4ea4acecc0f217560f79ad3abfcc0361d6d557ba
+F test/kvtest.c feb4358fb022da8ebd098c45811f2f6507688bb6c43aa72b3e840df19026317b
F test/lastinsert.test 42e948fd6442f07d60acbd15d33fb86473e0ef63
F test/laststmtchanges.test ae613f53819206b3222771828d024154d51db200
F test/lemon-test01.y 58b764610fd934e189ffbb0bbfa33d171b9cb06019b55bdc04d090d6767e11d7
@@ -1188,7 +1197,7 @@ F test/multiplex.test dc0d67b66f84b484a83cb8bbdf3f0a7f49562ccd
F test/multiplex2.test 580ca5817c7edbe4cc68fa150609c9473393003a
F test/multiplex3.test d228f59eac91839a977eac19f21d053f03e4d101
F test/multiplex4.test e8ae4c4bd70606a5727743241f13b5701990abe4
-F test/mutex1.test ea2cc74d97f077b9e74c84cbd024f14d79a8126f
+F test/mutex1.test 177db2e4edb530f2ff21edc52ac79a412dbe63e4c47c3ae9504d3fb4f1ce81fa
F test/mutex2.test bfeaeac2e73095b2ac32285d2756e3a65e681660
F test/nan.test 437d40e6d0778b050d7750726c0cbd2c9936b81962926e8f8c48ca698f00f4d1
F test/nockpt.test 8c43b25af63b0bd620cf1b003529e37b6f1dc53bd22690e96a1bd73f78dde53a
@@ -1204,7 +1213,7 @@ F test/numcast.test 5d126f7f581432e86a90d1e35cac625164aec4a1
F test/numindex1.test 20a5450d4b056e48cd5db30e659f13347a099823
F test/offset1.test f06b83657bcf26f9ce805e67450e189e282143b2
F test/openv2.test 0d3040974bf402e19b7df4b783e447289d7ab394
-F test/optfuzz-db01.c a0c256905c8ac79f9a5de2f374a3d9f757bef0dca2a238dc7c10cc8a38031834
+F test/optfuzz-db01.c 9f2fa80b8f84ebbf1f2e8b13421a4e0477fe300f6686fbd76cac1d2db66e0fdc
F test/optfuzz-db01.txt 21f6bdeadc701cf11528276e2a55c70bfcb846ba42df327f979bd9e7b6ce7041
F test/optfuzz.c 50e330304eb1992e15ddd11f3daaad9bcc0d9aaad09cb2bcc77f9515df2e88b1
F test/orderby1.test 6bf0ce45cbfb1cf4779dd418ac5e8cf66abfa04de2c1d2edf1e0e85f1520d8f3
@@ -1234,7 +1243,7 @@ F test/parser1.test 6ccdf5e459a5dc4673d3273dc311a7e9742ca952dd0551a6a6320d27035c
F test/pcache.test c8acbedd3b6fd0f9a7ca887a83b11d24a007972b
F test/pcache2.test af7f3deb1a819f77a6d0d81534e97d1cf62cd442
F test/percentile.test 4243af26b8f3f4555abe166f723715a1f74c77ff
-F test/permutations.test c83339862d72b6272f957905205f874e6eefdbad2823380452c4f0128fd3d906
+F test/permutations.test 94bfbc9d32449fb3ef7d31962f8cdcd57dc59490681db84bd72236d4af7b5815
F test/pg_common.tcl 3b27542224db1e713ae387459b5d117c836a5f6e328846922993b6d2b7640d9f
F test/pragma.test 59becdfd720b80d463ab750f69f7118fde10dfd556aa5d554f3bf6b7e5ea7533
F test/pragma2.test e5d5c176360c321344249354c0c16aec46214c9f
@@ -1243,7 +1252,7 @@ F test/pragma4.test 10c624e45a83c0096a82a7579a5ff658542391d3b77355192da6572c8c17
F test/pragma5.test 7b33fc43e2e41abf17f35fb73f71b49671a380ea92a6c94b6ce530a25f8d9102
F test/pragmafault.test 275edaf3161771d37de60e5c2b412627ac94cef11739236bec12ed1258b240f8
F test/prefixes.test b524a1c44bffec225b9aec98bd728480352aa8532ac4c15771fb85e8beef65d9
-F test/printf.test 0300699733e53101b2ce48800518427249edd4053bb50fa0621c6607482f0fdb
+F test/printf.test 390d0d7fcffc3c4ea3c1bb4cbb267444e32b33b048ae21895f23a291844fe1da
F test/printf2.test 30b5dd0b4b992dc5626496846ecce17ff592cacbcb11c3e589f3ac4d7e129dae
F test/progress.test ebab27f670bd0d4eb9d20d49cef96e68141d92fb
F test/ptrchng.test ef1aa72d6cf35a2bbd0869a649b744e9d84977fc
@@ -1305,14 +1314,14 @@ F test/securedel.test 2f70b2449186a1921bd01ec9da407fbfa98c3a7a5521854c300c194b2f
F test/securedel2.test 2d54c28e46eb1fd6902089958b20b1b056c6f1c5
F test/select1.test 009a6d8eacd9684d046302b8d13b50846a87e39d6f08e92178aa13e95ea29a2d
F test/select2.test 352480e0e9c66eda9c3044e412abdf5be0215b56
-F test/select3.test ddd1bc6d0c8dece136321c11bd26d0d8ad17f2b27c72935fdd6574d8cb99d1d4
+F test/select3.test c49fbb758903f3718e2de5aa4655eda4838131cbea24a86db908f8b6889aa68c
F test/select4.test e8a2502e3623f3058871030599a48abb35789d2244d5b380ecf3696873fdd4a4
F test/select5.test df9ec0d218cedceb4fe7b63262025b547b50a55e59148c6f40b60ca25f1d4546
F test/select6.test 319d45e414cdd321bf17cfacedaf19e3935ad64dac357c53f1492338c6e9b801
F test/select7.test f659f231489349e8c5734e610803d7654207318f
F test/select8.test 8c8f5ae43894c891efc5755ed905467d1d67ad5d
F test/select9.test aebc2bb0c3bc44606125033cbcaac2c8d1f33a95
-F test/selectA.test b8a590f6493cad5b0bb4dfe1709bf7dcda0b6c40bb4caf32d1e36a89eebc8fc5
+F test/selectA.test 68de52409e45a3313d00b8461b48bef4fb729faf36ade9067a994eae55cc86f4
F test/selectB.test 954e4e49cf1f896d61794e440669e03a27ceea25
F test/selectC.test e25243f8ca503e06f252eb0218976d07cfeceac3
F test/selectD.test fc20452847a01775710090383cfb4423275d2f745fed61f34fbf37573ac0d214
@@ -1335,7 +1344,7 @@ F test/sharedA.test 49d87ec54ab640fbbc3786ee3c01de94aaa482a3a9f834ad3fe92770eb69
F test/sharedB.test 16cc7178e20965d75278f410943109b77b2e645e
F test/shared_err.test 32634e404a3317eeb94abc7a099c556a346fdb8fb3858dbe222a4cbb8926a939
F test/sharedlock.test 5ede3c37439067c43b0198f580fd374ebf15d304
-F test/shell1.test 5bd10014ec494744f5e966a1521334e9d612119a0afcfa5251684a4e1f2ffc66
+F test/shell1.test a1cf47c5e110560ff25a714570bfd53bfaceeb61db5cad3072a4064f17ebd10e
F test/shell2.test e242a9912f44f4c23c3d1d802a83e934e84c853b
F test/shell3.test ac8c2b744014c3e9a0e26bfd829ab65f00923dc1a91ffd044863e9423cc91494
F test/shell4.test 1c6aef11daaa2d6830acaba3ac9cbec93fbc1c3d5530743a637f39b3987d08ce
@@ -1376,7 +1385,7 @@ F test/speed3.test 694affeb9100526007436334cf7d08f3d74b85ef
F test/speed4.test abc0ad3399dcf9703abed2fff8705e4f8e416715
F test/speed4p.explain 6b5f104ebeb34a038b2f714150f51d01143e59aa
F test/speed4p.test 377a0c48e5a92e0b11c1c5ebb1bc9d83a7312c922bc0cb05970ef5d6a96d1f0c
-F test/speedtest1.c d564e7689a731f691adfe2cf3f3f735d3e11f100eebb065e2a0a267fdc39fb26
+F test/speedtest1.c a8b5afe72d78ff365012aba48d3f0c579e957facb7630f765f58a6ae4656d20d
F test/spellfix.test 951a6405d49d1a23d6b78027d3877b4a33eeb8221dcab5704b499755bb4f552e
F test/spellfix2.test dfc8f519a3fc204cb2dfa8b4f29821ae90f6f8c3
F test/spellfix3.test 0f9efaaa502a0e0a09848028518a6fb096c8ad33
@@ -1384,7 +1393,7 @@ F test/spellfix4.test 51c7c26514ade169855c66bcf130bd5acfb4d7fd090cc624645ab275ae
F test/sqldiff1.test 28cd737cf1b0078b1ec1bbf425e674c47785835e
F test/sqllimits1.test 264f4b0f941800ba139d25e33ee919c5d95fea06dfbe8ac291d6811a30984ca5
F test/sqllog.test 6af6cb0b09f4e44e1917e06ce85be7670302517a
-F test/stat.test 423257dc36e5865fb9dd1d9051ac985763b6fba1daec134932f37772d5ed1e64
+F test/stat.test 15a3106eddedfc882f64bc09f237b4169be4b92dd57c93031b8ff8b13af3e7c5
F test/statfault.test f525a7bf633e50afd027700e9a486090684b1ac1
F test/stmt.test 54ed2cc0764bf3e48a058331813c3dbd19fc1d0827c3d8369914a5d8f564ec75
F test/stmtvtab1.test 6873dfb24f8e79cbb5b799b95c2e4349060eb7a3b811982749a84b359468e2d5
@@ -1443,7 +1452,7 @@ F test/tkt-385a5b56b9.test 5204a7cba0e28c99df0acbf95af5e1af4d32965a7a14de6eccebf
F test/tkt-38cb5df375.test f3cc8671f1eb604d4ae9cf886ed4366bec656678
F test/tkt-3998683a16.test 6d1d04d551ed1704eb3396ca87bb9ccc8c5c1eb7
F test/tkt-3a77c9714e.test 90e3e8455ee945a4076d4c44062b8845708af24a880355328fe7008f2047c9f0
-F test/tkt-3fe897352e.test 6849fde0a87165ff83f54f5047af7c743d72af26908fadb90174f3294450b3f4
+F test/tkt-3fe897352e.test 27e26eb0f1811aeba4d65aba43a4c52e99da5e70
F test/tkt-4a03edc4c8.test 91c0e135888cdc3d4eea82406a44b05c8c1648d0
F test/tkt-4c86b126f2.test cbcc611becd0396890169ab23102dd70048bbc9a
F test/tkt-4dd95f6943.test 3d0ce415d2ee15d3d564121960016b9c7be79407
@@ -1603,7 +1612,7 @@ F test/trustschema1.test 4e970aef0bfe0cee139703cc7209d0e0f07725d999b180ba50770f4
F test/tt3_checkpoint.c 9e75cf7c1c364f52e1c47fd0f14c4340a9db0fe1
F test/tt3_index.c 39eec10a35f57672225be4d182862152896dee4a
F test/tt3_lookaside1.c 0377e202c3c2a50d688cb65ba203afeda6fafeb9
-F test/tt3_stress.c c57d804716165811d979d4a719e05baccd79277f
+F test/tt3_stress.c f9a769ca8b026ecc76ee93ca8c9700a5619f8e51c581107c4053ba6ac97f616f
F test/tt3_vacuum.c 1753f45917699c9c1f66b64c717a717c9379f776
F test/types.test bf816ce73c7dfcfe26b700c19f97ef4050d194ff
F test/types2.test 1aeb81976841a91eef292723649b5c4fe3bc3cac
@@ -1661,7 +1670,7 @@ F test/vtab_alter.test 736e66fb5ec7b4fee58229aa3ada2f27ec58bc58c00edae4836890c37
F test/vtab_err.test dcc8b7b9cb67522b3fe7a272c73856829dae4ab7fdb30399aea1b6981bda2b65
F test/vtab_shared.test 5253bff2355a9a3f014c15337da7e177ab0ef8ad
F test/vtabdrop.test 65d4cf6722972e5499bdaf0c0d70ee3b8133944a4e4bc31862563f32a7edca12
-F test/wal.test cdf0ca6cc0447520d19ef1c83287824ebeb3e82d75af856511ba96841a79fc9b
+F test/wal.test 16180bc4becda176428ad02eaea437b4b8f5ae099314de443a4e12b2dcc007a2
F test/wal2.test 537f59e5c5932e3b45bf3591ae3e48a2601360c2e52821b633e222fe6ebd5b09
F test/wal3.test 2a93004bc0fb2b5c29888964024695bade278ab2
F test/wal4.test 4744e155cd6299c6bd99d3eab1c82f77db9cdb3c
@@ -1692,13 +1701,14 @@ F test/walprotocol2.test 7d3b6b4bf0b12f8007121b1e6ef714bc99101fb3b48e46371df1db8
F test/walro.test cb438d05ba0d191f10b688e39c4f0cd5b71569a1d1f4440e5bdf3c6880e08c20
F test/walro2.test 0e79dd15cbdb4f482c01ea248373669c732414a726b357d04846a816afafb768
F test/walrofault.test c70cb6e308c443867701856cce92ad8288cd99488fa52afab77cca6cfd51af68
+F test/walsetlk.test 11f7fe792fdce54cf09874dab824e0627f2eedecfb9f7983e325606ec5184e0c
F test/walshared.test 0befc811dcf0b287efae21612304d15576e35417
F test/walslow.test c05c68d4dc2700a982f89133ce103a1a84cc285f
F test/walthread.test 14b20fcfa6ae152f5d8e12f5dc8a8a724b7ef189f5d8ef1e2ceab79f2af51747
F test/walvfs.test ca81c9f427e0e5434076dfa948fd1d8e6d5ddd192b2fb6991635d81da5f3f5d4
F test/wapp.tcl b440cd8cf57953d3a49e7ee81e6a18f18efdaf113b69f7d8482b0710a64566ec
F test/wapptest.tcl 3cca775aede0591756a1fc0da55bbb3715d8c363873fd2cfdd4d555b0a4af57d x
-F test/where.test 19c709c9f0f6ed12c23f909f6592aa55fba34269d5a2898537aa27a22b9ce650
+F test/where.test f5e62453537e5b335b69f3b09f8a02ce3328289fad5d866e25371284b837d78d
F test/where2.test 478d2170637b9211f593120648858593bf2445a1
F test/where3.test 2341a294e17193a6b1699ea7f192124a5286ca6acfcc3f4b06d16c931fbcda2c
F test/where4.test 4a371bfcc607f41d233701bdec33ac2972908ba8
@@ -1706,14 +1716,14 @@ F test/where5.test fdf66f96d29a064b63eb543e28da4dfdccd81ad2
F test/where6.test 5da5a98cec820d488e82708301b96cb8c18a258b
F test/where7.test 75722434c486ac9e74718caa6cce234f45ba34c0b6c0f9555b29eb8bb5f6ade1
F test/where8.test 461ca40265ed996a6305da99bb024b0e41602bb586acf544c08f95922358e49f
-F test/where9.test 2c554b97bbdb2fdf26c57099f60db8a52bfcf7c147f2c256f9798fa0e267ca85
+F test/where9.test 8e3e0ff42cc17156f52361a1c012281550d0d632912fec92d1d6df74db7a8e6d
F test/whereA.test 6c6a420ca7d313242f9b1bd471dc80e4d0f8323700ba9c78df0bb843d4daa3b4
F test/whereB.test 0def95db3bdec220a731c7e4bec5930327c1d8c5
F test/whereC.test cae295158703cb3fc23bf1a108a9ab730efff0f6
F test/whereD.test c1c335e914e28b122e000e9310f02d2be83e1c9dbca2e29f46bd732703944d1b
F test/whereE.test b3a055eef928c992b0a33198a7b8dc10eea5ad2f
F test/whereF.test 3d9412b1199d3e2bed34fcb76b4c48d0bf4df95d27e3f8dd27b6f8b4716d0d89
-F test/whereG.test c9378b285828754377ef47fbece7264018c0a3743e7eb686e89917bb9df10885
+F test/whereG.test 9363b2a97d914cb1b81aff5069ef0cf2a071a67e2b604eac6fe9c0114017d9aa
F test/whereH.test e4b07f7a3c2f5d31195cd33710054c78667573b2
F test/whereI.test a2874062140ed4aba9ffae76e6190a3df6fc73d1373fdfa8fd632945082a5364
F test/whereJ.test 88287550f6ee604422403b053455b1ad894eeaa5c35d348532dfa1439286cb9a
@@ -1725,9 +1735,9 @@ F test/wherelimit.test 592081800806d297dd7449b1030c863d2883d6d42901837ccd2e5a9bd
F test/wherelimit2.test 9bf0aa56cca40ea0e4c5e2915341355a2bbc0859ec4ce1589197fe2a9d94635f
F test/win32heap.test 10fd891266bd00af68671e702317726375e5407561d859be1aa04696f2aeee74
F test/win32lock.test fbf107c91d8f5512be5a5b87c4c42ab9fdd54972
-F test/win32longpath.test 169c75a3b2e43481f4a62122510210c67b08f26d
+F test/win32longpath.test 4baffc3acb2e5188a5e3a895b2b543ed09e62f7c72d713c1feebf76222fe9976
F test/win32nolock.test ac4f08811a562e45a5755e661f45ca85892bdbbc
-F test/window1.test ec792f92e63ee457447c5c04de8f8d42f4a94b842b5bac1f403ac38a6d867c22
+F test/window1.test e52b81fff0c3cb122a1240f336688eb81bea2967a99c4ddb78969adec7aadc2a
F test/window2.tcl 492c125fa550cda1dd3555768a2303b3effbeceee215293adf8871efc25f1476
F test/window2.test e466a88bd626d66edc3d352d7d7e1d5531e0079b549ba44efb029d1fbff9fd3c
F test/window3.tcl acea6e86a4324a210fd608d06741010ca83ded9fde438341cb978c49928faf03
@@ -1740,7 +1750,7 @@ F test/window7.tcl 6a1210f05d40ec89c22960213a22cd3f98d4e2f2eb20646c83c8c30d4d761
F test/window7.test 1d31276961ae7801edc72173edaf7593e3cbc79c06d1f1f09e20d8418af403cd
F test/window8.tcl f2711aa3571e4e6b0dad98db8d95fd6cb8d9db0c92bbdf535f153b07606a1ce2
F test/window8.test c4331b27a6f66d69fa8f8bab10cc731db1a81d293ae108a68f7c3487fa94e65b
-F test/window9.test c22c25377c820613e1842fe7ad4af7c03df625f6a7caee99e6fdb4fcd52e0a8b
+F test/window9.test 4d8c875b73febdbac9b8f2b52ec132b98f48261cdafd6b08db62bc6d8ff913fc
F test/windowA.test 6d63dc1260daa17141a55007600581778523a8b420629f1282d2acfc36af23be
F test/windowB.test 7a983ea1cc1cf72be7f378e4b32f6cb2d73014c5cd8b25aaee825164cd4269e5
F test/windowerr.tcl f5acd6fbc210d7b5546c0e879d157888455cd4a17a1d3f28f07c1c8a387019e0
@@ -1753,7 +1763,7 @@ F test/with4.test 257be66c0c67fee1defbbac0f685c3465e2cad037f21ce65f23f86084f1982
F test/withM.test 693b61765f2b387b5e3e24a4536e2e82de15ff64
F test/without_rowid1.test 9cfb83705c506e3849fa7efc88a3c9a15f9a50bf9b1516b41757a7cef9bba8c3
F test/without_rowid2.test af260339f79d13cb220288b67cd287fbcf81ad99
-F test/without_rowid3.test 392e6e12f275d11d931a8bc4580e573342f391639c87ffb631010a7b3cedfdc0
+F test/without_rowid3.test 96426a6c9a2a5cf62bbe55ea1ad038eaaf4bf743f40a1ad517233b8e5a3d4339
F test/without_rowid4.test 4e08bcbaee0399f35d58b5581881e7a6243d458a
F test/without_rowid5.test 89b1c587bd92a0590e440da33e7666bf4891572a
F test/without_rowid6.test 8463b20098e9f75a501a9f17dfb42fffc79068eac0b2775fe56ef2281d2df45e
@@ -1772,26 +1782,26 @@ F tool/build-all-msvc.bat c12328d06c45fec8baada5949e3d5af54bf8c887 x
F tool/build-shell.sh 950f47c6174f1eea171319438b93ba67ff5bf367
F tool/cg_anno.tcl c1f875f5a4c9caca3d59937b16aff716f8b1883935f1b4c9ae23124705bc8099 x
F tool/checkSpacing.c 810e51703529a204fc4e1eb060e9ab663e3c06d2
-F tool/dbhash.c 19560c9a2aa2b269b6a5108259b93d26d12f8f0877c31fe9f8f61dfbd219ba63
+F tool/dbhash.c 5da0c61032d23d74f2ab84ffc5740f0e8abec94f2c45c0b4306be7eb3ae96df0
F tool/dbtotxt.c b2221864a20fb391c46bd31bc1fbdc4a96f5c8a89bef58f421eb9b9c36b1702c
F tool/dbtotxt.md c9a57af8739957ef36d2cfad5c4b1443ff3688ed33e4901ee200c8b651f43f3c
F tool/extract-sqlite3h.tcl 069ceab0cee26cba99952bfa08c0b23e35941c837acabe143f0c355d96c9e2eb x
F tool/extract.c 054069d81b095fbdc189a6f5d4466e40380505e2
-F tool/fast_vacuum.c 5ba0d6f5963a0a63bdc42840f678bad75b2ebce1
+F tool/fast_vacuum.c c129ae2924a48310c7b766810391da9e8fda532b9f6bd3f9a9e3a799a1b42af9
F tool/fragck.tcl 5265a95126abcf6ab357f7efa544787e5963f439
F tool/fuzzershell.c e1d90a03ca790d7c331c2aae08ca46ff435f1ae1faa6cb9cc48f4687c18fdc6e
F tool/genfkey.README cf68fddd4643bbe3ff8e31b8b6d8b0a1b85e20f4
F tool/genfkey.test b6afd7b825d797a1e1274f519ab5695373552ecad5cd373530c63533638a5a4f
F tool/getlock.c f4c39b651370156cae979501a7b156bdba50e7ce
-F tool/index_usage.c 9ec344d29cbeb03fdc0fce668eedfb7495792170de933adf95cf8d6904a166ad
+F tool/index_usage.c f62a0c701b2c7ff2f3e21d206f093c123f222dbf07136a10ffd1ca15a5c706c5
F tool/kvtest-speed.sh 4761a9c4b3530907562314d7757995787f7aef8f
-F tool/lemon.c a361b85fa230560b783006ac002a6a8bad214c3b9d7fa48980aecc2b691ddcad
+F tool/lemon.c 600a58b9d1b8ec5419373982428e927ca208826edacb91ca42ab94514d006039
F tool/lempar.c e8899b28488f060d0ff931539ea6311b16b22dce068c086c788a06d5e8d01ab7
F tool/libvers.c caafc3b689638a1d88d44bc5f526c2278760d9b9
F tool/loadfts.c c3c64e4d5e90e8ba41159232c2189dba4be7b862
F tool/logest.c 11346aa019e2e77a00902aa7d0cabd27bd2e8cca
F tool/max-limits.c cbb635fbb37ae4d05f240bfb5b5270bb63c54439
-F tool/mkautoconfamal.sh 422fc365358a2e92876ffc62971a0ff28ed472fc8bcf9de0df921c736fdeca5e
+F tool/mkautoconfamal.sh f62353eb6c06ab264da027fd4507d09914433dbdcab9cb011cdc18016f1ab3b8
F tool/mkccode.tcl 86463e68ce9c15d3041610fedd285ce32a5cf7a58fc88b3202b8b76837650dbe x
F tool/mkctimec.tcl dd183b73ae1c28249669741c250525f0407e579a70482371668fd5f130d9feb3
F tool/mkkeywordhash.c 11a3f3af8e787d0c5ca459ed66fe80fd09e661876506e7b978ec08c19477bdc2
@@ -1799,16 +1809,16 @@ F tool/mkmsvcmin.tcl 6ecab9fe22c2c8de4d82d4c46797bda3d2deac8e763885f5a38d0c44a89
F tool/mkopcodec.tcl d1b6362bd3aa80d5520d4d6f3765badf01f6c43c
F tool/mkopcodeh.tcl 352a4319c0ad869eb26442bf7c3b015aa15594c21f1cce5a6420dbe999367c21
F tool/mkopts.tcl 680f785fdb09729fd9ac50632413da4eadbdf9071535e3f26d03795828ab07fa
-F tool/mkpragmatab.tcl 62663c65d9191aada624a787e1ee3420f268a3c27999ad0ffb77a6918ddc1e52
+F tool/mkpragmatab.tcl ae5585ae76ca26e4d6ccd5ea9cdebaf5efefb318bf989497a0e846cd711d9ab1
F tool/mkshellc.tcl 70a9978e363b0f3280ca9ce1c46d72563ff479c1930a12a7375e3881b7325712
F tool/mksourceid.c 36aa8020014aed0836fd13c51d6dc9219b0df1761d6b5f58ff5b616211b079b9
F tool/mkspeedsql.tcl a1a334d288f7adfe6e996f2e712becf076745c97
F tool/mksqlite3c-noext.tcl 4f7cfef5152b0c91920355cbfc1d608a4ad242cb819f1aea07f6d0274f584a7f
-F tool/mksqlite3c.tcl 5fed3d75069d8f66f202d3b5200b0cea4aa7108481acd06732a06fdd42eb83a2
-F tool/mksqlite3h.tcl 080873e3856eceb9d289a08a00c4b30f875ea3feadcbece796bd509b1532792c
+F tool/mksqlite3c.tcl f4ef476510eca4124c874a72029f1e01bc54a896b1724e8f9eef0d8bfae0e84c
+F tool/mksqlite3h.tcl 1f5e4a1dbbbc43c83cc6e74fe32c6c620502240b66c7c0f33a51378e78fc4edf
F tool/mksqlite3internalh.tcl eb994013e833359137eb53a55acdad0b5ae1049b
F tool/mkvsix.tcl b9e0777a213c23156b6542842c238479e496ebf5
-F tool/offsets.c fe4262fdfa378e8f5499a42136d17bf3b98f6091
+F tool/offsets.c 8ed2b344d33f06e71366a9b93ccedaa38c096cc1dbd4c3c26ad08c6115285845
F tool/omittest.tcl 6616fbf384f0f630113eab27d41d4530435dd94e2883307759988b45f0604a3b
F tool/opcodesum.tcl 740ed206ba8c5040018988129abbf3089a0ccf4a
F tool/pagesig.c ff0ca355fd3c2398e933da5e22439bbff89b803b
@@ -1816,22 +1826,22 @@ F tool/replace.tcl 60f91e8dd06ab81f74d213ecbd9c9945f32ac048
F tool/restore_jrnl.tcl 6957a34f8f1f0f8285e07536225ec3b292a9024a
F tool/rollback-test.c 9fc98427d1e23e84429d7e6d07d9094fbdec65a5
F tool/run-speed-test.sh f95d19fd669b68c4c38b6b475242841d47c66076
-F tool/showdb.c 9b2dbb4b7a00afaf8fc1719f0d775775effa5b135ac1a2c23f1c3f5d670c4e15
+F tool/showdb.c cdf631fe4c962bcf55e80a81f2ea02812901e73ab5751f83688797d0d18b65f5
F tool/showjournal.c 5bad7ae8784a43d2b270d953060423b8bd480818
-F tool/showlocks.c 9920bcc64f58378ff1118caead34147201f48c68
+F tool/showlocks.c 9cc5e66d4ebbf2d194f39db2527ece92077e86ae627ddd233ee48e16e8142564
F tool/showshm.c a0ab6ec32dd1f11218ca2a4018f8fb875b59414801ab8ceed8b2e69b7b45a809
F tool/showstat4.c 0682ebea7abf4d3657f53c4a243f2e7eab48eab344ed36a94bb75dcd19a5c2a1
F tool/showwal.c ad9d768f96ca6199ad3a8c9562d679680bd032dd01204ea3e5ea6fb931d81847
F tool/soak1.tcl 8d407956e1a45b485a8e072470a3e629a27037fe
-F tool/spaceanal.tcl c161d838825d0242317c7cc13b1eb2126f8cec031950ef31114d42732cb2674e
-F tool/speed-check.sh 2b042d703a9472f08c3b13be27afac658426f8e4fc87cd2d575953fda86f08d1
+F tool/spaceanal.tcl a95036b36622e25cffd65a55b22d6af53dfbbff0de02d45dd0059bb3c9978609
+F tool/speed-check.sh 615cbdf50f1409ef3bbf9f682e396df80f49d97ed93ed3e61c8e91fae6afde58
F tool/speedtest.tcl 06c76698485ccf597b9e7dbb1ac70706eb873355
F tool/speedtest16.c ecb6542862151c3e6509bbc00509b234562ae81e
F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
F tool/speedtest8inst1.c 7ce07da76b5e745783e703a834417d725b7d45fd
F tool/split-sqlite3c.tcl 3efcd4240b738f6bb2b5af0aea7e1e0ef9bc1c61654f645076cec883030b710c
-F tool/sqldiff.c 7b9b7238284f02131dbb8f21a4e862409bff728045c5473139d28c67ac87580e
+F tool/sqldiff.c 5046b8e227213ad016b336eb5a933e252e1f0fd1e07060c5755e259a30891287
F tool/sqlite3_analyzer.c.in 7eeaae8b0d7577662acaabbb11107af0659d1b41bc1dfdd4d91422de27127968
F tool/sqltclsh.c.in 1bcc2e9da58fadf17b0bf6a50e68c1159e602ce057210b655d50bad5aaaef898
F tool/sqltclsh.tcl 862f4cf1418df5e1315b5db3b5ebe88969e2a784525af5fbf9596592f14ed848
@@ -1846,7 +1856,7 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee
F tool/warnings.sh 09311479bdc290e20ec8e35a3d1b14b096bbd96222277cfd6274c3a99b3d012f
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
F vsixtest/App.xaml b76d3b48860e7454775c47ea38ffea9c4abe3e85
-F vsixtest/App.xaml.cpp c465147f50871165c60ca16955219f6c5812d6d8
+F vsixtest/App.xaml.cpp 41158ee43269820136fa3bba00c0bd91b26cc38b650ee392aec2a8d823e54318
F vsixtest/App.xaml.h 4a9768e2983d05600ad1e1c2f1b00a132967da9f
F vsixtest/Assets/LockScreenLogo.scale-200.png e820c9a3deb909197081b0bf3216c06e13905f0a
F vsixtest/Assets/SplashScreen.scale-200.png cab70988ca71bebec7bfeb3b6dbafe17b9ab0b4a
@@ -1866,7 +1876,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P e4a18601e5093896e5b323c21aec986b07259353d2ef9455d0a81c6846f40282
-R 31d44a5c5eab4f547b6c4029493d0d87
+P 623ab585d1aa1bdde2df17f1936aa4eec2d997b274acc5c7b291d9566a9ec2c5 9cb03beae42d814a1b1b69f72865fde502d3f443313ec29edd010d1de40225eb
+R c595fc81cb22682ebca5cb12ad90110f
U dan
-Z 8413be68bb1b4ef61cb95011e58e4ac0
+Z edc7c2a0a189c2ca88c2dfd10b0672a6
diff --git a/manifest.uuid b/manifest.uuid
index 68d268c74..378d47249 100644
--- a/manifest.uuid
+++ b/manifest.uuid
@@ -1 +1 @@
-623ab585d1aa1bdde2df17f1936aa4eec2d997b274acc5c7b291d9566a9ec2c5 \ No newline at end of file
+5ee3c27e20d12a126fb773b428bb864102b949a5b26a8d5c523753dcedf4be10 \ No newline at end of file
diff --git a/src/alter.c b/src/alter.c
index c357f2207..8109545d7 100644
--- a/src/alter.c
+++ b/src/alter.c
@@ -52,22 +52,22 @@ static int isAlterableTable(Parse *pParse, Table *pTab){
static void renameTestSchema(Parse *pParse, const char *zDb, int bTemp){
sqlite3NestedParse(pParse,
"SELECT 1 "
- "FROM \"%w\".%s "
+ "FROM \"%w\"." DFLT_SCHEMA_TABLE " "
"WHERE name NOT LIKE 'sqliteX_%%' ESCAPE 'X'"
" AND sql NOT LIKE 'create virtual%%'"
" AND sqlite_rename_test(%Q, sql, type, name, %d)=NULL ",
- zDb, MASTER_NAME,
+ zDb,
zDb, bTemp
);
if( bTemp==0 ){
sqlite3NestedParse(pParse,
"SELECT 1 "
- "FROM temp.%s "
+ "FROM temp." DFLT_SCHEMA_TABLE " "
"WHERE name NOT LIKE 'sqliteX_%%' ESCAPE 'X'"
" AND sql NOT LIKE 'create virtual%%'"
" AND sqlite_rename_test(%Q, sql, type, name, 1)=NULL ",
- MASTER_NAME, zDb
+ zDb
);
}
}
@@ -123,7 +123,10 @@ void sqlite3AlterRenameTable(
/* Check that a table or index named 'zName' does not already exist
** in database iDb. If so, this is an error.
*/
- if( sqlite3FindTable(db, zName, zDb) || sqlite3FindIndex(db, zName, zDb) ){
+ if( sqlite3FindTable(db, zName, zDb)
+ || sqlite3FindIndex(db, zName, zDb)
+ || sqlite3IsShadowTableOf(db, pTab, zName)
+ ){
sqlite3ErrorMsg(pParse,
"there is already another table or index with this name: %s", zName);
goto exit_rename_table;
@@ -182,17 +185,17 @@ void sqlite3AlterRenameTable(
/* Rewrite all CREATE TABLE, INDEX, TRIGGER or VIEW statements in
** the schema to use the new table name. */
sqlite3NestedParse(pParse,
- "UPDATE \"%w\".%s SET "
+ "UPDATE \"%w\"." DFLT_SCHEMA_TABLE " SET "
"sql = sqlite_rename_table(%Q, type, name, sql, %Q, %Q, %d) "
"WHERE (type!='index' OR tbl_name=%Q COLLATE nocase)"
"AND name NOT LIKE 'sqliteX_%%' ESCAPE 'X'"
- , zDb, MASTER_NAME, zDb, zTabName, zName, (iDb==1), zTabName
+ , zDb, zDb, zTabName, zName, (iDb==1), zTabName
);
- /* Update the tbl_name and name columns of the sqlite_master table
+ /* Update the tbl_name and name columns of the sqlite_schema table
** as required. */
sqlite3NestedParse(pParse,
- "UPDATE %Q.%s SET "
+ "UPDATE %Q." DFLT_SCHEMA_TABLE " SET "
"tbl_name = %Q, "
"name = CASE "
"WHEN type='table' THEN %Q "
@@ -202,7 +205,7 @@ void sqlite3AlterRenameTable(
"ELSE name END "
"WHERE tbl_name=%Q COLLATE nocase AND "
"(type='table' OR type='index' OR type='trigger');",
- zDb, MASTER_NAME,
+ zDb,
zName, zName, zName,
nTabName, zTabName
);
@@ -223,7 +226,7 @@ void sqlite3AlterRenameTable(
** as required. */
if( iDb!=1 ){
sqlite3NestedParse(pParse,
- "UPDATE sqlite_temp_master SET "
+ "UPDATE sqlite_temp_schema SET "
"sql = sqlite_rename_table(%Q, type, name, sql, %Q, %Q, 1), "
"tbl_name = "
"CASE WHEN tbl_name=%Q COLLATE nocase AND "
@@ -256,6 +259,22 @@ exit_rename_table:
}
/*
+** Write code that will raise an error if the table described by
+** zDb and zTab is not empty.
+*/
+static void sqlite3ErrorIfNotEmpty(
+ Parse *pParse, /* Parsing context */
+ const char *zDb, /* Schema holding the table */
+ const char *zTab, /* Table to check for empty */
+ const char *zErr /* Error message text */
+){
+ sqlite3NestedParse(pParse,
+ "SELECT raise(ABORT,%Q) FROM \"%w\".\"%w\"",
+ zErr, zDb, zTab
+ );
+}
+
+/*
** This function is called after an "ALTER TABLE ... ADD" statement
** has been parsed. Argument pColDef contains the text of the new
** column definition.
@@ -307,7 +326,8 @@ void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
return;
}
if( pNew->pIndex ){
- sqlite3ErrorMsg(pParse, "Cannot add a UNIQUE column");
+ sqlite3ErrorMsg(pParse,
+ "Cannot add a UNIQUE column");
return;
}
if( (pCol->colFlags & COLFLAG_GENERATED)==0 ){
@@ -320,16 +340,15 @@ void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
pDflt = 0;
}
if( (db->flags&SQLITE_ForeignKeys) && pNew->pFKey && pDflt ){
- sqlite3ErrorMsg(pParse,
+ sqlite3ErrorIfNotEmpty(pParse, zDb, zTab,
"Cannot add a REFERENCES column with non-NULL default value");
- return;
}
if( pCol->notNull && !pDflt ){
- sqlite3ErrorMsg(pParse,
+ sqlite3ErrorIfNotEmpty(pParse, zDb, zTab,
"Cannot add a NOT NULL column with default value NULL");
- return;
}
+
/* Ensure the default expression is something that sqlite3ValueFromExpr()
** can handle (i.e. not CURRENT_TIME etc.)
*/
@@ -343,14 +362,13 @@ void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
return;
}
if( !pVal ){
- sqlite3ErrorMsg(pParse,"Cannot add a column with non-constant default");
- return;
+ sqlite3ErrorIfNotEmpty(pParse, zDb, zTab,
+ "Cannot add a column with non-constant default");
}
sqlite3ValueFree(pVal);
}
}else if( pCol->colFlags & COLFLAG_STORED ){
- sqlite3ErrorMsg(pParse, "cannot add a STORED column");
- return;
+ sqlite3ErrorIfNotEmpty(pParse, zDb, zTab, "cannot add a STORED column");
}
@@ -364,10 +382,10 @@ void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
}
db->mDbFlags |= DBFLAG_PreferBuiltin;
sqlite3NestedParse(pParse,
- "UPDATE \"%w\".%s SET "
+ "UPDATE \"%w\"." DFLT_SCHEMA_TABLE " SET "
"sql = substr(sql,1,%d) || ', ' || %Q || substr(sql,%d) "
"WHERE type = 'table' AND name = %Q",
- zDb, MASTER_NAME, pNew->addColOffset, zCol, pNew->addColOffset+1,
+ zDb, pNew->addColOffset, zCol, pNew->addColOffset+1,
zTab
);
sqlite3DbFree(db, zCol);
@@ -569,7 +587,7 @@ void sqlite3AlterRenameColumn(
/* Do the rename operation using a recursive UPDATE statement that
** uses the sqlite_rename_column() SQL function to compute the new
- ** CREATE statement text for the sqlite_master table.
+ ** CREATE statement text for the sqlite_schema table.
*/
sqlite3MayAbort(pParse);
zNew = sqlite3NameFromToken(db, pNew);
@@ -577,21 +595,20 @@ void sqlite3AlterRenameColumn(
assert( pNew->n>0 );
bQuote = sqlite3Isquote(pNew->z[0]);
sqlite3NestedParse(pParse,
- "UPDATE \"%w\".%s SET "
+ "UPDATE \"%w\"." DFLT_SCHEMA_TABLE " SET "
"sql = sqlite_rename_column(sql, type, name, %Q, %Q, %d, %Q, %d, %d) "
"WHERE name NOT LIKE 'sqliteX_%%' ESCAPE 'X' "
" AND (type != 'index' OR tbl_name = %Q)"
" AND sql NOT LIKE 'create virtual%%'",
- zDb, MASTER_NAME,
+ zDb,
zDb, pTab->zName, iCol, zNew, bQuote, iSchema==1,
pTab->zName
);
sqlite3NestedParse(pParse,
- "UPDATE temp.%s SET "
+ "UPDATE temp." DFLT_SCHEMA_TABLE " SET "
"sql = sqlite_rename_column(sql, type, name, %Q, %Q, %d, %Q, %d, 1) "
"WHERE type IN ('trigger', 'view')",
- MASTER_NAME,
zDb, pTab->zName, iCol, zNew, bQuote
);
diff --git a/src/analyze.c b/src/analyze.c
index eee71fbbd..76f8f818a 100644
--- a/src/analyze.c
+++ b/src/analyze.c
@@ -188,6 +188,11 @@ static void openStatTable(
Vdbe *v = sqlite3GetVdbe(pParse);
int aRoot[ArraySize(aTable)];
u8 aCreateTbl[ArraySize(aTable)];
+#ifdef SQLITE_ENABLE_STAT4
+ const int nToOpen = OptimizationEnabled(db,SQLITE_Stat4) ? 2 : 1;
+#else
+ const int nToOpen = 1;
+#endif
if( v==0 ) return;
assert( sqlite3BtreeHoldsAllMutexes(db) );
@@ -200,8 +205,9 @@ static void openStatTable(
for(i=0; i<ArraySize(aTable); i++){
const char *zTab = aTable[i].zName;
Table *pStat;
+ aCreateTbl[i] = 0;
if( (pStat = sqlite3FindTable(db, zTab, pDb->zDbSName))==0 ){
- if( aTable[i].zCols ){
+ if( i<nToOpen ){
/* The sqlite_statN table does not exist. Create it. Note that a
** side-effect of the CREATE TABLE statement is to leave the rootpage
** of the new table in register pParse->regRoot. This is important
@@ -217,7 +223,6 @@ static void openStatTable(
** associated with the table zWhere. If zWhere is NULL, delete the
** entire contents of the table. */
aRoot[i] = pStat->tnum;
- aCreateTbl[i] = 0;
sqlite3TableLock(pParse, iDb, aRoot[i], 1, zTab);
if( zWhere ){
sqlite3NestedParse(pParse,
@@ -236,7 +241,7 @@ static void openStatTable(
}
/* Open the sqlite_stat[134] tables for writing. */
- for(i=0; aTable[i].zCols; i++){
+ for(i=0; i<nToOpen; i++){
assert( i<ArraySize(aTable) );
sqlite3VdbeAddOp4Int(v, OP_OpenWrite, iStatCur+i, aRoot[i], iDb, 3);
sqlite3VdbeChangeP5(v, aCreateTbl[i]);
@@ -275,9 +280,12 @@ struct StatSample {
};
struct StatAccum {
sqlite3 *db; /* Database connection, for malloc() */
- tRowcnt nRow; /* Number of rows in the entire table */
+ tRowcnt nEst; /* Estimated number of rows */
+ tRowcnt nRow; /* Number of rows visited so far */
+ int nLimit; /* Analysis row-scan limit */
int nCol; /* Number of columns in index + pk/rowid */
int nKeyCol; /* Number of index columns w/o the pk/rowid */
+ u8 nSkipAhead; /* Number of times of skip-ahead */
StatSample current; /* Current row as a StatSample */
#ifdef SQLITE_ENABLE_STAT4
tRowcnt nPSample; /* How often to do a periodic sample */
@@ -357,27 +365,28 @@ static void sampleCopy(StatAccum *p, StatSample *pTo, StatSample *pFrom){
static void statAccumDestructor(void *pOld){
StatAccum *p = (StatAccum*)pOld;
#ifdef SQLITE_ENABLE_STAT4
- int i;
- for(i=0; i<p->nCol; i++) sampleClear(p->db, p->aBest+i);
- for(i=0; i<p->mxSample; i++) sampleClear(p->db, p->a+i);
- sampleClear(p->db, &p->current);
+ if( p->mxSample ){
+ int i;
+ for(i=0; i<p->nCol; i++) sampleClear(p->db, p->aBest+i);
+ for(i=0; i<p->mxSample; i++) sampleClear(p->db, p->a+i);
+ sampleClear(p->db, &p->current);
+ }
#endif
sqlite3DbFree(p->db, p);
}
/*
-** Implementation of the stat_init(N,K,C) SQL function. The three parameters
+** Implementation of the stat_init(N,K,C,L) SQL function. The four parameters
** are:
** N: The number of columns in the index including the rowid/pk (note 1)
** K: The number of columns in the index excluding the rowid/pk.
-** C: The number of rows in the index (note 2)
+** C: Estimated number of rows in the index
+** L: A limit on the number of rows to scan, or 0 for no-limit
**
** Note 1: In the special case of the covering index that implements a
** WITHOUT ROWID table, N is the number of PRIMARY KEY columns, not the
** total number of columns in the table.
**
-** Note 2: C is only used for STAT4.
-**
** For indexes on ordinary rowid tables, N==K+1. But for indexes on
** WITHOUT ROWID tables, N=K+P where P is the number of columns in the
** PRIMARY KEY of the table. The covering index that implements the
@@ -398,9 +407,10 @@ static void statInit(
int nKeyCol; /* Number of key columns */
int nColUp; /* nCol rounded up for alignment */
int n; /* Bytes of space to allocate */
- sqlite3 *db; /* Database connection */
+ sqlite3 *db = sqlite3_context_db_handle(context); /* Database connection */
#ifdef SQLITE_ENABLE_STAT4
- int mxSample = SQLITE_STAT4_SAMPLES;
+ /* Maximum number of samples. 0 if STAT4 data is not collected */
+ int mxSample = OptimizationEnabled(db,SQLITE_Stat4) ?SQLITE_STAT4_SAMPLES :0;
#endif
/* Decode the three function arguments */
@@ -415,13 +425,14 @@ static void statInit(
/* Allocate the space required for the StatAccum object */
n = sizeof(*p)
+ sizeof(tRowcnt)*nColUp /* StatAccum.anEq */
- + sizeof(tRowcnt)*nColUp /* StatAccum.anDLt */
+ + sizeof(tRowcnt)*nColUp; /* StatAccum.anDLt */
#ifdef SQLITE_ENABLE_STAT4
- + sizeof(tRowcnt)*nColUp /* StatAccum.anLt */
- + sizeof(StatSample)*(nCol+mxSample) /* StatAccum.aBest[], a[] */
- + sizeof(tRowcnt)*3*nColUp*(nCol+mxSample)
+ if( mxSample ){
+ n += sizeof(tRowcnt)*nColUp /* StatAccum.anLt */
+ + sizeof(StatSample)*(nCol+mxSample) /* StatAccum.aBest[], a[] */
+ + sizeof(tRowcnt)*3*nColUp*(nCol+mxSample);
+ }
#endif
- ;
db = sqlite3_context_db_handle(context);
p = sqlite3DbMallocZero(db, n);
if( p==0 ){
@@ -430,20 +441,23 @@ static void statInit(
}
p->db = db;
+ p->nEst = sqlite3_value_int64(argv[2]);
p->nRow = 0;
+ p->nLimit = sqlite3_value_int64(argv[3]);
p->nCol = nCol;
p->nKeyCol = nKeyCol;
+ p->nSkipAhead = 0;
p->current.anDLt = (tRowcnt*)&p[1];
p->current.anEq = &p->current.anDLt[nColUp];
#ifdef SQLITE_ENABLE_STAT4
- {
+ p->mxSample = p->nLimit==0 ? mxSample : 0;
+ if( mxSample ){
u8 *pSpace; /* Allocated space not yet assigned */
int i; /* Used to iterate through p->aSample[] */
p->iGet = -1;
- p->mxSample = mxSample;
- p->nPSample = (tRowcnt)(sqlite3_value_int64(argv[2])/(mxSample/3+1) + 1);
+ p->nPSample = (tRowcnt)(p->nEst/(mxSample/3+1) + 1);
p->current.anLt = &p->current.anEq[nColUp];
p->iPrn = 0x689e962d*(u32)nCol ^ 0xd0944565*(u32)sqlite3_value_int(argv[2]);
@@ -471,7 +485,7 @@ static void statInit(
sqlite3_result_blob(context, p, sizeof(*p), statAccumDestructor);
}
static const FuncDef statInitFuncdef = {
- 2+IsStat4, /* nArg */
+ 4, /* nArg */
SQLITE_UTF8, /* funcFlags */
0, /* pUserData */
0, /* pNext */
@@ -675,10 +689,13 @@ static void samplePushPrevious(StatAccum *p, int iChng){
** R Rowid for the current row. Might be a key record for
** WITHOUT ROWID tables.
**
-** This SQL function always returns NULL. It's purpose it to accumulate
-** statistical data and/or samples in the StatAccum object about the
-** index being analyzed. The stat_get() SQL function will later be used to
-** extract relevant information for constructing the sqlite_statN tables.
+** The purpose of this routine is to collect statistical data and/or
+** samples from the index being analyzed into the StatAccum object.
+** The stat_get() SQL function will be used afterwards to
+** retrieve the information gathered.
+**
+** This SQL function usually returns NULL, but might return an integer
+** if it wants the byte-code to do special processing.
**
** The R parameter is only used for STAT4
*/
@@ -704,7 +721,7 @@ static void statPush(
}else{
/* Second and subsequent calls get processed here */
#ifdef SQLITE_ENABLE_STAT4
- samplePushPrevious(p, iChng);
+ if( p->mxSample ) samplePushPrevious(p, iChng);
#endif
/* Update anDLt[], anLt[] and anEq[] to reflect the values that apply
@@ -715,26 +732,25 @@ static void statPush(
for(i=iChng; i<p->nCol; i++){
p->current.anDLt[i]++;
#ifdef SQLITE_ENABLE_STAT4
- p->current.anLt[i] += p->current.anEq[i];
+ if( p->mxSample ) p->current.anLt[i] += p->current.anEq[i];
#endif
p->current.anEq[i] = 1;
}
}
- p->nRow++;
-#ifdef SQLITE_ENABLE_STAT4
- if( sqlite3_value_type(argv[2])==SQLITE_INTEGER ){
- sampleSetRowidInt64(p->db, &p->current, sqlite3_value_int64(argv[2]));
- }else{
- sampleSetRowid(p->db, &p->current, sqlite3_value_bytes(argv[2]),
- sqlite3_value_blob(argv[2]));
- }
- p->current.iHash = p->iPrn = p->iPrn*1103515245 + 12345;
-#endif
+ p->nRow++;
#ifdef SQLITE_ENABLE_STAT4
- {
- tRowcnt nLt = p->current.anLt[p->nCol-1];
+ if( p->mxSample ){
+ tRowcnt nLt;
+ if( sqlite3_value_type(argv[2])==SQLITE_INTEGER ){
+ sampleSetRowidInt64(p->db, &p->current, sqlite3_value_int64(argv[2]));
+ }else{
+ sampleSetRowid(p->db, &p->current, sqlite3_value_bytes(argv[2]),
+ sqlite3_value_blob(argv[2]));
+ }
+ p->current.iHash = p->iPrn = p->iPrn*1103515245 + 12345;
+ nLt = p->current.anLt[p->nCol-1];
/* Check if this is to be a periodic sample. If so, add it. */
if( (nLt/p->nPSample)!=(nLt+1)/p->nPSample ){
p->current.isPSample = 1;
@@ -750,9 +766,14 @@ static void statPush(
sampleCopy(p, &p->aBest[i], &p->current);
}
}
- }
+ }else
#endif
+ if( p->nLimit && p->nRow>(tRowcnt)p->nLimit*(p->nSkipAhead+1) ){
+ p->nSkipAhead++;
+ sqlite3_result_int(context, p->current.anDLt[0]>0);
+ }
}
+
static const FuncDef statPushFuncdef = {
2+IsStat4, /* nArg */
SQLITE_UTF8, /* funcFlags */
@@ -804,6 +825,7 @@ static void statGet(
|| eCall==STAT_GET_ROWID || eCall==STAT_GET_NLT
|| eCall==STAT_GET_NDLT
);
+ assert( eCall==STAT_GET_STAT1 || p->mxSample );
if( eCall==STAT_GET_STAT1 )
#else
assert( argc==1 );
@@ -839,7 +861,8 @@ static void statGet(
return;
}
- sqlite3_snprintf(24, zRet, "%llu", (u64)p->nRow);
+ sqlite3_snprintf(24, zRet, "%llu",
+ p->nSkipAhead ? (u64)p->nEst : (u64)p->nRow);
z = zRet + sqlite3Strlen30(zRet);
for(i=0; i<p->nKeyCol; i++){
u64 nDistinct = p->current.anDLt[i] + 1;
@@ -915,19 +938,43 @@ static const FuncDef statGetFuncdef = {
{0}
};
-static void callStatGet(Parse *pParse, int regStat4, int iParam, int regOut){
+static void callStatGet(Parse *pParse, int regStat, int iParam, int regOut){
#ifdef SQLITE_ENABLE_STAT4
- sqlite3VdbeAddOp2(pParse->pVdbe, OP_Integer, iParam, regStat4+1);
+ sqlite3VdbeAddOp2(pParse->pVdbe, OP_Integer, iParam, regStat+1);
#elif SQLITE_DEBUG
assert( iParam==STAT_GET_STAT1 );
#else
UNUSED_PARAMETER( iParam );
#endif
- assert( regOut!=regStat4 && regOut!=regStat4+1 );
- sqlite3VdbeAddFunctionCall(pParse, 0, regStat4, regOut, 1+IsStat4,
+ assert( regOut!=regStat && regOut!=regStat+1 );
+ sqlite3VdbeAddFunctionCall(pParse, 0, regStat, regOut, 1+IsStat4,
&statGetFuncdef, 0);
}
+#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
+/* Add a comment to the most recent VDBE opcode that is the name
+** of the k-th column of the pIdx index.
+*/
+static void analyzeVdbeCommentIndexWithColumnName(
+ Vdbe *v, /* Prepared statement under construction */
+ Index *pIdx, /* Index whose column is being loaded */
+ int k /* Which column index */
+){
+ int i; /* Index of column in the table */
+ assert( k>=0 && k<pIdx->nColumn );
+ i = pIdx->aiColumn[k];
+ if( NEVER(i==XN_ROWID) ){
+ VdbeComment((v,"%s.rowid",pIdx->zName));
+ }else if( i==XN_EXPR ){
+ VdbeComment((v,"%s.expr(%d)",pIdx->zName, k));
+ }else{
+ VdbeComment((v,"%s.%s", pIdx->zName, pIdx->pTable->aCol[i].zName));
+ }
+}
+#else
+# define analyzeVdbeCommentIndexWithColumnName(a,b,c)
+#endif /* SQLITE_DEBUG */
+
/*
** Generate code to do an analysis of all indices associated with
** a single table.
@@ -950,12 +997,11 @@ static void analyzeOneTable(
int iDb; /* Index of database containing pTab */
u8 needTableCnt = 1; /* True to count the table */
int regNewRowid = iMem++; /* Rowid for the inserted record */
- int regStat4 = iMem++; /* Register to hold StatAccum object */
+ int regStat = iMem++; /* Register to hold StatAccum object */
int regChng = iMem++; /* Index of changed index field */
-#ifdef SQLITE_ENABLE_STAT4
int regRowid = iMem++; /* Rowid argument passed to stat_push() */
-#endif
int regTemp = iMem++; /* Temporary use register */
+ int regTemp2 = iMem++; /* Second temporary use register */
int regTabname = iMem++; /* Register containing table name */
int regIdxname = iMem++; /* Register containing index name */
int regStat1 = iMem++; /* Value for the stat column of sqlite_stat1 */
@@ -1083,17 +1129,26 @@ static void analyzeOneTable(
** (1) the number of columns in the index including the rowid
** (or for a WITHOUT ROWID table, the number of PK columns),
** (2) the number of columns in the key without the rowid/pk
- ** (3) the number of rows in the index,
- **
- **
- ** The third argument is only used for STAT4
+ ** (3) estimated number of rows in the index,
*/
+ sqlite3VdbeAddOp2(v, OP_Integer, nCol, regStat+1);
+ assert( regRowid==regStat+2 );
+ sqlite3VdbeAddOp2(v, OP_Integer, pIdx->nKeyCol, regRowid);
#ifdef SQLITE_ENABLE_STAT4
- sqlite3VdbeAddOp2(v, OP_Count, iIdxCur, regStat4+3);
+ if( OptimizationEnabled(db, SQLITE_Stat4) ){
+ sqlite3VdbeAddOp2(v, OP_Count, iIdxCur, regTemp);
+ addrRewind = sqlite3VdbeAddOp1(v, OP_Rewind, iIdxCur);
+ VdbeCoverage(v);
+ }else
#endif
- sqlite3VdbeAddOp2(v, OP_Integer, nCol, regStat4+1);
- sqlite3VdbeAddOp2(v, OP_Integer, pIdx->nKeyCol, regStat4+2);
- sqlite3VdbeAddFunctionCall(pParse, 0, regStat4+1, regStat4, 2+IsStat4,
+ {
+ addrRewind = sqlite3VdbeAddOp1(v, OP_Rewind, iIdxCur);
+ VdbeCoverage(v);
+ sqlite3VdbeAddOp3(v, OP_Count, iIdxCur, regTemp, 1);
+ }
+ assert( regTemp2==regStat+4 );
+ sqlite3VdbeAddOp2(v, OP_Integer, db->nAnalysisLimit, regTemp2);
+ sqlite3VdbeAddFunctionCall(pParse, 0, regStat+1, regStat, 4,
&statInitFuncdef, 0);
/* Implementation of the following:
@@ -1104,8 +1159,6 @@ static void analyzeOneTable(
** goto next_push_0;
**
*/
- addrRewind = sqlite3VdbeAddOp1(v, OP_Rewind, iIdxCur);
- VdbeCoverage(v);
sqlite3VdbeAddOp2(v, OP_Integer, 0, regChng);
addrNextRow = sqlite3VdbeCurrentAddr(v);
@@ -1138,6 +1191,7 @@ static void analyzeOneTable(
char *pColl = (char*)sqlite3LocateCollSeq(pParse, pIdx->azColl[i]);
sqlite3VdbeAddOp2(v, OP_Integer, i, regChng);
sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, i, regTemp);
+ analyzeVdbeCommentIndexWithColumnName(v,pIdx,i);
aGotoChng[i] =
sqlite3VdbeAddOp4(v, OP_Ne, regTemp, 0, regPrev+i, pColl, P4_COLLSEQ);
sqlite3VdbeChangeP5(v, SQLITE_NULLEQ);
@@ -1158,6 +1212,7 @@ static void analyzeOneTable(
for(i=0; i<nColTest; i++){
sqlite3VdbeJumpHere(v, aGotoChng[i]);
sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, i, regPrev+i);
+ analyzeVdbeCommentIndexWithColumnName(v,pIdx,i);
}
sqlite3VdbeResolveLabel(v, endDistinctTest);
sqlite3DbFree(db, aGotoChng);
@@ -1171,30 +1226,46 @@ static void analyzeOneTable(
** if !eof(csr) goto next_row;
*/
#ifdef SQLITE_ENABLE_STAT4
- assert( regRowid==(regStat4+2) );
- if( HasRowid(pTab) ){
- sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdxCur, regRowid);
- }else{
- Index *pPk = sqlite3PrimaryKeyIndex(pIdx->pTable);
- int j, k, regKey;
- regKey = sqlite3GetTempRange(pParse, pPk->nKeyCol);
- for(j=0; j<pPk->nKeyCol; j++){
- k = sqlite3TableColumnToIndex(pIdx, pPk->aiColumn[j]);
- assert( k>=0 && k<pIdx->nColumn );
- sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, k, regKey+j);
- VdbeComment((v, "%s", pTab->aCol[pPk->aiColumn[j]].zName));
+ if( OptimizationEnabled(db, SQLITE_Stat4) ){
+ assert( regRowid==(regStat+2) );
+ if( HasRowid(pTab) ){
+ sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdxCur, regRowid);
+ }else{
+ Index *pPk = sqlite3PrimaryKeyIndex(pIdx->pTable);
+ int j, k, regKey;
+ regKey = sqlite3GetTempRange(pParse, pPk->nKeyCol);
+ for(j=0; j<pPk->nKeyCol; j++){
+ k = sqlite3TableColumnToIndex(pIdx, pPk->aiColumn[j]);
+ assert( k>=0 && k<pIdx->nColumn );
+ sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, k, regKey+j);
+ analyzeVdbeCommentIndexWithColumnName(v,pIdx,k);
+ }
+ sqlite3VdbeAddOp3(v, OP_MakeRecord, regKey, pPk->nKeyCol, regRowid);
+ sqlite3ReleaseTempRange(pParse, regKey, pPk->nKeyCol);
}
- sqlite3VdbeAddOp3(v, OP_MakeRecord, regKey, pPk->nKeyCol, regRowid);
- sqlite3ReleaseTempRange(pParse, regKey, pPk->nKeyCol);
}
#endif
- assert( regChng==(regStat4+1) );
- sqlite3VdbeAddFunctionCall(pParse, 1, regStat4, regTemp, 2+IsStat4,
- &statPushFuncdef, 0);
- sqlite3VdbeAddOp2(v, OP_Next, iIdxCur, addrNextRow); VdbeCoverage(v);
+ assert( regChng==(regStat+1) );
+ {
+ sqlite3VdbeAddFunctionCall(pParse, 1, regStat, regTemp, 2+IsStat4,
+ &statPushFuncdef, 0);
+ if( db->nAnalysisLimit ){
+ int j1, j2, j3;
+ j1 = sqlite3VdbeAddOp1(v, OP_IsNull, regTemp); VdbeCoverage(v);
+ j2 = sqlite3VdbeAddOp1(v, OP_If, regTemp); VdbeCoverage(v);
+ j3 = sqlite3VdbeAddOp4Int(v, OP_SeekGT, iIdxCur, 0, regPrev, 1);
+ VdbeCoverage(v);
+ sqlite3VdbeJumpHere(v, j1);
+ sqlite3VdbeAddOp2(v, OP_Next, iIdxCur, addrNextRow); VdbeCoverage(v);
+ sqlite3VdbeJumpHere(v, j2);
+ sqlite3VdbeJumpHere(v, j3);
+ }else{
+ sqlite3VdbeAddOp2(v, OP_Next, iIdxCur, addrNextRow); VdbeCoverage(v);
+ }
+ }
/* Add the entry to the stat1 table. */
- callStatGet(pParse, regStat4, STAT_GET_STAT1, regStat1);
+ callStatGet(pParse, regStat, STAT_GET_STAT1, regStat1);
assert( "BBB"[0]==SQLITE_AFF_TEXT );
sqlite3VdbeAddOp4(v, OP_MakeRecord, regTabname, 3, regTemp, "BBB", 0);
sqlite3VdbeAddOp2(v, OP_NewRowid, iStatCur, regNewRowid);
@@ -1206,7 +1277,7 @@ static void analyzeOneTable(
/* Add the entries to the stat4 table. */
#ifdef SQLITE_ENABLE_STAT4
- {
+ if( OptimizationEnabled(db, SQLITE_Stat4) && db->nAnalysisLimit==0 ){
int regEq = regStat1;
int regLt = regStat1+1;
int regDLt = regStat1+2;
@@ -1220,12 +1291,12 @@ static void analyzeOneTable(
pParse->nMem = MAX(pParse->nMem, regCol+nCol);
addrNext = sqlite3VdbeCurrentAddr(v);
- callStatGet(pParse, regStat4, STAT_GET_ROWID, regSampleRowid);
+ callStatGet(pParse, regStat, STAT_GET_ROWID, regSampleRowid);
addrIsNull = sqlite3VdbeAddOp1(v, OP_IsNull, regSampleRowid);
VdbeCoverage(v);
- callStatGet(pParse, regStat4, STAT_GET_NEQ, regEq);
- callStatGet(pParse, regStat4, STAT_GET_NLT, regLt);
- callStatGet(pParse, regStat4, STAT_GET_NDLT, regDLt);
+ callStatGet(pParse, regStat, STAT_GET_NEQ, regEq);
+ callStatGet(pParse, regStat, STAT_GET_NLT, regLt);
+ callStatGet(pParse, regStat, STAT_GET_NDLT, regDLt);
sqlite3VdbeAddOp4Int(v, seekOp, iTabCur, addrNext, regSampleRowid, 0);
VdbeCoverage(v);
for(i=0; i<nCol; i++){
diff --git a/src/backup.c b/src/backup.c
index 233d0cee7..77e7ed950 100644
--- a/src/backup.c
+++ b/src/backup.c
@@ -112,7 +112,7 @@ static Btree *findBtree(sqlite3 *pErrorDb, sqlite3 *pDb, const char *zDb){
*/
static int setDestPgsz(sqlite3_backup *p){
int rc;
- rc = sqlite3BtreeSetPageSize(p->pDest,sqlite3BtreeGetPageSize(p->pSrc),-1,0);
+ rc = sqlite3BtreeSetPageSize(p->pDest,sqlite3BtreeGetPageSize(p->pSrc),0,0);
return rc;
}
diff --git a/src/btree.c b/src/btree.c
index abe0b844f..76069a33e 100644
--- a/src/btree.c
+++ b/src/btree.c
@@ -69,7 +69,7 @@ int sqlite3BtreeTrace=1; /* True to enable tracing */
** but the test harness needs to access it so we make it global for
** test builds.
**
-** Access to this variable is protected by SQLITE_MUTEX_STATIC_MASTER.
+** Access to this variable is protected by SQLITE_MUTEX_STATIC_MAIN.
*/
#ifdef SQLITE_TEST
BtShared *SQLITE_WSD sqlite3SharedCacheList = 0;
@@ -200,16 +200,18 @@ static int hasSharedCacheTableLock(
** table. */
if( isIndex ){
HashElem *p;
+ int bSeen = 0;
for(p=sqliteHashFirst(&pSchema->idxHash); p; p=sqliteHashNext(p)){
Index *pIdx = (Index *)sqliteHashData(p);
if( pIdx->tnum==(int)iRoot ){
- if( iTab ){
+ if( bSeen ){
/* Two or more indexes share the same root page. There must
** be imposter tables. So just return true. The assert is not
** useful in that case. */
return 1;
}
iTab = pIdx->pTable->tnum;
+ bSeen = 1;
}
}
}else{
@@ -355,7 +357,7 @@ static int setSharedCacheTableLock(Btree *p, Pgno iTable, u8 eLock){
/* A connection with the read-uncommitted flag set will never try to
** obtain a read-lock using this function. The only read-lock obtained
- ** by a connection in read-uncommitted mode is on the sqlite_master
+ ** by a connection in read-uncommitted mode is on the sqlite_schema
** table, and that lock is obtained in BtreeBeginTrans(). */
assert( 0==(p->db->flags&SQLITE_ReadUncommit) || eLock==WRITE_LOCK );
@@ -991,7 +993,7 @@ static void ptrmapPut(BtShared *pBt, Pgno key, u8 eType, Pgno parent, int *pRC){
if( *pRC ) return;
assert( sqlite3_mutex_held(pBt->mutex) );
- /* The master-journal page number must never be used as a pointer map page */
+ /* The super-journal page number must never be used as a pointer map page */
assert( 0==PTRMAP_ISPAGE(pBt, PENDING_BYTE_PAGE(pBt)) );
assert( pBt->autoVacuum );
@@ -1751,7 +1753,7 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
nFrag = iFreeBlk - iEnd;
if( iEnd>iFreeBlk ) return SQLITE_CORRUPT_PAGE(pPage);
iEnd = iFreeBlk + get2byte(&data[iFreeBlk+2]);
- if( NEVER(iEnd > pPage->pBt->usableSize) ){
+ if( iEnd > pPage->pBt->usableSize ){
return SQLITE_CORRUPT_PAGE(pPage);
}
iSize = iEnd - iStart;
@@ -2304,8 +2306,7 @@ static int btreeInvokeBusyHandler(void *pArg){
BtShared *pBt = (BtShared*)pArg;
assert( pBt->db );
assert( sqlite3_mutex_held(pBt->db->mutex) );
- return sqlite3InvokeBusyHandler(&pBt->db->busyHandler,
- sqlite3PagerFile(pBt->pPager));
+ return sqlite3InvokeBusyHandler(&pBt->db->busyHandler);
}
/*
@@ -2421,7 +2422,7 @@ int sqlite3BtreeOpen(
#if SQLITE_THREADSAFE
mutexOpen = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_OPEN);
sqlite3_mutex_enter(mutexOpen);
- mutexShared = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
+ mutexShared = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN);
sqlite3_mutex_enter(mutexShared);
#endif
for(pBt=GLOBAL(BtShared*,sqlite3SharedCacheList); pBt; pBt=pBt->pNext){
@@ -2540,7 +2541,7 @@ int sqlite3BtreeOpen(
pBt->nRef = 1;
if( p->sharable ){
MUTEX_LOGIC( sqlite3_mutex *mutexShared; )
- MUTEX_LOGIC( mutexShared = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);)
+ MUTEX_LOGIC( mutexShared = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN);)
if( SQLITE_THREADSAFE && sqlite3GlobalConfig.bCoreMutex ){
pBt->mutex = sqlite3MutexAlloc(SQLITE_MUTEX_FAST);
if( pBt->mutex==0 ){
@@ -2629,13 +2630,13 @@ btree_open_out:
*/
static int removeFromSharingList(BtShared *pBt){
#ifndef SQLITE_OMIT_SHARED_CACHE
- MUTEX_LOGIC( sqlite3_mutex *pMaster; )
+ MUTEX_LOGIC( sqlite3_mutex *pMainMtx; )
BtShared *pList;
int removed = 0;
assert( sqlite3_mutex_notheld(pBt->mutex) );
- MUTEX_LOGIC( pMaster = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); )
- sqlite3_mutex_enter(pMaster);
+ MUTEX_LOGIC( pMainMtx = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN); )
+ sqlite3_mutex_enter(pMainMtx);
pBt->nRef--;
if( pBt->nRef<=0 ){
if( GLOBAL(BtShared*,sqlite3SharedCacheList)==pBt ){
@@ -2654,7 +2655,7 @@ static int removeFromSharingList(BtShared *pBt){
}
removed = 1;
}
- sqlite3_mutex_leave(pMaster);
+ sqlite3_mutex_leave(pMainMtx);
return removed;
#else
return 1;
@@ -2856,19 +2857,17 @@ int sqlite3BtreeSetPagerFlags(
*/
int sqlite3BtreeSetPageSize(Btree *p, int pageSize, int nReserve, int iFix){
int rc = SQLITE_OK;
+ int x;
BtShared *pBt = p->pBt;
- assert( nReserve>=-1 && nReserve<=254 );
+ assert( nReserve>=0 && nReserve<=255 );
sqlite3BtreeEnter(p);
- if( nReserve>=0 ){
- pBt->nReserveWanted = nReserve + 1;
- }
+ pBt->nReserveWanted = nReserve;
+ x = pBt->pageSize - pBt->usableSize;
+ if( nReserve<x ) nReserve = x;
if( pBt->btsFlags & BTS_PAGESIZE_FIXED ){
sqlite3BtreeLeave(p);
return SQLITE_READONLY;
}
- if( nReserve<0 ){
- nReserve = pBt->pageSize - pBt->usableSize;
- }
assert( nReserve>=0 && nReserve<=255 );
if( pageSize>=512 && pageSize<=SQLITE_MAX_PAGE_SIZE &&
((pageSize-1)&pageSize)==0 ){
@@ -2919,12 +2918,12 @@ int sqlite3BtreeGetReserveNoMutex(Btree *p){
** The amount of reserve can only grow - never shrink.
*/
int sqlite3BtreeGetRequestedReserve(Btree *p){
- int n;
+ int n1, n2;
sqlite3BtreeEnter(p);
- n = ((int)p->pBt->nReserveWanted) - 1;
- if( n<0 ) n = sqlite3BtreeGetReserveNoMutex(p);
+ n1 = (int)p->pBt->nReserveWanted;
+ n2 = sqlite3BtreeGetReserveNoMutex(p);
sqlite3BtreeLeave(p);
- return n;
+ return n1>n2 ? n1 : n2;
}
@@ -3374,6 +3373,7 @@ int sqlite3BtreeNewDb(Btree *p){
*/
int sqlite3BtreeBeginTrans(Btree *p, int wrflag, int *pSchemaVersion){
BtShared *pBt = p->pBt;
+ Pager *pPager = pBt->pPager;
int rc = SQLITE_OK;
sqlite3BtreeEnter(p);
@@ -3389,7 +3389,7 @@ int sqlite3BtreeBeginTrans(Btree *p, int wrflag, int *pSchemaVersion){
assert( pBt->inTransaction==TRANS_WRITE || IfNotOmitAV(pBt->bDoTruncate)==0 );
if( (p->db->flags & SQLITE_ResetDatabase)
- && sqlite3PagerIsreadonly(pBt->pPager)==0
+ && sqlite3PagerIsreadonly(pPager)==0
){
pBt->btsFlags &= ~BTS_READ_ONLY;
}
@@ -3431,12 +3431,24 @@ int sqlite3BtreeBeginTrans(Btree *p, int wrflag, int *pSchemaVersion){
/* Any read-only or read-write transaction implies a read-lock on
** page 1. So if some other shared-cache client already has a write-lock
** on page 1, the transaction cannot be opened. */
- rc = querySharedCacheTableLock(p, MASTER_ROOT, READ_LOCK);
+ rc = querySharedCacheTableLock(p, SCHEMA_ROOT, READ_LOCK);
if( SQLITE_OK!=rc ) goto trans_begun;
pBt->btsFlags &= ~BTS_INITIALLY_EMPTY;
if( pBt->nPage==0 ) pBt->btsFlags |= BTS_INITIALLY_EMPTY;
do {
+ sqlite3PagerWalDb(pPager, p->db);
+
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+ /* If transitioning from no transaction directly to a write transaction,
+ ** block for the WRITER lock first if possible. */
+ if( pBt->pPage1==0 && wrflag ){
+ assert( pBt->inTransaction==TRANS_NONE );
+ rc = sqlite3PagerWalWriteLock(pPager, 1);
+ if( rc!=SQLITE_BUSY && rc!=SQLITE_OK ) break;
+ }
+#endif
+
/* Call lockBtree() until either pBt->pPage1 is populated or
** lockBtree() returns something other than SQLITE_OK. lockBtree()
** may return SQLITE_OK but leave pBt->pPage1 set to 0 if after
@@ -3450,7 +3462,7 @@ int sqlite3BtreeBeginTrans(Btree *p, int wrflag, int *pSchemaVersion){
if( (pBt->btsFlags & BTS_READ_ONLY)!=0 ){
rc = SQLITE_READONLY;
}else{
- rc = sqlite3PagerBegin(pBt->pPager,wrflag>1,sqlite3TempInMemory(p->db));
+ rc = sqlite3PagerBegin(pPager, wrflag>1, sqlite3TempInMemory(p->db));
if( rc==SQLITE_OK ){
rc = newDatabase(pBt);
}else if( rc==SQLITE_BUSY_SNAPSHOT && pBt->inTransaction==TRANS_NONE ){
@@ -3463,11 +3475,15 @@ int sqlite3BtreeBeginTrans(Btree *p, int wrflag, int *pSchemaVersion){
}
if( rc!=SQLITE_OK ){
+ (void)sqlite3PagerWalWriteLock(pPager, 0);
unlockBtreeIfUnused(pBt);
}
}while( (rc&0xFF)==SQLITE_BUSY && pBt->inTransaction==TRANS_NONE &&
btreeInvokeBusyHandler(pBt) );
- sqlite3PagerResetLockTimeout(pBt->pPager);
+ sqlite3PagerWalDb(pPager, 0);
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+ if( rc==SQLITE_BUSY_TIMEOUT ) rc = SQLITE_BUSY;
+#endif
if( rc==SQLITE_OK ){
if( p->inTrans==TRANS_NONE ){
@@ -3519,7 +3535,7 @@ trans_begun:
** open savepoints. If the second parameter is greater than 0 and
** the sub-journal is not already open, then it will be opened here.
*/
- rc = sqlite3PagerOpenSavepoint(pBt->pPager, p->db->nSavepoint);
+ rc = sqlite3PagerOpenSavepoint(pPager, p->db->nSavepoint);
}
}
@@ -3967,18 +3983,18 @@ static int autoVacuumCommit(BtShared *pBt){
**
** This call is a no-op if no write-transaction is currently active on pBt.
**
-** Otherwise, sync the database file for the btree pBt. zMaster points to
-** the name of a master journal file that should be written into the
-** individual journal file, or is NULL, indicating no master journal file
+** Otherwise, sync the database file for the btree pBt. zSuperJrnl points to
+** the name of a super-journal file that should be written into the
+** individual journal file, or is NULL, indicating no super-journal file
** (single database transaction).
**
-** When this is called, the master journal should already have been
+** When this is called, the super-journal should already have been
** created, populated with this journal pointer and synced to disk.
**
** Once this is routine has returned, the only thing required to commit
** the write-transaction for this database file is to delete the journal.
*/
-int sqlite3BtreeCommitPhaseOne(Btree *p, const char *zMaster){
+int sqlite3BtreeCommitPhaseOne(Btree *p, const char *zSuperJrnl){
int rc = SQLITE_OK;
if( p->inTrans==TRANS_WRITE ){
BtShared *pBt = p->pBt;
@@ -3995,7 +4011,7 @@ int sqlite3BtreeCommitPhaseOne(Btree *p, const char *zMaster){
sqlite3PagerTruncateImage(pBt->pPager, pBt->nPage);
}
#endif
- rc = sqlite3PagerCommitPhaseOne(pBt->pPager, zMaster, 0);
+ rc = sqlite3PagerCommitPhaseOne(pBt->pPager, zSuperJrnl, 0);
sqlite3BtreeLeave(p);
}
return rc;
@@ -4058,7 +4074,7 @@ static void btreeEndTransaction(Btree *p){
** the upper layer will attempt a rollback. However, if the second argument
** is non-zero then this b-tree transaction is part of a multi-file
** transaction. In this case, the transaction has already been committed
-** (by deleting a master journal file) and the caller will ignore this
+** (by deleting a super-journal file) and the caller will ignore this
** functions return code. So, even if an error occurs in the pager layer,
** reset the b-tree objects internal state to indicate that the write
** transaction has been closed. This is quite safe, as the pager will have
@@ -7155,7 +7171,7 @@ static int editPage(
assert( nCell>=0 );
if( iOld<iNew ){
int nShift = pageFreeArray(pPg, iOld, iNew-iOld, pCArray);
- if( nShift>nCell ) return SQLITE_CORRUPT_BKPT;
+ if( NEVER(nShift>nCell) ) return SQLITE_CORRUPT_BKPT;
memmove(pPg->aCellIdx, &pPg->aCellIdx[nShift*2], nCell*2);
nCell -= nShift;
}
@@ -8756,7 +8772,11 @@ int sqlite3BtreeInsert(
assert( pPage->intKey || pX->nKey>=0 );
assert( pPage->leaf || !pPage->intKey );
if( pPage->nFree<0 ){
- rc = btreeComputeFreeSpace(pPage);
+ if( pCur->eState>CURSOR_INVALID ){
+ rc = SQLITE_CORRUPT_BKPT;
+ }else{
+ rc = btreeComputeFreeSpace(pPage);
+ }
if( rc ) return rc;
}
@@ -9463,7 +9483,7 @@ void sqlite3BtreeGetMeta(Btree *p, int idx, u32 *pMeta){
sqlite3BtreeEnter(p);
assert( p->inTrans>TRANS_NONE );
- assert( SQLITE_OK==querySharedCacheTableLock(p, MASTER_ROOT, READ_LOCK) );
+ assert( SQLITE_OK==querySharedCacheTableLock(p, SCHEMA_ROOT, READ_LOCK) );
assert( pBt->pPage1 );
assert( idx>=0 && idx<=15 );
@@ -9512,7 +9532,6 @@ int sqlite3BtreeUpdateMeta(Btree *p, int idx, u32 iMeta){
return rc;
}
-#ifndef SQLITE_OMIT_BTREECOUNT
/*
** The first argument, pCur, is a cursor opened on some b-tree. Count the
** number of entries in the b-tree and write the result to *pnEntry.
@@ -9585,7 +9604,6 @@ int sqlite3BtreeCount(sqlite3 *db, BtCursor *pCur, i64 *pnEntry){
/* An error has occurred. Return an error code. */
return rc;
}
-#endif
/*
** Return the pager associated with a BTree. This routine is used for
@@ -9618,7 +9636,7 @@ static void checkAppendMsg(
sqlite3_str_vappendf(&pCheck->errMsg, zFormat, ap);
va_end(ap);
if( pCheck->errMsg.accError==SQLITE_NOMEM ){
- pCheck->mallocFailed = 1;
+ pCheck->bOomFault = 1;
}
}
#endif /* SQLITE_OMIT_INTEGRITY_CHECK */
@@ -9683,7 +9701,7 @@ static void checkPtrmap(
rc = ptrmapGet(pCheck->pBt, iChild, &ePtrmapType, &iPtrmapParent);
if( rc!=SQLITE_OK ){
- if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ) pCheck->mallocFailed = 1;
+ if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ) pCheck->bOomFault = 1;
checkAppendMsg(pCheck, "Failed to read ptrmap key=%d", iChild);
return;
}
@@ -10128,7 +10146,7 @@ char *sqlite3BtreeIntegrityCheck(
sCheck.nPage = btreePagecount(sCheck.pBt);
sCheck.mxErr = mxErr;
sCheck.nErr = 0;
- sCheck.mallocFailed = 0;
+ sCheck.bOomFault = 0;
sCheck.zPfx = 0;
sCheck.v1 = 0;
sCheck.v2 = 0;
@@ -10142,12 +10160,12 @@ char *sqlite3BtreeIntegrityCheck(
sCheck.aPgRef = sqlite3MallocZero((sCheck.nPage / 8)+ 1);
if( !sCheck.aPgRef ){
- sCheck.mallocFailed = 1;
+ sCheck.bOomFault = 1;
goto integrity_ck_cleanup;
}
sCheck.heap = (u32*)sqlite3PageMalloc( pBt->pageSize );
if( sCheck.heap==0 ){
- sCheck.mallocFailed = 1;
+ sCheck.bOomFault = 1;
goto integrity_ck_cleanup;
}
@@ -10222,7 +10240,7 @@ char *sqlite3BtreeIntegrityCheck(
integrity_ck_cleanup:
sqlite3PageFree(sCheck.heap);
sqlite3_free(sCheck.aPgRef);
- if( sCheck.mallocFailed ){
+ if( sCheck.bOomFault ){
sqlite3_str_reset(&sCheck.errMsg);
sCheck.nErr++;
}
@@ -10342,13 +10360,13 @@ void *sqlite3BtreeSchema(Btree *p, int nBytes, void(*xFree)(void *)){
/*
** Return SQLITE_LOCKED_SHAREDCACHE if another user of the same shared
** btree as the argument handle holds an exclusive lock on the
-** sqlite_master table. Otherwise SQLITE_OK.
+** sqlite_schema table. Otherwise SQLITE_OK.
*/
int sqlite3BtreeSchemaLocked(Btree *p){
int rc;
assert( sqlite3_mutex_held(p->db->mutex) );
sqlite3BtreeEnter(p);
- rc = querySharedCacheTableLock(p, MASTER_ROOT, READ_LOCK);
+ rc = querySharedCacheTableLock(p, SCHEMA_ROOT, READ_LOCK);
assert( rc==SQLITE_OK || rc==SQLITE_LOCKED_SHAREDCACHE );
sqlite3BtreeLeave(p);
return rc;
diff --git a/src/btree.h b/src/btree.h
index 680742a21..53f915879 100644
--- a/src/btree.h
+++ b/src/btree.h
@@ -79,7 +79,7 @@ int sqlite3BtreeGetReserveNoMutex(Btree *p);
int sqlite3BtreeSetAutoVacuum(Btree *, int);
int sqlite3BtreeGetAutoVacuum(Btree *);
int sqlite3BtreeBeginTrans(Btree*,int,int*);
-int sqlite3BtreeCommitPhaseOne(Btree*, const char *zMaster);
+int sqlite3BtreeCommitPhaseOne(Btree*, const char*);
int sqlite3BtreeCommitPhaseTwo(Btree*, int);
int sqlite3BtreeCommit(Btree*);
int sqlite3BtreeRollback(Btree*,int,int);
@@ -336,9 +336,7 @@ int sqlite3BtreeCursorIsValid(BtCursor*);
#endif
int sqlite3BtreeCursorIsValidNN(BtCursor*);
-#ifndef SQLITE_OMIT_BTREECOUNT
int sqlite3BtreeCount(sqlite3*, BtCursor*, i64*);
-#endif
#ifdef SQLITE_TEST
int sqlite3BtreeCursorInfo(BtCursor*, int*, int);
diff --git a/src/btreeInt.h b/src/btreeInt.h
index 34b33096b..faa726a6c 100644
--- a/src/btreeInt.h
+++ b/src/btreeInt.h
@@ -381,7 +381,7 @@ struct Btree {
**
** Fields in this structure are accessed under the BtShared.mutex
** mutex, except for nRef and pNext which are accessed under the
-** global SQLITE_MUTEX_STATIC_MASTER mutex. The pPager field
+** global SQLITE_MUTEX_STATIC_MAIN mutex. The pPager field
** may not be modified once it is initially set as long as nRef>0.
** The pSchema field may be set once under BtShared.mutex and
** thereafter is unchanged as long as nRef>0.
@@ -417,7 +417,7 @@ struct BtShared {
#endif
u8 inTransaction; /* Transaction state */
u8 max1bytePayload; /* Maximum first byte of cell for a 1-byte payload */
- u8 nReserveWanted; /* 1 more than desired number of extra bytes per page */
+ u8 nReserveWanted; /* Desired number of extra bytes per page */
u16 btsFlags; /* Boolean parameters. See BTS_* macros below */
u16 maxLocal; /* Maximum local payload in non-LEAFDATA tables */
u16 minLocal; /* Minimum local payload in non-LEAFDATA tables */
@@ -679,7 +679,7 @@ struct IntegrityCk {
Pgno nPage; /* Number of pages in the database */
int mxErr; /* Stop accumulating errors when this reaches zero */
int nErr; /* Number of messages written to zErrMsg so far */
- int mallocFailed; /* A memory allocation error has occurred */
+ int bOomFault; /* A memory allocation error has occurred */
const char *zPfx; /* Error message prefix */
int v1, v2; /* Values for up to two %d fields in zPfx */
StrAccum errMsg; /* Accumulate the error message text here */
diff --git a/src/build.c b/src/build.c
index c9396708d..0f331c21b 100644
--- a/src/build.c
+++ b/src/build.c
@@ -207,12 +207,21 @@ void sqlite3FinishCoding(Parse *pParse){
*/
sqlite3AutoincrementBegin(pParse);
- /* Code constant expressions that where factored out of inner loops */
+ /* Code constant expressions that where factored out of inner loops.
+ **
+ ** The pConstExpr list might also contain expressions that we simply
+ ** want to keep around until the Parse object is deleted. Such
+ ** expressions have iConstExprReg==0. Do not generate code for
+ ** those expressions, of course.
+ */
if( pParse->pConstExpr ){
ExprList *pEL = pParse->pConstExpr;
pParse->okConstFactor = 0;
for(i=0; i<pEL->nExpr; i++){
- sqlite3ExprCode(pParse, pEL->a[i].pExpr, pEL->a[i].u.iConstExprReg);
+ int iReg = pEL->a[i].u.iConstExprReg;
+ if( iReg>0 ){
+ sqlite3ExprCode(pParse, pEL->a[i].pExpr, iReg);
+ }
}
}
@@ -244,7 +253,7 @@ void sqlite3FinishCoding(Parse *pParse){
** outermost parser.
**
** Not everything is nestable. This facility is designed to permit
-** INSERT, UPDATE, and DELETE operations against SQLITE_MASTER. Use
+** INSERT, UPDATE, and DELETE operations against the schema table. Use
** care if you decide to try to use this routine for some other purposes.
*/
void sqlite3NestedParse(Parse *pParse, const char *zFormat, ...){
@@ -312,22 +321,59 @@ Table *sqlite3FindTable(sqlite3 *db, const char *zName, const char *zDatabase){
return 0;
}
#endif
- while(1){
- for(i=OMIT_TEMPDB; i<db->nDb; i++){
- int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */
- if( zDatabase==0 || sqlite3DbIsNamed(db, j, zDatabase) ){
- assert( sqlite3SchemaMutexHeld(db, j, 0) );
- p = sqlite3HashFind(&db->aDb[j].pSchema->tblHash, zName);
- if( p ) return p;
+ if( zDatabase ){
+ for(i=0; i<db->nDb; i++){
+ if( sqlite3StrICmp(zDatabase, db->aDb[i].zDbSName)==0 ) break;
+ }
+ if( i>=db->nDb ){
+ /* No match against the official names. But always match "main"
+ ** to schema 0 as a legacy fallback. */
+ if( sqlite3StrICmp(zDatabase,"main")==0 ){
+ i = 0;
+ }else{
+ return 0;
+ }
+ }
+ p = sqlite3HashFind(&db->aDb[i].pSchema->tblHash, zName);
+ if( p==0 && sqlite3StrNICmp(zName, "sqlite_", 7)==0 ){
+ if( i==1 ){
+ if( sqlite3StrICmp(zName+7, &ALT_TEMP_SCHEMA_TABLE[7])==0
+ || sqlite3StrICmp(zName+7, &ALT_SCHEMA_TABLE[7])==0
+ || sqlite3StrICmp(zName+7, &DFLT_SCHEMA_TABLE[7])==0
+ ){
+ p = sqlite3HashFind(&db->aDb[1].pSchema->tblHash,
+ DFLT_TEMP_SCHEMA_TABLE);
+ }
+ }else{
+ if( sqlite3StrICmp(zName+7, &ALT_SCHEMA_TABLE[7])==0 ){
+ p = sqlite3HashFind(&db->aDb[i].pSchema->tblHash,
+ DFLT_SCHEMA_TABLE);
+ }
+ }
+ }
+ }else{
+ /* Match against TEMP first */
+ p = sqlite3HashFind(&db->aDb[1].pSchema->tblHash, zName);
+ if( p ) return p;
+ /* The main database is second */
+ p = sqlite3HashFind(&db->aDb[0].pSchema->tblHash, zName);
+ if( p ) return p;
+ /* Attached databases are in order of attachment */
+ for(i=2; i<db->nDb; i++){
+ assert( sqlite3SchemaMutexHeld(db, i, 0) );
+ p = sqlite3HashFind(&db->aDb[i].pSchema->tblHash, zName);
+ if( p ) break;
+ }
+ if( p==0 && sqlite3StrNICmp(zName, "sqlite_", 7)==0 ){
+ if( sqlite3StrICmp(zName+7, &ALT_SCHEMA_TABLE[7])==0 ){
+ p = sqlite3HashFind(&db->aDb[0].pSchema->tblHash, DFLT_SCHEMA_TABLE);
+ }else if( sqlite3StrICmp(zName+7, &ALT_TEMP_SCHEMA_TABLE[7])==0 ){
+ p = sqlite3HashFind(&db->aDb[1].pSchema->tblHash,
+ DFLT_TEMP_SCHEMA_TABLE);
}
}
- /* Not found. If the name we were looking for was temp.sqlite_master
- ** then change the name to sqlite_temp_master and try again. */
- if( sqlite3StrICmp(zName, MASTER_NAME)!=0 ) break;
- if( sqlite3_stricmp(zDatabase, db->aDb[1].zDbSName)!=0 ) break;
- zName = TEMP_MASTER_NAME;
}
- return 0;
+ return p;
}
/*
@@ -717,13 +763,13 @@ char *sqlite3NameFromToken(sqlite3 *db, Token *pName){
}
/*
-** Open the sqlite_master table stored in database number iDb for
+** Open the sqlite_schema table stored in database number iDb for
** writing. The table is opened using cursor 0.
*/
-void sqlite3OpenMasterTable(Parse *p, int iDb){
+void sqlite3OpenSchemaTable(Parse *p, int iDb){
Vdbe *v = sqlite3GetVdbe(p);
- sqlite3TableLock(p, iDb, MASTER_ROOT, 1, MASTER_NAME);
- sqlite3VdbeAddOp4Int(v, OP_OpenWrite, 0, MASTER_ROOT, iDb, 5);
+ sqlite3TableLock(p, iDb, SCHEMA_ROOT, 1, DFLT_SCHEMA_TABLE);
+ sqlite3VdbeAddOp4Int(v, OP_OpenWrite, 0, SCHEMA_ROOT, iDb, 5);
if( p->nTab==0 ){
p->nTab = 1;
}
@@ -831,7 +877,7 @@ int sqlite3WritableSchema(sqlite3 *db){
** "sqlite_" (in upper, lower or mixed case). This portion of the namespace
** is reserved for internal use.
**
-** When parsing the sqlite_master table, this routine also checks to
+** When parsing the sqlite_schema table, this routine also checks to
** make sure the "type", "name", and "tbl_name" columns are consistent
** with the SQL.
*/
@@ -1003,7 +1049,7 @@ void sqlite3StartTable(
Token *pName; /* Unqualified name of the table to create */
if( db->init.busy && db->init.newTnum==1 ){
- /* Special case: Parsing the sqlite_master or sqlite_temp_master schema */
+ /* Special case: Parsing the sqlite_schema or sqlite_temp_schema schema */
iDb = db->init.iDb;
zName = sqlite3DbStrDup(db, SCHEMA_TABLE(iDb));
pName = pName1;
@@ -1109,7 +1155,7 @@ void sqlite3StartTable(
#endif
/* Begin generating the code that will insert the table record into
- ** the SQLITE_MASTER table. Note in particular that we must go ahead
+ ** the schema table. Note in particular that we must go ahead
** and allocate the record number for the table entry now. Before any
** PRIMARY KEY or UNIQUE keywords are parsed. Those keywords will cause
** indices to be created and the table record must come before the
@@ -1145,7 +1191,7 @@ void sqlite3StartTable(
sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_TEXT_ENCODING, ENC(db));
sqlite3VdbeJumpHere(v, addr1);
- /* This just creates a place-holder record in the sqlite_master table.
+ /* This just creates a place-holder record in the sqlite_schema table.
** The record created does not contain anything yet. It will be replaced
** by the real entry in code generated at sqlite3EndTable().
**
@@ -1163,7 +1209,7 @@ void sqlite3StartTable(
pParse->addrCrTab =
sqlite3VdbeAddOp3(v, OP_CreateBtree, iDb, reg2, BTREE_INTKEY);
}
- sqlite3OpenMasterTable(pParse, iDb);
+ sqlite3OpenSchemaTable(pParse, iDb);
sqlite3VdbeAddOp2(v, OP_NewRowid, 0, reg1);
sqlite3VdbeAddOp4(v, OP_Blob, 6, reg3, 0, nullRow, P4_STATIC);
sqlite3VdbeAddOp3(v, OP_Insert, 0, reg3, reg1);
@@ -1973,9 +2019,9 @@ static void recomputeColumnsNotIndexed(Index *pIdx){
** (1) Set all columns of the PRIMARY KEY schema object to be NOT NULL.
** (2) Convert P3 parameter of the OP_CreateBtree from BTREE_INTKEY
** into BTREE_BLOBKEY.
-** (3) Bypass the creation of the sqlite_master table entry
+** (3) Bypass the creation of the sqlite_schema table entry
** for the PRIMARY KEY as the primary key index is now
-** identified by the sqlite_master table entry of the table itself.
+** identified by the sqlite_schema table entry of the table itself.
** (4) Set the Index.tnum of the PRIMARY KEY Index object in the
** schema to the rootpage from the main table.
** (5) Add all table columns to the PRIMARY KEY Index object
@@ -2062,7 +2108,7 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
if( !db->init.imposterTable ) pPk->uniqNotNull = 1;
nPk = pPk->nColumn = pPk->nKeyCol;
- /* Bypass the creation of the PRIMARY KEY btree and the sqlite_master
+ /* Bypass the creation of the PRIMARY KEY btree and the sqlite_schema
** table entry. This is only required if currently generating VDBE
** code for a CREATE TABLE (not when parsing one as part of reading
** a database schema). */
@@ -2131,6 +2177,28 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
recomputeColumnsNotIndexed(pPk);
}
+
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+/*
+** Return true if pTab is a virtual table and zName is a shadow table name
+** for that virtual table.
+*/
+int sqlite3IsShadowTableOf(sqlite3 *db, Table *pTab, const char *zName){
+ int nName; /* Length of zName */
+ Module *pMod; /* Module for the virtual table */
+
+ if( !IsVirtual(pTab) ) return 0;
+ nName = sqlite3Strlen30(pTab->zName);
+ if( sqlite3_strnicmp(zName, pTab->zName, nName)!=0 ) return 0;
+ if( zName[nName]!='_' ) return 0;
+ pMod = (Module*)sqlite3HashFind(&db->aModule, pTab->azModuleArg[0]);
+ if( pMod==0 ) return 0;
+ if( pMod->pModule->iVersion<3 ) return 0;
+ if( pMod->pModule->xShadowName==0 ) return 0;
+ return pMod->pModule->xShadowName(zName+nName+1);
+}
+#endif /* ifndef SQLITE_OMIT_VIRTUALTABLE */
+
#ifndef SQLITE_OMIT_VIRTUALTABLE
/*
** Return true if zName is a shadow table name in the current database
@@ -2142,8 +2210,6 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
int sqlite3ShadowTableName(sqlite3 *db, const char *zName){
char *zTail; /* Pointer to the last "_" in zName */
Table *pTab; /* Table that zName is a shadow of */
- Module *pMod; /* Module for the virtual table */
-
zTail = strrchr(zName, '_');
if( zTail==0 ) return 0;
*zTail = 0;
@@ -2151,14 +2217,11 @@ int sqlite3ShadowTableName(sqlite3 *db, const char *zName){
*zTail = '_';
if( pTab==0 ) return 0;
if( !IsVirtual(pTab) ) return 0;
- pMod = (Module*)sqlite3HashFind(&db->aModule, pTab->azModuleArg[0]);
- if( pMod==0 ) return 0;
- if( pMod->pModule->iVersion<3 ) return 0;
- if( pMod->pModule->xShadowName==0 ) return 0;
- return pMod->pModule->xShadowName(zTail+1);
+ return sqlite3IsShadowTableOf(db, pTab, zName);
}
#endif /* ifndef SQLITE_OMIT_VIRTUALTABLE */
+
#ifdef SQLITE_DEBUG
/*
** Mark all nodes of an expression as EP_Immutable, indicating that
@@ -2193,12 +2256,12 @@ static void markExprListImmutable(ExprList *pList){
** is added to the internal hash tables, assuming no errors have
** occurred.
**
-** An entry for the table is made in the master table on disk, unless
+** An entry for the table is made in the schema table on disk, unless
** this is a temporary table or db->init.busy==1. When db->init.busy==1
-** it means we are reading the sqlite_master table because we just
-** connected to the database or because the sqlite_master table has
+** it means we are reading the sqlite_schema table because we just
+** connected to the database or because the sqlite_schema table has
** recently changed, so the entry for this table already exists in
-** the sqlite_master table. We do not want to create it again.
+** the sqlite_schema table. We do not want to create it again.
**
** If the pSelect argument is not NULL, it means that this routine
** was called to create a table generated from a
@@ -2229,12 +2292,12 @@ void sqlite3EndTable(
}
/* If the db->init.busy is 1 it means we are reading the SQL off the
- ** "sqlite_master" or "sqlite_temp_master" table on the disk.
+ ** "sqlite_schema" or "sqlite_temp_schema" table on the disk.
** So do not write to the disk again. Extract the root page number
** for the table from the db->init.newTnum field. (The page number
** should have been put there by the sqliteOpenCb routine.)
**
- ** If the root page number is 1, that means this is the sqlite_master
+ ** If the root page number is 1, that means this is the sqlite_schema
** table itself. So mark it read-only.
*/
if( db->init.busy ){
@@ -2321,7 +2384,7 @@ void sqlite3EndTable(
}
/* If not initializing, then create a record for the new table
- ** in the SQLITE_MASTER table of the database.
+ ** in the schema table of the database.
**
** If this is a TEMPORARY table, write the entry into the auxiliary
** file instead of into the main database file.
@@ -2423,14 +2486,14 @@ void sqlite3EndTable(
}
/* A slot for the record has already been allocated in the
- ** SQLITE_MASTER table. We just need to update that slot with all
+ ** schema table. We just need to update that slot with all
** the information we've collected.
*/
sqlite3NestedParse(pParse,
- "UPDATE %Q.%s "
- "SET type='%s', name=%Q, tbl_name=%Q, rootpage=#%d, sql=%Q "
- "WHERE rowid=#%d",
- db->aDb[iDb].zDbSName, MASTER_NAME,
+ "UPDATE %Q." DFLT_SCHEMA_TABLE
+ " SET type='%s', name=%Q, tbl_name=%Q, rootpage=#%d, sql=%Q"
+ " WHERE rowid=#%d",
+ db->aDb[iDb].zDbSName,
zType,
p->zName,
p->zName,
@@ -2558,7 +2621,7 @@ void sqlite3CreateView(
sEnd.z = &z[n-1];
sEnd.n = 1;
- /* Use sqlite3EndTable() to add the view to the SQLITE_MASTER table */
+ /* Use sqlite3EndTable() to add the view to the schema table */
sqlite3EndTable(pParse, 0, &sEnd, 0, 0);
create_view_fail:
@@ -2773,7 +2836,7 @@ void sqlite3RootPageMoved(sqlite3 *db, int iDb, int iFrom, int iTo){
/*
** Write code to erase the table with root-page iTable from database iDb.
-** Also write code to modify the sqlite_master table and internal schema
+** Also write code to modify the sqlite_schema table and internal schema
** if a root-page of another table is moved by the btree-layer whilst
** erasing iTable (this can happen with an auto-vacuum database).
*/
@@ -2786,7 +2849,7 @@ static void destroyRootPage(Parse *pParse, int iTable, int iDb){
#ifndef SQLITE_OMIT_AUTOVACUUM
/* OP_Destroy stores an in integer r1. If this integer
** is non-zero, then it is the root page number of a table moved to
- ** location iTable. The following code modifies the sqlite_master table to
+ ** location iTable. The following code modifies the sqlite_schema table to
** reflect this.
**
** The "#NNN" in the SQL is a special constant that means whatever value
@@ -2794,15 +2857,16 @@ static void destroyRootPage(Parse *pParse, int iTable, int iDb){
** token for additional information.
*/
sqlite3NestedParse(pParse,
- "UPDATE %Q.%s SET rootpage=%d WHERE #%d AND rootpage=#%d",
- pParse->db->aDb[iDb].zDbSName, MASTER_NAME, iTable, r1, r1);
+ "UPDATE %Q." DFLT_SCHEMA_TABLE
+ " SET rootpage=%d WHERE #%d AND rootpage=#%d",
+ pParse->db->aDb[iDb].zDbSName, iTable, r1, r1);
#endif
sqlite3ReleaseTempReg(pParse, r1);
}
/*
** Write VDBE code to erase table pTab and all associated indices on disk.
-** Code to update the sqlite_master tables and internal schema definitions
+** Code to update the sqlite_schema tables and internal schema definitions
** in case a root-page belonging to another table is moved by the btree layer
** is also added (this can happen with an auto-vacuum database).
*/
@@ -2895,8 +2959,8 @@ void sqlite3CodeDropTable(Parse *pParse, Table *pTab, int iDb, int isView){
#endif
/* Drop all triggers associated with the table being dropped. Code
- ** is generated to remove entries from sqlite_master and/or
- ** sqlite_temp_master if required.
+ ** is generated to remove entries from sqlite_schema and/or
+ ** sqlite_temp_schema if required.
*/
pTrigger = sqlite3TriggerList(pParse, pTab);
while( pTrigger ){
@@ -2920,16 +2984,17 @@ void sqlite3CodeDropTable(Parse *pParse, Table *pTab, int iDb, int isView){
}
#endif
- /* Drop all SQLITE_MASTER table and index entries that refer to the
- ** table. The program name loops through the master table and deletes
+ /* Drop all entries in the schema table that refer to the
+ ** table. The program name loops through the schema table and deletes
** every row that refers to a table of the same name as the one being
** dropped. Triggers are handled separately because a trigger can be
** created in the temp database that refers to a table in another
** database.
*/
sqlite3NestedParse(pParse,
- "DELETE FROM %Q.%s WHERE tbl_name=%Q and type!='trigger'",
- pDb->zDbSName, MASTER_NAME, pTab->zName);
+ "DELETE FROM %Q." DFLT_SCHEMA_TABLE
+ " WHERE tbl_name=%Q and type!='trigger'",
+ pDb->zDbSName, pTab->zName);
if( !isView && !IsVirtual(pTab) ){
destroyTable(pParse, pTab);
}
@@ -3065,7 +3130,7 @@ void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, int noErr){
}
#endif
- /* Generate code to remove the table from the master table
+ /* Generate code to remove the table from the schema table
** on disk.
*/
v = sqlite3GetVdbe(pParse);
@@ -3519,10 +3584,7 @@ void sqlite3CreateIndex(
#if SQLITE_USER_AUTHENTICATION
&& sqlite3UserAuthTable(pTab->zName)==0
#endif
-#ifdef SQLITE_ALLOW_SQLITE_MASTER_INDEX
- && sqlite3StrICmp(&pTab->zName[7],"master")!=0
-#endif
- ){
+ ){
sqlite3ErrorMsg(pParse, "table %s may not be indexed", pTab->zName);
goto exit_create_index;
}
@@ -3544,7 +3606,7 @@ void sqlite3CreateIndex(
** index or table with the same name.
**
** Exception: If we are reading the names of permanent indices from the
- ** sqlite_master table (because some other process changed the schema) and
+ ** sqlite_schema table (because some other process changed the schema) and
** one of the index names collides with the name of a temporary table or
** index, then we will continue to process this index.
**
@@ -3888,8 +3950,8 @@ void sqlite3CreateIndex(
/* If this is the initial CREATE INDEX statement (or CREATE TABLE if the
** index is an implied index for a UNIQUE or PRIMARY KEY constraint) then
** emit code to allocate the index rootpage on disk and make an entry for
- ** the index in the sqlite_master table and populate the index with
- ** content. But, do not do this if we are simply reading the sqlite_master
+ ** the index in the sqlite_schema table and populate the index with
+ ** content. But, do not do this if we are simply reading the sqlite_schema
** table to parse the schema, or if this index is the PRIMARY KEY index
** of a WITHOUT ROWID table.
**
@@ -3933,11 +3995,11 @@ void sqlite3CreateIndex(
zStmt = 0;
}
- /* Add an entry in sqlite_master for this index
+ /* Add an entry in sqlite_schema for this index
*/
sqlite3NestedParse(pParse,
- "INSERT INTO %Q.%s VALUES('index',%Q,%Q,#%d,%Q);",
- db->aDb[iDb].zDbSName, MASTER_NAME,
+ "INSERT INTO %Q." DFLT_SCHEMA_TABLE " VALUES('index',%Q,%Q,#%d,%Q);",
+ db->aDb[iDb].zDbSName,
pIndex->zName,
pTab->zName,
iMem,
@@ -4013,9 +4075,10 @@ exit_create_index:
** are based on typical values found in actual indices.
*/
void sqlite3DefaultRowEst(Index *pIdx){
- /* 10, 9, 8, 7, 6 */
- LogEst aVal[] = { 33, 32, 30, 28, 26 };
+ /* 10, 9, 8, 7, 6 */
+ static const LogEst aVal[] = { 33, 32, 30, 28, 26 };
LogEst *a = pIdx->aiRowLogEst;
+ LogEst x;
int nCopy = MIN(ArraySize(aVal), pIdx->nKeyCol);
int i;
@@ -4024,10 +4087,21 @@ void sqlite3DefaultRowEst(Index *pIdx){
/* Set the first entry (number of rows in the index) to the estimated
** number of rows in the table, or half the number of rows in the table
- ** for a partial index. But do not let the estimate drop below 10. */
- a[0] = pIdx->pTable->nRowLogEst;
- if( pIdx->pPartIdxWhere!=0 ) a[0] -= 10; assert( 10==sqlite3LogEst(2) );
- if( a[0]<33 ) a[0] = 33; assert( 33==sqlite3LogEst(10) );
+ ** for a partial index.
+ **
+ ** 2020-05-27: If some of the stat data is coming from the sqlite_stat1
+ ** table but other parts we are having to guess at, then do not let the
+ ** estimated number of rows in the table be less than 1000 (LogEst 99).
+ ** Failure to do this can cause the indexes for which we do not have
+ ** stat1 data to be ignored by the query planner. tag-20200527-1
+ */
+ x = pIdx->pTable->nRowLogEst;
+ assert( 99==sqlite3LogEst(1000) );
+ if( x<99 ){
+ pIdx->pTable->nRowLogEst = x = 99;
+ }
+ if( pIdx->pPartIdxWhere!=0 ) x -= 10; assert( 10==sqlite3LogEst(2) );
+ a[0] = x;
/* Estimate that a[1] is 10, a[2] is 9, a[3] is 8, a[4] is 7, a[5] is
** 6 and each subsequent value (if any) is 5. */
@@ -4090,13 +4164,13 @@ void sqlite3DropIndex(Parse *pParse, SrcList *pName, int ifExists){
}
#endif
- /* Generate code to remove the index and from the master table */
+ /* Generate code to remove the index and from the schema table */
v = sqlite3GetVdbe(pParse);
if( v ){
sqlite3BeginWriteOperation(pParse, 1, iDb);
sqlite3NestedParse(pParse,
- "DELETE FROM %Q.%s WHERE name=%Q AND type='index'",
- db->aDb[iDb].zDbSName, MASTER_NAME, pIndex->zName
+ "DELETE FROM %Q." DFLT_SCHEMA_TABLE " WHERE name=%Q AND type='index'",
+ db->aDb[iDb].zDbSName, pIndex->zName
);
sqlite3ClearStatTables(pParse, iDb, "idx", pIndex->zName);
sqlite3ChangeCookie(pParse, iDb);
@@ -4650,7 +4724,7 @@ int sqlite3OpenTempDatabase(Parse *pParse){
}
db->aDb[1].pBt = pBt;
assert( db->aDb[1].pSchema );
- if( SQLITE_NOMEM==sqlite3BtreeSetPageSize(pBt, db->nextPagesize, -1, 0) ){
+ if( SQLITE_NOMEM==sqlite3BtreeSetPageSize(pBt, db->nextPagesize, 0, 0) ){
sqlite3OomFault(db);
return 1;
}
@@ -4761,7 +4835,7 @@ void sqlite3HaltConstraint(
u8 p5Errmsg /* P5_ErrMsg type */
){
Vdbe *v = sqlite3GetVdbe(pParse);
- assert( (errCode&0xff)==SQLITE_CONSTRAINT );
+ assert( (errCode&0xff)==SQLITE_CONSTRAINT || pParse->nested );
if( onError==OE_Abort ){
sqlite3MayAbort(pParse);
}
diff --git a/src/ctime.c b/src/ctime.c
index 7a2ace931..e3e1e79a9 100644
--- a/src/ctime.c
+++ b/src/ctime.c
@@ -193,6 +193,9 @@ static const char * const sqlite3azCompileOpt[] = {
#if SQLITE_ENABLE_BATCH_ATOMIC_WRITE
"ENABLE_BATCH_ATOMIC_WRITE",
#endif
+#if SQLITE_ENABLE_BYTECODE_VTAB
+ "ENABLE_BYTECODE_VTAB",
+#endif
#if SQLITE_ENABLE_CEROD
"ENABLE_CEROD=" CTIMEOPT_VAL(SQLITE_ENABLE_CEROD),
#endif
@@ -511,9 +514,6 @@ static const char * const sqlite3azCompileOpt[] = {
#if SQLITE_OMIT_BLOB_LITERAL
"OMIT_BLOB_LITERAL",
#endif
-#if SQLITE_OMIT_BTREECOUNT
- "OMIT_BTREECOUNT",
-#endif
#if SQLITE_OMIT_CAST
"OMIT_CAST",
#endif
diff --git a/src/date.c b/src/date.c
index fff062fb5..9cba27f59 100644
--- a/src/date.c
+++ b/src/date.c
@@ -515,7 +515,7 @@ static int osLocaltime(time_t *t, struct tm *pTm){
#if !HAVE_LOCALTIME_R && !HAVE_LOCALTIME_S
struct tm *pX;
#if SQLITE_THREADSAFE>0
- sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
+ sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN);
#endif
sqlite3_mutex_enter(mutex);
pX = localtime(t);
@@ -1211,10 +1211,10 @@ static void currentTimeFunc(
#if HAVE_GMTIME_R
pTm = gmtime_r(&t, &sNow);
#else
- sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
+ sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN));
pTm = gmtime(&t);
if( pTm ) memcpy(&sNow, pTm, sizeof(sNow));
- sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
+ sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN));
#endif
if( pTm ){
strftime(zBuf, 20, zFormat, &sNow);
diff --git a/src/dbstat.c b/src/dbstat.c
index bddde79ce..78173c397 100644
--- a/src/dbstat.c
+++ b/src/dbstat.c
@@ -724,10 +724,10 @@ static int statFilter(
pSql = sqlite3_str_new(pTab->db);
sqlite3_str_appendf(pSql,
"SELECT * FROM ("
- "SELECT 'sqlite_master' AS name,1 AS rootpage,'table' AS type"
+ "SELECT 'sqlite_schema' AS name,1 AS rootpage,'table' AS type"
" UNION ALL "
"SELECT name,rootpage,type"
- " FROM \"%w\".sqlite_master WHERE rootpage!=0)",
+ " FROM \"%w\".sqlite_schema WHERE rootpage!=0)",
pTab->db->aDb[pCsr->iDb].zDbSName);
if( zName ){
sqlite3_str_appendf(pSql, "WHERE name=%Q", zName);
diff --git a/src/delete.c b/src/delete.c
index 5e73f76bb..ae2f85b3a 100644
--- a/src/delete.c
+++ b/src/delete.c
@@ -51,7 +51,7 @@ Table *sqlite3SrcListLookup(Parse *pParse, SrcList *pSrc){
** 1) It is a virtual table and no implementation of the xUpdate method
** has been provided
**
-** 2) It is a system table (i.e. sqlite_master), this call is not
+** 2) It is a system table (i.e. sqlite_schema), this call is not
** part of a nested parse and writable_schema pragma has not
** been specified
**
@@ -858,6 +858,7 @@ void sqlite3GenerateRowIndexDelete(
&iPartIdxLabel, pPrior, r1);
sqlite3VdbeAddOp3(v, OP_IdxDelete, iIdxCur+i, r1,
pIdx->uniqNotNull ? pIdx->nKeyCol : pIdx->nColumn);
+ sqlite3VdbeChangeP5(v, 1); /* Cause IdxDelete to error if no entry found */
sqlite3ResolvePartIdxLabel(pParse, iPartIdxLabel);
pPrior = pIdx;
}
diff --git a/src/expr.c b/src/expr.c
index 23e00db2e..abc4b12cf 100644
--- a/src/expr.c
+++ b/src/expr.c
@@ -52,6 +52,9 @@ char sqlite3ExprAffinity(const Expr *pExpr){
op = pExpr->op;
if( op==TK_SELECT ){
assert( pExpr->flags&EP_xIsSelect );
+ assert( pExpr->x.pSelect!=0 );
+ assert( pExpr->x.pSelect->pEList!=0 );
+ assert( pExpr->x.pSelect->pEList->a[0].pExpr!=0 );
return sqlite3ExprAffinity(pExpr->x.pSelect->pEList->a[0].pExpr);
}
if( op==TK_REGISTER ) op = pExpr->op2;
@@ -195,7 +198,7 @@ CollSeq *sqlite3ExprCollSeq(Parse *pParse, const Expr *pExpr){
&& ALWAYS(!ExprHasProperty(p, EP_xIsSelect))
){
int i;
- for(i=0; i<p->x.pList->nExpr; i++){
+ for(i=0; ALWAYS(i<p->x.pList->nExpr); i++){
if( ExprHasProperty(p->x.pList->a[i].pExpr, EP_Collate) ){
pNext = p->x.pList->a[i].pExpr;
break;
@@ -1988,10 +1991,10 @@ Expr *sqlite3ExprSimplifiedAndOr(Expr *pExpr){
**
** The sqlite3ExprIsConstantOrFunction() is used for evaluating DEFAULT
** expressions in a CREATE TABLE statement. The Walker.eCode value is 5
-** when parsing an existing schema out of the sqlite_master table and 4
+** when parsing an existing schema out of the sqlite_schema table and 4
** when processing a new CREATE TABLE statement. A bound parameter raises
** an error for new statements, but is silently converted
-** to NULL for existing schemas. This allows sqlite_master tables that
+** to NULL for existing schemas. This allows sqlite_schema tables that
** contain a bound parameter because they were generated by older versions
** of SQLite to be parsed by newer versions of SQLite without raising a
** malformed schema error.
@@ -2043,15 +2046,17 @@ static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){
/* Fall through */
case TK_IF_NULL_ROW:
case TK_REGISTER:
+ case TK_DOT:
testcase( pExpr->op==TK_REGISTER );
testcase( pExpr->op==TK_IF_NULL_ROW );
+ testcase( pExpr->op==TK_DOT );
pWalker->eCode = 0;
return WRC_Abort;
case TK_VARIABLE:
if( pWalker->eCode==5 ){
/* Silently convert bound parameters that appear inside of CREATE
** statements into a NULL when parsing the CREATE statement text out
- ** of the sqlite_master table */
+ ** of the sqlite_schema table */
pExpr->op = TK_NULL;
}else if( pWalker->eCode==4 ){
/* A bound parameter in a CREATE statement that originates from
@@ -2184,12 +2189,12 @@ int sqlite3ExprIsConstantOrGroupBy(Parse *pParse, Expr *p, ExprList *pGroupBy){
** the expression is constant or a function call with constant arguments.
** Return and 0 if there are any variables.
**
-** isInit is true when parsing from sqlite_master. isInit is false when
+** isInit is true when parsing from sqlite_schema. isInit is false when
** processing a new CREATE TABLE statement. When isInit is true, parameters
** (such as ? or $abc) in the expression are converted into NULL. When
** isInit is false, parameters raise an error. Parameters should not be
** allowed in a CREATE TABLE statement, but some legacy versions of SQLite
-** allowed it, so we need to support it when reading sqlite_master for
+** allowed it, so we need to support it when reading sqlite_schema for
** backwards compatibility.
**
** If isInit is true, set EP_FromDDL on every TK_FUNCTION node.
@@ -2552,7 +2557,7 @@ int sqlite3FindInIndex(
if( pParse->nErr==0 && (p = isCandidateForInOpt(pX))!=0 ){
sqlite3 *db = pParse->db; /* Database connection */
Table *pTab; /* Table <table>. */
- i16 iDb; /* Database idx for pTab */
+ int iDb; /* Database idx for pTab */
ExprList *pEList = p->pEList;
int nExpr = pEList->nExpr;
@@ -2563,6 +2568,7 @@ int sqlite3FindInIndex(
/* Code an OP_Transaction and OP_TableLock for <table>. */
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
+ assert( iDb>=0 && iDb<SQLITE_MAX_ATTACHED );
sqlite3CodeVerifySchema(pParse, iDb);
sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName);
@@ -3700,6 +3706,13 @@ static int exprCodeInlineFunction(
sqlite3VdbeResolveLabel(v, endCoalesce);
break;
}
+ case INLINEFUNC_iif: {
+ Expr caseExpr;
+ memset(&caseExpr, 0, sizeof(caseExpr));
+ caseExpr.op = TK_CASE;
+ caseExpr.x.pList = pFarg;
+ return sqlite3ExprCodeTarget(pParse, &caseExpr, target);
+ }
default: {
/* The UNLIKELY() function is a no-op. The result is the value
@@ -3789,10 +3802,7 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
int p5 = 0;
assert( target>0 && target<=pParse->nMem );
- if( v==0 ){
- assert( pParse->db->mallocFailed );
- return 0;
- }
+ assert( v!=0 );
expr_code_doover:
if( pExpr==0 ){
@@ -3804,7 +3814,10 @@ expr_code_doover:
switch( op ){
case TK_AGG_COLUMN: {
AggInfo *pAggInfo = pExpr->pAggInfo;
- struct AggInfo_col *pCol = &pAggInfo->aCol[pExpr->iAgg];
+ struct AggInfo_col *pCol;
+ assert( pAggInfo!=0 );
+ assert( pExpr->iAgg>=0 && pExpr->iAgg<pAggInfo->nColumn );
+ pCol = &pAggInfo->aCol[pExpr->iAgg];
if( !pAggInfo->directMode ){
assert( pCol->iMem>0 );
return pCol->iMem;
@@ -4104,7 +4117,10 @@ expr_code_doover:
}
case TK_AGG_FUNCTION: {
AggInfo *pInfo = pExpr->pAggInfo;
- if( pInfo==0 ){
+ if( pInfo==0
+ || NEVER(pExpr->iAgg<0)
+ || NEVER(pExpr->iAgg>=pInfo->nFunc)
+ ){
assert( !ExprHasProperty(pExpr, EP_IntValue) );
sqlite3ErrorMsg(pParse, "misuse of aggregate: %s()", pExpr->u.zToken);
}else{
@@ -4252,7 +4268,9 @@ expr_code_doover:
int nCol;
testcase( op==TK_EXISTS );
testcase( op==TK_SELECT );
- if( op==TK_SELECT && (nCol = pExpr->x.pSelect->pEList->nExpr)!=1 ){
+ if( pParse->db->mallocFailed ){
+ return 0;
+ }else if( op==TK_SELECT && (nCol = pExpr->x.pSelect->pEList->nExpr)!=1 ){
sqlite3SubselectError(pParse, nCol, 1);
}else{
return sqlite3CodeSubselect(pParse, pExpr);
@@ -4482,7 +4500,7 @@ expr_code_doover:
|| pExpr->affExpr==OE_Fail
|| pExpr->affExpr==OE_Ignore
);
- if( !pParse->pTriggerTab ){
+ if( !pParse->pTriggerTab && !pParse->nested ){
sqlite3ErrorMsg(pParse,
"RAISE() may only be used within a trigger-program");
return 0;
@@ -4496,8 +4514,9 @@ expr_code_doover:
v, OP_Halt, SQLITE_OK, OE_Ignore, 0, pExpr->u.zToken,0);
VdbeCoverage(v);
}else{
- sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_TRIGGER,
- pExpr->affExpr, pExpr->u.zToken, 0, 0);
+ sqlite3HaltConstraint(pParse,
+ pParse->pTriggerTab ? SQLITE_CONSTRAINT_TRIGGER : SQLITE_ERROR,
+ pExpr->affExpr, pExpr->u.zToken, 0, 0);
}
break;
@@ -4615,9 +4634,10 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){
assert( pExpr==0 || !ExprHasVVAProperty(pExpr,EP_Immutable) );
assert( target>0 && target<=pParse->nMem );
- inReg = sqlite3ExprCodeTarget(pParse, pExpr, target);
assert( pParse->pVdbe!=0 || pParse->db->mallocFailed );
- if( inReg!=target && pParse->pVdbe ){
+ if( pParse->pVdbe==0 ) return;
+ inReg = sqlite3ExprCodeTarget(pParse, pExpr, target);
+ if( inReg!=target ){
u8 op;
if( ExprHasProperty(pExpr,EP_Subquery) ){
op = OP_Copy;
@@ -5636,11 +5656,26 @@ int sqlite3ExprCoveredByIndex(
*/
struct SrcCount {
SrcList *pSrc; /* One particular FROM clause in a nested query */
+ int iSrcInner; /* Smallest cursor number in this context */
int nThis; /* Number of references to columns in pSrcList */
int nOther; /* Number of references to columns in other FROM clauses */
};
/*
+** xSelect callback for sqlite3FunctionUsesThisSrc(). If this is the first
+** SELECT with a FROM clause encountered during this iteration, set
+** SrcCount.iSrcInner to the cursor number of the leftmost object in
+** the FROM cause.
+*/
+static int selectSrcCount(Walker *pWalker, Select *pSel){
+ struct SrcCount *p = pWalker->u.pSrcCount;
+ if( p->iSrcInner==0x7FFFFFFF && ALWAYS(pSel->pSrc) && pSel->pSrc->nSrc ){
+ pWalker->u.pSrcCount->iSrcInner = pSel->pSrc->a[0].iCursor;
+ }
+ return WRC_Continue;
+}
+
+/*
** Count the number of references to columns.
*/
static int exprSrcCount(Walker *pWalker, Expr *pExpr){
@@ -5660,7 +5695,7 @@ static int exprSrcCount(Walker *pWalker, Expr *pExpr){
}
if( i<nSrc ){
p->nThis++;
- }else if( nSrc==0 || pExpr->iTable<pSrc->a[0].iCursor ){
+ }else if( pExpr->iTable<p->iSrcInner ){
/* In a well-formed parse tree (no name resolution errors),
** TK_COLUMN nodes with smaller Expr.iTable values are in an
** outer context. Those are the only ones to count as "other" */
@@ -5682,9 +5717,10 @@ int sqlite3FunctionUsesThisSrc(Expr *pExpr, SrcList *pSrcList){
assert( pExpr->op==TK_AGG_FUNCTION );
memset(&w, 0, sizeof(w));
w.xExprCallback = exprSrcCount;
- w.xSelectCallback = sqlite3SelectWalkNoop;
+ w.xSelectCallback = selectSrcCount;
w.u.pSrcCount = &cnt;
cnt.pSrc = pSrcList;
+ cnt.iSrcInner = (pSrcList&&pSrcList->nSrc)?pSrcList->a[0].iCursor:0x7FFFFFFF;
cnt.nThis = 0;
cnt.nOther = 0;
sqlite3WalkExprList(&w, pExpr->x.pList);
@@ -5697,6 +5733,64 @@ int sqlite3FunctionUsesThisSrc(Expr *pExpr, SrcList *pSrcList){
}
/*
+** This is a Walker expression node callback.
+**
+** For Expr nodes that contain pAggInfo pointers, make sure the AggInfo
+** object that is referenced does not refer directly to the Expr. If
+** it does, make a copy. This is done because the pExpr argument is
+** subject to change.
+**
+** The copy is stored on pParse->pConstExpr with a register number of 0.
+** This will cause the expression to be deleted automatically when the
+** Parse object is destroyed, but the zero register number means that it
+** will not generate any code in the preamble.
+*/
+static int agginfoPersistExprCb(Walker *pWalker, Expr *pExpr){
+ if( ALWAYS(!ExprHasProperty(pExpr, EP_TokenOnly|EP_Reduced))
+ && pExpr->pAggInfo!=0
+ ){
+ AggInfo *pAggInfo = pExpr->pAggInfo;
+ int iAgg = pExpr->iAgg;
+ Parse *pParse = pWalker->pParse;
+ sqlite3 *db = pParse->db;
+ assert( pExpr->op==TK_AGG_COLUMN || pExpr->op==TK_AGG_FUNCTION );
+ if( pExpr->op==TK_AGG_COLUMN ){
+ assert( iAgg>=0 && iAgg<pAggInfo->nColumn );
+ if( pAggInfo->aCol[iAgg].pCExpr==pExpr ){
+ pExpr = sqlite3ExprDup(db, pExpr, 0);
+ if( pExpr ){
+ pAggInfo->aCol[iAgg].pCExpr = pExpr;
+ pParse->pConstExpr =
+ sqlite3ExprListAppend(pParse, pParse->pConstExpr, pExpr);
+ }
+ }
+ }else{
+ assert( iAgg>=0 && iAgg<pAggInfo->nFunc );
+ if( pAggInfo->aFunc[iAgg].pFExpr==pExpr ){
+ pExpr = sqlite3ExprDup(db, pExpr, 0);
+ if( pExpr ){
+ pAggInfo->aFunc[iAgg].pFExpr = pExpr;
+ pParse->pConstExpr =
+ sqlite3ExprListAppend(pParse, pParse->pConstExpr, pExpr);
+ }
+ }
+ }
+ }
+ return WRC_Continue;
+}
+
+/*
+** Initialize a Walker object so that will persist AggInfo entries referenced
+** by the tree that is walked.
+*/
+void sqlite3AggInfoPersistWalkerInit(Walker *pWalker, Parse *pParse){
+ memset(pWalker, 0, sizeof(*pWalker));
+ pWalker->pParse = pParse;
+ pWalker->xExprCallback = agginfoPersistExprCb;
+ pWalker->xSelectCallback = sqlite3SelectWalkNoop;
+}
+
+/*
** Add a new element to the pAggInfo->aCol[] array. Return the index of
** the new element. Return a negative number if malloc fails.
*/
@@ -5726,7 +5820,7 @@ static int addAggInfoFunc(sqlite3 *db, AggInfo *pInfo){
&i
);
return i;
-}
+}
/*
** This is the xExprCallback for a tree walker. It is used to
@@ -5777,7 +5871,7 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){
pCol->iColumn = pExpr->iColumn;
pCol->iMem = ++pParse->nMem;
pCol->iSorterColumn = -1;
- pCol->pExpr = pExpr;
+ pCol->pCExpr = pExpr;
if( pAggInfo->pGroupBy ){
int j, n;
ExprList *pGB = pAggInfo->pGroupBy;
@@ -5820,7 +5914,7 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){
*/
struct AggInfo_func *pItem = pAggInfo->aFunc;
for(i=0; i<pAggInfo->nFunc; i++, pItem++){
- if( sqlite3ExprCompare(0, pItem->pExpr, pExpr, -1)==0 ){
+ if( sqlite3ExprCompare(0, pItem->pFExpr, pExpr, -1)==0 ){
break;
}
}
@@ -5832,7 +5926,7 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){
if( i>=0 ){
assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
pItem = &pAggInfo->aFunc[i];
- pItem->pExpr = pExpr;
+ pItem->pFExpr = pExpr;
pItem->iMem = ++pParse->nMem;
assert( !ExprHasProperty(pExpr, EP_IntValue) );
pItem->pFunc = sqlite3FindFunction(pParse->db,
@@ -5859,15 +5953,6 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){
}
return WRC_Continue;
}
-static int analyzeAggregatesInSelect(Walker *pWalker, Select *pSelect){
- UNUSED_PARAMETER(pSelect);
- pWalker->walkerDepth++;
- return WRC_Continue;
-}
-static void analyzeAggregatesInSelectEnd(Walker *pWalker, Select *pSelect){
- UNUSED_PARAMETER(pSelect);
- pWalker->walkerDepth--;
-}
/*
** Analyze the pExpr expression looking for aggregate functions and
@@ -5881,8 +5966,8 @@ static void analyzeAggregatesInSelectEnd(Walker *pWalker, Select *pSelect){
void sqlite3ExprAnalyzeAggregates(NameContext *pNC, Expr *pExpr){
Walker w;
w.xExprCallback = analyzeAggregate;
- w.xSelectCallback = analyzeAggregatesInSelect;
- w.xSelectCallback2 = analyzeAggregatesInSelectEnd;
+ w.xSelectCallback = sqlite3WalkerDepthIncrease;
+ w.xSelectCallback2 = sqlite3WalkerDepthDecrease;
w.walkerDepth = 0;
w.u.pNC = pNC;
w.pParse = 0;
diff --git a/src/func.c b/src/func.c
index 167b6afd7..48b5f5f19 100644
--- a/src/func.c
+++ b/src/func.c
@@ -1283,7 +1283,7 @@ static void replaceFunc(
** whose index is a power of two: 1, 2, 4, 8, 16, 32, ... */
u8 *zOld;
zOld = zOut;
- zOut = sqlite3_realloc64(zOut, (int)nOut + (nOut - nStr - 1));
+ zOut = sqlite3Realloc(zOut, (int)nOut + (nOut - nStr - 1));
if( zOut==0 ){
sqlite3_result_error_nomem(context);
sqlite3_free(zOld);
@@ -1980,7 +1980,7 @@ void sqlite3RegisterBuiltinFunctions(void){
FUNCTION(upper, 1, 0, 0, upperFunc ),
FUNCTION(lower, 1, 0, 0, lowerFunc ),
FUNCTION(hex, 1, 0, 0, hexFunc ),
- INLINE_FUNC(ifnull, 2, INLINEFUNC_coalesce, SQLITE_FUNC_COALESCE),
+ INLINE_FUNC(ifnull, 2, INLINEFUNC_coalesce, 0 ),
VFUNCTION(random, 0, 0, 0, randomFunc ),
VFUNCTION(randomblob, 1, 0, 0, randomBlob ),
FUNCTION(nullif, 2, 0, 1, nullifFunc ),
@@ -2020,7 +2020,8 @@ void sqlite3RegisterBuiltinFunctions(void){
#endif
FUNCTION(coalesce, 1, 0, 0, 0 ),
FUNCTION(coalesce, 0, 0, 0, 0 ),
- INLINE_FUNC(coalesce, -1, INLINEFUNC_coalesce, SQLITE_FUNC_COALESCE),
+ INLINE_FUNC(coalesce, -1, INLINEFUNC_coalesce, 0 ),
+ INLINE_FUNC(iif, 3, INLINEFUNC_iif, 0 ),
};
#ifndef SQLITE_OMIT_ALTERTABLE
sqlite3AlterFunctions();
diff --git a/src/global.c b/src/global.c
index aeddada6f..c6bdbad1b 100644
--- a/src/global.c
+++ b/src/global.c
@@ -300,6 +300,11 @@ sqlite3_uint64 sqlite3NProfileCnt = 0;
int sqlite3PendingByte = 0x40000000;
#endif
+/*
+** Flags for select tracing and the ".selecttrace" macro of the CLI
+*/
+/**/ u32 sqlite3SelectTrace = 0;
+
#include "opcodes.h"
/*
** Properties of opcodes. The OPFLG_INITIALIZER macro is
diff --git a/src/insert.c b/src/insert.c
index f4049fb3d..dadc8be3e 100644
--- a/src/insert.c
+++ b/src/insert.c
@@ -1944,7 +1944,7 @@ void sqlite3GenerateConstraintChecks(
sqlite3TableAffinity(v, pTab, regNewData+1);
bAffinityDone = 1;
}
- VdbeNoopComment((v, "uniqueness check for %s", pIdx->zName));
+ VdbeNoopComment((v, "prep index %s", pIdx->zName));
iThisCur = iIdxCur+ix;
@@ -2610,7 +2610,7 @@ static int xferOptimization(
return 0; /* FROM clause does not contain a real table */
}
if( pSrc->tnum==pDest->tnum && pSrc->pSchema==pDest->pSchema ){
- testcase( pSrc!=pDest ); /* Possible due to bad sqlite_master.rootpage */
+ testcase( pSrc!=pDest ); /* Possible due to bad sqlite_schema.rootpage */
return 0; /* tab1 and tab2 may not be the same table */
}
if( HasRowid(pDest)!=HasRowid(pSrc) ){
diff --git a/src/loadext.c b/src/loadext.c
index 067c47c17..7007e3137 100644
--- a/src/loadext.c
+++ b/src/loadext.c
@@ -689,7 +689,7 @@ int sqlite3_enable_load_extension(sqlite3 *db, int onoff){
** The following object holds the list of automatically loaded
** extensions.
**
-** This list is shared across threads. The SQLITE_MUTEX_STATIC_MASTER
+** This list is shared across threads. The SQLITE_MUTEX_STATIC_MAIN
** mutex must be held while accessing this list.
*/
typedef struct sqlite3AutoExtList sqlite3AutoExtList;
@@ -731,7 +731,7 @@ int sqlite3_auto_extension(
{
u32 i;
#if SQLITE_THREADSAFE
- sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
+ sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN);
#endif
wsdAutoextInit;
sqlite3_mutex_enter(mutex);
@@ -769,7 +769,7 @@ int sqlite3_cancel_auto_extension(
void (*xInit)(void)
){
#if SQLITE_THREADSAFE
- sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
+ sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN);
#endif
int i;
int n = 0;
@@ -796,7 +796,7 @@ void sqlite3_reset_auto_extension(void){
#endif
{
#if SQLITE_THREADSAFE
- sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
+ sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN);
#endif
wsdAutoextInit;
sqlite3_mutex_enter(mutex);
@@ -826,7 +826,7 @@ void sqlite3AutoLoadExtensions(sqlite3 *db){
for(i=0; go; i++){
char *zErrmsg;
#if SQLITE_THREADSAFE
- sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
+ sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN);
#endif
#ifdef SQLITE_OMIT_LOAD_EXTENSION
const sqlite3_api_routines *pThunk = 0;
diff --git a/src/main.c b/src/main.c
index f186d6ede..e0ceb1cb3 100644
--- a/src/main.c
+++ b/src/main.c
@@ -25,15 +25,78 @@
#if defined(SQLITE_ENABLE_ICU) || defined(SQLITE_ENABLE_ICU_COLLATIONS)
# include "sqliteicu.h"
#endif
+
+/*
+** This is an extension initializer that is a no-op and always
+** succeeds, except that it fails if the fault-simulation is set
+** to 500.
+*/
+static int sqlite3TestExtInit(sqlite3 *db){
+ (void)db;
+ return sqlite3FaultSim(500);
+}
+
+
+/*
+** Forward declarations of external module initializer functions
+** for modules that need them.
+*/
+#ifdef SQLITE_ENABLE_FTS1
+int sqlite3Fts1Init(sqlite3*);
+#endif
+#ifdef SQLITE_ENABLE_FTS2
+int sqlite3Fts2Init(sqlite3*);
+#endif
+#ifdef SQLITE_ENABLE_FTS5
+int sqlite3Fts5Init(sqlite3*);
+#endif
#ifdef SQLITE_ENABLE_JSON1
int sqlite3Json1Init(sqlite3*);
#endif
#ifdef SQLITE_ENABLE_STMTVTAB
int sqlite3StmtVtabInit(sqlite3*);
#endif
+
+/*
+** An array of pointers to extension initializer functions for
+** built-in extensions.
+*/
+static int (*const sqlite3BuiltinExtensions[])(sqlite3*) = {
+#ifdef SQLITE_ENABLE_FTS1
+ sqlite3Fts1Init,
+#endif
+#ifdef SQLITE_ENABLE_FTS2
+ sqlite3Fts2Init,
+#endif
+#ifdef SQLITE_ENABLE_FTS3
+ sqlite3Fts3Init,
+#endif
#ifdef SQLITE_ENABLE_FTS5
-int sqlite3Fts5Init(sqlite3*);
+ sqlite3Fts5Init,
+#endif
+#if defined(SQLITE_ENABLE_ICU) || defined(SQLITE_ENABLE_ICU_COLLATIONS)
+ sqlite3IcuInit,
+#endif
+#ifdef SQLITE_ENABLE_RTREE
+ sqlite3RtreeInit,
+#endif
+#ifdef SQLITE_ENABLE_DBPAGE_VTAB
+ sqlite3DbpageRegister,
+#endif
+#ifdef SQLITE_ENABLE_DBSTAT_VTAB
+ sqlite3DbstatRegister,
+#endif
+ sqlite3TestExtInit,
+#ifdef SQLITE_ENABLE_JSON1
+ sqlite3Json1Init,
+#endif
+#ifdef SQLITE_ENABLE_STMTVTAB
+ sqlite3StmtVtabInit,
#endif
+#ifdef SQLITE_ENABLE_BYTECODE_VTAB
+ sqlite3VdbeBytecodeVtabInit,
+#endif
+};
#ifndef SQLITE_AMALGAMATION
/* IMPLEMENTATION-OF: R-46656-45156 The sqlite3_version[] string constant
@@ -138,7 +201,7 @@ char *sqlite3_data_directory = 0;
** without blocking.
*/
int sqlite3_initialize(void){
- MUTEX_LOGIC( sqlite3_mutex *pMaster; ) /* The main static mutex */
+ MUTEX_LOGIC( sqlite3_mutex *pMainMtx; ) /* The main static mutex */
int rc; /* Result code */
#ifdef SQLITE_EXTRA_INIT
int bRunExtraInit = 0; /* Extra initialization needed */
@@ -178,13 +241,13 @@ int sqlite3_initialize(void){
if( rc ) return rc;
/* Initialize the malloc() system and the recursive pInitMutex mutex.
- ** This operation is protected by the STATIC_MASTER mutex. Note that
+ ** This operation is protected by the STATIC_MAIN mutex. Note that
** MutexAlloc() is called for a static mutex prior to initializing the
** malloc subsystem - this implies that the allocation of a static
** mutex must not require support from the malloc subsystem.
*/
- MUTEX_LOGIC( pMaster = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); )
- sqlite3_mutex_enter(pMaster);
+ MUTEX_LOGIC( pMainMtx = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN); )
+ sqlite3_mutex_enter(pMainMtx);
sqlite3GlobalConfig.isMutexInit = 1;
if( !sqlite3GlobalConfig.isMallocInit ){
rc = sqlite3MallocInit();
@@ -202,7 +265,7 @@ int sqlite3_initialize(void){
if( rc==SQLITE_OK ){
sqlite3GlobalConfig.nRefInitMutex++;
}
- sqlite3_mutex_leave(pMaster);
+ sqlite3_mutex_leave(pMainMtx);
/* If rc is not SQLITE_OK at this point, then either the malloc
** subsystem could not be initialized or the system failed to allocate
@@ -250,6 +313,7 @@ int sqlite3_initialize(void){
if( rc==SQLITE_OK ){
sqlite3PCacheBufferSetup( sqlite3GlobalConfig.pPage,
sqlite3GlobalConfig.szPage, sqlite3GlobalConfig.nPage);
+ sqlite3MemoryBarrier();
sqlite3GlobalConfig.isInit = 1;
#ifdef SQLITE_EXTRA_INIT
bRunExtraInit = 1;
@@ -262,14 +326,14 @@ int sqlite3_initialize(void){
/* Go back under the static mutex and clean up the recursive
** mutex to prevent a resource leak.
*/
- sqlite3_mutex_enter(pMaster);
+ sqlite3_mutex_enter(pMainMtx);
sqlite3GlobalConfig.nRefInitMutex--;
if( sqlite3GlobalConfig.nRefInitMutex<=0 ){
assert( sqlite3GlobalConfig.nRefInitMutex==0 );
sqlite3_mutex_free(sqlite3GlobalConfig.pInitMutex);
sqlite3GlobalConfig.pInitMutex = 0;
}
- sqlite3_mutex_leave(pMaster);
+ sqlite3_mutex_leave(pMainMtx);
/* The following is just a sanity check to make sure SQLite has
** been compiled correctly. It is important to run this code, but
@@ -1551,8 +1615,7 @@ const char *sqlite3ErrStr(int rc){
*/
static int sqliteDefaultBusyCallback(
void *ptr, /* Database connection */
- int count, /* Number of times table has been busy */
- sqlite3_file *pFile /* The file on which the lock occurred */
+ int count /* Number of times table has been busy */
){
#if SQLITE_OS_WIN || HAVE_USLEEP
/* This case is for systems that have support for sleeping for fractions of
@@ -1566,31 +1629,6 @@ static int sqliteDefaultBusyCallback(
int tmout = db->busyTimeout;
int delay, prior;
-#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
- if( sqlite3OsFileControl(pFile,SQLITE_FCNTL_LOCK_TIMEOUT,&tmout)==SQLITE_OK ){
- if( count ){
- /* If this is the second or later invocation of the busy-handler,
- ** but tmout==0, then code in wal.c must have disabled the blocking
- ** lock before the SQLITE_BUSY error was hit. In this case, no delay
- ** occurred while waiting for the lock, so fall through to the xSleep()
- ** code below to delay a while before retrying the lock.
- **
- ** Alternatively, if tmout!=0, then SQLite has already waited
- ** sqlite3.busyTimeout ms for a lock. In this case, return 0 to
- ** indicate that the lock should not be retried and the SQLITE_BUSY
- ** error returned to the application. */
- if( tmout ){
- tmout = 0;
- sqlite3OsFileControl(pFile, SQLITE_FCNTL_LOCK_TIMEOUT, &tmout);
- return 0;
- }
- }else{
- return 1;
- }
- }
-#else
- UNUSED_PARAMETER(pFile);
-#endif
assert( count>=0 );
if( count < NDELAY ){
delay = delays[count];
@@ -1610,7 +1648,6 @@ static int sqliteDefaultBusyCallback(
** must be done in increments of whole seconds */
sqlite3 *db = (sqlite3 *)ptr;
int tmout = ((sqlite3 *)ptr)->busyTimeout;
- UNUSED_PARAMETER(pFile);
if( (count+1)*1000 > tmout ){
return 0;
}
@@ -1628,19 +1665,10 @@ static int sqliteDefaultBusyCallback(
** If this routine returns non-zero, the lock is retried. If it
** returns 0, the operation aborts with an SQLITE_BUSY error.
*/
-int sqlite3InvokeBusyHandler(BusyHandler *p, sqlite3_file *pFile){
+int sqlite3InvokeBusyHandler(BusyHandler *p){
int rc;
if( p->xBusyHandler==0 || p->nBusy<0 ) return 0;
- if( p->bExtraFileArg ){
- /* Add an extra parameter with the pFile pointer to the end of the
- ** callback argument list */
- int (*xTra)(void*,int,sqlite3_file*);
- xTra = (int(*)(void*,int,sqlite3_file*))p->xBusyHandler;
- rc = xTra(p->pBusyArg, p->nBusy, pFile);
- }else{
- /* Legacy style busy handler callback */
- rc = p->xBusyHandler(p->pBusyArg, p->nBusy);
- }
+ rc = p->xBusyHandler(p->pBusyArg, p->nBusy);
if( rc==0 ){
p->nBusy = -1;
}else{
@@ -1665,7 +1693,6 @@ int sqlite3_busy_handler(
db->busyHandler.xBusyHandler = xBusy;
db->busyHandler.pBusyArg = pArg;
db->busyHandler.nBusy = 0;
- db->busyHandler.bExtraFileArg = 0;
db->busyTimeout = 0;
sqlite3_mutex_leave(db->mutex);
return SQLITE_OK;
@@ -1716,7 +1743,6 @@ int sqlite3_busy_timeout(sqlite3 *db, int ms){
sqlite3_busy_handler(db, (int(*)(void*,int))sqliteDefaultBusyCallback,
(void*)db);
db->busyTimeout = ms;
- db->busyHandler.bExtraFileArg = 1;
}else{
sqlite3_busy_handler(db, 0, 0);
}
@@ -3042,6 +3068,7 @@ static int openDatabase(
int isThreadsafe; /* True for threadsafe connections */
char *zOpen = 0; /* Filename argument to pass to BtreeOpen() */
char *zErrMsg = 0; /* Error message from sqlite3ParseUri() */
+ int i; /* Loop counter */
#ifdef SQLITE_ENABLE_API_ARMOR
if( ppDb==0 ) return SQLITE_MISUSE_BKPT;
@@ -3085,7 +3112,7 @@ static int openDatabase(
SQLITE_OPEN_MAIN_JOURNAL |
SQLITE_OPEN_TEMP_JOURNAL |
SQLITE_OPEN_SUBJOURNAL |
- SQLITE_OPEN_MASTER_JOURNAL |
+ SQLITE_OPEN_SUPER_JOURNAL |
SQLITE_OPEN_NOMUTEX |
SQLITE_OPEN_FULLMUTEX |
SQLITE_OPEN_WAL
@@ -3190,6 +3217,9 @@ static int openDatabase(
#if defined(SQLITE_DEFAULT_DEFENSIVE)
| SQLITE_Defensive
#endif
+#if defined(SQLITE_DEFAULT_LEGACY_ALTER_TABLE)
+ | SQLITE_LegacyAlter
+#endif
;
sqlite3HashInit(&db->aCollSeq);
#ifndef SQLITE_OMIT_VIRTUALTABLE
@@ -3232,7 +3262,7 @@ static int openDatabase(
testcase( (1<<(flags&7))==0x04 ); /* READWRITE */
testcase( (1<<(flags&7))==0x40 ); /* READWRITE | CREATE */
if( ((1<<(flags&7)) & 0x46)==0 ){
- rc = SQLITE_MISUSE_BKPT; /* IMP: R-65497-44594 */
+ rc = SQLITE_MISUSE_BKPT; /* IMP: R-18321-05872 */
}else{
rc = sqlite3ParseUri(zVfs, zFilename, &flags, &db->pVfs, &zOpen, &zErrMsg);
}
@@ -3282,14 +3312,11 @@ static int openDatabase(
sqlite3RegisterPerConnectionBuiltinFunctions(db);
rc = sqlite3_errcode(db);
-#ifdef SQLITE_ENABLE_FTS5
- /* Register any built-in FTS5 module before loading the automatic
- ** extensions. This allows automatic extensions to register FTS5
- ** tokenizers and auxiliary functions. */
- if( !db->mallocFailed && rc==SQLITE_OK ){
- rc = sqlite3Fts5Init(db);
+
+ /* Load compiled-in extensions */
+ for(i=0; rc==SQLITE_OK && i<ArraySize(sqlite3BuiltinExtensions); i++){
+ rc = sqlite3BuiltinExtensions[i](db);
}
-#endif
/* Load automatic extensions - extensions that have been registered
** using the sqlite3_automatic_extension() API.
@@ -3302,62 +3329,6 @@ static int openDatabase(
}
}
-#ifdef SQLITE_ENABLE_FTS1
- if( !db->mallocFailed ){
- extern int sqlite3Fts1Init(sqlite3*);
- rc = sqlite3Fts1Init(db);
- }
-#endif
-
-#ifdef SQLITE_ENABLE_FTS2
- if( !db->mallocFailed && rc==SQLITE_OK ){
- extern int sqlite3Fts2Init(sqlite3*);
- rc = sqlite3Fts2Init(db);
- }
-#endif
-
-#ifdef SQLITE_ENABLE_FTS3 /* automatically defined by SQLITE_ENABLE_FTS4 */
- if( !db->mallocFailed && rc==SQLITE_OK ){
- rc = sqlite3Fts3Init(db);
- }
-#endif
-
-#if defined(SQLITE_ENABLE_ICU) || defined(SQLITE_ENABLE_ICU_COLLATIONS)
- if( !db->mallocFailed && rc==SQLITE_OK ){
- rc = sqlite3IcuInit(db);
- }
-#endif
-
-#ifdef SQLITE_ENABLE_RTREE
- if( !db->mallocFailed && rc==SQLITE_OK){
- rc = sqlite3RtreeInit(db);
- }
-#endif
-
-#ifdef SQLITE_ENABLE_DBPAGE_VTAB
- if( !db->mallocFailed && rc==SQLITE_OK){
- rc = sqlite3DbpageRegister(db);
- }
-#endif
-
-#ifdef SQLITE_ENABLE_DBSTAT_VTAB
- if( !db->mallocFailed && rc==SQLITE_OK){
- rc = sqlite3DbstatRegister(db);
- }
-#endif
-
-#ifdef SQLITE_ENABLE_JSON1
- if( !db->mallocFailed && rc==SQLITE_OK){
- rc = sqlite3Json1Init(db);
- }
-#endif
-
-#ifdef SQLITE_ENABLE_STMTVTAB
- if( !db->mallocFailed && rc==SQLITE_OK){
- rc = sqlite3StmtVtabInit(db);
- }
-#endif
-
#ifdef SQLITE_ENABLE_INTERNAL_FUNCTIONS
/* Testing use only!!! The -DSQLITE_ENABLE_INTERNAL_FUNCTIONS=1 compile-time
** option gives access to internal functions by default.
@@ -3846,7 +3817,7 @@ int sqlite3_file_control(sqlite3 *db, const char *zDbName, int op, void *pArg){
}else if( op==SQLITE_FCNTL_RESERVE_BYTES ){
int iNew = *(int*)pArg;
*(int*)pArg = sqlite3BtreeGetRequestedReserve(pBtree);
- if( iNew>=0 && iNew<=254 ){
+ if( iNew>=0 && iNew<=255 ){
sqlite3BtreeSetPageSize(pBtree, 0, iNew, 0);
}
rc = SQLITE_OK;
@@ -4118,7 +4089,7 @@ int sqlite3_test_control(int op, ...){
/* sqlite3_test_control(SQLITE_TESTCTRL_EXTRA_SCHEMA_CHECKS, int);
**
** Set or clear a flag that causes SQLite to verify that type, name,
- ** and tbl_name fields of the sqlite_master table. This is normally
+ ** and tbl_name fields of the sqlite_schema table. This is normally
** on, but it is sometimes useful to turn it off for testing.
*/
case SQLITE_TESTCTRL_EXTRA_SCHEMA_CHECKS: {
diff --git a/src/malloc.c b/src/malloc.c
index a19d8bdfb..577836ef9 100644
--- a/src/malloc.c
+++ b/src/malloc.c
@@ -111,7 +111,7 @@ sqlite3_int64 sqlite3_soft_heap_limit64(sqlite3_int64 n){
}
mem0.alarmThreshold = n;
nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED);
- mem0.nearlyFull = (n>0 && n<=nUsed);
+ AtomicStore(&mem0.nearlyFull, n>0 && n<=nUsed);
sqlite3_mutex_leave(mem0.mutex);
excess = sqlite3_memory_used() - n;
if( excess>0 ) sqlite3_release_memory((int)(excess & 0x7fffffff));
@@ -179,7 +179,7 @@ int sqlite3MallocInit(void){
** sqlite3_soft_heap_limit().
*/
int sqlite3HeapNearlyFull(void){
- return mem0.nearlyFull;
+ return AtomicLoad(&mem0.nearlyFull);
}
/*
@@ -243,7 +243,7 @@ static void mallocWithAlarm(int n, void **pp){
if( mem0.alarmThreshold>0 ){
sqlite3_int64 nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED);
if( nUsed >= mem0.alarmThreshold - nFull ){
- mem0.nearlyFull = 1;
+ AtomicStore(&mem0.nearlyFull, 1);
sqlite3MallocAlarm(nFull);
if( mem0.hardLimit ){
nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED);
@@ -253,7 +253,7 @@ static void mallocWithAlarm(int n, void **pp){
}
}
}else{
- mem0.nearlyFull = 0;
+ AtomicStore(&mem0.nearlyFull, 0);
}
}
p = sqlite3GlobalConfig.m.xMalloc(nFull);
@@ -482,10 +482,12 @@ void *sqlite3Realloc(void *pOld, u64 nBytes){
sqlite3MallocAlarm(nDiff);
}
pNew = sqlite3GlobalConfig.m.xRealloc(pOld, nNew);
+#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
if( pNew==0 && mem0.alarmThreshold>0 ){
sqlite3MallocAlarm((int)nBytes);
pNew = sqlite3GlobalConfig.m.xRealloc(pOld, nNew);
}
+#endif
if( pNew ){
nNew = sqlite3MallocSize(pNew);
sqlite3StatusUp(SQLITE_STATUS_MEMORY_USED, nNew-nOld);
@@ -670,7 +672,7 @@ static SQLITE_NOINLINE void *dbReallocFinish(sqlite3 *db, void *p, u64 n){
assert( sqlite3MemdebugHasType(p, (MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
assert( sqlite3MemdebugNoType(p, (u8)~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
- pNew = sqlite3_realloc64(p, n);
+ pNew = sqlite3Realloc(p, n);
if( !pNew ){
sqlite3OomFault(db);
}
diff --git a/src/mem3.c b/src/mem3.c
index 2de028daa..16463d6a5 100644
--- a/src/mem3.c
+++ b/src/mem3.c
@@ -118,16 +118,16 @@ static SQLITE_WSD struct Mem3Global {
/*
** The minimum amount of free space that we have seen.
*/
- u32 mnMaster;
+ u32 mnKeyBlk;
/*
- ** iMaster is the index of the master chunk. Most new allocations
- ** occur off of this chunk. szMaster is the size (in Mem3Blocks)
- ** of the current master. iMaster is 0 if there is not master chunk.
- ** The master chunk is not in either the aiHash[] or aiSmall[].
+ ** iKeyBlk is the index of the key chunk. Most new allocations
+ ** occur off of this chunk. szKeyBlk is the size (in Mem3Blocks)
+ ** of the current key chunk. iKeyBlk is 0 if there is no key chunk.
+ ** The key chunk is not in either the aiHash[] or aiSmall[].
*/
- u32 iMaster;
- u32 szMaster;
+ u32 iKeyBlk;
+ u32 szKeyBlk;
/*
** Array of lists of free blocks according to the block size
@@ -263,34 +263,34 @@ static void *memsys3Checkout(u32 i, u32 nBlock){
}
/*
-** Carve a piece off of the end of the mem3.iMaster free chunk.
-** Return a pointer to the new allocation. Or, if the master chunk
+** Carve a piece off of the end of the mem3.iKeyBlk free chunk.
+** Return a pointer to the new allocation. Or, if the key chunk
** is not large enough, return 0.
*/
-static void *memsys3FromMaster(u32 nBlock){
+static void *memsys3FromKeyBlk(u32 nBlock){
assert( sqlite3_mutex_held(mem3.mutex) );
- assert( mem3.szMaster>=nBlock );
- if( nBlock>=mem3.szMaster-1 ){
- /* Use the entire master */
- void *p = memsys3Checkout(mem3.iMaster, mem3.szMaster);
- mem3.iMaster = 0;
- mem3.szMaster = 0;
- mem3.mnMaster = 0;
+ assert( mem3.szKeyBlk>=nBlock );
+ if( nBlock>=mem3.szKeyBlk-1 ){
+ /* Use the entire key chunk */
+ void *p = memsys3Checkout(mem3.iKeyBlk, mem3.szKeyBlk);
+ mem3.iKeyBlk = 0;
+ mem3.szKeyBlk = 0;
+ mem3.mnKeyBlk = 0;
return p;
}else{
- /* Split the master block. Return the tail. */
+ /* Split the key block. Return the tail. */
u32 newi, x;
- newi = mem3.iMaster + mem3.szMaster - nBlock;
- assert( newi > mem3.iMaster+1 );
- mem3.aPool[mem3.iMaster+mem3.szMaster-1].u.hdr.prevSize = nBlock;
- mem3.aPool[mem3.iMaster+mem3.szMaster-1].u.hdr.size4x |= 2;
+ newi = mem3.iKeyBlk + mem3.szKeyBlk - nBlock;
+ assert( newi > mem3.iKeyBlk+1 );
+ mem3.aPool[mem3.iKeyBlk+mem3.szKeyBlk-1].u.hdr.prevSize = nBlock;
+ mem3.aPool[mem3.iKeyBlk+mem3.szKeyBlk-1].u.hdr.size4x |= 2;
mem3.aPool[newi-1].u.hdr.size4x = nBlock*4 + 1;
- mem3.szMaster -= nBlock;
- mem3.aPool[newi-1].u.hdr.prevSize = mem3.szMaster;
- x = mem3.aPool[mem3.iMaster-1].u.hdr.size4x & 2;
- mem3.aPool[mem3.iMaster-1].u.hdr.size4x = mem3.szMaster*4 | x;
- if( mem3.szMaster < mem3.mnMaster ){
- mem3.mnMaster = mem3.szMaster;
+ mem3.szKeyBlk -= nBlock;
+ mem3.aPool[newi-1].u.hdr.prevSize = mem3.szKeyBlk;
+ x = mem3.aPool[mem3.iKeyBlk-1].u.hdr.size4x & 2;
+ mem3.aPool[mem3.iKeyBlk-1].u.hdr.size4x = mem3.szKeyBlk*4 | x;
+ if( mem3.szKeyBlk < mem3.mnKeyBlk ){
+ mem3.mnKeyBlk = mem3.szKeyBlk;
}
return (void*)&mem3.aPool[newi];
}
@@ -304,13 +304,13 @@ static void *memsys3FromMaster(u32 nBlock){
** This routine examines all entries on the given list and tries
** to coalesce each entries with adjacent free chunks.
**
-** If it sees a chunk that is larger than mem3.iMaster, it replaces
-** the current mem3.iMaster with the new larger chunk. In order for
-** this mem3.iMaster replacement to work, the master chunk must be
+** If it sees a chunk that is larger than mem3.iKeyBlk, it replaces
+** the current mem3.iKeyBlk with the new larger chunk. In order for
+** this mem3.iKeyBlk replacement to work, the key chunk must be
** linked into the hash tables. That is not the normal state of
-** affairs, of course. The calling routine must link the master
+** affairs, of course. The calling routine must link the key
** chunk before invoking this routine, then must unlink the (possibly
-** changed) master chunk once this routine has finished.
+** changed) key chunk once this routine has finished.
*/
static void memsys3Merge(u32 *pRoot){
u32 iNext, prev, size, i, x;
@@ -337,9 +337,9 @@ static void memsys3Merge(u32 *pRoot){
}else{
size /= 4;
}
- if( size>mem3.szMaster ){
- mem3.iMaster = i;
- mem3.szMaster = size;
+ if( size>mem3.szKeyBlk ){
+ mem3.iKeyBlk = i;
+ mem3.szKeyBlk = size;
}
}
}
@@ -388,26 +388,26 @@ static void *memsys3MallocUnsafe(int nByte){
/* STEP 2:
** Try to satisfy the allocation by carving a piece off of the end
- ** of the master chunk. This step usually works if step 1 fails.
+ ** of the key chunk. This step usually works if step 1 fails.
*/
- if( mem3.szMaster>=nBlock ){
- return memsys3FromMaster(nBlock);
+ if( mem3.szKeyBlk>=nBlock ){
+ return memsys3FromKeyBlk(nBlock);
}
/* STEP 3:
** Loop through the entire memory pool. Coalesce adjacent free
- ** chunks. Recompute the master chunk as the largest free chunk.
+ ** chunks. Recompute the key chunk as the largest free chunk.
** Then try again to satisfy the allocation by carving a piece off
- ** of the end of the master chunk. This step happens very
+ ** of the end of the key chunk. This step happens very
** rarely (we hope!)
*/
for(toFree=nBlock*16; toFree<(mem3.nPool*16); toFree *= 2){
memsys3OutOfMemory(toFree);
- if( mem3.iMaster ){
- memsys3Link(mem3.iMaster);
- mem3.iMaster = 0;
- mem3.szMaster = 0;
+ if( mem3.iKeyBlk ){
+ memsys3Link(mem3.iKeyBlk);
+ mem3.iKeyBlk = 0;
+ mem3.szKeyBlk = 0;
}
for(i=0; i<N_HASH; i++){
memsys3Merge(&mem3.aiHash[i]);
@@ -415,10 +415,10 @@ static void *memsys3MallocUnsafe(int nByte){
for(i=0; i<MX_SMALL-1; i++){
memsys3Merge(&mem3.aiSmall[i]);
}
- if( mem3.szMaster ){
- memsys3Unlink(mem3.iMaster);
- if( mem3.szMaster>=nBlock ){
- return memsys3FromMaster(nBlock);
+ if( mem3.szKeyBlk ){
+ memsys3Unlink(mem3.iKeyBlk);
+ if( mem3.szKeyBlk>=nBlock ){
+ return memsys3FromKeyBlk(nBlock);
}
}
}
@@ -448,23 +448,23 @@ static void memsys3FreeUnsafe(void *pOld){
mem3.aPool[i+size-1].u.hdr.size4x &= ~2;
memsys3Link(i);
- /* Try to expand the master using the newly freed chunk */
- if( mem3.iMaster ){
- while( (mem3.aPool[mem3.iMaster-1].u.hdr.size4x&2)==0 ){
- size = mem3.aPool[mem3.iMaster-1].u.hdr.prevSize;
- mem3.iMaster -= size;
- mem3.szMaster += size;
- memsys3Unlink(mem3.iMaster);
- x = mem3.aPool[mem3.iMaster-1].u.hdr.size4x & 2;
- mem3.aPool[mem3.iMaster-1].u.hdr.size4x = mem3.szMaster*4 | x;
- mem3.aPool[mem3.iMaster+mem3.szMaster-1].u.hdr.prevSize = mem3.szMaster;
+ /* Try to expand the key using the newly freed chunk */
+ if( mem3.iKeyBlk ){
+ while( (mem3.aPool[mem3.iKeyBlk-1].u.hdr.size4x&2)==0 ){
+ size = mem3.aPool[mem3.iKeyBlk-1].u.hdr.prevSize;
+ mem3.iKeyBlk -= size;
+ mem3.szKeyBlk += size;
+ memsys3Unlink(mem3.iKeyBlk);
+ x = mem3.aPool[mem3.iKeyBlk-1].u.hdr.size4x & 2;
+ mem3.aPool[mem3.iKeyBlk-1].u.hdr.size4x = mem3.szKeyBlk*4 | x;
+ mem3.aPool[mem3.iKeyBlk+mem3.szKeyBlk-1].u.hdr.prevSize = mem3.szKeyBlk;
}
- x = mem3.aPool[mem3.iMaster-1].u.hdr.size4x & 2;
- while( (mem3.aPool[mem3.iMaster+mem3.szMaster-1].u.hdr.size4x&1)==0 ){
- memsys3Unlink(mem3.iMaster+mem3.szMaster);
- mem3.szMaster += mem3.aPool[mem3.iMaster+mem3.szMaster-1].u.hdr.size4x/4;
- mem3.aPool[mem3.iMaster-1].u.hdr.size4x = mem3.szMaster*4 | x;
- mem3.aPool[mem3.iMaster+mem3.szMaster-1].u.hdr.prevSize = mem3.szMaster;
+ x = mem3.aPool[mem3.iKeyBlk-1].u.hdr.size4x & 2;
+ while( (mem3.aPool[mem3.iKeyBlk+mem3.szKeyBlk-1].u.hdr.size4x&1)==0 ){
+ memsys3Unlink(mem3.iKeyBlk+mem3.szKeyBlk);
+ mem3.szKeyBlk += mem3.aPool[mem3.iKeyBlk+mem3.szKeyBlk-1].u.hdr.size4x/4;
+ mem3.aPool[mem3.iKeyBlk-1].u.hdr.size4x = mem3.szKeyBlk*4 | x;
+ mem3.aPool[mem3.iKeyBlk+mem3.szKeyBlk-1].u.hdr.prevSize = mem3.szKeyBlk;
}
}
}
@@ -560,11 +560,11 @@ static int memsys3Init(void *NotUsed){
mem3.aPool = (Mem3Block *)sqlite3GlobalConfig.pHeap;
mem3.nPool = (sqlite3GlobalConfig.nHeap / sizeof(Mem3Block)) - 2;
- /* Initialize the master block. */
- mem3.szMaster = mem3.nPool;
- mem3.mnMaster = mem3.szMaster;
- mem3.iMaster = 1;
- mem3.aPool[0].u.hdr.size4x = (mem3.szMaster<<2) + 2;
+ /* Initialize the key block. */
+ mem3.szKeyBlk = mem3.nPool;
+ mem3.mnKeyBlk = mem3.szKeyBlk;
+ mem3.iKeyBlk = 1;
+ mem3.aPool[0].u.hdr.size4x = (mem3.szKeyBlk<<2) + 2;
mem3.aPool[mem3.nPool].u.hdr.prevSize = mem3.nPool;
mem3.aPool[mem3.nPool].u.hdr.size4x = 1;
@@ -624,7 +624,7 @@ void sqlite3Memsys3Dump(const char *zFilename){
fprintf(out, "%p %6d bytes checked out\n", &mem3.aPool[i], (size/4)*8-8);
}else{
fprintf(out, "%p %6d bytes free%s\n", &mem3.aPool[i], (size/4)*8-8,
- i==mem3.iMaster ? " **master**" : "");
+ i==mem3.iKeyBlk ? " **key**" : "");
}
}
for(i=0; i<MX_SMALL-1; i++){
@@ -645,9 +645,9 @@ void sqlite3Memsys3Dump(const char *zFilename){
}
fprintf(out, "\n");
}
- fprintf(out, "master=%d\n", mem3.iMaster);
- fprintf(out, "nowUsed=%d\n", mem3.nPool*8 - mem3.szMaster*8);
- fprintf(out, "mxUsed=%d\n", mem3.nPool*8 - mem3.mnMaster*8);
+ fprintf(out, "key=%d\n", mem3.iKeyBlk);
+ fprintf(out, "nowUsed=%d\n", mem3.nPool*8 - mem3.szKeyBlk*8);
+ fprintf(out, "mxUsed=%d\n", mem3.nPool*8 - mem3.mnKeyBlk*8);
sqlite3_mutex_leave(mem3.mutex);
if( out==stdout ){
fflush(stdout);
diff --git a/src/memdb.c b/src/memdb.c
index 2ddecae72..9edbef157 100644
--- a/src/memdb.c
+++ b/src/memdb.c
@@ -166,7 +166,7 @@ static int memdbEnlarge(MemFile *p, sqlite3_int64 newSz){
}
newSz *= 2;
if( newSz>p->szMax ) newSz = p->szMax;
- pNew = sqlite3_realloc64(p->aData, newSz);
+ pNew = sqlite3Realloc(p->aData, newSz);
if( pNew==0 ) return SQLITE_NOMEM;
p->aData = pNew;
p->szAlloc = newSz;
@@ -344,7 +344,7 @@ static int memdbOpen(
return SQLITE_OK;
}
-#if 0 /* Only used to delete rollback journals, master journals, and WAL
+#if 0 /* Only used to delete rollback journals, super-journals, and WAL
** files, none of which exist in memdb. So this routine is never used */
/*
** Delete the file located at zPath. If the dirSync argument is true,
@@ -613,10 +613,11 @@ int sqlite3MemdbInit(void){
sqlite3_vfs *pLower = sqlite3_vfs_find(0);
int sz = pLower->szOsFile;
memdb_vfs.pAppData = pLower;
- /* In all known configurations of SQLite, the size of a default
- ** sqlite3_file is greater than the size of a memdb sqlite3_file.
- ** Should that ever change, remove the following NEVER() */
- if( NEVER(sz<sizeof(MemFile)) ) sz = sizeof(MemFile);
+ /* The following conditional can only be true when compiled for
+ ** Windows x86 and SQLITE_MAX_MMAP_SIZE=0. We always leave
+ ** it in, to be safe, but it is marked as NO_TEST since there
+ ** is no way to reach it under most builds. */
+ if( sz<sizeof(MemFile) ) sz = sizeof(MemFile); /*NO_TEST*/
memdb_vfs.szOsFile = sz;
return sqlite3_vfs_register(&memdb_vfs, 0);
}
diff --git a/src/mutex_unix.c b/src/mutex_unix.c
index 9282d2801..2afaddec6 100644
--- a/src/mutex_unix.c
+++ b/src/mutex_unix.c
@@ -112,7 +112,7 @@ static int pthreadMutexEnd(void){ return SQLITE_OK; }
** <ul>
** <li> SQLITE_MUTEX_FAST
** <li> SQLITE_MUTEX_RECURSIVE
-** <li> SQLITE_MUTEX_STATIC_MASTER
+** <li> SQLITE_MUTEX_STATIC_MAIN
** <li> SQLITE_MUTEX_STATIC_MEM
** <li> SQLITE_MUTEX_STATIC_OPEN
** <li> SQLITE_MUTEX_STATIC_PRNG
diff --git a/src/mutex_w32.c b/src/mutex_w32.c
index 8a8ae289b..09deda409 100644
--- a/src/mutex_w32.c
+++ b/src/mutex_w32.c
@@ -171,7 +171,7 @@ static int winMutexEnd(void){
** <ul>
** <li> SQLITE_MUTEX_FAST
** <li> SQLITE_MUTEX_RECURSIVE
-** <li> SQLITE_MUTEX_STATIC_MASTER
+** <li> SQLITE_MUTEX_STATIC_MAIN
** <li> SQLITE_MUTEX_STATIC_MEM
** <li> SQLITE_MUTEX_STATIC_OPEN
** <li> SQLITE_MUTEX_STATIC_PRNG
diff --git a/src/notify.c b/src/notify.c
index 8137226f3..4960ab76b 100644
--- a/src/notify.c
+++ b/src/notify.c
@@ -29,12 +29,12 @@
*/
#define assertMutexHeld() \
- assert( sqlite3_mutex_held(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER)) )
+ assert( sqlite3_mutex_held(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN)) )
/*
** Head of a linked list of all sqlite3 objects created by this process
** for which either sqlite3.pBlockingConnection or sqlite3.pUnlockConnection
-** is not NULL. This variable may only accessed while the STATIC_MASTER
+** is not NULL. This variable may only accessed while the STATIC_MAIN
** mutex is held.
*/
static sqlite3 *SQLITE_WSD sqlite3BlockedList = 0;
@@ -108,20 +108,20 @@ static void addToBlockedList(sqlite3 *db){
}
/*
-** Obtain the STATIC_MASTER mutex.
+** Obtain the STATIC_MAIN mutex.
*/
static void enterMutex(void){
- sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
+ sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN));
checkListProperties(0);
}
/*
-** Release the STATIC_MASTER mutex.
+** Release the STATIC_MAIN mutex.
*/
static void leaveMutex(void){
assertMutexHeld();
checkListProperties(0);
- sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
+ sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN));
}
/*
@@ -232,7 +232,7 @@ void sqlite3ConnectionUnlocked(sqlite3 *db){
void *aStatic[16]; /* Starter space for aArg[]. No malloc required */
aArg = aStatic;
- enterMutex(); /* Enter STATIC_MASTER mutex */
+ enterMutex(); /* Enter STATIC_MAIN mutex */
/* This loop runs once for each entry in the blocked-connections list. */
for(pp=&sqlite3BlockedList; *pp; /* no-op */ ){
@@ -315,7 +315,7 @@ void sqlite3ConnectionUnlocked(sqlite3 *db){
xUnlockNotify(aArg, nArg);
}
sqlite3_free(aDyn);
- leaveMutex(); /* Leave STATIC_MASTER mutex */
+ leaveMutex(); /* Leave STATIC_MAIN mutex */
}
/*
diff --git a/src/os.c b/src/os.c
index b729e95e6..a1a276f43 100644
--- a/src/os.c
+++ b/src/os.c
@@ -353,7 +353,7 @@ sqlite3_vfs *sqlite3_vfs_find(const char *zVfs){
if( rc ) return 0;
#endif
#if SQLITE_THREADSAFE
- mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
+ mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN);
#endif
sqlite3_mutex_enter(mutex);
for(pVfs = vfsList; pVfs; pVfs=pVfs->pNext){
@@ -368,7 +368,7 @@ sqlite3_vfs *sqlite3_vfs_find(const char *zVfs){
** Unlink a VFS from the linked list
*/
static void vfsUnlink(sqlite3_vfs *pVfs){
- assert( sqlite3_mutex_held(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER)) );
+ assert( sqlite3_mutex_held(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN)) );
if( pVfs==0 ){
/* No-op */
}else if( vfsList==pVfs ){
@@ -399,7 +399,7 @@ int sqlite3_vfs_register(sqlite3_vfs *pVfs, int makeDflt){
if( pVfs==0 ) return SQLITE_MISUSE_BKPT;
#endif
- MUTEX_LOGIC( mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); )
+ MUTEX_LOGIC( mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN); )
sqlite3_mutex_enter(mutex);
vfsUnlink(pVfs);
if( makeDflt || vfsList==0 ){
@@ -423,7 +423,7 @@ int sqlite3_vfs_unregister(sqlite3_vfs *pVfs){
int rc = sqlite3_initialize();
if( rc ) return rc;
#endif
- MUTEX_LOGIC( mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); )
+ MUTEX_LOGIC( mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN); )
sqlite3_mutex_enter(mutex);
vfsUnlink(pVfs);
sqlite3_mutex_leave(mutex);
diff --git a/src/os_unix.c b/src/os_unix.c
index 56e53929e..3571f3f2c 100644
--- a/src/os_unix.c
+++ b/src/os_unix.c
@@ -1565,8 +1565,9 @@ static int osSetPosixAdvisoryLock(
struct flock *pLock, /* The description of the lock */
unixFile *pFile /* Structure holding timeout value */
){
+ int tm = pFile->iBusyTimeout;
int rc = osFcntl(h,F_SETLK,pLock);
- while( rc<0 && pFile->iBusyTimeout>0 ){
+ while( rc<0 && tm>0 ){
/* On systems that support some kind of blocking file lock with a timeout,
** make appropriate changes here to invoke that blocking file lock. On
** generic posix, however, there is no such API. So we simply try the
@@ -1574,7 +1575,7 @@ static int osSetPosixAdvisoryLock(
** the lock is obtained. */
usleep(1000);
rc = osFcntl(h,F_SETLK,pLock);
- pFile->iBusyTimeout--;
+ tm--;
}
return rc;
}
@@ -3339,7 +3340,7 @@ static int unixRead(
assert( offset>=0 );
assert( amt>0 );
- /* If this is a database file (not a journal, master-journal or temp
+ /* If this is a database file (not a journal, super-journal or temp
** file), the bytes in the locking range should never be read or written. */
#if 0
assert( pFile->pPreallocatedUnused==0
@@ -3452,7 +3453,7 @@ static int unixWrite(
assert( id );
assert( amt>0 );
- /* If this is a database file (not a journal, master-journal or temp
+ /* If this is a database file (not a journal, super-journal or temp
** file), the bytes in the locking range should never be read or written. */
#if 0
assert( pFile->pPreallocatedUnused==0
@@ -4316,13 +4317,20 @@ static int unixShmSystemLock(
assert( n>=1 && n<=SQLITE_SHM_NLOCK );
if( pShmNode->hShm>=0 ){
+ int res;
/* Initialize the locking parameters */
f.l_type = lockType;
f.l_whence = SEEK_SET;
f.l_start = ofst;
f.l_len = n;
- rc = osSetPosixAdvisoryLock(pShmNode->hShm, &f, pFile);
- rc = (rc!=(-1)) ? SQLITE_OK : SQLITE_BUSY;
+ res = osSetPosixAdvisoryLock(pShmNode->hShm, &f, pFile);
+ if( res==-1 ){
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+ rc = (pFile->iBusyTimeout ? SQLITE_BUSY_TIMEOUT : SQLITE_BUSY);
+#else
+ rc = SQLITE_BUSY;
+#endif
+ }
}
/* Update the global lock state and do debug tracing */
@@ -4819,22 +4827,26 @@ static int unixShmLock(
assert( pShmNode->hShm>=0 || pDbFd->pInode->bProcessLock==1 );
assert( pShmNode->hShm<0 || pDbFd->pInode->bProcessLock==0 );
- /* Check that, if this to be a blocking lock, that locks have been
- ** obtained in the following order.
+ /* Check that, if this to be a blocking lock, no locks that occur later
+ ** in the following list than the lock being obtained are already held:
**
** 1. Checkpointer lock (ofst==1).
- ** 2. Recover lock (ofst==2).
+ ** 2. Write lock (ofst==0).
** 3. Read locks (ofst>=3 && ofst<SQLITE_SHM_NLOCK).
- ** 4. Write lock (ofst==0).
**
** In other words, if this is a blocking lock, none of the locks that
** occur later in the above list than the lock being obtained may be
- ** held. */
+ ** held.
+ **
+ ** It is not permitted to block on the RECOVER lock.
+ */
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
- assert( pDbFd->iBusyTimeout==0
- || (flags & SQLITE_SHM_UNLOCK) || ofst==0
- || ((p->exclMask|p->sharedMask)&~((1<<ofst)-2))==0
- );
+ assert( (flags & SQLITE_SHM_UNLOCK) || pDbFd->iBusyTimeout==0 || (
+ (ofst!=2) /* not RECOVER */
+ && (ofst!=1 || (p->exclMask|p->sharedMask)==0)
+ && (ofst!=0 || (p->exclMask|p->sharedMask)<3)
+ && (ofst<3 || (p->exclMask|p->sharedMask)<(1<<ofst))
+ ));
#endif
mask = (1<<(ofst+n)) - (1<<ofst);
@@ -5761,7 +5773,7 @@ static int proxyTransformUnixFile(unixFile*, const char*);
/*
** Search for an unused file descriptor that was opened on the database
-** file (not a journal or master-journal file) identified by pathname
+** file (not a journal or super-journal file) identified by pathname
** zPath with SQLITE_OPEN_XXX flags matching those passed as the second
** argument to this function.
**
@@ -5895,7 +5907,7 @@ static int findCreateFileMode(
while( zPath[nDb]!='-' ){
/* In normal operation, the journal file name will always contain
** a '-' character. However in 8+3 filename mode, or if a corrupt
- ** rollback journal specifies a master journal with a goofy name, then
+ ** rollback journal specifies a super-journal with a goofy name, then
** the '-' might be missing. */
if( nDb==0 || zPath[nDb]=='.' ) return SQLITE_OK;
nDb--;
@@ -5968,12 +5980,12 @@ static int unixOpen(
struct statfs fsInfo;
#endif
- /* If creating a master or main-file journal, this function will open
+ /* If creating a super- or main-file journal, this function will open
** a file-descriptor on the directory too. The first time unixSync()
** is called the directory file descriptor will be fsync()ed and close()d.
*/
int isNewJrnl = (isCreate && (
- eType==SQLITE_OPEN_MASTER_JOURNAL
+ eType==SQLITE_OPEN_SUPER_JOURNAL
|| eType==SQLITE_OPEN_MAIN_JOURNAL
|| eType==SQLITE_OPEN_WAL
));
@@ -5996,17 +6008,17 @@ static int unixOpen(
assert(isExclusive==0 || isCreate);
assert(isDelete==0 || isCreate);
- /* The main DB, main journal, WAL file and master journal are never
+ /* The main DB, main journal, WAL file and super-journal are never
** automatically deleted. Nor are they ever temporary files. */
assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MAIN_DB );
assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MAIN_JOURNAL );
- assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MASTER_JOURNAL );
+ assert( (!isDelete && zName) || eType!=SQLITE_OPEN_SUPER_JOURNAL );
assert( (!isDelete && zName) || eType!=SQLITE_OPEN_WAL );
/* Assert that the upper layer has set one of the "file-type" flags. */
assert( eType==SQLITE_OPEN_MAIN_DB || eType==SQLITE_OPEN_TEMP_DB
|| eType==SQLITE_OPEN_MAIN_JOURNAL || eType==SQLITE_OPEN_TEMP_JOURNAL
- || eType==SQLITE_OPEN_SUBJOURNAL || eType==SQLITE_OPEN_MASTER_JOURNAL
+ || eType==SQLITE_OPEN_SUBJOURNAL || eType==SQLITE_OPEN_SUPER_JOURNAL
|| eType==SQLITE_OPEN_TRANSIENT_DB || eType==SQLITE_OPEN_WAL
);
@@ -6199,7 +6211,7 @@ static int unixOpen(
#endif
assert( zPath==0 || zPath[0]=='/'
- || eType==SQLITE_OPEN_MASTER_JOURNAL || eType==SQLITE_OPEN_MAIN_JOURNAL
+ || eType==SQLITE_OPEN_SUPER_JOURNAL || eType==SQLITE_OPEN_MAIN_JOURNAL
);
rc = fillInUnixFile(pVfs, fd, pFile, zPath, ctrlFlags);
diff --git a/src/os_win.c b/src/os_win.c
index 32758ab76..a03f3bfab 100644
--- a/src/os_win.c
+++ b/src/os_win.c
@@ -1290,17 +1290,17 @@ int sqlite3_win32_compact_heap(LPUINT pnLargest){
*/
int sqlite3_win32_reset_heap(){
int rc;
- MUTEX_LOGIC( sqlite3_mutex *pMaster; ) /* The main static mutex */
+ MUTEX_LOGIC( sqlite3_mutex *pMainMtx; ) /* The main static mutex */
MUTEX_LOGIC( sqlite3_mutex *pMem; ) /* The memsys static mutex */
- MUTEX_LOGIC( pMaster = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); )
+ MUTEX_LOGIC( pMainMtx = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN); )
MUTEX_LOGIC( pMem = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MEM); )
- sqlite3_mutex_enter(pMaster);
+ sqlite3_mutex_enter(pMainMtx);
sqlite3_mutex_enter(pMem);
winMemAssertMagic();
if( winMemGetHeap()!=NULL && winMemGetOwned() && sqlite3_memory_used()==0 ){
/*
** At this point, there should be no outstanding memory allocations on
- ** the heap. Also, since both the master and memsys locks are currently
+ ** the heap. Also, since both the main and memsys locks are currently
** being held by us, no other function (i.e. from another thread) should
** be able to even access the heap. Attempt to destroy and recreate our
** isolated Win32 native heap now.
@@ -1323,7 +1323,7 @@ int sqlite3_win32_reset_heap(){
rc = SQLITE_BUSY;
}
sqlite3_mutex_leave(pMem);
- sqlite3_mutex_leave(pMaster);
+ sqlite3_mutex_leave(pMainMtx);
return rc;
}
#endif /* SQLITE_WIN32_MALLOC */
@@ -3502,6 +3502,7 @@ static void winModeBit(winFile *pFile, unsigned char mask, int *pArg){
/* Forward references to VFS helper methods used for temporary files */
static int winGetTempname(sqlite3_vfs *, char **);
static int winIsDir(const void *);
+static BOOL winIsLongPathPrefix(const char *);
static BOOL winIsDriveLetterAndColon(const char *);
/*
@@ -5022,7 +5023,7 @@ static int winOpen(
#ifndef NDEBUG
int isOpenJournal = (isCreate && (
- eType==SQLITE_OPEN_MASTER_JOURNAL
+ eType==SQLITE_OPEN_SUPER_JOURNAL
|| eType==SQLITE_OPEN_MAIN_JOURNAL
|| eType==SQLITE_OPEN_WAL
));
@@ -5043,17 +5044,17 @@ static int winOpen(
assert(isExclusive==0 || isCreate);
assert(isDelete==0 || isCreate);
- /* The main DB, main journal, WAL file and master journal are never
+ /* The main DB, main journal, WAL file and super-journal are never
** automatically deleted. Nor are they ever temporary files. */
assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MAIN_DB );
assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MAIN_JOURNAL );
- assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MASTER_JOURNAL );
+ assert( (!isDelete && zName) || eType!=SQLITE_OPEN_SUPER_JOURNAL );
assert( (!isDelete && zName) || eType!=SQLITE_OPEN_WAL );
/* Assert that the upper layer has set one of the "file-type" flags. */
assert( eType==SQLITE_OPEN_MAIN_DB || eType==SQLITE_OPEN_TEMP_DB
|| eType==SQLITE_OPEN_MAIN_JOURNAL || eType==SQLITE_OPEN_TEMP_JOURNAL
- || eType==SQLITE_OPEN_SUBJOURNAL || eType==SQLITE_OPEN_MASTER_JOURNAL
+ || eType==SQLITE_OPEN_SUBJOURNAL || eType==SQLITE_OPEN_SUPER_JOURNAL
|| eType==SQLITE_OPEN_TRANSIENT_DB || eType==SQLITE_OPEN_WAL
);
@@ -5271,7 +5272,9 @@ static int winOpen(
if( isReadonly ){
pFile->ctrlFlags |= WINFILE_RDONLY;
}
- if( sqlite3_uri_boolean(zName, "psow", SQLITE_POWERSAFE_OVERWRITE) ){
+ if( (flags & SQLITE_OPEN_MAIN_DB)
+ && sqlite3_uri_boolean(zName, "psow", SQLITE_POWERSAFE_OVERWRITE)
+ ){
pFile->ctrlFlags |= WINFILE_PSOW;
}
pFile->lastErrno = NO_ERROR;
@@ -5482,6 +5485,17 @@ static int winAccess(
}
/*
+** Returns non-zero if the specified path name starts with the "long path"
+** prefix.
+*/
+static BOOL winIsLongPathPrefix(
+ const char *zPathname
+){
+ return ( zPathname[0]=='\\' && zPathname[1]=='\\'
+ && zPathname[2]=='?' && zPathname[3]=='\\' );
+}
+
+/*
** Returns non-zero if the specified path name starts with a drive letter
** followed by a colon character.
*/
@@ -5545,10 +5559,11 @@ static int winFullPathname(
char *zOut;
#endif
- /* If this path name begins with "/X:", where "X" is any alphabetic
- ** character, discard the initial "/" from the pathname.
+ /* If this path name begins with "/X:" or "\\?\", where "X" is any
+ ** alphabetic character, discard the initial "/" from the pathname.
*/
- if( zRelative[0]=='/' && winIsDriveLetterAndColon(zRelative+1) ){
+ if( zRelative[0]=='/' && (winIsDriveLetterAndColon(zRelative+1)
+ || winIsLongPathPrefix(zRelative+1)) ){
zRelative++;
}
diff --git a/src/pager.c b/src/pager.c
index 0d08a2dfa..729174a2a 100644
--- a/src/pager.c
+++ b/src/pager.c
@@ -70,8 +70,8 @@
** (5) All writes to the database file are synced prior to the rollback journal
** being deleted, truncated, or zeroed.
**
-** (6) If a master journal file is used, then all writes to the database file
-** are synced prior to the master journal being deleted.
+** (6) If a super-journal file is used, then all writes to the database file
+** are synced prior to the super-journal being deleted.
**
** Definition: Two databases (or the same database at two points it time)
** are said to be "logically equivalent" if they give the same answer to
@@ -488,29 +488,29 @@ struct PagerSavepoint {
** need only update the change-counter once, for the first transaction
** committed.
**
-** setMaster
+** setSuper
**
** When PagerCommitPhaseOne() is called to commit a transaction, it may
-** (or may not) specify a master-journal name to be written into the
+** (or may not) specify a super-journal name to be written into the
** journal file before it is synced to disk.
**
-** Whether or not a journal file contains a master-journal pointer affects
+** Whether or not a journal file contains a super-journal pointer affects
** the way in which the journal file is finalized after the transaction is
** committed or rolled back when running in "journal_mode=PERSIST" mode.
-** If a journal file does not contain a master-journal pointer, it is
+** If a journal file does not contain a super-journal pointer, it is
** finalized by overwriting the first journal header with zeroes. If
-** it does contain a master-journal pointer the journal file is finalized
+** it does contain a super-journal pointer the journal file is finalized
** by truncating it to zero bytes, just as if the connection were
** running in "journal_mode=truncate" mode.
**
-** Journal files that contain master journal pointers cannot be finalized
+** Journal files that contain super-journal pointers cannot be finalized
** simply by overwriting the first journal-header with zeroes, as the
-** master journal pointer could interfere with hot-journal rollback of any
+** super-journal pointer could interfere with hot-journal rollback of any
** subsequently interrupted transaction that reuses the journal file.
**
** The flag is cleared as soon as the journal file is finalized (either
** by PagerCommitPhaseTwo or PagerRollback). If an IO error prevents the
-** journal file from being successfully finalized, the setMaster flag
+** journal file from being successfully finalized, the setSuper flag
** is cleared anyway (and the pager will move to ERROR state).
**
** doNotSpill
@@ -642,7 +642,7 @@ struct Pager {
u8 eState; /* Pager state (OPEN, READER, WRITER_LOCKED..) */
u8 eLock; /* Current lock held on database file */
u8 changeCountDone; /* Set after incrementing the change-counter */
- u8 setMaster; /* True if a m-j name has been written to jrnl */
+ u8 setSuper; /* Super-jrnl name is written into jrnl */
u8 doNotSpill; /* Do not spill the cache when non-zero */
u8 subjInMemory; /* True to use in-memory sub-journals */
u8 bUseFetch; /* True to use xFetch() */
@@ -920,7 +920,7 @@ static int assert_pager_state(Pager *p){
assert( pPager->dbSize==pPager->dbOrigSize );
assert( pPager->dbOrigSize==pPager->dbFileSize );
assert( pPager->dbOrigSize==pPager->dbHintSize );
- assert( pPager->setMaster==0 );
+ assert( pPager->setSuper==0 );
break;
case PAGER_WRITER_CACHEMOD:
@@ -1274,66 +1274,66 @@ static void checkPage(PgHdr *pPg){
/*
** When this is called the journal file for pager pPager must be open.
-** This function attempts to read a master journal file name from the
+** This function attempts to read a super-journal file name from the
** end of the file and, if successful, copies it into memory supplied
-** by the caller. See comments above writeMasterJournal() for the format
-** used to store a master journal file name at the end of a journal file.
+** by the caller. See comments above writeSuperJournal() for the format
+** used to store a super-journal file name at the end of a journal file.
**
-** zMaster must point to a buffer of at least nMaster bytes allocated by
+** zSuper must point to a buffer of at least nSuper bytes allocated by
** the caller. This should be sqlite3_vfs.mxPathname+1 (to ensure there is
-** enough space to write the master journal name). If the master journal
-** name in the journal is longer than nMaster bytes (including a
-** nul-terminator), then this is handled as if no master journal name
+** enough space to write the super-journal name). If the super-journal
+** name in the journal is longer than nSuper bytes (including a
+** nul-terminator), then this is handled as if no super-journal name
** were present in the journal.
**
-** If a master journal file name is present at the end of the journal
-** file, then it is copied into the buffer pointed to by zMaster. A
-** nul-terminator byte is appended to the buffer following the master
-** journal file name.
+** If a super-journal file name is present at the end of the journal
+** file, then it is copied into the buffer pointed to by zSuper. A
+** nul-terminator byte is appended to the buffer following the
+** super-journal file name.
**
-** If it is determined that no master journal file name is present
-** zMaster[0] is set to 0 and SQLITE_OK returned.
+** If it is determined that no super-journal file name is present
+** zSuper[0] is set to 0 and SQLITE_OK returned.
**
** If an error occurs while reading from the journal file, an SQLite
** error code is returned.
*/
-static int readMasterJournal(sqlite3_file *pJrnl, char *zMaster, u32 nMaster){
+static int readSuperJournal(sqlite3_file *pJrnl, char *zSuper, u32 nSuper){
int rc; /* Return code */
- u32 len; /* Length in bytes of master journal name */
+ u32 len; /* Length in bytes of super-journal name */
i64 szJ; /* Total size in bytes of journal file pJrnl */
u32 cksum; /* MJ checksum value read from journal */
u32 u; /* Unsigned loop counter */
unsigned char aMagic[8]; /* A buffer to hold the magic header */
- zMaster[0] = '\0';
+ zSuper[0] = '\0';
if( SQLITE_OK!=(rc = sqlite3OsFileSize(pJrnl, &szJ))
|| szJ<16
|| SQLITE_OK!=(rc = read32bits(pJrnl, szJ-16, &len))
- || len>=nMaster
+ || len>=nSuper
|| len>szJ-16
|| len==0
|| SQLITE_OK!=(rc = read32bits(pJrnl, szJ-12, &cksum))
|| SQLITE_OK!=(rc = sqlite3OsRead(pJrnl, aMagic, 8, szJ-8))
|| memcmp(aMagic, aJournalMagic, 8)
- || SQLITE_OK!=(rc = sqlite3OsRead(pJrnl, zMaster, len, szJ-16-len))
+ || SQLITE_OK!=(rc = sqlite3OsRead(pJrnl, zSuper, len, szJ-16-len))
){
return rc;
}
- /* See if the checksum matches the master journal name */
+ /* See if the checksum matches the super-journal name */
for(u=0; u<len; u++){
- cksum -= zMaster[u];
+ cksum -= zSuper[u];
}
if( cksum ){
/* If the checksum doesn't add up, then one or more of the disk sectors
- ** containing the master journal filename is corrupted. This means
+ ** containing the super-journal filename is corrupted. This means
** definitely roll back, so just return SQLITE_OK and report a (nul)
- ** master-journal filename.
+ ** super-journal filename.
*/
len = 0;
}
- zMaster[len] = '\0';
- zMaster[len+1] = '\0';
+ zSuper[len] = '\0';
+ zSuper[len+1] = '\0';
return SQLITE_OK;
}
@@ -1661,50 +1661,50 @@ static int readJournalHdr(
/*
-** Write the supplied master journal name into the journal file for pager
-** pPager at the current location. The master journal name must be the last
+** Write the supplied super-journal name into the journal file for pager
+** pPager at the current location. The super-journal name must be the last
** thing written to a journal file. If the pager is in full-sync mode, the
** journal file descriptor is advanced to the next sector boundary before
** anything is written. The format is:
**
** + 4 bytes: PAGER_MJ_PGNO.
-** + N bytes: Master journal filename in utf-8.
-** + 4 bytes: N (length of master journal name in bytes, no nul-terminator).
-** + 4 bytes: Master journal name checksum.
+** + N bytes: super-journal filename in utf-8.
+** + 4 bytes: N (length of super-journal name in bytes, no nul-terminator).
+** + 4 bytes: super-journal name checksum.
** + 8 bytes: aJournalMagic[].
**
-** The master journal page checksum is the sum of the bytes in the master
-** journal name, where each byte is interpreted as a signed 8-bit integer.
+** The super-journal page checksum is the sum of the bytes in thesuper-journal
+** name, where each byte is interpreted as a signed 8-bit integer.
**
-** If zMaster is a NULL pointer (occurs for a single database transaction),
+** If zSuper is a NULL pointer (occurs for a single database transaction),
** this call is a no-op.
*/
-static int writeMasterJournal(Pager *pPager, const char *zMaster){
+static int writeSuperJournal(Pager *pPager, const char *zSuper){
int rc; /* Return code */
- int nMaster; /* Length of string zMaster */
+ int nSuper; /* Length of string zSuper */
i64 iHdrOff; /* Offset of header in journal file */
i64 jrnlSize; /* Size of journal file on disk */
- u32 cksum = 0; /* Checksum of string zMaster */
+ u32 cksum = 0; /* Checksum of string zSuper */
- assert( pPager->setMaster==0 );
+ assert( pPager->setSuper==0 );
assert( !pagerUseWal(pPager) );
- if( !zMaster
+ if( !zSuper
|| pPager->journalMode==PAGER_JOURNALMODE_MEMORY
|| !isOpen(pPager->jfd)
){
return SQLITE_OK;
}
- pPager->setMaster = 1;
+ pPager->setSuper = 1;
assert( pPager->journalHdr <= pPager->journalOff );
- /* Calculate the length in bytes and the checksum of zMaster */
- for(nMaster=0; zMaster[nMaster]; nMaster++){
- cksum += zMaster[nMaster];
+ /* Calculate the length in bytes and the checksum of zSuper */
+ for(nSuper=0; zSuper[nSuper]; nSuper++){
+ cksum += zSuper[nSuper];
}
/* If in full-sync mode, advance to the next disk sector before writing
- ** the master journal name. This is in case the previous page written to
+ ** the super-journal name. This is in case the previous page written to
** the journal has already been synced.
*/
if( pPager->fullSync ){
@@ -1712,25 +1712,25 @@ static int writeMasterJournal(Pager *pPager, const char *zMaster){
}
iHdrOff = pPager->journalOff;
- /* Write the master journal data to the end of the journal file. If
+ /* Write the super-journal data to the end of the journal file. If
** an error occurs, return the error code to the caller.
*/
if( (0 != (rc = write32bits(pPager->jfd, iHdrOff, PAGER_MJ_PGNO(pPager))))
- || (0 != (rc = sqlite3OsWrite(pPager->jfd, zMaster, nMaster, iHdrOff+4)))
- || (0 != (rc = write32bits(pPager->jfd, iHdrOff+4+nMaster, nMaster)))
- || (0 != (rc = write32bits(pPager->jfd, iHdrOff+4+nMaster+4, cksum)))
+ || (0 != (rc = sqlite3OsWrite(pPager->jfd, zSuper, nSuper, iHdrOff+4)))
+ || (0 != (rc = write32bits(pPager->jfd, iHdrOff+4+nSuper, nSuper)))
+ || (0 != (rc = write32bits(pPager->jfd, iHdrOff+4+nSuper+4, cksum)))
|| (0 != (rc = sqlite3OsWrite(pPager->jfd, aJournalMagic, 8,
- iHdrOff+4+nMaster+8)))
+ iHdrOff+4+nSuper+8)))
){
return rc;
}
- pPager->journalOff += (nMaster+20);
+ pPager->journalOff += (nSuper+20);
/* If the pager is in peristent-journal mode, then the physical
- ** journal-file may extend past the end of the master-journal name
+ ** journal-file may extend past the end of the super-journal name
** and 8 bytes of magic data just written to the file. This is
** dangerous because the code to rollback a hot-journal file
- ** will not be able to find the master-journal name to determine
+ ** will not be able to find the super-journal name to determine
** whether or not the journal is hot.
**
** Easiest thing to do in this scenario is to truncate the journal
@@ -1891,7 +1891,7 @@ static void pager_unlock(Pager *pPager){
pPager->journalOff = 0;
pPager->journalHdr = 0;
- pPager->setMaster = 0;
+ pPager->setSuper = 0;
}
/*
@@ -2007,7 +2007,7 @@ static int pagerFlushOnCommit(Pager *pPager, int bCommit){
** to the first error encountered (the journal finalization one) is
** returned.
*/
-static int pager_end_transaction(Pager *pPager, int hasMaster, int bCommit){
+static int pager_end_transaction(Pager *pPager, int hasSuper, int bCommit){
int rc = SQLITE_OK; /* Error code from journal finalization operation */
int rc2 = SQLITE_OK; /* Error code from db file unlock operation */
@@ -2059,7 +2059,7 @@ static int pager_end_transaction(Pager *pPager, int hasMaster, int bCommit){
}else if( pPager->journalMode==PAGER_JOURNALMODE_PERSIST
|| (pPager->exclusiveMode && pPager->journalMode!=PAGER_JOURNALMODE_WAL)
){
- rc = zeroJournalHdr(pPager, hasMaster||pPager->tempFile);
+ rc = zeroJournalHdr(pPager, hasSuper||pPager->tempFile);
pPager->journalOff = 0;
}else{
/* This branch may be executed with Pager.journalMode==MEMORY if
@@ -2132,7 +2132,7 @@ static int pager_end_transaction(Pager *pPager, int hasMaster, int bCommit){
rc2 = pagerUnlockDb(pPager, SHARED_LOCK);
}
pPager->eState = PAGER_READER;
- pPager->setMaster = 0;
+ pPager->setSuper = 0;
return (rc==SQLITE_OK?rc2:rc);
}
@@ -2440,36 +2440,36 @@ static int pager_playback_one_page(
}
/*
-** Parameter zMaster is the name of a master journal file. A single journal
-** file that referred to the master journal file has just been rolled back.
-** This routine checks if it is possible to delete the master journal file,
+** Parameter zSuper is the name of a super-journal file. A single journal
+** file that referred to the super-journal file has just been rolled back.
+** This routine checks if it is possible to delete the super-journal file,
** and does so if it is.
**
-** Argument zMaster may point to Pager.pTmpSpace. So that buffer is not
+** Argument zSuper may point to Pager.pTmpSpace. So that buffer is not
** available for use within this function.
**
-** When a master journal file is created, it is populated with the names
+** When a super-journal file is created, it is populated with the names
** of all of its child journals, one after another, formatted as utf-8
** encoded text. The end of each child journal file is marked with a
-** nul-terminator byte (0x00). i.e. the entire contents of a master journal
+** nul-terminator byte (0x00). i.e. the entire contents of a super-journal
** file for a transaction involving two databases might be:
**
** "/home/bill/a.db-journal\x00/home/bill/b.db-journal\x00"
**
-** A master journal file may only be deleted once all of its child
+** A super-journal file may only be deleted once all of its child
** journals have been rolled back.
**
-** This function reads the contents of the master-journal file into
+** This function reads the contents of the super-journal file into
** memory and loops through each of the child journal names. For
** each child journal, it checks if:
**
** * if the child journal exists, and if so
-** * if the child journal contains a reference to master journal
-** file zMaster
+** * if the child journal contains a reference to super-journal
+** file zSuper
**
** If a child journal can be found that matches both of the criteria
** above, this function returns without doing anything. Otherwise, if
-** no such child journal can be found, file zMaster is deleted from
+** no such child journal can be found, file zSuper is deleted from
** the file-system using sqlite3OsDelete().
**
** If an IO error within this function, an error code is returned. This
@@ -2478,99 +2478,99 @@ static int pager_playback_one_page(
** occur, SQLITE_OK is returned.
**
** TODO: This function allocates a single block of memory to load
-** the entire contents of the master journal file. This could be
+** the entire contents of the super-journal file. This could be
** a couple of kilobytes or so - potentially larger than the page
** size.
*/
-static int pager_delmaster(Pager *pPager, const char *zMaster){
+static int pager_delsuper(Pager *pPager, const char *zSuper){
sqlite3_vfs *pVfs = pPager->pVfs;
int rc; /* Return code */
- sqlite3_file *pMaster; /* Malloc'd master-journal file descriptor */
+ sqlite3_file *pSuper; /* Malloc'd super-journal file descriptor */
sqlite3_file *pJournal; /* Malloc'd child-journal file descriptor */
- char *zMasterJournal = 0; /* Contents of master journal file */
- i64 nMasterJournal; /* Size of master journal file */
+ char *zSuperJournal = 0; /* Contents of super-journal file */
+ i64 nSuperJournal; /* Size of super-journal file */
char *zJournal; /* Pointer to one journal within MJ file */
- char *zMasterPtr; /* Space to hold MJ filename from a journal file */
- int nMasterPtr; /* Amount of space allocated to zMasterPtr[] */
+ char *zSuperPtr; /* Space to hold super-journal filename */
+ int nSuperPtr; /* Amount of space allocated to zSuperPtr[] */
- /* Allocate space for both the pJournal and pMaster file descriptors.
- ** If successful, open the master journal file for reading.
+ /* Allocate space for both the pJournal and pSuper file descriptors.
+ ** If successful, open the super-journal file for reading.
*/
- pMaster = (sqlite3_file *)sqlite3MallocZero(pVfs->szOsFile * 2);
- pJournal = (sqlite3_file *)(((u8 *)pMaster) + pVfs->szOsFile);
- if( !pMaster ){
+ pSuper = (sqlite3_file *)sqlite3MallocZero(pVfs->szOsFile * 2);
+ pJournal = (sqlite3_file *)(((u8 *)pSuper) + pVfs->szOsFile);
+ if( !pSuper ){
rc = SQLITE_NOMEM_BKPT;
}else{
- const int flags = (SQLITE_OPEN_READONLY|SQLITE_OPEN_MASTER_JOURNAL);
- rc = sqlite3OsOpen(pVfs, zMaster, pMaster, flags, 0);
+ const int flags = (SQLITE_OPEN_READONLY|SQLITE_OPEN_SUPER_JOURNAL);
+ rc = sqlite3OsOpen(pVfs, zSuper, pSuper, flags, 0);
}
- if( rc!=SQLITE_OK ) goto delmaster_out;
+ if( rc!=SQLITE_OK ) goto delsuper_out;
- /* Load the entire master journal file into space obtained from
- ** sqlite3_malloc() and pointed to by zMasterJournal. Also obtain
- ** sufficient space (in zMasterPtr) to hold the names of master
- ** journal files extracted from regular rollback-journals.
+ /* Load the entire super-journal file into space obtained from
+ ** sqlite3_malloc() and pointed to by zSuperJournal. Also obtain
+ ** sufficient space (in zSuperPtr) to hold the names of super-journal
+ ** files extracted from regular rollback-journals.
*/
- rc = sqlite3OsFileSize(pMaster, &nMasterJournal);
- if( rc!=SQLITE_OK ) goto delmaster_out;
- nMasterPtr = pVfs->mxPathname+1;
- zMasterJournal = sqlite3Malloc(nMasterJournal + nMasterPtr + 2);
- if( !zMasterJournal ){
+ rc = sqlite3OsFileSize(pSuper, &nSuperJournal);
+ if( rc!=SQLITE_OK ) goto delsuper_out;
+ nSuperPtr = pVfs->mxPathname+1;
+ zSuperJournal = sqlite3Malloc(nSuperJournal + nSuperPtr + 2);
+ if( !zSuperJournal ){
rc = SQLITE_NOMEM_BKPT;
- goto delmaster_out;
+ goto delsuper_out;
}
- zMasterPtr = &zMasterJournal[nMasterJournal+2];
- rc = sqlite3OsRead(pMaster, zMasterJournal, (int)nMasterJournal, 0);
- if( rc!=SQLITE_OK ) goto delmaster_out;
- zMasterJournal[nMasterJournal] = 0;
- zMasterJournal[nMasterJournal+1] = 0;
+ zSuperPtr = &zSuperJournal[nSuperJournal+2];
+ rc = sqlite3OsRead(pSuper, zSuperJournal, (int)nSuperJournal, 0);
+ if( rc!=SQLITE_OK ) goto delsuper_out;
+ zSuperJournal[nSuperJournal] = 0;
+ zSuperJournal[nSuperJournal+1] = 0;
- zJournal = zMasterJournal;
- while( (zJournal-zMasterJournal)<nMasterJournal ){
+ zJournal = zSuperJournal;
+ while( (zJournal-zSuperJournal)<nSuperJournal ){
int exists;
rc = sqlite3OsAccess(pVfs, zJournal, SQLITE_ACCESS_EXISTS, &exists);
if( rc!=SQLITE_OK ){
- goto delmaster_out;
+ goto delsuper_out;
}
if( exists ){
- /* One of the journals pointed to by the master journal exists.
- ** Open it and check if it points at the master journal. If
- ** so, return without deleting the master journal file.
+ /* One of the journals pointed to by the super-journal exists.
+ ** Open it and check if it points at the super-journal. If
+ ** so, return without deleting the super-journal file.
** NB: zJournal is really a MAIN_JOURNAL. But call it a
- ** MASTER_JOURNAL here so that the VFS will not send the zJournal
+ ** SUPER_JOURNAL here so that the VFS will not send the zJournal
** name into sqlite3_database_file_object().
*/
int c;
- int flags = (SQLITE_OPEN_READONLY|SQLITE_OPEN_MASTER_JOURNAL);
+ int flags = (SQLITE_OPEN_READONLY|SQLITE_OPEN_SUPER_JOURNAL);
rc = sqlite3OsOpen(pVfs, zJournal, pJournal, flags, 0);
if( rc!=SQLITE_OK ){
- goto delmaster_out;
+ goto delsuper_out;
}
- rc = readMasterJournal(pJournal, zMasterPtr, nMasterPtr);
+ rc = readSuperJournal(pJournal, zSuperPtr, nSuperPtr);
sqlite3OsClose(pJournal);
if( rc!=SQLITE_OK ){
- goto delmaster_out;
+ goto delsuper_out;
}
- c = zMasterPtr[0]!=0 && strcmp(zMasterPtr, zMaster)==0;
+ c = zSuperPtr[0]!=0 && strcmp(zSuperPtr, zSuper)==0;
if( c ){
- /* We have a match. Do not delete the master journal file. */
- goto delmaster_out;
+ /* We have a match. Do not delete the super-journal file. */
+ goto delsuper_out;
}
}
zJournal += (sqlite3Strlen30(zJournal)+1);
}
- sqlite3OsClose(pMaster);
- rc = sqlite3OsDelete(pVfs, zMaster, 0);
+ sqlite3OsClose(pSuper);
+ rc = sqlite3OsDelete(pVfs, zSuper, 0);
-delmaster_out:
- sqlite3_free(zMasterJournal);
- if( pMaster ){
- sqlite3OsClose(pMaster);
+delsuper_out:
+ sqlite3_free(zSuperJournal);
+ if( pSuper ){
+ sqlite3OsClose(pSuper);
assert( !isOpen(pJournal) );
- sqlite3_free(pMaster);
+ sqlite3_free(pSuper);
}
return rc;
}
@@ -2648,7 +2648,7 @@ int sqlite3SectorSize(sqlite3_file *pFile){
** pager based on the value returned by the xSectorSize method
** of the open database file. The sector size will be used
** to determine the size and alignment of journal header and
-** master journal pointers within created journal files.
+** super-journal pointers within created journal files.
**
** For temporary files the effective sector size is always 512 bytes.
**
@@ -2747,7 +2747,7 @@ static int pager_playback(Pager *pPager, int isHot){
Pgno mxPg = 0; /* Size of the original file in pages */
int rc; /* Result code of a subroutine */
int res = 1; /* Value returned by sqlite3OsAccess() */
- char *zMaster = 0; /* Name of master journal file if any */
+ char *zSuper = 0; /* Name of super-journal file if any */
int needPagerReset; /* True to reset page prior to first page rollback */
int nPlayback = 0; /* Total number of pages restored from journal */
u32 savedPageSize = pPager->pageSize;
@@ -2761,8 +2761,8 @@ static int pager_playback(Pager *pPager, int isHot){
goto end_playback;
}
- /* Read the master journal name from the journal, if it is present.
- ** If a master journal file name is specified, but the file is not
+ /* Read the super-journal name from the journal, if it is present.
+ ** If a super-journal file name is specified, but the file is not
** present on disk, then the journal is not hot and does not need to be
** played back.
**
@@ -2772,12 +2772,12 @@ static int pager_playback(Pager *pPager, int isHot){
** mxPathname is 512, which is the same as the minimum allowable value
** for pageSize.
*/
- zMaster = pPager->pTmpSpace;
- rc = readMasterJournal(pPager->jfd, zMaster, pPager->pVfs->mxPathname+1);
- if( rc==SQLITE_OK && zMaster[0] ){
- rc = sqlite3OsAccess(pVfs, zMaster, SQLITE_ACCESS_EXISTS, &res);
+ zSuper = pPager->pTmpSpace;
+ rc = readSuperJournal(pPager->jfd, zSuper, pPager->pVfs->mxPathname+1);
+ if( rc==SQLITE_OK && zSuper[0] ){
+ rc = sqlite3OsAccess(pVfs, zSuper, SQLITE_ACCESS_EXISTS, &res);
}
- zMaster = 0;
+ zSuper = 0;
if( rc!=SQLITE_OK || !res ){
goto end_playback;
}
@@ -2904,8 +2904,8 @@ end_playback:
pPager->changeCountDone = pPager->tempFile;
if( rc==SQLITE_OK ){
- zMaster = pPager->pTmpSpace;
- rc = readMasterJournal(pPager->jfd, zMaster, pPager->pVfs->mxPathname+1);
+ zSuper = pPager->pTmpSpace;
+ rc = readSuperJournal(pPager->jfd, zSuper, pPager->pVfs->mxPathname+1);
testcase( rc!=SQLITE_OK );
}
if( rc==SQLITE_OK
@@ -2914,14 +2914,14 @@ end_playback:
rc = sqlite3PagerSync(pPager, 0);
}
if( rc==SQLITE_OK ){
- rc = pager_end_transaction(pPager, zMaster[0]!='\0', 0);
+ rc = pager_end_transaction(pPager, zSuper[0]!='\0', 0);
testcase( rc!=SQLITE_OK );
}
- if( rc==SQLITE_OK && zMaster[0] && res ){
- /* If there was a master journal and this routine will return success,
- ** see if it is possible to delete the master journal.
+ if( rc==SQLITE_OK && zSuper[0] && res ){
+ /* If there was a super-journal and this routine will return success,
+ ** see if it is possible to delete the super-journal.
*/
- rc = pager_delmaster(pPager, zMaster);
+ rc = pager_delsuper(pPager, zSuper);
testcase( rc!=SQLITE_OK );
}
if( isHot && nPlayback ){
@@ -3300,7 +3300,7 @@ static int pagerOpenWalIfPresent(Pager *pPager){
/*
** Playback savepoint pSavepoint. Or, if pSavepoint==NULL, then playback
-** the entire master journal file. The case pSavepoint==NULL occurs when
+** the entire super-journal file. The case pSavepoint==NULL occurs when
** a ROLLBACK TO command is invoked on a SAVEPOINT that is a transaction
** savepoint.
**
@@ -5040,8 +5040,8 @@ sqlite3_file *sqlite3_database_file_object(const char *zName){
** just deleted using OsDelete, *pExists is set to 0 and SQLITE_OK
** is returned.
**
-** This routine does not check if there is a master journal filename
-** at the end of the file. If there is, and that master journal file
+** This routine does not check if there is a super-journal filename
+** at the end of the file. If there is, and that super-journal file
** does not exist, then the journal file is not really hot. In this
** case this routine will return a false-positive. The pager_playback()
** routine will discover that the journal file is not really hot and
@@ -5705,7 +5705,6 @@ void sqlite3PagerUnrefPageOne(DbPage *pPg){
assert( pPg->pgno==1 );
assert( (pPg->flags & PGHDR_MMAP)==0 ); /* Page1 is never memory mapped */
pPager = pPg->pPager;
- sqlite3PagerResetLockTimeout(pPager);
sqlite3PcacheRelease(pPg);
pagerUnlockIfUnused(pPager);
}
@@ -5787,7 +5786,7 @@ static int pager_open_journal(Pager *pPager){
/* TODO: Check if all of these are really required. */
pPager->nRec = 0;
pPager->journalOff = 0;
- pPager->setMaster = 0;
+ pPager->setSuper = 0;
pPager->journalHdr = 0;
rc = writeJournalHdr(pPager);
}
@@ -6299,9 +6298,9 @@ static int pager_incr_changecounter(Pager *pPager, int isDirectMode){
** If successful, or if called on a pager for which it is a no-op, this
** function returns SQLITE_OK. Otherwise, an IO error code is returned.
*/
-int sqlite3PagerSync(Pager *pPager, const char *zMaster){
+int sqlite3PagerSync(Pager *pPager, const char *zSuper){
int rc = SQLITE_OK;
- void *pArg = (void*)zMaster;
+ void *pArg = (void*)zSuper;
rc = sqlite3OsFileControl(pPager->fd, SQLITE_FCNTL_SYNC, pArg);
if( rc==SQLITE_NOTFOUND ) rc = SQLITE_OK;
if( rc==SQLITE_OK && !pPager->noSync ){
@@ -6339,10 +6338,10 @@ int sqlite3PagerExclusiveLock(Pager *pPager){
}
/*
-** Sync the database file for the pager pPager. zMaster points to the name
-** of a master journal file that should be written into the individual
-** journal file. zMaster may be NULL, which is interpreted as no master
-** journal (a single database transaction).
+** Sync the database file for the pager pPager. zSuper points to the name
+** of a super-journal file that should be written into the individual
+** journal file. zSuper may be NULL, which is interpreted as no
+** super-journal (a single database transaction).
**
** This routine ensures that:
**
@@ -6354,9 +6353,9 @@ int sqlite3PagerExclusiveLock(Pager *pPager){
**
** The only thing that remains to commit the transaction is to finalize
** (delete, truncate or zero the first part of) the journal file (or
-** delete the master journal file if specified).
+** delete the super-journal file if specified).
**
-** Note that if zMaster==NULL, this does not overwrite a previous value
+** Note that if zSuper==NULL, this does not overwrite a previous value
** passed to an sqlite3PagerCommitPhaseOne() call.
**
** If the final parameter - noSync - is true, then the database file itself
@@ -6366,7 +6365,7 @@ int sqlite3PagerExclusiveLock(Pager *pPager){
*/
int sqlite3PagerCommitPhaseOne(
Pager *pPager, /* Pager object */
- const char *zMaster, /* If not NULL, the master journal name */
+ const char *zSuper, /* If not NULL, the super-journal name */
int noSync /* True to omit the xSync on the db file */
){
int rc = SQLITE_OK; /* Return code */
@@ -6384,8 +6383,8 @@ int sqlite3PagerCommitPhaseOne(
/* Provide the ability to easily simulate an I/O error during testing */
if( sqlite3FaultSim(400) ) return SQLITE_IOERR;
- PAGERTRACE(("DATABASE SYNC: File=%s zMaster=%s nSize=%d\n",
- pPager->zFilename, zMaster, pPager->dbSize));
+ PAGERTRACE(("DATABASE SYNC: File=%s zSuper=%s nSize=%d\n",
+ pPager->zFilename, zSuper, pPager->dbSize));
/* If no database changes have been made, return early. */
if( pPager->eState<PAGER_WRITER_CACHEMOD ) return SQLITE_OK;
@@ -6424,7 +6423,7 @@ int sqlite3PagerCommitPhaseOne(
*/
#ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE
sqlite3_file *fd = pPager->fd;
- int bBatch = zMaster==0 /* An SQLITE_IOCAP_BATCH_ATOMIC commit */
+ int bBatch = zSuper==0 /* An SQLITE_IOCAP_BATCH_ATOMIC commit */
&& (sqlite3OsDeviceCharacteristics(fd) & SQLITE_IOCAP_BATCH_ATOMIC)
&& !pPager->noSync
&& sqlite3JournalIsInMemory(pPager->jfd);
@@ -6462,7 +6461,7 @@ int sqlite3PagerCommitPhaseOne(
|| pPager->journalMode==PAGER_JOURNALMODE_OFF
|| pPager->journalMode==PAGER_JOURNALMODE_WAL
);
- if( !zMaster && isOpen(pPager->jfd)
+ if( !zSuper && isOpen(pPager->jfd)
&& pPager->journalOff==jrnlBufferSize(pPager)
&& pPager->dbSize>=pPager->dbOrigSize
&& (!(pPg = sqlite3PcacheDirtyList(pPager->pPCache)) || 0==pPg->pDirty)
@@ -6483,7 +6482,7 @@ int sqlite3PagerCommitPhaseOne(
}
#else /* SQLITE_ENABLE_ATOMIC_WRITE */
#ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE
- if( zMaster ){
+ if( zSuper ){
rc = sqlite3JournalCreate(pPager->jfd);
if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
assert( bBatch==0 );
@@ -6493,11 +6492,11 @@ int sqlite3PagerCommitPhaseOne(
#endif /* !SQLITE_ENABLE_ATOMIC_WRITE */
if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
- /* Write the master journal name into the journal file. If a master
- ** journal file name has already been written to the journal file,
- ** or if zMaster is NULL (no master journal), then this call is a no-op.
+ /* Write the super-journal name into the journal file. If a
+ ** super-journal file name has already been written to the journal file,
+ ** or if zSuper is NULL (no super-journal), then this call is a no-op.
*/
- rc = writeMasterJournal(pPager, zMaster);
+ rc = writeSuperJournal(pPager, zSuper);
if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
/* Sync the journal file and write all dirty pages to the database.
@@ -6565,7 +6564,7 @@ int sqlite3PagerCommitPhaseOne(
/* Finally, sync the database file. */
if( !noSync ){
- rc = sqlite3PagerSync(pPager, zMaster);
+ rc = sqlite3PagerSync(pPager, zSuper);
}
IOTRACE(("DBSYNC %p\n", pPager))
}
@@ -6630,7 +6629,7 @@ int sqlite3PagerCommitPhaseTwo(Pager *pPager){
}
PAGERTRACE(("COMMIT %d\n", PAGERID(pPager)));
- rc = pager_end_transaction(pPager, pPager->setMaster, 1);
+ rc = pager_end_transaction(pPager, pPager->setSuper, 1);
return pager_error(pPager, rc);
}
@@ -6675,7 +6674,7 @@ int sqlite3PagerRollback(Pager *pPager){
if( pagerUseWal(pPager) ){
int rc2;
rc = sqlite3PagerSavepoint(pPager, SAVEPOINT_ROLLBACK, -1);
- rc2 = pager_end_transaction(pPager, pPager->setMaster, 0);
+ rc2 = pager_end_transaction(pPager, pPager->setSuper, 0);
if( rc==SQLITE_OK ) rc = rc2;
}else if( !isOpen(pPager->jfd) || pPager->eState==PAGER_WRITER_LOCKED ){
int eState = pPager->eState;
@@ -6998,16 +6997,6 @@ sqlite3_file *sqlite3PagerFile(Pager *pPager){
return pPager->fd;
}
-#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
-/*
-** Reset the lock timeout for pager.
-*/
-void sqlite3PagerResetLockTimeout(Pager *pPager){
- int x = 0;
- sqlite3OsFileControl(pPager->fd, SQLITE_FCNTL_LOCK_TIMEOUT, &x);
-}
-#endif
-
/*
** Return the file handle for the journal file (if it exists).
** This will be either the rollback journal or the WAL file.
@@ -7421,7 +7410,6 @@ int sqlite3PagerCheckpoint(
pPager->walSyncFlags, pPager->pageSize, (u8 *)pPager->pTmpSpace,
pnLog, pnCkpt
);
- sqlite3PagerResetLockTimeout(pPager);
}
return rc;
}
@@ -7586,7 +7574,31 @@ int sqlite3PagerCloseWal(Pager *pPager, sqlite3 *db){
return rc;
}
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+/*
+** If pager pPager is a wal-mode database not in exclusive locking mode,
+** invoke the sqlite3WalWriteLock() function on the associated Wal object
+** with the same db and bLock parameters as were passed to this function.
+** Return an SQLite error code if an error occurs, or SQLITE_OK otherwise.
+*/
+int sqlite3PagerWalWriteLock(Pager *pPager, int bLock){
+ int rc = SQLITE_OK;
+ if( pagerUseWal(pPager) && pPager->exclusiveMode==0 ){
+ rc = sqlite3WalWriteLock(pPager->pWal, bLock);
+ }
+ return rc;
+}
+/*
+** Set the database handle used by the wal layer to determine if
+** blocking locks are required.
+*/
+void sqlite3PagerWalDb(Pager *pPager, sqlite3 *db){
+ if( pagerUseWal(pPager) ){
+ sqlite3WalDb(pPager->pWal, db);
+ }
+}
+#endif
#ifdef SQLITE_ENABLE_SNAPSHOT
/*
@@ -7606,7 +7618,10 @@ int sqlite3PagerSnapshotGet(Pager *pPager, sqlite3_snapshot **ppSnapshot){
** read transaction is opened, attempt to read from the snapshot it
** identifies. If this is not a WAL database, return an error.
*/
-int sqlite3PagerSnapshotOpen(Pager *pPager, sqlite3_snapshot *pSnapshot){
+int sqlite3PagerSnapshotOpen(
+ Pager *pPager,
+ sqlite3_snapshot *pSnapshot
+){
int rc = SQLITE_OK;
if( pPager->pWal ){
sqlite3WalSnapshotOpen(pPager->pWal, pSnapshot);
diff --git a/src/pager.h b/src/pager.h
index 2c99d67a9..3d3270f59 100644
--- a/src/pager.h
+++ b/src/pager.h
@@ -46,8 +46,8 @@ typedef struct PgHdr DbPage;
** Page number PAGER_MJ_PGNO is never used in an SQLite database (it is
** reserved for working around a windows/posix incompatibility). It is
** used in the journal to signify that the remainder of the journal file
-** is devoted to storing a master journal name - there are no more pages to
-** roll back. See comments for function writeMasterJournal() in pager.c
+** is devoted to storing a super-journal name - there are no more pages to
+** roll back. See comments for function writeSuperJournal() in pager.c
** for details.
*/
#define PAGER_MJ_PGNO(x) ((Pgno)((PENDING_BYTE/((x)->pageSize))+1))
@@ -161,9 +161,9 @@ void *sqlite3PagerGetExtra(DbPage *);
/* Functions used to manage pager transactions and savepoints. */
void sqlite3PagerPagecount(Pager*, int*);
int sqlite3PagerBegin(Pager*, int exFlag, int);
-int sqlite3PagerCommitPhaseOne(Pager*,const char *zMaster, int);
+int sqlite3PagerCommitPhaseOne(Pager*,const char *zSuper, int);
int sqlite3PagerExclusiveLock(Pager*);
-int sqlite3PagerSync(Pager *pPager, const char *zMaster);
+int sqlite3PagerSync(Pager *pPager, const char *zSuper);
int sqlite3PagerCommitPhaseTwo(Pager*);
int sqlite3PagerRollback(Pager*);
int sqlite3PagerOpenSavepoint(Pager *pPager, int n);
@@ -177,14 +177,22 @@ int sqlite3PagerSharedLock(Pager *pPager);
int sqlite3PagerOpenWal(Pager *pPager, int *pisOpen);
int sqlite3PagerCloseWal(Pager *pPager, sqlite3*);
# ifdef SQLITE_ENABLE_SNAPSHOT
- int sqlite3PagerSnapshotGet(Pager *pPager, sqlite3_snapshot **ppSnapshot);
- int sqlite3PagerSnapshotOpen(Pager *pPager, sqlite3_snapshot *pSnapshot);
+ int sqlite3PagerSnapshotGet(Pager*, sqlite3_snapshot **ppSnapshot);
+ int sqlite3PagerSnapshotOpen(Pager*, sqlite3_snapshot *pSnapshot);
int sqlite3PagerSnapshotRecover(Pager *pPager);
int sqlite3PagerSnapshotCheck(Pager *pPager, sqlite3_snapshot *pSnapshot);
void sqlite3PagerSnapshotUnlock(Pager *pPager);
# endif
#endif
+#if !defined(SQLITE_OMIT_WAL) && defined(SQLITE_ENABLE_SETLK_TIMEOUT)
+ int sqlite3PagerWalWriteLock(Pager*, int);
+ void sqlite3PagerWalDb(Pager*, sqlite3*);
+#else
+# define sqlite3PagerWalWriteLock(y,z) SQLITE_OK
+# define sqlite3PagerWalDb(x,y)
+#endif
+
#ifdef SQLITE_DIRECT_OVERFLOW_READ
int sqlite3PagerDirectReadOk(Pager *pPager, Pgno pgno);
#endif
@@ -210,11 +218,6 @@ int sqlite3PagerIsMemdb(Pager*);
void sqlite3PagerCacheStat(Pager *, int, int, int *);
void sqlite3PagerClearCache(Pager*);
int sqlite3SectorSize(sqlite3_file *);
-#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
-void sqlite3PagerResetLockTimeout(Pager *pPager);
-#else
-# define sqlite3PagerResetLockTimeout(X)
-#endif
/* Functions used to truncate the database file. */
void sqlite3PagerTruncateImage(Pager*,Pgno);
diff --git a/src/parse.y b/src/parse.y
index 3616e3de2..f444aea62 100644
--- a/src/parse.y
+++ b/src/parse.y
@@ -111,6 +111,27 @@ static void disableLookaside(Parse *pParse){
DisableLookaside;
}
+#if !defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) \
+ && defined(SQLITE_UDL_CAPABLE_PARSER)
+/*
+** Issue an error message if an ORDER BY or LIMIT clause occurs on an
+** UPDATE or DELETE statement.
+*/
+static void updateDeleteLimitError(
+ Parse *pParse,
+ ExprList *pOrderBy,
+ Expr *pLimit
+){
+ if( pOrderBy ){
+ sqlite3ErrorMsg(pParse, "syntax error near \"ORDER BY\"");
+ }else{
+ sqlite3ErrorMsg(pParse, "syntax error near \"LIMIT\"");
+ }
+ sqlite3ExprListDelete(pParse->db, pOrderBy);
+ sqlite3ExprDelete(pParse->db, pLimit);
+}
+#endif /* SQLITE_ENABLE_UPDATE_DELETE_LIMIT */
+
} // end %include
// Input is a single SQL command
@@ -840,18 +861,20 @@ limit_opt(A) ::= LIMIT expr(X) COMMA expr(Y).
/////////////////////////// The DELETE statement /////////////////////////////
//
-%ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
+%if SQLITE_ENABLE_UPDATE_DELETE_LIMIT || SQLITE_UDL_CAPABLE_PARSER
cmd ::= with DELETE FROM xfullname(X) indexed_opt(I) where_opt(W)
orderby_opt(O) limit_opt(L). {
sqlite3SrcListIndexedBy(pParse, X, &I);
#ifndef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
- sqlite3ExprListDelete(pParse->db, O); O = 0;
- sqlite3ExprDelete(pParse->db, L); L = 0;
+ if( O || L ){
+ updateDeleteLimitError(pParse,O,L);
+ O = 0;
+ L = 0;
+ }
#endif
sqlite3DeleteFrom(pParse,X,W,O,L);
}
-%endif
-%ifndef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
+%else
cmd ::= with DELETE FROM xfullname(X) indexed_opt(I) where_opt(W). {
sqlite3SrcListIndexedBy(pParse, X, &I);
sqlite3DeleteFrom(pParse,X,W,0,0);
@@ -866,18 +889,24 @@ where_opt(A) ::= WHERE expr(X). {A = X;}
////////////////////////// The UPDATE command ////////////////////////////////
//
-%ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
+%if SQLITE_ENABLE_UPDATE_DELETE_LIMIT || SQLITE_UDL_CAPABLE_PARSER
cmd ::= with UPDATE orconf(R) xfullname(X) indexed_opt(I) SET setlist(Y) from(F)
where_opt(W) orderby_opt(O) limit_opt(L). {
sqlite3SrcListIndexedBy(pParse, X, &I);
X = sqlite3SrcListAppendList(pParse, X, F);
sqlite3ExprListCheckLength(pParse,Y,"set list");
+#ifndef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
+ if( O || L ){
+ updateDeleteLimitError(pParse,O,L);
+ O = 0;
+ L = 0;
+ }
+#endif
sqlite3Update(pParse,X,Y,W,R,O,L,0);
}
-%endif
-%ifndef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
+%else
cmd ::= with UPDATE orconf(R) xfullname(X) indexed_opt(I) SET setlist(Y) from(F)
- where_opt(W). {
+ where_opt(W). {
sqlite3SrcListIndexedBy(pParse, X, &I);
sqlite3ExprListCheckLength(pParse,Y,"set list");
X = sqlite3SrcListAppendList(pParse, X, F);
@@ -885,6 +914,8 @@ cmd ::= with UPDATE orconf(R) xfullname(X) indexed_opt(I) SET setlist(Y) from(F)
}
%endif
+
+
%type setlist {ExprList*}
%destructor setlist {sqlite3ExprListDelete(pParse->db, $$);}
@@ -1317,7 +1348,7 @@ uniqueflag(A) ::= . {A = OE_None;}
//
// IMPORTANT COMPATIBILITY NOTE: Some prior versions of SQLite accepted
// COLLATE clauses and ASC or DESC keywords on ID lists in inappropriate
-// places - places that might have been stored in the sqlite_master schema.
+// places - places that might have been stored in the sqlite_schema table.
// Those extra features were ignored. But because they might be in some
// (busted) old databases, we need to continue parsing them when loading
// historical schemas.
@@ -1372,16 +1403,14 @@ cmd ::= DROP INDEX ifexists(E) fullname(X). {sqlite3DropIndex(pParse, X, E);}
///////////////////////////// The VACUUM command /////////////////////////////
//
-%ifndef SQLITE_OMIT_VACUUM
-%ifndef SQLITE_OMIT_ATTACH
+%if !SQLITE_OMIT_VACUUM && !SQLITE_OMIT_ATTACH
%type vinto {Expr*}
%destructor vinto {sqlite3ExprDelete(pParse->db, $$);}
cmd ::= VACUUM vinto(Y). {sqlite3Vacuum(pParse,0,Y);}
cmd ::= VACUUM nm(X) vinto(Y). {sqlite3Vacuum(pParse,&X,Y);}
vinto(A) ::= INTO expr(X). {A = X;}
vinto(A) ::= . {A = 0;}
-%endif SQLITE_OMIT_ATTACH
-%endif SQLITE_OMIT_VACUUM
+%endif
///////////////////////////// The PRAGMA command /////////////////////////////
//
diff --git a/src/pragma.c b/src/pragma.c
index c5b5bb667..fa4ef748c 100644
--- a/src/pragma.c
+++ b/src/pragma.c
@@ -555,7 +555,7 @@ void sqlite3Pragma(
** buffer that the pager module resizes using sqlite3_realloc().
*/
db->nextPagesize = sqlite3Atoi(zRight);
- if( SQLITE_NOMEM==sqlite3BtreeSetPageSize(pBt, db->nextPagesize,-1,0) ){
+ if( SQLITE_NOMEM==sqlite3BtreeSetPageSize(pBt, db->nextPagesize,0,0) ){
sqlite3OomFault(db);
}
}
@@ -1138,15 +1138,14 @@ void sqlite3Pragma(
*/
case PragTyp_TABLE_INFO: if( zRight ){
Table *pTab;
+ sqlite3CodeVerifyNamedSchema(pParse, zDb);
pTab = sqlite3LocateTable(pParse, LOCATE_NOERR, zRight, zDb);
if( pTab ){
- int iTabDb = sqlite3SchemaToIndex(db, pTab->pSchema);
int i, k;
int nHidden = 0;
Column *pCol;
Index *pPk = sqlite3PrimaryKeyIndex(pTab);
pParse->nMem = 7;
- sqlite3CodeVerifySchema(pParse, iTabDb);
sqlite3ViewGetColumnNames(pParse, pTab);
for(i=0, pCol=pTab->aCol; i<pTab->nCol; i++, pCol++){
int isHidden = 0;
@@ -1403,7 +1402,6 @@ void sqlite3Pragma(
regRow = ++pParse->nMem;
k = sqliteHashFirst(&db->aDb[iDb].pSchema->tblHash);
while( k ){
- int iTabDb;
if( zRight ){
pTab = sqlite3LocateTable(pParse, 0, zRight, zDb);
k = 0;
@@ -1412,23 +1410,24 @@ void sqlite3Pragma(
k = sqliteHashNext(k);
}
if( pTab==0 || pTab->pFKey==0 ) continue;
- iTabDb = sqlite3SchemaToIndex(db, pTab->pSchema);
- sqlite3CodeVerifySchema(pParse, iTabDb);
- sqlite3TableLock(pParse, iTabDb, pTab->tnum, 0, pTab->zName);
+ iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
+ zDb = db->aDb[iDb].zDbSName;
+ sqlite3CodeVerifySchema(pParse, iDb);
+ sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName);
if( pTab->nCol+regRow>pParse->nMem ) pParse->nMem = pTab->nCol + regRow;
- sqlite3OpenTable(pParse, 0, iTabDb, pTab, OP_OpenRead);
+ sqlite3OpenTable(pParse, 0, iDb, pTab, OP_OpenRead);
sqlite3VdbeLoadString(v, regResult, pTab->zName);
for(i=1, pFK=pTab->pFKey; pFK; i++, pFK=pFK->pNextFrom){
pParent = sqlite3FindTable(db, pFK->zTo, zDb);
if( pParent==0 ) continue;
pIdx = 0;
- sqlite3TableLock(pParse, iTabDb, pParent->tnum, 0, pParent->zName);
+ sqlite3TableLock(pParse, iDb, pParent->tnum, 0, pParent->zName);
x = sqlite3FkLocateIndex(pParse, pParent, pFK, &pIdx, 0);
if( x==0 ){
if( pIdx==0 ){
- sqlite3OpenTable(pParse, i, iTabDb, pParent, OP_OpenRead);
+ sqlite3OpenTable(pParse, i, iDb, pParent, OP_OpenRead);
}else{
- sqlite3VdbeAddOp3(v, OP_OpenRead, i, pIdx->tnum, iTabDb);
+ sqlite3VdbeAddOp3(v, OP_OpenRead, i, pIdx->tnum, iDb);
sqlite3VdbeSetP4KeyInfo(pParse, pIdx);
}
}else{
@@ -1729,7 +1728,6 @@ void sqlite3Pragma(
}
sqlite3VdbeAddOp2(v, OP_Next, iDataCur, loopTop); VdbeCoverage(v);
sqlite3VdbeJumpHere(v, loopTop-1);
-#ifndef SQLITE_OMIT_BTREECOUNT
if( !isQuick ){
sqlite3VdbeLoadString(v, 2, "wrong # of entries in index ");
for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
@@ -1743,7 +1741,6 @@ void sqlite3Pragma(
sqlite3VdbeJumpHere(v, addr);
}
}
-#endif /* SQLITE_OMIT_BTREECOUNT */
}
}
{
@@ -1892,6 +1889,7 @@ void sqlite3Pragma(
aOp[1].p1 = iDb;
aOp[1].p2 = iCookie;
aOp[1].p3 = sqlite3Atoi(zRight);
+ aOp[1].p5 = 1;
}else{
/* Read the specified cookie value */
static const VdbeOpList readCookie[] = {
@@ -2178,6 +2176,25 @@ void sqlite3Pragma(
break;
}
+ /*
+ ** PRAGMA analysis_limit
+ ** PRAGMA analysis_limit = N
+ **
+ ** Configure the maximum number of rows that ANALYZE will examine
+ ** in each index that it looks at. Return the new limit.
+ */
+ case PragTyp_ANALYSIS_LIMIT: {
+ sqlite3_int64 N;
+ if( zRight
+ && sqlite3DecOrHexToI64(zRight, &N)==SQLITE_OK
+ && N>=0
+ ){
+ db->nAnalysisLimit = (int)(N&0x7fffffff);
+ }
+ returnSingleInt(v, db->nAnalysisLimit);
+ break;
+ }
+
#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
/*
** Report the current state of file logs for all databases
diff --git a/src/pragma.h b/src/pragma.h
index 7046695a5..be99befb2 100644
--- a/src/pragma.h
+++ b/src/pragma.h
@@ -6,49 +6,50 @@
/* The various pragma types */
#define PragTyp_ACTIVATE_EXTENSIONS 0
-#define PragTyp_HEADER_VALUE 1
-#define PragTyp_AUTO_VACUUM 2
-#define PragTyp_FLAG 3
-#define PragTyp_BUSY_TIMEOUT 4
-#define PragTyp_CACHE_SIZE 5
-#define PragTyp_CACHE_SPILL 6
-#define PragTyp_CASE_SENSITIVE_LIKE 7
-#define PragTyp_COLLATION_LIST 8
-#define PragTyp_COMPILE_OPTIONS 9
-#define PragTyp_DATA_STORE_DIRECTORY 10
-#define PragTyp_DATABASE_LIST 11
-#define PragTyp_DEFAULT_CACHE_SIZE 12
-#define PragTyp_ENCODING 13
-#define PragTyp_FOREIGN_KEY_CHECK 14
-#define PragTyp_FOREIGN_KEY_LIST 15
-#define PragTyp_FUNCTION_LIST 16
-#define PragTyp_HARD_HEAP_LIMIT 17
-#define PragTyp_INCREMENTAL_VACUUM 18
-#define PragTyp_INDEX_INFO 19
-#define PragTyp_INDEX_LIST 20
-#define PragTyp_INTEGRITY_CHECK 21
-#define PragTyp_JOURNAL_MODE 22
-#define PragTyp_JOURNAL_SIZE_LIMIT 23
-#define PragTyp_LOCK_PROXY_FILE 24
-#define PragTyp_LOCKING_MODE 25
-#define PragTyp_PAGE_COUNT 26
-#define PragTyp_MMAP_SIZE 27
-#define PragTyp_MODULE_LIST 28
-#define PragTyp_OPTIMIZE 29
-#define PragTyp_PAGE_SIZE 30
-#define PragTyp_PRAGMA_LIST 31
-#define PragTyp_SECURE_DELETE 32
-#define PragTyp_SHRINK_MEMORY 33
-#define PragTyp_SOFT_HEAP_LIMIT 34
-#define PragTyp_SYNCHRONOUS 35
-#define PragTyp_TABLE_INFO 36
-#define PragTyp_TEMP_STORE 37
-#define PragTyp_TEMP_STORE_DIRECTORY 38
-#define PragTyp_THREADS 39
-#define PragTyp_WAL_AUTOCHECKPOINT 40
-#define PragTyp_WAL_CHECKPOINT 41
-#define PragTyp_LOCK_STATUS 42
-#define PragTyp_STATS 43
+#define PragTyp_ANALYSIS_LIMIT 1
+#define PragTyp_HEADER_VALUE 2
+#define PragTyp_AUTO_VACUUM 3
+#define PragTyp_FLAG 4
+#define PragTyp_BUSY_TIMEOUT 5
+#define PragTyp_CACHE_SIZE 6
+#define PragTyp_CACHE_SPILL 7
+#define PragTyp_CASE_SENSITIVE_LIKE 8
+#define PragTyp_COLLATION_LIST 9
+#define PragTyp_COMPILE_OPTIONS 10
+#define PragTyp_DATA_STORE_DIRECTORY 11
+#define PragTyp_DATABASE_LIST 12
+#define PragTyp_DEFAULT_CACHE_SIZE 13
+#define PragTyp_ENCODING 14
+#define PragTyp_FOREIGN_KEY_CHECK 15
+#define PragTyp_FOREIGN_KEY_LIST 16
+#define PragTyp_FUNCTION_LIST 17
+#define PragTyp_HARD_HEAP_LIMIT 18
+#define PragTyp_INCREMENTAL_VACUUM 19
+#define PragTyp_INDEX_INFO 20
+#define PragTyp_INDEX_LIST 21
+#define PragTyp_INTEGRITY_CHECK 22
+#define PragTyp_JOURNAL_MODE 23
+#define PragTyp_JOURNAL_SIZE_LIMIT 24
+#define PragTyp_LOCK_PROXY_FILE 25
+#define PragTyp_LOCKING_MODE 26
+#define PragTyp_PAGE_COUNT 27
+#define PragTyp_MMAP_SIZE 28
+#define PragTyp_MODULE_LIST 29
+#define PragTyp_OPTIMIZE 30
+#define PragTyp_PAGE_SIZE 31
+#define PragTyp_PRAGMA_LIST 32
+#define PragTyp_SECURE_DELETE 33
+#define PragTyp_SHRINK_MEMORY 34
+#define PragTyp_SOFT_HEAP_LIMIT 35
+#define PragTyp_SYNCHRONOUS 36
+#define PragTyp_TABLE_INFO 37
+#define PragTyp_TEMP_STORE 38
+#define PragTyp_TEMP_STORE_DIRECTORY 39
+#define PragTyp_THREADS 40
+#define PragTyp_WAL_AUTOCHECKPOINT 41
+#define PragTyp_WAL_CHECKPOINT 42
+#define PragTyp_LOCK_STATUS 43
+#define PragTyp_STATS 44
/* Property flags associated with various pragma. */
#define PragFlg_NeedSchema 0x01 /* Force schema load before running */
@@ -139,6 +140,11 @@ static const PragmaName aPragmaName[] = {
/* ColNames: */ 0, 0,
/* iArg: */ 0 },
#endif
+ {/* zName: */ "analysis_limit",
+ /* ePragTyp: */ PragTyp_ANALYSIS_LIMIT,
+ /* ePragFlg: */ PragFlg_Result0,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ 0 },
#if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)
{/* zName: */ "application_id",
/* ePragTyp: */ PragTyp_HEADER_VALUE,
@@ -275,7 +281,7 @@ static const PragmaName aPragmaName[] = {
#if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER)
{/* zName: */ "foreign_key_check",
/* ePragTyp: */ PragTyp_FOREIGN_KEY_CHECK,
- /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0,
+ /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_Result1|PragFlg_SchemaOpt,
/* ColNames: */ 37, 4,
/* iArg: */ 0 },
#endif
@@ -639,4 +645,4 @@ static const PragmaName aPragmaName[] = {
/* iArg: */ SQLITE_WriteSchema|SQLITE_NoSchemaError },
#endif
};
-/* Number of pragmas: 66 on by default, 76 total. */
+/* Number of pragmas: 67 on by default, 77 total. */
diff --git a/src/prepare.c b/src/prepare.c
index 228d14876..2d4f7a3ba 100644
--- a/src/prepare.c
+++ b/src/prepare.c
@@ -177,7 +177,7 @@ int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg, u32 mFlags){
char const *azArg[6];
int meta[5];
InitData initData;
- const char *zMasterName;
+ const char *zSchemaTabName;
int openedTransaction = 0;
int mask = ((db->mDbFlags & DBFLAG_EncodingFixed) | ~DBFLAG_EncodingFixed);
@@ -189,13 +189,13 @@ int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg, u32 mFlags){
db->init.busy = 1;
- /* Construct the in-memory representation schema tables (sqlite_master or
- ** sqlite_temp_master) by invoking the parser directly. The appropriate
+ /* Construct the in-memory representation schema tables (sqlite_schema or
+ ** sqlite_temp_schema) by invoking the parser directly. The appropriate
** table name will be inserted automatically by the parser so we can just
** use the abbreviation "x" here. The parser will also automatically tag
** the schema table as read-only. */
azArg[0] = "table";
- azArg[1] = zMasterName = SCHEMA_TABLE(iDb);
+ azArg[1] = zSchemaTabName = SCHEMA_TABLE(iDb);
azArg[2] = azArg[1];
azArg[3] = "1";
azArg[4] = "CREATE TABLE x(type text,name text,tbl_name text,"
@@ -333,7 +333,7 @@ int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg, u32 mFlags){
char *zSql;
zSql = sqlite3MPrintf(db,
"SELECT*FROM\"%w\".%s ORDER BY rowid",
- db->aDb[iDb].zDbSName, zMasterName);
+ db->aDb[iDb].zDbSName, zSchemaTabName);
#ifndef SQLITE_OMIT_AUTHORIZATION
{
sqlite3_xauth xAuth;
@@ -363,7 +363,7 @@ int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg, u32 mFlags){
** current sqlite3_prepare() operation will fail, but the following one
** will attempt to compile the supplied statement against whatever subset
** of the schema was loaded before the error occurred. The primary
- ** purpose of this is to allow access to the sqlite_master table
+ ** purpose of this is to allow access to the sqlite_schema table
** even when its contents have been corrupted.
*/
DbSetProperty(db, iDb, DB_SchemaLoaded);
@@ -504,17 +504,18 @@ static void schemaIsValid(Parse *pParse){
** attached database is returned.
*/
int sqlite3SchemaToIndex(sqlite3 *db, Schema *pSchema){
- int i = -1000000;
+ int i = -32768;
- /* If pSchema is NULL, then return -1000000. This happens when code in
+ /* If pSchema is NULL, then return -32768. This happens when code in
** expr.c is trying to resolve a reference to a transient table (i.e. one
** created by a sub-select). In this case the return value of this
** function should never be used.
**
- ** We return -1000000 instead of the more usual -1 simply because using
- ** -1000000 as the incorrect index into db->aDb[] is much
+ ** We return -32768 instead of the more usual -1 simply because using
+ ** -32768 as the incorrect index into db->aDb[] is much
** more likely to cause a segfault than -1 (of course there are assert()
- ** statements too, but it never hurts to play the odds).
+ ** statements too, but it never hurts to play the odds) and
+ ** -32768 will still fit into a 16-bit signed integer.
*/
assert( sqlite3_mutex_held(db->mutex) );
if( pSchema ){
@@ -530,10 +531,25 @@ int sqlite3SchemaToIndex(sqlite3 *db, Schema *pSchema){
}
/*
+** Deallocate a single AggInfo object
+*/
+static void agginfoFree(sqlite3 *db, AggInfo *p){
+ sqlite3DbFree(db, p->aCol);
+ sqlite3DbFree(db, p->aFunc);
+ sqlite3DbFree(db, p);
+}
+
+/*
** Free all memory allocations in the pParse object
*/
void sqlite3ParserReset(Parse *pParse){
sqlite3 *db = pParse->db;
+ AggInfo *pThis = pParse->pAggList;
+ while( pThis ){
+ AggInfo *pNext = pThis->pNext;
+ agginfoFree(db, pThis);
+ pThis = pNext;
+ }
sqlite3DbFree(db, pParse->aLabel);
sqlite3ExprListDelete(db, pParse->pConstExpr);
if( db ){
@@ -727,7 +743,7 @@ static int sqlite3LockAndPrepare(
**
** If the statement is successfully recompiled, return SQLITE_OK. Otherwise,
** if the statement cannot be recompiled because another connection has
-** locked the sqlite3_master table, return SQLITE_LOCKED. If any other error
+** locked the sqlite3_schema table, return SQLITE_LOCKED. If any other error
** occurs, return SQLITE_SCHEMA.
*/
int sqlite3Reprepare(Vdbe *p){
diff --git a/src/printf.c b/src/printf.c
index fc77f68df..ae957022a 100644
--- a/src/printf.c
+++ b/src/printf.c
@@ -195,6 +195,13 @@ static char *printfTempBuf(sqlite3_str *pAccum, sqlite3_int64 n){
#define etBUFSIZE SQLITE_PRINT_BUF_SIZE /* Size of the output buffer */
/*
+** Hard limit on the precision of floating-point conversions.
+*/
+#ifndef SQLITE_PRINTF_PRECISION_LIMIT
+# define SQLITE_FP_PRECISION_LIMIT 100000000
+#endif
+
+/*
** Render a string given by "fmt" into the StrAccum object.
*/
void sqlite3_str_vappendf(
@@ -394,6 +401,8 @@ void sqlite3_str_vappendf(
** xtype The class of the conversion.
** infop Pointer to the appropriate info struct.
*/
+ assert( width>=0 );
+ assert( precision>=(-1) );
switch( xtype ){
case etPOINTER:
flag_long = sizeof(char*)==sizeof(i64) ? 2 :
@@ -515,6 +524,11 @@ void sqlite3_str_vappendf(
length = 0;
#else
if( precision<0 ) precision = 6; /* Set default precision */
+#ifdef SQLITE_FP_PRECISION_LIMIT
+ if( precision>SQLITE_FP_PRECISION_LIMIT ){
+ precision = SQLITE_FP_PRECISION_LIMIT;
+ }
+#endif
if( realvalue<0.0 ){
realvalue = -realvalue;
prefix = '-';
@@ -797,7 +811,7 @@ void sqlite3_str_vappendf(
}
isnull = escarg==0;
if( isnull ) escarg = (xtype==etSQLESCAPE2 ? "NULL" : "(NULL)");
- /* For %q, %Q, and %w, the precision is the number of byte (or
+ /* For %q, %Q, and %w, the precision is the number of bytes (or
** characters if the ! flags is present) to use from the input.
** Because of the extra quoting characters inserted, the number
** of output characters may be larger than the precision.
@@ -924,7 +938,7 @@ static int sqlite3StrAccumEnlarge(StrAccum *p, int N){
if( p->db ){
zNew = sqlite3DbRealloc(p->db, zOld, p->nAlloc);
}else{
- zNew = sqlite3_realloc64(zOld, p->nAlloc);
+ zNew = sqlite3Realloc(zOld, p->nAlloc);
}
if( zNew ){
assert( p->zText!=0 || p->nChar==0 );
@@ -1266,7 +1280,7 @@ void sqlite3_log(int iErrCode, const char *zFormat, ...){
void sqlite3DebugPrintf(const char *zFormat, ...){
va_list ap;
StrAccum acc;
- char zBuf[500];
+ char zBuf[SQLITE_PRINT_BUF_SIZE*10];
sqlite3StrAccumInit(&acc, 0, zBuf, sizeof(zBuf), 0);
va_start(ap,zFormat);
sqlite3_str_vappendf(&acc, zFormat, ap);
diff --git a/src/resolve.c b/src/resolve.c
index 76cdc8ccd..2b2a3fa12 100644
--- a/src/resolve.c
+++ b/src/resolve.c
@@ -17,6 +17,11 @@
#include "sqliteInt.h"
/*
+** Magic table number to mean the EXCLUDED table in an UPSERT statement.
+*/
+#define EXCLUDED_TABLE_NUMBER 2
+
+/*
** Walk the expression tree pExpr and increase the aggregate function
** depth (the Expr.op2 field) by N on every TK_AGG_FUNCTION node.
** This needs to occur when copying a TK_AGG_FUNCTION node from an
@@ -24,6 +29,8 @@
**
** incrAggFunctionDepth(pExpr,n) is the main routine. incrAggDepth(..)
** is a helper function - a callback for the tree walker.
+**
+** See also the sqlite3WindowExtraAggFuncDepth() routine in window.c
*/
static int incrAggDepth(Walker *pWalker, Expr *pExpr){
if( pExpr->op==TK_AGG_FUNCTION ) pExpr->op2 += pWalker->u.n;
@@ -384,7 +391,7 @@ static int lookupName(
Upsert *pUpsert = pNC->uNC.pUpsert;
if( pUpsert && sqlite3StrICmp("excluded",zTab)==0 ){
pTab = pUpsert->pUpsertSrc->a[0].pTab;
- pExpr->iTable = 2;
+ pExpr->iTable = EXCLUDED_TABLE_NUMBER;
}
}
#endif /* SQLITE_OMIT_UPSERT */
@@ -409,14 +416,15 @@ static int lookupName(
if( iCol<pTab->nCol ){
cnt++;
#ifndef SQLITE_OMIT_UPSERT
- if( pExpr->iTable==2 ){
+ if( pExpr->iTable==EXCLUDED_TABLE_NUMBER ){
testcase( iCol==(-1) );
if( IN_RENAME_OBJECT ){
pExpr->iColumn = iCol;
pExpr->y.pTab = pTab;
eNewExprOp = TK_COLUMN;
}else{
- pExpr->iTable = pNC->uNC.pUpsert->regData + iCol;
+ pExpr->iTable = pNC->uNC.pUpsert->regData +
+ sqlite3TableColumnToStorage(pTab, iCol);
eNewExprOp = TK_REGISTER;
ExprSetProperty(pExpr, EP_Alias);
}
diff --git a/src/select.c b/src/select.c
index 757fa3265..9ef94b105 100644
--- a/src/select.c
+++ b/src/select.c
@@ -15,20 +15,6 @@
#include "sqliteInt.h"
/*
-** Trace output macros
-*/
-#if SELECTTRACE_ENABLED
-/***/ int sqlite3SelectTrace = 0;
-# define SELECTTRACE(K,P,S,X) \
- if(sqlite3SelectTrace&(K)) \
- sqlite3DebugPrintf("%u/%d/%p: ",(S)->selId,(P)->addrExplain,(S)),\
- sqlite3DebugPrintf X
-#else
-# define SELECTTRACE(K,P,S,X)
-#endif
-
-
-/*
** An instance of the following object is used to record information about
** how to process the DISTINCT keyword, to simplify passing that information
** into the selectInnerLoop() routine.
@@ -139,9 +125,9 @@ Select *sqlite3SelectNew(
u32 selFlags, /* Flag parameters, such as SF_Distinct */
Expr *pLimit /* LIMIT value. NULL means not used */
){
- Select *pNew;
+ Select *pNew, *pAllocated;
Select standin;
- pNew = sqlite3DbMallocRawNN(pParse->db, sizeof(*pNew) );
+ pAllocated = pNew = sqlite3DbMallocRawNN(pParse->db, sizeof(*pNew) );
if( pNew==0 ){
assert( pParse->db->mallocFailed );
pNew = &standin;
@@ -175,12 +161,11 @@ Select *sqlite3SelectNew(
#endif
if( pParse->db->mallocFailed ) {
clearSelect(pParse->db, pNew, pNew!=&standin);
- pNew = 0;
+ pAllocated = 0;
}else{
assert( pNew->pSrc!=0 || pParse->nErr>0 );
}
- assert( pNew!=&standin );
- return pNew;
+ return pAllocated;
}
@@ -192,21 +177,6 @@ void sqlite3SelectDelete(sqlite3 *db, Select *p){
}
/*
-** Delete all the substructure for p, but keep p allocated. Redefine
-** p to be a single SELECT where every column of the result set has a
-** value of NULL.
-*/
-void sqlite3SelectReset(Parse *pParse, Select *p){
- if( ALWAYS(p) ){
- clearSelect(pParse->db, p, 0);
- memset(&p->iLimit, 0, sizeof(Select) - offsetof(Select,iLimit));
- p->pEList = sqlite3ExprListAppend(pParse, 0,
- sqlite3ExprAlloc(pParse->db,TK_NULL,0,0));
- p->pSrc = sqlite3DbMallocZero(pParse->db, sizeof(SrcList));
- }
-}
-
-/*
** Return a pointer to the right-most SELECT statement in a compound.
*/
static Select *findRightmost(Select *p){
@@ -2748,9 +2718,7 @@ static int multiSelect(
selectOpName(p->op)));
rc = sqlite3Select(pParse, p, &uniondest);
testcase( rc!=SQLITE_OK );
- /* Query flattening in sqlite3Select() might refill p->pOrderBy.
- ** Be sure to delete p->pOrderBy, therefore, to avoid a memory leak. */
- sqlite3ExprListDelete(db, p->pOrderBy);
+ assert( p->pOrderBy==0 );
pDelete = p->pPrior;
p->pPrior = pPrior;
p->pOrderBy = 0;
@@ -3823,6 +3791,7 @@ static int flattenSubquery(
Expr *pWhere; /* The WHERE clause */
struct SrcList_item *pSubitem; /* The subquery */
sqlite3 *db = pParse->db;
+ Walker w; /* Walker to persist agginfo data */
/* Check to see if flattening is permitted. Return 0 if not.
*/
@@ -4136,7 +4105,7 @@ static int flattenSubquery(
** We look at every expression in the outer query and every place we see
** "a" we substitute "x*3" and every place we see "b" we substitute "y+10".
*/
- if( pSub->pOrderBy ){
+ if( pSub->pOrderBy && (pParent->selFlags & SF_NoopOrderBy)==0 ){
/* At this point, any non-zero iOrderByCol values indicate that the
** ORDER BY column expression is identical to the iOrderByCol'th
** expression returned by SELECT statement pSub. Since these values
@@ -4160,7 +4129,13 @@ static int flattenSubquery(
if( isLeftJoin>0 ){
sqlite3SetJoinExpr(pWhere, iNewParent);
}
- pParent->pWhere = sqlite3ExprAnd(pParse, pWhere, pParent->pWhere);
+ if( pWhere ){
+ if( pParent->pWhere ){
+ pParent->pWhere = sqlite3PExpr(pParse, TK_AND, pWhere, pParent->pWhere);
+ }else{
+ pParent->pWhere = pWhere;
+ }
+ }
if( db->mallocFailed==0 ){
SubstContext x;
x.pParse = pParse;
@@ -4197,6 +4172,8 @@ static int flattenSubquery(
/* Finially, delete what is left of the subquery and return
** success.
*/
+ sqlite3AggInfoPersistWalkerInit(&w, pParse);
+ sqlite3WalkSelect(&w,pSub1);
sqlite3SelectDelete(db, pSub1);
#if SELECTTRACE_ENABLED
@@ -4457,11 +4434,14 @@ static int pushDownWhereTerms(
){
Expr *pNew;
int nChng = 0;
+ Select *pSel;
if( pWhere==0 ) return 0;
if( pSubq->selFlags & SF_Recursive ) return 0; /* restriction (2) */
#ifndef SQLITE_OMIT_WINDOWFUNC
- if( pSubq->pWin ) return 0; /* restriction (6) */
+ for(pSel=pSubq; pSel; pSel=pSel->pPrior){
+ if( pSel->pWin ) return 0; /* restriction (6) */
+ }
#endif
#ifdef SQLITE_DEBUG
@@ -4661,6 +4641,14 @@ static int convertCompoundSelectToSubquery(Walker *pWalker, Select *p){
for(pX=p; pX && (pX->op==TK_ALL || pX->op==TK_SELECT); pX=pX->pPrior){}
if( pX==0 ) return WRC_Continue;
a = p->pOrderBy->a;
+#ifndef SQLITE_OMIT_WINDOWFUNC
+ /* If iOrderByCol is already non-zero, then it has already been matched
+ ** to a result column of the SELECT statement. This occurs when the
+ ** SELECT is rewritten for window-functions processing and then passed
+ ** to sqlite3SelectPrep() and similar a second time. The rewriting done
+ ** by this function is not required in this case. */
+ if( a[0].u.x.iOrderByCol ) return WRC_Continue;
+#endif
for(i=p->pOrderBy->nExpr-1; i>=0; i--){
if( a[i].pExpr->flags & EP_Collate ) break;
}
@@ -5260,29 +5248,6 @@ static int selectExpander(Walker *pWalker, Select *p){
return WRC_Continue;
}
-/*
-** No-op routine for the parse-tree walker.
-**
-** When this routine is the Walker.xExprCallback then expression trees
-** are walked without any actions being taken at each node. Presumably,
-** when this routine is used for Walker.xExprCallback then
-** Walker.xSelectCallback is set to do something useful for every
-** subquery in the parser tree.
-*/
-int sqlite3ExprWalkNoop(Walker *NotUsed, Expr *NotUsed2){
- UNUSED_PARAMETER2(NotUsed, NotUsed2);
- return WRC_Continue;
-}
-
-/*
-** No-op routine for the parse-tree walker for SELECT statements.
-** subquery in the parser tree.
-*/
-int sqlite3SelectWalkNoop(Walker *NotUsed, Select *NotUsed2){
- UNUSED_PARAMETER2(NotUsed, NotUsed2);
- return WRC_Continue;
-}
-
#if SQLITE_DEBUG
/*
** Always assert. This xSelectCallback2 implementation proves that the
@@ -5424,7 +5389,7 @@ static void resetAccumulator(Parse *pParse, AggInfo *pAggInfo){
struct AggInfo_func *pFunc;
int nReg = pAggInfo->nFunc + pAggInfo->nColumn;
if( nReg==0 ) return;
- if( pParse->nErr ) return;
+ if( pParse->nErr || pParse->db->mallocFailed ) return;
#ifdef SQLITE_DEBUG
/* Verify that all AggInfo registers are within the range specified by
** AggInfo.mnReg..AggInfo.mxReg */
@@ -5441,7 +5406,7 @@ static void resetAccumulator(Parse *pParse, AggInfo *pAggInfo){
sqlite3VdbeAddOp3(v, OP_Null, 0, pAggInfo->mnReg, pAggInfo->mxReg);
for(pFunc=pAggInfo->aFunc, i=0; i<pAggInfo->nFunc; i++, pFunc++){
if( pFunc->iDistinct>=0 ){
- Expr *pE = pFunc->pExpr;
+ Expr *pE = pFunc->pFExpr;
assert( !ExprHasProperty(pE, EP_xIsSelect) );
if( pE->x.pList==0 || pE->x.pList->nExpr!=1 ){
sqlite3ErrorMsg(pParse, "DISTINCT aggregates must have exactly one "
@@ -5465,8 +5430,8 @@ static void finalizeAggFunctions(Parse *pParse, AggInfo *pAggInfo){
int i;
struct AggInfo_func *pF;
for(i=0, pF=pAggInfo->aFunc; i<pAggInfo->nFunc; i++, pF++){
- ExprList *pList = pF->pExpr->x.pList;
- assert( !ExprHasProperty(pF->pExpr, EP_xIsSelect) );
+ ExprList *pList = pF->pFExpr->x.pList;
+ assert( !ExprHasProperty(pF->pFExpr, EP_xIsSelect) );
sqlite3VdbeAddOp2(v, OP_AggFinal, pF->iMem, pList ? pList->nExpr : 0);
sqlite3VdbeAppendP4(v, pF->pFunc, P4_FUNCDEF);
}
@@ -5495,22 +5460,26 @@ static void updateAccumulator(Parse *pParse, int regAcc, AggInfo *pAggInfo){
int nArg;
int addrNext = 0;
int regAgg;
- ExprList *pList = pF->pExpr->x.pList;
- assert( !ExprHasProperty(pF->pExpr, EP_xIsSelect) );
- assert( !IsWindowFunc(pF->pExpr) );
- if( ExprHasProperty(pF->pExpr, EP_WinFunc) ){
- Expr *pFilter = pF->pExpr->y.pWin->pFilter;
+ ExprList *pList = pF->pFExpr->x.pList;
+ assert( !ExprHasProperty(pF->pFExpr, EP_xIsSelect) );
+ assert( !IsWindowFunc(pF->pFExpr) );
+ if( ExprHasProperty(pF->pFExpr, EP_WinFunc) ){
+ Expr *pFilter = pF->pFExpr->y.pWin->pFilter;
if( pAggInfo->nAccumulator
&& (pF->pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL)
+ && regAcc
){
+ /* If regAcc==0, there there exists some min() or max() function
+ ** without a FILTER clause that will ensure the magnet registers
+ ** are populated. */
if( regHit==0 ) regHit = ++pParse->nMem;
- /* If this is the first row of the group (regAcc==0), clear the
+ /* If this is the first row of the group (regAcc contains 0), clear the
** "magnet" register regHit so that the accumulator registers
** are populated if the FILTER clause jumps over the the
** invocation of min() or max() altogether. Or, if this is not
- ** the first row (regAcc==1), set the magnet register so that the
- ** accumulators are not populated unless the min()/max() is invoked and
- ** indicates that they should be. */
+ ** the first row (regAcc contains 1), set the magnet register so that
+ ** the accumulators are not populated unless the min()/max() is invoked
+ ** and indicates that they should be. */
sqlite3VdbeAddOp2(v, OP_Copy, regAcc, regHit);
}
addrNext = sqlite3VdbeMakeLabel(pParse);
@@ -5561,7 +5530,7 @@ static void updateAccumulator(Parse *pParse, int regAcc, AggInfo *pAggInfo){
addrHitTest = sqlite3VdbeAddOp1(v, OP_If, regHit); VdbeCoverage(v);
}
for(i=0, pC=pAggInfo->aCol; i<pAggInfo->nAccumulator; i++, pC++){
- sqlite3ExprCode(pParse, pC->pExpr, pC->iMem);
+ sqlite3ExprCode(pParse, pC->pCExpr, pC->iMem);
}
pAggInfo->directMode = 0;
@@ -5804,10 +5773,10 @@ int sqlite3Select(
Expr *pWhere; /* The WHERE clause. May be NULL */
ExprList *pGroupBy; /* The GROUP BY clause. May be NULL */
Expr *pHaving; /* The HAVING clause. May be NULL */
+ AggInfo *pAggInfo = 0; /* Aggregate information */
int rc = 1; /* Value to return from this function */
DistinctCtx sDistinct; /* Info on how to code the DISTINCT keyword */
SortCtx sSort; /* Info on how to code the ORDER BY clause */
- AggInfo sAggInfo; /* Information used by aggregate queries */
int iEnd; /* Address of the end of the query */
sqlite3 *db; /* The database connection */
ExprList *pMinMaxOrderBy = 0; /* Added ORDER BY for min/max queries */
@@ -5819,7 +5788,6 @@ int sqlite3Select(
return 1;
}
if( sqlite3AuthCheck(pParse, SQLITE_SELECT, 0, 0, 0) ) return 1;
- memset(&sAggInfo, 0, sizeof(sAggInfo));
#if SELECTTRACE_ENABLED
SELECTTRACE(1,pParse,p, ("begin processing:\n", pParse->addrExplain));
if( sqlite3SelectTrace & 0x100 ){
@@ -5841,6 +5809,7 @@ int sqlite3Select(
sqlite3ExprListDelete(db, p->pOrderBy);
p->pOrderBy = 0;
p->selFlags &= ~SF_Distinct;
+ p->selFlags |= SF_NoopOrderBy;
}
sqlite3SelectPrep(pParse, p, 0);
if( pParse->nErr || db->mallocFailed ){
@@ -5876,7 +5845,7 @@ int sqlite3Select(
memset(&sSort, 0, sizeof(sSort));
sSort.pOrderBy = p->pOrderBy;
- /* Try to various optimizations (flattening subqueries, and strength
+ /* Try to do various optimizations (flattening subqueries, and strength
** reduction of join operators) in the FROM clause up into the main query
*/
#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
@@ -5885,6 +5854,11 @@ int sqlite3Select(
Select *pSub = pItem->pSelect;
Table *pTab = pItem->pTab;
+ /* The expander should have already created transient Table objects
+ ** even for FROM clause elements such as subqueries that do not correspond
+ ** to a real table */
+ assert( pTab!=0 );
+
/* Convert LEFT JOIN into JOIN if there are terms of the right table
** of the LEFT JOIN used in the WHERE clause.
*/
@@ -6276,7 +6250,7 @@ int sqlite3Select(
u16 wctrlFlags = (sDistinct.isTnct ? WHERE_WANT_DISTINCT : 0)
| (p->selFlags & SF_FixedLimit);
#ifndef SQLITE_OMIT_WINDOWFUNC
- Window *pWin = p->pWin; /* Master window object (or NULL) */
+ Window *pWin = p->pWin; /* Main window object (or NULL) */
if( pWin ){
sqlite3WindowCodeInit(pParse, p);
}
@@ -6409,14 +6383,21 @@ int sqlite3Select(
** sAggInfo for all TK_AGG_FUNCTION nodes in expressions of the
** SELECT statement.
*/
+ pAggInfo = sqlite3DbMallocZero(db, sizeof(*pAggInfo) );
+ if( pAggInfo==0 ){
+ goto select_end;
+ }
+ pAggInfo->pNext = pParse->pAggList;
+ pParse->pAggList = pAggInfo;
+ pAggInfo->selId = p->selId;
memset(&sNC, 0, sizeof(sNC));
sNC.pParse = pParse;
sNC.pSrcList = pTabList;
- sNC.uNC.pAggInfo = &sAggInfo;
+ sNC.uNC.pAggInfo = pAggInfo;
VVA_ONLY( sNC.ncFlags = NC_UAggInfo; )
- sAggInfo.mnReg = pParse->nMem+1;
- sAggInfo.nSortingColumn = pGroupBy ? pGroupBy->nExpr : 0;
- sAggInfo.pGroupBy = pGroupBy;
+ pAggInfo->mnReg = pParse->nMem+1;
+ pAggInfo->nSortingColumn = pGroupBy ? pGroupBy->nExpr : 0;
+ pAggInfo->pGroupBy = pGroupBy;
sqlite3ExprAnalyzeAggList(&sNC, pEList);
sqlite3ExprAnalyzeAggList(&sNC, sSort.pOrderBy);
if( pHaving ){
@@ -6429,14 +6410,14 @@ int sqlite3Select(
}
sqlite3ExprAnalyzeAggregates(&sNC, pHaving);
}
- sAggInfo.nAccumulator = sAggInfo.nColumn;
- if( p->pGroupBy==0 && p->pHaving==0 && sAggInfo.nFunc==1 ){
- minMaxFlag = minMaxQuery(db, sAggInfo.aFunc[0].pExpr, &pMinMaxOrderBy);
+ pAggInfo->nAccumulator = pAggInfo->nColumn;
+ if( p->pGroupBy==0 && p->pHaving==0 && pAggInfo->nFunc==1 ){
+ minMaxFlag = minMaxQuery(db, pAggInfo->aFunc[0].pFExpr, &pMinMaxOrderBy);
}else{
minMaxFlag = WHERE_ORDERBY_NORMAL;
}
- for(i=0; i<sAggInfo.nFunc; i++){
- Expr *pExpr = sAggInfo.aFunc[i].pExpr;
+ for(i=0; i<pAggInfo->nFunc; i++){
+ Expr *pExpr = pAggInfo->aFunc[i].pFExpr;
assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
sNC.ncFlags |= NC_InAggFunc;
sqlite3ExprAnalyzeAggList(&sNC, pExpr->x.pList);
@@ -6448,22 +6429,22 @@ int sqlite3Select(
#endif
sNC.ncFlags &= ~NC_InAggFunc;
}
- sAggInfo.mxReg = pParse->nMem;
+ pAggInfo->mxReg = pParse->nMem;
if( db->mallocFailed ) goto select_end;
#if SELECTTRACE_ENABLED
if( sqlite3SelectTrace & 0x400 ){
int ii;
- SELECTTRACE(0x400,pParse,p,("After aggregate analysis:\n"));
+ SELECTTRACE(0x400,pParse,p,("After aggregate analysis %p:\n", pAggInfo));
sqlite3TreeViewSelect(0, p, 0);
- for(ii=0; ii<sAggInfo.nColumn; ii++){
+ for(ii=0; ii<pAggInfo->nColumn; ii++){
sqlite3DebugPrintf("agg-column[%d] iMem=%d\n",
- ii, sAggInfo.aCol[ii].iMem);
- sqlite3TreeViewExpr(0, sAggInfo.aCol[ii].pExpr, 0);
+ ii, pAggInfo->aCol[ii].iMem);
+ sqlite3TreeViewExpr(0, pAggInfo->aCol[ii].pCExpr, 0);
}
- for(ii=0; ii<sAggInfo.nFunc; ii++){
+ for(ii=0; ii<pAggInfo->nFunc; ii++){
sqlite3DebugPrintf("agg-func[%d]: iMem=%d\n",
- ii, sAggInfo.aFunc[ii].iMem);
- sqlite3TreeViewExpr(0, sAggInfo.aFunc[ii].pExpr, 0);
+ ii, pAggInfo->aFunc[ii].iMem);
+ sqlite3TreeViewExpr(0, pAggInfo->aFunc[ii].pFExpr, 0);
}
}
#endif
@@ -6488,10 +6469,11 @@ int sqlite3Select(
** that we do not need it after all, the OP_SorterOpen instruction
** will be converted into a Noop.
*/
- sAggInfo.sortingIdx = pParse->nTab++;
- pKeyInfo = sqlite3KeyInfoFromExprList(pParse,pGroupBy,0,sAggInfo.nColumn);
+ pAggInfo->sortingIdx = pParse->nTab++;
+ pKeyInfo = sqlite3KeyInfoFromExprList(pParse, pGroupBy,
+ 0, pAggInfo->nColumn);
addrSortingIdx = sqlite3VdbeAddOp4(v, OP_SorterOpen,
- sAggInfo.sortingIdx, sAggInfo.nSortingColumn,
+ pAggInfo->sortingIdx, pAggInfo->nSortingColumn,
0, (char*)pKeyInfo, P4_KEYINFO);
/* Initialize memory locations used by GROUP BY aggregate processing
@@ -6546,8 +6528,8 @@ int sqlite3Select(
nGroupBy = pGroupBy->nExpr;
nCol = nGroupBy;
j = nGroupBy;
- for(i=0; i<sAggInfo.nColumn; i++){
- if( sAggInfo.aCol[i].iSorterColumn>=j ){
+ for(i=0; i<pAggInfo->nColumn; i++){
+ if( pAggInfo->aCol[i].iSorterColumn>=j ){
nCol++;
j++;
}
@@ -6555,8 +6537,8 @@ int sqlite3Select(
regBase = sqlite3GetTempRange(pParse, nCol);
sqlite3ExprCodeExprList(pParse, pGroupBy, regBase, 0, 0);
j = nGroupBy;
- for(i=0; i<sAggInfo.nColumn; i++){
- struct AggInfo_col *pCol = &sAggInfo.aCol[i];
+ for(i=0; i<pAggInfo->nColumn; i++){
+ struct AggInfo_col *pCol = &pAggInfo->aCol[i];
if( pCol->iSorterColumn>=j ){
int r1 = j + regBase;
sqlite3ExprCodeGetColumnOfTable(v,
@@ -6566,16 +6548,16 @@ int sqlite3Select(
}
regRecord = sqlite3GetTempReg(pParse);
sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase, nCol, regRecord);
- sqlite3VdbeAddOp2(v, OP_SorterInsert, sAggInfo.sortingIdx, regRecord);
+ sqlite3VdbeAddOp2(v, OP_SorterInsert, pAggInfo->sortingIdx, regRecord);
sqlite3ReleaseTempReg(pParse, regRecord);
sqlite3ReleaseTempRange(pParse, regBase, nCol);
sqlite3WhereEnd(pWInfo);
- sAggInfo.sortingIdxPTab = sortPTab = pParse->nTab++;
+ pAggInfo->sortingIdxPTab = sortPTab = pParse->nTab++;
sortOut = sqlite3GetTempReg(pParse);
sqlite3VdbeAddOp3(v, OP_OpenPseudo, sortPTab, sortOut, nCol);
- sqlite3VdbeAddOp2(v, OP_SorterSort, sAggInfo.sortingIdx, addrEnd);
+ sqlite3VdbeAddOp2(v, OP_SorterSort, pAggInfo->sortingIdx, addrEnd);
VdbeComment((v, "GROUP BY sort")); VdbeCoverage(v);
- sAggInfo.useSortingIdx = 1;
+ pAggInfo->useSortingIdx = 1;
}
/* If the index or temporary table used by the GROUP BY sort
@@ -6599,14 +6581,14 @@ int sqlite3Select(
*/
addrTopOfLoop = sqlite3VdbeCurrentAddr(v);
if( groupBySort ){
- sqlite3VdbeAddOp3(v, OP_SorterData, sAggInfo.sortingIdx,
+ sqlite3VdbeAddOp3(v, OP_SorterData, pAggInfo->sortingIdx,
sortOut, sortPTab);
}
for(j=0; j<pGroupBy->nExpr; j++){
if( groupBySort ){
sqlite3VdbeAddOp3(v, OP_Column, sortPTab, j, iBMem+j);
}else{
- sAggInfo.directMode = 1;
+ pAggInfo->directMode = 1;
sqlite3ExprCode(pParse, pGroupBy->a[j].pExpr, iBMem+j);
}
}
@@ -6636,14 +6618,14 @@ int sqlite3Select(
** the current row
*/
sqlite3VdbeJumpHere(v, addr1);
- updateAccumulator(pParse, iUseFlag, &sAggInfo);
+ updateAccumulator(pParse, iUseFlag, pAggInfo);
sqlite3VdbeAddOp2(v, OP_Integer, 1, iUseFlag);
VdbeComment((v, "indicate data in accumulator"));
/* End of the loop
*/
if( groupBySort ){
- sqlite3VdbeAddOp2(v, OP_SorterNext, sAggInfo.sortingIdx, addrTopOfLoop);
+ sqlite3VdbeAddOp2(v, OP_SorterNext, pAggInfo->sortingIdx, addrTopOfLoop);
VdbeCoverage(v);
}else{
sqlite3WhereEnd(pWInfo);
@@ -6676,7 +6658,7 @@ int sqlite3Select(
VdbeCoverage(v);
VdbeComment((v, "Groupby result generator entry point"));
sqlite3VdbeAddOp1(v, OP_Return, regOutputRow);
- finalizeAggFunctions(pParse, &sAggInfo);
+ finalizeAggFunctions(pParse, pAggInfo);
sqlite3ExprIfFalse(pParse, pHaving, addrOutputRow+1, SQLITE_JUMPIFNULL);
selectInnerLoop(pParse, p, -1, &sSort,
&sDistinct, pDest,
@@ -6687,16 +6669,15 @@ int sqlite3Select(
/* Generate a subroutine that will reset the group-by accumulator
*/
sqlite3VdbeResolveLabel(v, addrReset);
- resetAccumulator(pParse, &sAggInfo);
+ resetAccumulator(pParse, pAggInfo);
sqlite3VdbeAddOp2(v, OP_Integer, 0, iUseFlag);
VdbeComment((v, "indicate accumulator empty"));
sqlite3VdbeAddOp1(v, OP_Return, regReset);
} /* endif pGroupBy. Begin aggregate queries without GROUP BY: */
else {
-#ifndef SQLITE_OMIT_BTREECOUNT
Table *pTab;
- if( (pTab = isSimpleCount(p, &sAggInfo))!=0 ){
+ if( (pTab = isSimpleCount(p, pAggInfo))!=0 ){
/* If isSimpleCount() returns a pointer to a Table structure, then
** the SQL statement is of the form:
**
@@ -6730,13 +6711,15 @@ int sqlite3Select(
** passed to keep OP_OpenRead happy.
*/
if( !HasRowid(pTab) ) pBest = sqlite3PrimaryKeyIndex(pTab);
- for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
- if( pIdx->bUnordered==0
- && pIdx->szIdxRow<pTab->szTabRow
- && pIdx->pPartIdxWhere==0
- && (!pBest || pIdx->szIdxRow<pBest->szIdxRow)
- ){
- pBest = pIdx;
+ if( !p->pSrc->a[0].fg.notIndexed ){
+ for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
+ if( pIdx->bUnordered==0
+ && pIdx->szIdxRow<pTab->szTabRow
+ && pIdx->pPartIdxWhere==0
+ && (!pBest || pIdx->szIdxRow<pBest->szIdxRow)
+ ){
+ pBest = pIdx;
+ }
}
}
if( pBest ){
@@ -6749,12 +6732,10 @@ int sqlite3Select(
if( pKeyInfo ){
sqlite3VdbeChangeP4(v, -1, (char *)pKeyInfo, P4_KEYINFO);
}
- sqlite3VdbeAddOp2(v, OP_Count, iCsr, sAggInfo.aFunc[0].iMem);
+ sqlite3VdbeAddOp2(v, OP_Count, iCsr, pAggInfo->aFunc[0].iMem);
sqlite3VdbeAddOp1(v, OP_Close, iCsr);
explainSimpleCount(pParse, pTab, pBest);
- }else
-#endif /* SQLITE_OMIT_BTREECOUNT */
- {
+ }else{
int regAcc = 0; /* "populate accumulators" flag */
/* If there are accumulator registers but no min() or max() functions
@@ -6766,12 +6747,16 @@ int sqlite3Select(
** first row visited by the aggregate, so that they are updated at
** least once even if the FILTER clause means the min() or max()
** function visits zero rows. */
- if( sAggInfo.nAccumulator ){
- for(i=0; i<sAggInfo.nFunc; i++){
- if( ExprHasProperty(sAggInfo.aFunc[i].pExpr, EP_WinFunc) ) continue;
- if( sAggInfo.aFunc[i].pFunc->funcFlags&SQLITE_FUNC_NEEDCOLL ) break;
+ if( pAggInfo->nAccumulator ){
+ for(i=0; i<pAggInfo->nFunc; i++){
+ if( ExprHasProperty(pAggInfo->aFunc[i].pFExpr, EP_WinFunc) ){
+ continue;
+ }
+ if( pAggInfo->aFunc[i].pFunc->funcFlags&SQLITE_FUNC_NEEDCOLL ){
+ break;
+ }
}
- if( i==sAggInfo.nFunc ){
+ if( i==pAggInfo->nFunc ){
regAcc = ++pParse->nMem;
sqlite3VdbeAddOp2(v, OP_Integer, 0, regAcc);
}
@@ -6782,7 +6767,7 @@ int sqlite3Select(
** of output.
*/
assert( p->pGroupBy==0 );
- resetAccumulator(pParse, &sAggInfo);
+ resetAccumulator(pParse, pAggInfo);
/* If this query is a candidate for the min/max optimization, then
** minMaxFlag will have been previously set to either
@@ -6798,7 +6783,7 @@ int sqlite3Select(
if( pWInfo==0 ){
goto select_end;
}
- updateAccumulator(pParse, regAcc, &sAggInfo);
+ updateAccumulator(pParse, regAcc, pAggInfo);
if( regAcc ) sqlite3VdbeAddOp2(v, OP_Integer, 1, regAcc);
if( sqlite3WhereIsOrdered(pWInfo)>0 ){
sqlite3VdbeGoto(v, sqlite3WhereBreakLabel(pWInfo));
@@ -6806,7 +6791,7 @@ int sqlite3Select(
(minMaxFlag==WHERE_ORDERBY_MIN?"min":"max")));
}
sqlite3WhereEnd(pWInfo);
- finalizeAggFunctions(pParse, &sAggInfo);
+ finalizeAggFunctions(pParse, pAggInfo);
}
sSort.pOrderBy = 0;
@@ -6845,8 +6830,25 @@ int sqlite3Select(
*/
select_end:
sqlite3ExprListDelete(db, pMinMaxOrderBy);
- sqlite3DbFree(db, sAggInfo.aCol);
- sqlite3DbFree(db, sAggInfo.aFunc);
+#ifdef SQLITE_DEBUG
+ if( pAggInfo && !db->mallocFailed ){
+ for(i=0; i<pAggInfo->nColumn; i++){
+ Expr *pExpr = pAggInfo->aCol[i].pCExpr;
+ assert( pExpr!=0 || db->mallocFailed );
+ if( pExpr==0 ) continue;
+ assert( pExpr->pAggInfo==pAggInfo );
+ assert( pExpr->iAgg==i );
+ }
+ for(i=0; i<pAggInfo->nFunc; i++){
+ Expr *pExpr = pAggInfo->aFunc[i].pFExpr;
+ assert( pExpr!=0 || db->mallocFailed );
+ if( pExpr==0 ) continue;
+ assert( pExpr->pAggInfo==pAggInfo );
+ assert( pExpr->iAgg==i );
+ }
+ }
+#endif
+
#if SELECTTRACE_ENABLED
SELECTTRACE(0x1,pParse,p,("end processing\n"));
if( (sqlite3SelectTrace & 0x2000)!=0 && ExplainQueryPlanParent(pParse)==0 ){
diff --git a/src/shell.c.in b/src/shell.c.in
index 0218b7187..78a80da3e 100644
--- a/src/shell.c.in
+++ b/src/shell.c.in
@@ -935,7 +935,7 @@ static void shellModuleSchema(
** CREATE VIRTUAL TABLE
**
** This UDF is used by the .schema command to insert the schema name of
-** attached databases into the middle of the sqlite_master.sql field.
+** attached databases into the middle of the sqlite_schema.sql field.
*/
static void shellAddSchemaName(
sqlite3_context *pCtx,
@@ -1011,6 +1011,8 @@ INCLUDE ../ext/misc/completion.c
INCLUDE ../ext/misc/appendvfs.c
INCLUDE ../ext/misc/memtrace.c
INCLUDE ../ext/misc/uint.c
+INCLUDE ../ext/misc/decimal.c
+INCLUDE ../ext/misc/ieee754.c
#ifdef SQLITE_HAVE_ZLIB
INCLUDE ../ext/misc/zipfile.c
INCLUDE ../ext/misc/sqlar.c
@@ -1035,18 +1037,6 @@ struct OpenSession {
};
#endif
-/*
-** Shell output mode information from before ".explain on",
-** saved so that it can be restored by ".explain off"
-*/
-typedef struct SavedModeInfo SavedModeInfo;
-struct SavedModeInfo {
- int valid; /* Is there legit data in here? */
- int mode; /* Mode prior to ".explain on" */
- int showHeader; /* The ".header" setting prior to ".explain on" */
- int colWidth[100]; /* Column widths prior to ".explain on" */
-};
-
typedef struct ExpertInfo ExpertInfo;
struct ExpertInfo {
sqlite3expert *pExpert;
@@ -1116,8 +1106,9 @@ struct ShellState {
char rowSeparator[20]; /* Row separator character for MODE_Ascii */
char colSepPrior[20]; /* Saved column separator */
char rowSepPrior[20]; /* Saved row separator */
- int colWidth[100]; /* Requested width of each column when in column mode*/
- int actualWidth[100]; /* Actual width of each column */
+ int *colWidth; /* Requested width of each column in columnar modes */
+ int *actualWidth; /* Actual width of each column */
+ int nWidth; /* Number of slots in colWidth[] and actualWidth[] */
char nullValue[20]; /* The text to print when a NULL comes back from
** the database */
char outfile[FILENAME_MAX]; /* Filename for *out */
@@ -1178,6 +1169,7 @@ struct ShellState {
#define SHFLG_Newlines 0x00000010 /* .dump --newline flag */
#define SHFLG_CountChanges 0x00000020 /* .changes setting */
#define SHFLG_Echo 0x00000040 /* .echo or --echo setting */
+#define SHFLG_HeaderSet 0x00000080 /* .header has been used */
/*
** Macros for testing and setting shellFlgs
@@ -1202,6 +1194,10 @@ struct ShellState {
#define MODE_Ascii 10 /* Use ASCII unit and record separators (0x1F/0x1E) */
#define MODE_Pretty 11 /* Pretty-print schemas */
#define MODE_EQP 12 /* Converts EXPLAIN QUERY PLAN output into a graph */
+#define MODE_Json 13 /* Output JSON */
+#define MODE_Markdown 14 /* Markdown formatting */
+#define MODE_Table 15 /* MySQL-style table formatting */
+#define MODE_Box 16 /* Unicode box-drawing characters */
static const char *modeDescr[] = {
"line",
@@ -1216,7 +1212,11 @@ static const char *modeDescr[] = {
"explain",
"ascii",
"prettyprint",
- "eqp"
+ "eqp",
+ "json",
+ "markdown",
+ "table",
+ "box"
};
/*
@@ -1585,6 +1585,40 @@ static void output_c_string(FILE *out, const char *z){
}
/*
+** Output the given string as a quoted according to JSON quoting rules.
+*/
+static void output_json_string(FILE *out, const char *z, int n){
+ unsigned int c;
+ if( n<0 ) n = (int)strlen(z);
+ fputc('"', out);
+ while( n-- ){
+ c = *(z++);
+ if( c=='\\' || c=='"' ){
+ fputc('\\', out);
+ fputc(c, out);
+ }else if( c<=0x1f ){
+ fputc('\\', out);
+ if( c=='\b' ){
+ fputc('b', out);
+ }else if( c=='\f' ){
+ fputc('f', out);
+ }else if( c=='\n' ){
+ fputc('n', out);
+ }else if( c=='\r' ){
+ fputc('r', out);
+ }else if( c=='\t' ){
+ fputc('t', out);
+ }else{
+ raw_printf(out, "u%04x",c);
+ }
+ }else{
+ fputc(c, out);
+ }
+ }
+ fputc('"', out);
+}
+
+/*
** Output the given string with characters that are special to
** HTML escaped.
*/
@@ -1894,6 +1928,40 @@ static int progress_handler(void *pClientData) {
#endif /* SQLITE_OMIT_PROGRESS_CALLBACK */
/*
+** Print N dashes
+*/
+static void print_dashes(FILE *out, int N){
+ const char zDash[] = "--------------------------------------------------";
+ const int nDash = sizeof(zDash) - 1;
+ while( N>nDash ){
+ fputs(zDash, out);
+ N -= nDash;
+ }
+ raw_printf(out, "%.*s", N, zDash);
+}
+
+/*
+** Print a markdown or table-style row separator using ascii-art
+*/
+static void print_row_separator(
+ ShellState *p,
+ int nArg,
+ const char *zSep
+){
+ int i;
+ if( nArg>0 ){
+ fputs(zSep, p->out);
+ print_dashes(p->out, p->actualWidth[0]+2);
+ for(i=1; i<nArg; i++){
+ fputs(zSep, p->out);
+ print_dashes(p->out, p->actualWidth[i]+2);
+ }
+ fputs(zSep, p->out);
+ }
+ fputs("\n", p->out);
+}
+
+/*
** This is the callback routine that the shell
** invokes for each row of a query result.
*/
@@ -1902,7 +1970,7 @@ static int shell_callback(
int nArg, /* Number of result columns */
char **azArg, /* Text of each result column */
char **azCol, /* Column names */
- int *aiType /* Column types */
+ int *aiType /* Column types. Might be NULL */
){
int i;
ShellState *p = (ShellState*)pArg;
@@ -1923,71 +1991,27 @@ static int shell_callback(
}
break;
}
- case MODE_Explain:
- case MODE_Column: {
- static const int aExplainWidths[] = {4, 13, 4, 4, 4, 13, 2, 13};
- const int *colWidth;
- int showHdr;
- char *rowSep;
- int nWidth;
- if( p->cMode==MODE_Column ){
- colWidth = p->colWidth;
- nWidth = ArraySize(p->colWidth);
- showHdr = p->showHeader;
- rowSep = p->rowSeparator;
- }else{
- colWidth = aExplainWidths;
- nWidth = ArraySize(aExplainWidths);
- showHdr = 1;
- rowSep = SEP_Row;
+ case MODE_Explain: {
+ static const int aExplainWidth[] = {4, 13, 4, 4, 4, 13, 2, 13};
+ if( nArg>ArraySize(aExplainWidth) ){
+ nArg = ArraySize(aExplainWidth);
}
if( p->cnt++==0 ){
for(i=0; i<nArg; i++){
- int w, n;
- if( i<nWidth ){
- w = colWidth[i];
- }else{
- w = 0;
- }
- if( w==0 ){
- w = strlenChar(azCol[i] ? azCol[i] : "");
- if( w<10 ) w = 10;
- n = strlenChar(azArg && azArg[i] ? azArg[i] : p->nullValue);
- if( w<n ) w = n;
- }
- if( i<ArraySize(p->actualWidth) ){
- p->actualWidth[i] = w;
- }
- if( showHdr ){
- utf8_width_print(p->out, w, azCol[i]);
- utf8_printf(p->out, "%s", i==nArg-1 ? rowSep : " ");
- }
+ int w = aExplainWidth[i];
+ utf8_width_print(p->out, w, azCol[i]);
+ fputs(i==nArg-1 ? "\n" : " ", p->out);
}
- if( showHdr ){
- for(i=0; i<nArg; i++){
- int w;
- if( i<ArraySize(p->actualWidth) ){
- w = p->actualWidth[i];
- if( w<0 ) w = -w;
- }else{
- w = 10;
- }
- utf8_printf(p->out,"%-*.*s%s",w,w,
- "----------------------------------------------------------"
- "----------------------------------------------------------",
- i==nArg-1 ? rowSep : " ");
- }
+ for(i=0; i<nArg; i++){
+ int w = aExplainWidth[i];
+ print_dashes(p->out, w);
+ fputs(i==nArg-1 ? "\n" : " ", p->out);
}
}
if( azArg==0 ) break;
for(i=0; i<nArg; i++){
- int w;
- if( i<ArraySize(p->actualWidth) ){
- w = p->actualWidth[i];
- }else{
- w = 10;
- }
- if( p->cMode==MODE_Explain && azArg[i] && strlenChar(azArg[i])>w ){
+ int w = aExplainWidth[i];
+ if( azArg[i] && strlenChar(azArg[i])>w ){
w = strlenChar(azArg[i]);
}
if( i==1 && p->aiIndent && p->pStmt ){
@@ -1997,7 +2021,7 @@ static int shell_callback(
p->iIndent++;
}
utf8_width_print(p->out, w, azArg[i] ? azArg[i] : p->nullValue);
- utf8_printf(p->out, "%s", i==nArg-1 ? rowSep : " ");
+ fputs(i==nArg-1 ? "\n" : " ", p->out);
}
break;
}
@@ -2201,18 +2225,60 @@ static int shell_callback(
raw_printf(p->out,");\n");
break;
}
+ case MODE_Json: {
+ if( azArg==0 ) break;
+ if( p->cnt==0 ){
+ fputs("[{", p->out);
+ }else{
+ fputs(",\n{", p->out);
+ }
+ p->cnt++;
+ for(i=0; i<nArg; i++){
+ output_json_string(p->out, azCol[i], -1);
+ putc(':', p->out);
+ if( (azArg[i]==0) || (aiType && aiType[i]==SQLITE_NULL) ){
+ fputs("null",p->out);
+ }else if( aiType && aiType[i]==SQLITE_FLOAT ){
+ char z[50];
+ double r = sqlite3_column_double(p->pStmt, i);
+ sqlite3_uint64 ur;
+ memcpy(&ur,&r,sizeof(r));
+ if( ur==0x7ff0000000000000LL ){
+ raw_printf(p->out, "1e999");
+ }else if( ur==0xfff0000000000000LL ){
+ raw_printf(p->out, "-1e999");
+ }else{
+ sqlite3_snprintf(50,z,"%!.20g", r);
+ raw_printf(p->out, "%s", z);
+ }
+ }else if( aiType && aiType[i]==SQLITE_BLOB && p->pStmt ){
+ const void *pBlob = sqlite3_column_blob(p->pStmt, i);
+ int nBlob = sqlite3_column_bytes(p->pStmt, i);
+ output_json_string(p->out, pBlob, nBlob);
+ }else if( aiType && aiType[i]==SQLITE_TEXT ){
+ output_json_string(p->out, azArg[i], -1);
+ }else{
+ utf8_printf(p->out,"%s", azArg[i]);
+ }
+ if( i<nArg-1 ){
+ putc(',', p->out);
+ }
+ }
+ putc('}', p->out);
+ break;
+ }
case MODE_Quote: {
if( azArg==0 ) break;
if( p->cnt==0 && p->showHeader ){
for(i=0; i<nArg; i++){
- if( i>0 ) raw_printf(p->out, ",");
+ if( i>0 ) fputs(p->colSeparator, p->out);
output_quoted_string(p->out, azCol[i]);
}
- raw_printf(p->out,"\n");
+ fputs(p->rowSeparator, p->out);
}
p->cnt++;
for(i=0; i<nArg; i++){
- if( i>0 ) raw_printf(p->out, ",");
+ if( i>0 ) fputs(p->colSeparator, p->out);
if( (azArg[i]==0) || (aiType && aiType[i]==SQLITE_NULL) ){
utf8_printf(p->out,"NULL");
}else if( aiType && aiType[i]==SQLITE_TEXT ){
@@ -2234,7 +2300,7 @@ static int shell_callback(
output_quoted_string(p->out, azArg[i]);
}
}
- raw_printf(p->out,"\n");
+ fputs(p->rowSeparator, p->out);
break;
}
case MODE_Ascii: {
@@ -2307,16 +2373,16 @@ static void createSelftestTable(ShellState *p){
"INSERT INTO [_shell$self]\n"
" SELECT 'run',\n"
" 'SELECT hex(sha3_query(''SELECT type,name,tbl_name,sql "
- "FROM sqlite_master ORDER BY 2'',224))',\n"
+ "FROM sqlite_schema ORDER BY 2'',224))',\n"
" hex(sha3_query('SELECT type,name,tbl_name,sql "
- "FROM sqlite_master ORDER BY 2',224));\n"
+ "FROM sqlite_schema ORDER BY 2',224));\n"
"INSERT INTO [_shell$self]\n"
" SELECT 'run',"
" 'SELECT hex(sha3_query(''SELECT * FROM \"' ||"
" printf('%w',name) || '\" NOT INDEXED'',224))',\n"
" hex(sha3_query(printf('SELECT * FROM \"%w\" NOT INDEXED',name),224))\n"
" FROM (\n"
- " SELECT name FROM sqlite_master\n"
+ " SELECT name FROM sqlite_schema\n"
" WHERE type='table'\n"
" AND name<>'selftest'\n"
" AND coalesce(rootpage,0)>0\n"
@@ -2891,6 +2957,217 @@ static void bind_prepared_stmt(ShellState *pArg, sqlite3_stmt *pStmt){
}
/*
+** UTF8 box-drawing characters. Imagine box lines like this:
+**
+** 1
+** |
+** 4 --+-- 2
+** |
+** 3
+**
+** Each box characters has between 2 and 4 of the lines leading from
+** the center. The characters are here identified by the numbers of
+** their corresponding lines.
+*/
+#define BOX_24 "\342\224\200" /* U+2500 --- */
+#define BOX_13 "\342\224\202" /* U+2502 | */
+#define BOX_23 "\342\224\214" /* U+250c ,- */
+#define BOX_34 "\342\224\220" /* U+2510 -, */
+#define BOX_12 "\342\224\224" /* U+2514 '- */
+#define BOX_14 "\342\224\230" /* U+2518 -' */
+#define BOX_123 "\342\224\234" /* U+251c |- */
+#define BOX_134 "\342\224\244" /* U+2524 -| */
+#define BOX_234 "\342\224\254" /* U+252c -,- */
+#define BOX_124 "\342\224\264" /* U+2534 -'- */
+#define BOX_1234 "\342\224\274" /* U+253c -|- */
+
+/* Draw horizontal line N characters long using unicode box
+** characters
+*/
+static void print_box_line(FILE *out, int N){
+ const char zDash[] =
+ BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24
+ BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24;
+ const int nDash = sizeof(zDash) - 1;
+ N *= 3;
+ while( N>nDash ){
+ utf8_printf(out, zDash);
+ N -= nDash;
+ }
+ utf8_printf(out, "%.*s", N, zDash);
+}
+
+/*
+** Draw a horizontal separator for a MODE_Box table.
+*/
+static void print_box_row_separator(
+ ShellState *p,
+ int nArg,
+ const char *zSep1,
+ const char *zSep2,
+ const char *zSep3
+){
+ int i;
+ if( nArg>0 ){
+ utf8_printf(p->out, "%s", zSep1);
+ print_box_line(p->out, p->actualWidth[0]+2);
+ for(i=1; i<nArg; i++){
+ utf8_printf(p->out, "%s", zSep2);
+ print_box_line(p->out, p->actualWidth[i]+2);
+ }
+ utf8_printf(p->out, "%s", zSep3);
+ }
+ fputs("\n", p->out);
+}
+
+
+
+/*
+** Run a prepared statement and output the result in one of the
+** table-oriented formats: MODE_Column, MODE_Markdown, MODE_Table,
+** or MODE_Box.
+**
+** This is different from ordinary exec_prepared_stmt() in that
+** it has to run the entire query and gather the results into memory
+** first, in order to determine column widths, before providing
+** any output.
+*/
+static void exec_prepared_stmt_columnar(
+ ShellState *p, /* Pointer to ShellState */
+ sqlite3_stmt *pStmt /* Statment to run */
+){
+ int nRow = 0;
+ int nColumn = 0;
+ char **azData = 0;
+ char *zMsg = 0;
+ const char *z;
+ int rc;
+ int i, j, nTotal, w, n;
+ const char *colSep = 0;
+ const char *rowSep = 0;
+
+ rc = sqlite3_get_table(p->db, sqlite3_sql(pStmt),
+ &azData, &nRow, &nColumn, &zMsg);
+ if( rc ){
+ utf8_printf(p->out, "ERROR: %s\n", zMsg);
+ sqlite3_free(zMsg);
+ sqlite3_free_table(azData);
+ return;
+ }
+ if( nRow==0 || nColumn==0 ) goto columnar_end;
+ if( nColumn>p->nWidth ){
+ p->colWidth = realloc(p->colWidth, nColumn*2*sizeof(int));
+ if( p->colWidth==0 ) shell_out_of_memory();
+ for(i=p->nWidth; i<nColumn; i++) p->colWidth[i] = 0;
+ p->nWidth = nColumn;
+ p->actualWidth = &p->colWidth[nColumn];
+ }
+ memset(p->actualWidth, 0, nColumn*sizeof(int));
+ for(i=0; i<nColumn; i++){
+ w = p->colWidth[i];
+ if( w<0 ) w = -w;
+ p->actualWidth[i] = w;
+ }
+ nTotal = nColumn*(nRow+1);
+ for(i=0; i<nTotal; i++){
+ z = azData[i];
+ if( z==0 ) z = p->nullValue;
+ n = strlenChar(z);
+ j = i%nColumn;
+ if( n>p->actualWidth[j] ) p->actualWidth[j] = n;
+ }
+ if( seenInterrupt ) goto columnar_end;
+ switch( p->cMode ){
+ case MODE_Column: {
+ colSep = " ";
+ rowSep = "\n";
+ if( p->showHeader ){
+ for(i=0; i<nColumn; i++){
+ w = p->actualWidth[i];
+ if( p->colWidth[i]<0 ) w = -w;
+ utf8_width_print(p->out, w, azData[i]);
+ fputs(i==nColumn-1?"\n":" ", p->out);
+ }
+ for(i=0; i<nColumn; i++){
+ print_dashes(p->out, p->actualWidth[i]);
+ fputs(i==nColumn-1?"\n":" ", p->out);
+ }
+ }
+ break;
+ }
+ case MODE_Table: {
+ colSep = " | ";
+ rowSep = " |\n";
+ print_row_separator(p, nColumn, "+");
+ fputs("| ", p->out);
+ for(i=0; i<nColumn; i++){
+ w = p->actualWidth[i];
+ n = strlenChar(azData[i]);
+ utf8_printf(p->out, "%*s%s%*s", (w-n)/2, "", azData[i], (w-n+1)/2, "");
+ fputs(i==nColumn-1?" |\n":" | ", p->out);
+ }
+ print_row_separator(p, nColumn, "+");
+ break;
+ }
+ case MODE_Markdown: {
+ colSep = " | ";
+ rowSep = " |\n";
+ fputs("| ", p->out);
+ for(i=0; i<nColumn; i++){
+ w = p->actualWidth[i];
+ n = strlenChar(azData[i]);
+ utf8_printf(p->out, "%*s%s%*s", (w-n)/2, "", azData[i], (w-n+1)/2, "");
+ fputs(i==nColumn-1?" |\n":" | ", p->out);
+ }
+ print_row_separator(p, nColumn, "|");
+ break;
+ }
+ case MODE_Box: {
+ colSep = " " BOX_13 " ";
+ rowSep = " " BOX_13 "\n";
+ print_box_row_separator(p, nColumn, BOX_23, BOX_234, BOX_34);
+ utf8_printf(p->out, BOX_13 " ");
+ for(i=0; i<nColumn; i++){
+ w = p->actualWidth[i];
+ n = strlenChar(azData[i]);
+ utf8_printf(p->out, "%*s%s%*s%s",
+ (w-n)/2, "", azData[i], (w-n+1)/2, "",
+ i==nColumn-1?" "BOX_13"\n":" "BOX_13" ");
+ }
+ print_box_row_separator(p, nColumn, BOX_123, BOX_1234, BOX_134);
+ break;
+ }
+ }
+ for(i=nColumn, j=0; i<nTotal; i++, j++){
+ if( j==0 && p->cMode!=MODE_Column ){
+ utf8_printf(p->out, "%s", p->cMode==MODE_Box?BOX_13" ":"| ");
+ }
+ z = azData[i];
+ if( z==0 ) z = p->nullValue;
+ w = p->actualWidth[j];
+ if( p->colWidth[j]<0 ) w = -w;
+ utf8_width_print(p->out, w, z);
+ if( j==nColumn-1 ){
+ utf8_printf(p->out, "%s", rowSep);
+ j = -1;
+ if( seenInterrupt ) goto columnar_end;
+ }else{
+ utf8_printf(p->out, "%s", colSep);
+ }
+ }
+ if( p->cMode==MODE_Table ){
+ print_row_separator(p, nColumn, "+");
+ }else if( p->cMode==MODE_Box ){
+ print_box_row_separator(p, nColumn, BOX_12, BOX_124, BOX_14);
+ }
+columnar_end:
+ if( seenInterrupt ){
+ utf8_printf(p->out, "Interrupt\n");
+ }
+ sqlite3_free_table(azData);
+}
+
+/*
** Run a prepared statement
*/
static void exec_prepared_stmt(
@@ -2899,6 +3176,15 @@ static void exec_prepared_stmt(
){
int rc;
+ if( pArg->cMode==MODE_Column
+ || pArg->cMode==MODE_Table
+ || pArg->cMode==MODE_Box
+ || pArg->cMode==MODE_Markdown
+ ){
+ exec_prepared_stmt_columnar(pArg, pStmt);
+ return;
+ }
+
/* perform the first step. this will tell us if we
** have a result set or not and how wide it is.
*/
@@ -2946,6 +3232,9 @@ static void exec_prepared_stmt(
}
} while( SQLITE_ROW == rc );
sqlite3_free(pData);
+ if( pArg->cMode==MODE_Json ){
+ fputs("]\n", pArg->out);
+ }
}
}
}
@@ -3158,6 +3447,7 @@ static int shell_exec(
const char *zEQPLine = (const char*)sqlite3_column_text(pExplain,3);
int iEqpId = sqlite3_column_int(pExplain, 0);
int iParentId = sqlite3_column_int(pExplain, 1);
+ if( zEQPLine==0 ) zEQPLine = "";
if( zEQPLine[0]=='-' ) eqp_render(pArg);
eqp_append(pArg, iEqpId, iParentId, zEQPLine);
}
@@ -3395,7 +3685,7 @@ static int dump_callback(void *pArg, int nArg, char **azArg, char **azNotUsed){
if( strcmp(zTable, "sqlite_sequence")==0 ){
raw_printf(p->out, "DELETE FROM sqlite_sequence;\n");
}else if( sqlite3_strglob("sqlite_stat?", zTable)==0 ){
- raw_printf(p->out, "ANALYZE sqlite_master;\n");
+ raw_printf(p->out, "ANALYZE sqlite_schema;\n");
}else if( strncmp(zTable, "sqlite_", 7)==0 ){
return 0;
}else if( strncmp(zSql, "CREATE VIRTUAL TABLE", 20)==0 ){
@@ -3405,7 +3695,7 @@ static int dump_callback(void *pArg, int nArg, char **azArg, char **azNotUsed){
p->writableSchema = 1;
}
zIns = sqlite3_mprintf(
- "INSERT INTO sqlite_master(type,name,tbl_name,rootpage,sql)"
+ "INSERT INTO sqlite_schema(type,name,tbl_name,rootpage,sql)"
"VALUES('table','%q','%q',0,'%q');",
zTable, zTable, zSql);
utf8_printf(p->out, "%s\n", zIns);
@@ -3625,16 +3915,20 @@ static const char *(azHelp[]) = {
".log FILE|off Turn logging on or off. FILE can be stderr/stdout",
".mode MODE ?TABLE? Set output mode",
" MODE is one of:",
- " ascii Columns/rows delimited by 0x1F and 0x1E",
- " csv Comma-separated values",
- " column Left-aligned columns. (See .width)",
- " html HTML <table> code",
- " insert SQL insert statements for TABLE",
- " line One value per line",
- " list Values delimited by \"|\"",
- " quote Escape answers as for SQL",
- " tabs Tab-separated values",
- " tcl TCL list elements",
+ " ascii Columns/rows delimited by 0x1F and 0x1E",
+ " box Tables using unicode box-drawing characters",
+ " csv Comma-separated values",
+ " column Output in columns. (See .width)",
+ " html HTML <table> code",
+ " insert SQL insert statements for TABLE",
+ " json Results in a JSON array",
+ " line One value per line",
+ " list Values delimited by \"|\"",
+ " markdown Markdown table format",
+ " quote Escape answers as for SQL",
+ " table ASCII-art table",
+ " tabs Tab-separated values",
+ " tcl TCL list elements",
".nullvalue STRING Use STRING in place of NULL values",
".once ?OPTIONS? ?FILE? Output for the next SQL command only to FILE",
" If FILE begins with '|' then open as a pipe",
@@ -3642,7 +3936,7 @@ static const char *(azHelp[]) = {
" -e Send output to the system text editor",
" -x Send output as CSV to a spreadsheet (same as \".excel\")",
#ifdef SQLITE_DEBUG
- ".oom [--repeat M] [N] Simulate an OOM error on the N-th allocation",
+ ".oom ?--repeat M? ?N? Simulate an OOM error on the N-th allocation",
#endif
".open ?OPTIONS? ?FILE? Close existing database and reopen FILE",
" Options:",
@@ -3716,7 +4010,7 @@ static const char *(azHelp[]) = {
#endif
".sha3sum ... Compute a SHA3 hash of database content",
" Options:",
- " --schema Also hash the sqlite_master table",
+ " --schema Also hash the sqlite_schema table",
" --sha3-224 Use the sha3-224 algorithm",
" --sha3-256 Use the sha3-256 algorithm (default)",
" --sha3-384 Use the sha3-384 algorithm",
@@ -3759,7 +4053,7 @@ static const char *(azHelp[]) = {
".vfsinfo ?AUX? Information about the top-level VFS",
".vfslist List all available VFSes",
".vfsname ?AUX? Print the name of the VFS stack",
- ".width NUM1 NUM2 ... Set column widths for \"column\" mode",
+ ".width NUM1 NUM2 ... Set minimum column widths for columnar output",
" Negative values right-justify",
};
@@ -4264,6 +4558,8 @@ static void open_db(ShellState *p, int openFlags){
sqlite3_shathree_init(p->db, 0, 0);
sqlite3_completion_init(p->db, 0, 0);
sqlite3_uint_init(p->db, 0, 0);
+ sqlite3_decimal_init(p->db, 0, 0);
+ sqlite3_ieee_init(p->db, 0, 0);
#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB)
sqlite3_dbdata_init(p->db, 0, 0);
#endif
@@ -4596,6 +4892,7 @@ typedef struct ImportCtx ImportCtx;
struct ImportCtx {
const char *zFile; /* Name of the input file */
FILE *in; /* Read the CSV text from this input stream */
+ int (SQLITE_CDECL *xCloser)(FILE*); /* Func to close in */
char *z; /* Accumulated text for a field */
int n; /* Number of bytes in z */
int nAlloc; /* Space allocated for z[] */
@@ -4608,6 +4905,16 @@ struct ImportCtx {
int cRowSep; /* The row separator character. (Usually "\n") */
};
+/* Clean up resourced used by an ImportCtx */
+static void import_cleanup(ImportCtx *p){
+ if( p->in!=0 && p->xCloser!=0 ){
+ p->xCloser(p->in);
+ p->in = 0;
+ }
+ sqlite3_free(p->z);
+ p->z = 0;
+}
+
/* Append a single byte to z[] */
static void import_append_char(ImportCtx *p, int c){
if( p->n+1>=p->nAlloc ){
@@ -4856,7 +5163,7 @@ end_data_xfer:
** Try to transfer all rows of the schema that match zWhere. For
** each row, invoke xForEach() on the object defined by that row.
** If an error is encountered while moving forward through the
-** sqlite_master table, try again moving backwards.
+** sqlite_schema table, try again moving backwards.
*/
static void tryToCloneSchema(
ShellState *p,
@@ -4871,7 +5178,7 @@ static void tryToCloneSchema(
const unsigned char *zSql;
char *zErrMsg = 0;
- zQuery = sqlite3_mprintf("SELECT name, sql FROM sqlite_master"
+ zQuery = sqlite3_mprintf("SELECT name, sql FROM sqlite_schema"
" WHERE %s", zWhere);
rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
if( rc ){
@@ -4898,7 +5205,7 @@ static void tryToCloneSchema(
if( rc!=SQLITE_DONE ){
sqlite3_finalize(pQuery);
sqlite3_free(zQuery);
- zQuery = sqlite3_mprintf("SELECT name, sql FROM sqlite_master"
+ zQuery = sqlite3_mprintf("SELECT name, sql FROM sqlite_schema"
" WHERE %s ORDER BY rowid DESC", zWhere);
rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
if( rc ){
@@ -5067,12 +5374,7 @@ static int shell_dbinfo_command(ShellState *p, int nArg, char **azArg){
"SELECT data FROM sqlite_dbpage(?1) WHERE pgno=1",
-1, &pStmt, 0);
if( rc ){
- if( !sqlite3_compileoption_used("ENABLE_DBPAGE_VTAB") ){
- utf8_printf(stderr, "the \".dbinfo\" command requires the "
- "-DSQLITE_ENABLE_DBPAGE_VTAB compile-time options\n");
- }else{
- utf8_printf(stderr, "error: %s\n", sqlite3_errmsg(p->db));
- }
+ utf8_printf(stderr, "error: %s\n", sqlite3_errmsg(p->db));
sqlite3_finalize(pStmt);
return 1;
}
@@ -5107,11 +5409,11 @@ static int shell_dbinfo_command(ShellState *p, int nArg, char **azArg){
raw_printf(p->out, "\n");
}
if( zDb==0 ){
- zSchemaTab = sqlite3_mprintf("main.sqlite_master");
+ zSchemaTab = sqlite3_mprintf("main.sqlite_schema");
}else if( strcmp(zDb,"temp")==0 ){
- zSchemaTab = sqlite3_mprintf("%s", "sqlite_temp_master");
+ zSchemaTab = sqlite3_mprintf("%s", "sqlite_temp_schema");
}else{
- zSchemaTab = sqlite3_mprintf("\"%w\".sqlite_master", zDb);
+ zSchemaTab = sqlite3_mprintf("\"%w\".sqlite_schema", zDb);
}
for(i=0; i<ArraySize(aQuery); i++){
char *zSql = sqlite3_mprintf(aQuery[i].zSql, zSchemaTab);
@@ -5433,7 +5735,7 @@ static int lintFkeyIndexes(
" || ');'"
", "
" f.[table] "
- "FROM sqlite_master AS s, pragma_foreign_key_list(s.name) AS f "
+ "FROM sqlite_schema AS s, pragma_foreign_key_list(s.name) AS f "
"LEFT JOIN pragma_table_info AS p ON (pk-1=seq AND p.arg=f.[table]) "
"GROUP BY s.name, f.id "
"ORDER BY (CASE WHEN ? THEN f.[table] ELSE s.name END)"
@@ -6508,7 +6810,7 @@ static RecoverTable *recoverNewTable(
shellPreparePrintf(dbtmp, &rc, &pStmt,
"SELECT ("
" SELECT substr(data,1,1)==X'0D' FROM sqlite_dbpage WHERE pgno=rootpage"
- ") FROM sqlite_master WHERE name = %Q", zName
+ ") FROM sqlite_schema WHERE name = %Q", zName
);
if( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
bSqlIntkey = sqlite3_column_int(pStmt, 0);
@@ -6580,7 +6882,7 @@ static RecoverTable *recoverNewTable(
/*
** This function is called to search the schema recovered from the
-** sqlite_master table of the (possibly) corrupt database as part
+** sqlite_schema table of the (possibly) corrupt database as part
** of a ".recover" command. Specifically, for a table with root page
** iRoot and at least nCol columns. Additionally, if bIntkey is 0, the
** table must be a WITHOUT ROWID table, or if non-zero, not one of
@@ -6843,7 +7145,7 @@ static int recoverDatabaseCmd(ShellState *pState, int nArg, char **azArg){
");"
/* Extract data from page 1 and any linked pages into table
- ** recovery.schema. With the same schema as an sqlite_master table. */
+ ** recovery.schema. With the same schema as an sqlite_schema table. */
"CREATE TABLE recovery.schema(type, name, tbl_name, rootpage, sql);"
"INSERT INTO recovery.schema SELECT "
" max(CASE WHEN field=0 THEN value ELSE NULL END),"
@@ -6995,7 +7297,7 @@ static int recoverDatabaseCmd(ShellState *pState, int nArg, char **azArg){
if( sqlite3_strnicmp(zSql, "create virt", 11)==0 ){
const char *zName = (const char*)sqlite3_column_text(pStmt, 1);
char *zPrint = shellMPrintf(&rc,
- "INSERT INTO sqlite_master VALUES('table', %Q, %Q, 0, %Q)",
+ "INSERT INTO sqlite_schema VALUES('table', %Q, %Q, 0, %Q)",
zName, zName, zSql
);
raw_printf(pState->out, "%s;\n", zPrint);
@@ -7334,6 +7636,7 @@ static int do_meta_command(char *zLine, ShellState *p){
raw_printf(stderr, "The --preserve-rowids option is not compatible"
" with SQLITE_OMIT_VIRTUALTABLE\n");
rc = 1;
+ sqlite3_free(zLike);
goto meta_command_exit;
#else
ShellSetFlag(p, SHFLG_PreserveRowid);
@@ -7345,6 +7648,7 @@ static int do_meta_command(char *zLine, ShellState *p){
{
raw_printf(stderr, "Unknown option \"%s\" on \".dump\"\n", azArg[i]);
rc = 1;
+ sqlite3_free(zLike);
goto meta_command_exit;
}
}else if( zLike ){
@@ -7365,13 +7669,13 @@ static int do_meta_command(char *zLine, ShellState *p){
p->writableSchema = 0;
p->showHeader = 0;
/* Set writable_schema=ON since doing so forces SQLite to initialize
- ** as much of the schema as it can even if the sqlite_master table is
+ ** as much of the schema as it can even if the sqlite_schema table is
** corrupt. */
sqlite3_exec(p->db, "SAVEPOINT dump; PRAGMA writable_schema=ON", 0, 0, 0);
p->nErr = 0;
if( zLike==0 ) zLike = sqlite3_mprintf("true");
zSql = sqlite3_mprintf(
- "SELECT name, type, sql FROM sqlite_master "
+ "SELECT name, type, sql FROM sqlite_schema "
"WHERE (%s) AND type=='table'"
" AND sql NOT NULL"
" ORDER BY tbl_name='sqlite_sequence', rowid",
@@ -7380,7 +7684,7 @@ static int do_meta_command(char *zLine, ShellState *p){
run_schema_dump_query(p,zSql);
sqlite3_free(zSql);
zSql = sqlite3_mprintf(
- "SELECT sql FROM sqlite_master "
+ "SELECT sql FROM sqlite_schema "
"WHERE (%s) AND sql NOT NULL"
" AND type IN ('index','trigger','view')",
zLike
@@ -7427,7 +7731,7 @@ static int do_meta_command(char *zLine, ShellState *p){
p->autoEQP = AUTOEQP_full;
p->autoEQPtrace = 1;
open_db(p, 0);
- sqlite3_exec(p->db, "SELECT name FROM sqlite_master LIMIT 1", 0, 0, 0);
+ sqlite3_exec(p->db, "SELECT name FROM sqlite_schema LIMIT 1", 0, 0, 0);
sqlite3_exec(p->db, "PRAGMA vdbe_trace=ON;", 0, 0, 0);
#endif
}else{
@@ -7640,8 +7944,8 @@ static int do_meta_command(char *zLine, ShellState *p){
rc = sqlite3_exec(p->db,
"SELECT sql FROM"
" (SELECT sql sql, type type, tbl_name tbl_name, name name, rowid x"
- " FROM sqlite_master UNION ALL"
- " SELECT sql, type, tbl_name, name, rowid FROM sqlite_temp_master) "
+ " FROM sqlite_schema UNION ALL"
+ " SELECT sql, type, tbl_name, name, rowid FROM sqlite_temp_schema) "
"WHERE type!='meta' AND sql NOTNULL AND name NOT LIKE 'sqlite_%' "
"ORDER BY rowid",
callback, &data, &zErrMsg
@@ -7649,7 +7953,7 @@ static int do_meta_command(char *zLine, ShellState *p){
if( rc==SQLITE_OK ){
sqlite3_stmt *pStmt;
rc = sqlite3_prepare_v2(p->db,
- "SELECT rowid FROM sqlite_master"
+ "SELECT rowid FROM sqlite_schema"
" WHERE name GLOB 'sqlite_stat[134]'",
-1, &pStmt, 0);
doStats = sqlite3_step(pStmt)==SQLITE_ROW;
@@ -7658,21 +7962,22 @@ static int do_meta_command(char *zLine, ShellState *p){
if( doStats==0 ){
raw_printf(p->out, "/* No STAT tables available */\n");
}else{
- raw_printf(p->out, "ANALYZE sqlite_master;\n");
- sqlite3_exec(p->db, "SELECT 'ANALYZE sqlite_master'",
+ raw_printf(p->out, "ANALYZE sqlite_schema;\n");
+ sqlite3_exec(p->db, "SELECT 'ANALYZE sqlite_schema'",
callback, &data, &zErrMsg);
data.cMode = data.mode = MODE_Insert;
data.zDestTable = "sqlite_stat1";
shell_exec(&data, "SELECT * FROM sqlite_stat1", &zErrMsg);
data.zDestTable = "sqlite_stat4";
shell_exec(&data, "SELECT * FROM sqlite_stat4", &zErrMsg);
- raw_printf(p->out, "ANALYZE sqlite_master;\n");
+ raw_printf(p->out, "ANALYZE sqlite_schema;\n");
}
}else
if( c=='h' && strncmp(azArg[0], "headers", n)==0 ){
if( nArg==2 ){
p->showHeader = booleanValue(azArg[1]);
+ p->shellFlgs |= SHFLG_HeaderSet;
}else{
raw_printf(stderr, "Usage: .headers on|off\n");
rc = 1;
@@ -7702,7 +8007,6 @@ static int do_meta_command(char *zLine, ShellState *p){
char *zSql; /* An SQL statement */
ImportCtx sCtx; /* Reader context */
char *(SQLITE_CDECL *xRead)(ImportCtx*); /* Func to read one value */
- int (SQLITE_CDECL *xCloser)(FILE*); /* Func to close file */
int eVerbose = 0; /* Larger for more console output */
int nSkip = 0; /* Initial lines to skip */
int useOutputMode = 1; /* Use output mode to determine separators */
@@ -7808,11 +8112,11 @@ static int do_meta_command(char *zLine, ShellState *p){
#else
sCtx.in = popen(sCtx.zFile+1, "r");
sCtx.zFile = "<pipe>";
- xCloser = pclose;
+ sCtx.xCloser = pclose;
#endif
}else{
sCtx.in = fopen(sCtx.zFile, "rb");
- xCloser = fclose;
+ sCtx.xCloser = fclose;
}
if( sCtx.in==0 ){
utf8_printf(stderr, "Error: cannot open \"%s\"\n", zFile);
@@ -7832,11 +8136,10 @@ static int do_meta_command(char *zLine, ShellState *p){
}
while( (nSkip--)>0 ){
while( xRead(&sCtx) && sCtx.cTerm==sCtx.cColSep ){}
- sCtx.nLine++;
}
zSql = sqlite3_mprintf("SELECT * FROM %s", zTable);
if( zSql==0 ){
- xCloser(sCtx.in);
+ import_cleanup(&sCtx);
shell_out_of_memory();
}
nByte = strlen30(zSql);
@@ -7852,8 +8155,7 @@ static int do_meta_command(char *zLine, ShellState *p){
}
if( cSep=='(' ){
sqlite3_free(zCreate);
- sqlite3_free(sCtx.z);
- xCloser(sCtx.in);
+ import_cleanup(&sCtx);
utf8_printf(stderr,"%s: empty file\n", sCtx.zFile);
rc = 1;
goto meta_command_exit;
@@ -7867,8 +8169,7 @@ static int do_meta_command(char *zLine, ShellState *p){
if( rc ){
utf8_printf(stderr, "CREATE TABLE %s(...) failed: %s\n", zTable,
sqlite3_errmsg(p->db));
- sqlite3_free(sCtx.z);
- xCloser(sCtx.in);
+ import_cleanup(&sCtx);
rc = 1;
goto meta_command_exit;
}
@@ -7878,7 +8179,7 @@ static int do_meta_command(char *zLine, ShellState *p){
if( rc ){
if (pStmt) sqlite3_finalize(pStmt);
utf8_printf(stderr,"Error: %s\n", sqlite3_errmsg(p->db));
- xCloser(sCtx.in);
+ import_cleanup(&sCtx);
rc = 1;
goto meta_command_exit;
}
@@ -7888,7 +8189,7 @@ static int do_meta_command(char *zLine, ShellState *p){
if( nCol==0 ) return 0; /* no columns, no error */
zSql = sqlite3_malloc64( nByte*2 + 20 + nCol*2 );
if( zSql==0 ){
- xCloser(sCtx.in);
+ import_cleanup(&sCtx);
shell_out_of_memory();
}
sqlite3_snprintf(nByte+20, zSql, "INSERT INTO \"%w\" VALUES(?", zTable);
@@ -7907,7 +8208,7 @@ static int do_meta_command(char *zLine, ShellState *p){
if( rc ){
utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(p->db));
if (pStmt) sqlite3_finalize(pStmt);
- xCloser(sCtx.in);
+ import_cleanup(&sCtx);
rc = 1;
goto meta_command_exit;
}
@@ -7959,8 +8260,7 @@ static int do_meta_command(char *zLine, ShellState *p){
}
}while( sCtx.cTerm!=EOF );
- xCloser(sCtx.in);
- sqlite3_free(sCtx.z);
+ import_cleanup(&sCtx);
sqlite3_finalize(pStmt);
if( needCommit ) sqlite3_exec(p->db, "COMMIT", 0, 0, 0);
if( eVerbose>0 ){
@@ -7998,10 +8298,10 @@ static int do_meta_command(char *zLine, ShellState *p){
goto meta_command_exit;
}
zSql = sqlite3_mprintf(
- "SELECT rootpage, 0 FROM sqlite_master"
+ "SELECT rootpage, 0 FROM sqlite_schema"
" WHERE name='%q' AND type='index'"
"UNION ALL "
- "SELECT rootpage, 1 FROM sqlite_master"
+ "SELECT rootpage, 1 FROM sqlite_schema"
" WHERE name='%q' AND type='table'"
" AND sql LIKE '%%without%%rowid%%'",
azArg[1], azArg[1]
@@ -8199,6 +8499,9 @@ static int do_meta_command(char *zLine, ShellState *p){
sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
}else if( c2=='c' && strncmp(azArg[1],"columns",n2)==0 ){
p->mode = MODE_Column;
+ if( (p->shellFlgs & SHFLG_HeaderSet)==0 ){
+ p->showHeader = 1;
+ }
sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
}else if( c2=='l' && n2>2 && strncmp(azArg[1],"list",n2)==0 ){
p->mode = MODE_List;
@@ -8222,15 +8525,26 @@ static int do_meta_command(char *zLine, ShellState *p){
set_table_name(p, nArg>=3 ? azArg[2] : "table");
}else if( c2=='q' && strncmp(azArg[1],"quote",n2)==0 ){
p->mode = MODE_Quote;
+ sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Comma);
+ sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
}else if( c2=='a' && strncmp(azArg[1],"ascii",n2)==0 ){
p->mode = MODE_Ascii;
sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Unit);
sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Record);
+ }else if( c2=='m' && strncmp(azArg[1],"markdown",n2)==0 ){
+ p->mode = MODE_Markdown;
+ }else if( c2=='t' && strncmp(azArg[1],"table",n2)==0 ){
+ p->mode = MODE_Table;
+ }else if( c2=='b' && strncmp(azArg[1],"box",n2)==0 ){
+ p->mode = MODE_Box;
+ }else if( c2=='j' && strncmp(azArg[1],"json",n2)==0 ){
+ p->mode = MODE_Json;
}else if( nArg==1 ){
raw_printf(p->out, "current output mode: %s\n", modeDescr[p->mode]);
}else{
raw_printf(stderr, "Error: mode should be one of: "
- "ascii column csv html insert line list quote tabs tcl\n");
+ "ascii box column csv html insert json line list markdown "
+ "quote table tabs tcl\n");
rc = 1;
}
p->cMode = p->mode;
@@ -8722,8 +9036,11 @@ static int do_meta_command(char *zLine, ShellState *p){
}
}
if( zName!=0 ){
- int isMaster = sqlite3_strlike(zName, "sqlite_master", '\\')==0;
- if( isMaster || sqlite3_strlike(zName,"sqlite_temp_master", '\\')==0 ){
+ int isSchema = sqlite3_strlike(zName, "sqlite_master", '\\')==0
+ || sqlite3_strlike(zName, "sqlite_schema", '\\')==0
+ || sqlite3_strlike(zName,"sqlite_temp_master", '\\')==0
+ || sqlite3_strlike(zName,"sqlite_temp_schema", '\\')==0;
+ if( isSchema ){
char *new_argv[2], *new_colv[2];
new_argv[0] = sqlite3_mprintf(
"CREATE TABLE %s (\n"
@@ -8732,7 +9049,7 @@ static int do_meta_command(char *zLine, ShellState *p){
" tbl_name text,\n"
" rootpage integer,\n"
" sql text\n"
- ")", isMaster ? "sqlite_master" : "sqlite_temp_master");
+ ")", zName);
new_argv[1] = 0;
new_colv[0] = "sql";
new_colv[1] = 0;
@@ -8770,7 +9087,7 @@ static int do_meta_command(char *zLine, ShellState *p){
appendText(&sSelect, zDb, '\'');
appendText(&sSelect, " AS sname FROM ", 0);
appendText(&sSelect, zDb, quoteChar(zDb));
- appendText(&sSelect, ".sqlite_master", 0);
+ appendText(&sSelect, ".sqlite_schema", 0);
}
sqlite3_finalize(pStmt);
#ifndef SQLITE_OMIT_INTROSPECTION_PRAGMAS
@@ -8822,7 +9139,7 @@ static int do_meta_command(char *zLine, ShellState *p){
#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_SELECTTRACE)
if( c=='s' && n==11 && strncmp(azArg[0], "selecttrace", n)==0 ){
- sqlite3SelectTrace = (int)integerValue(azArg[1]);
+ sqlite3SelectTrace = nArg>=2 ? (int)integerValue(azArg[1]) : 0xffff;
}else
#endif
@@ -9214,12 +9531,12 @@ static int do_meta_command(char *zLine, ShellState *p){
}
}
if( bSchema ){
- zSql = "SELECT lower(name) FROM sqlite_master"
+ zSql = "SELECT lower(name) FROM sqlite_schema"
" WHERE type='table' AND coalesce(rootpage,0)>1"
- " UNION ALL SELECT 'sqlite_master'"
+ " UNION ALL SELECT 'sqlite_schema'"
" ORDER BY 1 collate nocase";
}else{
- zSql = "SELECT lower(name) FROM sqlite_master"
+ zSql = "SELECT lower(name) FROM sqlite_schema"
" WHERE type='table' AND coalesce(rootpage,0)>1"
" AND name NOT LIKE 'sqlite_%'"
" ORDER BY 1 collate nocase";
@@ -9236,8 +9553,8 @@ static int do_meta_command(char *zLine, ShellState *p){
appendText(&sQuery,"SELECT * FROM ", 0);
appendText(&sQuery,zTab,'"');
appendText(&sQuery," NOT INDEXED;", 0);
- }else if( strcmp(zTab, "sqlite_master")==0 ){
- appendText(&sQuery,"SELECT type,name,tbl_name,sql FROM sqlite_master"
+ }else if( strcmp(zTab, "sqlite_schema")==0 ){
+ appendText(&sQuery,"SELECT type,name,tbl_name,sql FROM sqlite_schema"
" ORDER BY name;", 0);
}else if( strcmp(zTab, "sqlite_sequence")==0 ){
appendText(&sQuery,"SELECT name,seq FROM sqlite_sequence"
@@ -9331,7 +9648,7 @@ static int do_meta_command(char *zLine, ShellState *p){
raw_printf(p->out, "\n");
utf8_printf(p->out, "%12.12s: %s\n","stats", azBool[p->statsOn!=0]);
utf8_printf(p->out, "%12.12s: ", "width");
- for (i=0;i<(int)ArraySize(p->colWidth) && p->colWidth[i] != 0;i++) {
+ for (i=0;i<p->nWidth;i++) {
raw_printf(p->out, "%d ", p->colWidth[i]);
}
raw_printf(p->out, "\n");
@@ -9388,7 +9705,7 @@ static int do_meta_command(char *zLine, ShellState *p){
appendText(&s, "||'.'||name FROM ", 0);
}
appendText(&s, zDbName, '"');
- appendText(&s, ".sqlite_master ", 0);
+ appendText(&s, ".sqlite_schema ", 0);
if( c=='t' ){
appendText(&s," WHERE type IN ('table','view')"
" AND name NOT LIKE 'sqlite_%'"
@@ -9880,7 +10197,11 @@ static int do_meta_command(char *zLine, ShellState *p){
if( c=='w' && strncmp(azArg[0], "width", n)==0 ){
int j;
assert( nArg<=ArraySize(azArg) );
- for(j=1; j<nArg && j<ArraySize(p->colWidth); j++){
+ p->nWidth = nArg-1;
+ p->colWidth = realloc(p->colWidth, p->nWidth*sizeof(int)*2);
+ if( p->colWidth==0 && p->nWidth>0 ) shell_out_of_memory();
+ if( p->nWidth ) p->actualWidth = &p->colWidth[p->nWidth];
+ for(j=1; j<nArg; j++){
p->colWidth[j-1] = (int)integerValue(azArg[j]);
}
}else
@@ -10225,6 +10546,7 @@ static const char zOptions[] =
" -ascii set output mode to 'ascii'\n"
" -bail stop after hitting an error\n"
" -batch force batch I/O\n"
+ " -box set output mode to 'box'\n"
" -column set output mode to 'column'\n"
" -cmd COMMAND run \"COMMAND\" before reading stdin\n"
" -csv set output mode to 'csv'\n"
@@ -10240,9 +10562,11 @@ static const char zOptions[] =
" -help show this message\n"
" -html set output mode to HTML\n"
" -interactive force interactive I/O\n"
+ " -json set output mode to 'json'\n"
" -line set output mode to 'line'\n"
" -list set output mode to 'list'\n"
" -lookaside SIZE N use N entries of SZ bytes for lookaside memory\n"
+ " -markdown set output mode to 'markdown'\n"
#if defined(SQLITE_ENABLE_DESERIALIZE)
" -maxsize N maximum size for a --deserialize database\n"
#endif
@@ -10262,6 +10586,7 @@ static const char zOptions[] =
" -sorterref SIZE sorter references threshold size\n"
#endif
" -stats print memory stats before each finalize\n"
+ " -table set output mode to 'table'\n"
" -version show SQLite version\n"
" -vfs NAME use NAME as the default VFS\n"
#ifdef SQLITE_ENABLE_VFSTRACE
@@ -10663,6 +10988,14 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
data.mode = MODE_Line;
}else if( strcmp(z,"-column")==0 ){
data.mode = MODE_Column;
+ }else if( strcmp(z,"-json")==0 ){
+ data.mode = MODE_Json;
+ }else if( strcmp(z,"-markdown")==0 ){
+ data.mode = MODE_Markdown;
+ }else if( strcmp(z,"-table")==0 ){
+ data.mode = MODE_Table;
+ }else if( strcmp(z,"-box")==0 ){
+ data.mode = MODE_Box;
}else if( strcmp(z,"-csv")==0 ){
data.mode = MODE_Csv;
memcpy(data.colSeparator,",",2);
@@ -10880,6 +11213,7 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
for(i=0; i<argcToFree; i++) free(argvToFree[i]);
free(argvToFree);
#endif
+ free(data.colWidth);
/* Clear the global data structure so that valgrind will detect memory
** leaks */
memset(&data, 0, sizeof(data));
diff --git a/src/sqlite.h.in b/src/sqlite.h.in
index a5e8d1497..dbcc0e989 100644
--- a/src/sqlite.h.in
+++ b/src/sqlite.h.in
@@ -299,26 +299,22 @@ typedef sqlite_uint64 sqlite3_uint64;
** the [sqlite3] object is successfully destroyed and all associated
** resources are deallocated.
**
-** ^If the database connection is associated with unfinalized prepared
-** statements or unfinished sqlite3_backup objects then sqlite3_close()
-** will leave the database connection open and return [SQLITE_BUSY].
-** ^If sqlite3_close_v2() is called with unfinalized prepared statements
-** and/or unfinished sqlite3_backups, then the database connection becomes
-** an unusable "zombie" which will automatically be deallocated when the
-** last prepared statement is finalized or the last sqlite3_backup is
-** finished. The sqlite3_close_v2() interface is intended for use with
-** host languages that are garbage collected, and where the order in which
-** destructors are called is arbitrary.
-**
-** Applications should [sqlite3_finalize | finalize] all [prepared statements],
-** [sqlite3_blob_close | close] all [BLOB handles], and
+** Ideally, applications should [sqlite3_finalize | finalize] all
+** [prepared statements], [sqlite3_blob_close | close] all [BLOB handles], and
** [sqlite3_backup_finish | finish] all [sqlite3_backup] objects associated
-** with the [sqlite3] object prior to attempting to close the object. ^If
-** sqlite3_close_v2() is called on a [database connection] that still has
-** outstanding [prepared statements], [BLOB handles], and/or
-** [sqlite3_backup] objects then it returns [SQLITE_OK] and the deallocation
-** of resources is deferred until all [prepared statements], [BLOB handles],
-** and [sqlite3_backup] objects are also destroyed.
+** with the [sqlite3] object prior to attempting to close the object.
+** ^If the database connection is associated with unfinalized prepared
+** statements, BLOB handlers, and/or unfinished sqlite3_backup objects then
+** sqlite3_close() will leave the database connection open and return
+** [SQLITE_BUSY]. ^If sqlite3_close_v2() is called with unfinalized prepared
+** statements, unclosed BLOB handlers, and/or unfinished sqlite3_backups,
+** it returns [SQLITE_OK] regardless, but instead of deallocating the database
+** connection immediately, it marks the database connection as an unusable
+** "zombie" and makes arrangements to automatically deallocate the database
+** connection after all prepared statements are finalized, all BLOB handles
+** are closed, and all backups have finished. The sqlite3_close_v2() interface
+** is intended for use with host languages that are garbage collected, and
+** where the order in which destructors are called is arbitrary.
**
** ^If an [sqlite3] object is destroyed while a transaction is open,
** the transaction is automatically rolled back.
@@ -507,10 +503,12 @@ int sqlite3_exec(
#define SQLITE_IOERR_BEGIN_ATOMIC (SQLITE_IOERR | (29<<8))
#define SQLITE_IOERR_COMMIT_ATOMIC (SQLITE_IOERR | (30<<8))
#define SQLITE_IOERR_ROLLBACK_ATOMIC (SQLITE_IOERR | (31<<8))
+#define SQLITE_IOERR_DATA (SQLITE_IOERR | (32<<8))
#define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8))
#define SQLITE_LOCKED_VTAB (SQLITE_LOCKED | (2<<8))
#define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8))
#define SQLITE_BUSY_SNAPSHOT (SQLITE_BUSY | (2<<8))
+#define SQLITE_BUSY_TIMEOUT (SQLITE_BUSY | (3<<8))
#define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1<<8))
#define SQLITE_CANTOPEN_ISDIR (SQLITE_CANTOPEN | (2<<8))
#define SQLITE_CANTOPEN_FULLPATH (SQLITE_CANTOPEN | (3<<8))
@@ -519,6 +517,7 @@ int sqlite3_exec(
#define SQLITE_CANTOPEN_SYMLINK (SQLITE_CANTOPEN | (6<<8))
#define SQLITE_CORRUPT_VTAB (SQLITE_CORRUPT | (1<<8))
#define SQLITE_CORRUPT_SEQUENCE (SQLITE_CORRUPT | (2<<8))
+#define SQLITE_CORRUPT_INDEX (SQLITE_CORRUPT | (3<<8))
#define SQLITE_READONLY_RECOVERY (SQLITE_READONLY | (1<<8))
#define SQLITE_READONLY_CANTLOCK (SQLITE_READONLY | (2<<8))
#define SQLITE_READONLY_ROLLBACK (SQLITE_READONLY | (3<<8))
@@ -565,7 +564,7 @@ int sqlite3_exec(
#define SQLITE_OPEN_MAIN_JOURNAL 0x00000800 /* VFS only */
#define SQLITE_OPEN_TEMP_JOURNAL 0x00001000 /* VFS only */
#define SQLITE_OPEN_SUBJOURNAL 0x00002000 /* VFS only */
-#define SQLITE_OPEN_MASTER_JOURNAL 0x00004000 /* VFS only */
+#define SQLITE_OPEN_SUPER_JOURNAL 0x00004000 /* VFS only */
#define SQLITE_OPEN_NOMUTEX 0x00008000 /* Ok for sqlite3_open_v2() */
#define SQLITE_OPEN_FULLMUTEX 0x00010000 /* Ok for sqlite3_open_v2() */
#define SQLITE_OPEN_SHAREDCACHE 0x00020000 /* Ok for sqlite3_open_v2() */
@@ -574,6 +573,9 @@ int sqlite3_exec(
#define SQLITE_OPEN_NOFOLLOW 0x01000000 /* Ok for sqlite3_open_v2() */
/* Reserved: 0x00F00000 */
+/* Legacy compatibility: */
+#define SQLITE_OPEN_MASTER_JOURNAL 0x00004000 /* VFS only */
+
/*
** CAPI3REF: Device Characteristics
@@ -871,7 +873,7 @@ struct sqlite3_io_methods {
** of the xSync method. In most cases, the pointer argument passed with
** this file-control is NULL. However, if the database file is being synced
** as part of a multi-database commit, the argument points to a nul-terminated
-** string containing the transactions master-journal file name. VFSes that
+** string containing the transactions super-journal file name. VFSes that
** do not need this signal should silently ignore this opcode. Applications
** should not call [sqlite3_file_control()] with this opcode as doing so may
** disrupt the operation of the specialized VFSes that do require it.
@@ -1114,6 +1116,11 @@ struct sqlite3_io_methods {
** happen either internally or externally and that are associated with
** a particular attached database.
**
+** <li>[[SQLITE_FCNTL_CKPT_START]]
+** The [SQLITE_FCNTL_CKPT_START] opcode is invoked from within a checkpoint
+** in wal mode before the client starts to copy pages from the wal
+** file to the database file.
+**
** <li>[[SQLITE_FCNTL_CKPT_DONE]]
** The [SQLITE_FCNTL_CKPT_DONE] opcode is invoked from within a checkpoint
** in wal mode after the client has finished copying pages from the wal
@@ -1158,6 +1165,7 @@ struct sqlite3_io_methods {
#define SQLITE_FCNTL_SIZE_LIMIT 36
#define SQLITE_FCNTL_CKPT_DONE 37
#define SQLITE_FCNTL_RESERVE_BYTES 38
+#define SQLITE_FCNTL_CKPT_START 39
/* deprecated names */
#define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE
@@ -1262,7 +1270,7 @@ typedef struct sqlite3_api_routines sqlite3_api_routines;
** <li> [SQLITE_OPEN_TEMP_JOURNAL]
** <li> [SQLITE_OPEN_TRANSIENT_DB]
** <li> [SQLITE_OPEN_SUBJOURNAL]
-** <li> [SQLITE_OPEN_MASTER_JOURNAL]
+** <li> [SQLITE_OPEN_SUPER_JOURNAL]
** <li> [SQLITE_OPEN_WAL]
** </ul>)^
**
@@ -1640,7 +1648,7 @@ int sqlite3_db_config(sqlite3*, int op, ...);
** by xInit. The pAppData pointer is used as the only parameter to
** xInit and xShutdown.
**
-** SQLite holds the [SQLITE_MUTEX_STATIC_MASTER] mutex when it invokes
+** SQLite holds the [SQLITE_MUTEX_STATIC_MAIN] mutex when it invokes
** the xInit method, so the xInit method need not be threadsafe. The
** xShutdown method is only called from [sqlite3_shutdown()] so it does
** not need to be threadsafe either. For all other methods, SQLite
@@ -2278,8 +2286,7 @@ struct sqlite3_mem_methods {
** [[SQLITE_DBCONFIG_TRUSTED_SCHEMA]]
** <dt>SQLITE_DBCONFIG_TRUSTED_SCHEMA</td>
** <dd>The SQLITE_DBCONFIG_TRUSTED_SCHEMA option tells SQLite to
-** assume that database schemas (the contents of the [sqlite_master] tables)
-** are untainted by malicious content.
+** assume that database schemas are untainted by malicious content.
** When the SQLITE_DBCONFIG_TRUSTED_SCHEMA option is disabled, SQLite
** takes additional defensive steps to protect the application from harm
** including:
@@ -3536,8 +3543,19 @@ int sqlite3_open_v2(
** that check if a database file was a URI that contained a specific query
** parameter, and if so obtains the value of that query parameter.
**
-** If F is the database filename pointer passed into the xOpen() method of
-** a VFS implementation or it is the return value of [sqlite3_db_filename()]
+** The first parameter to these interfaces (hereafter referred to
+** as F) must be one of:
+** <ul>
+** <li> A database filename pointer created by the SQLite core and
+** passed into the xOpen() method of a VFS implemention, or
+** <li> A filename obtained from [sqlite3_db_filename()], or
+** <li> A new filename constructed using [sqlite3_create_filename()].
+** </ul>
+** If the F parameter is not one of the above, then the behavior is
+** undefined and probably undesirable. Older versions of SQLite were
+** more tolerant of invalid F parameters than newer versions.
+**
+** If F is a suitable filename (as described in the previous paragraph)
** and if P is the name of the query parameter, then
** sqlite3_uri_parameter(F,P) returns the value of the P
** parameter if it exists or a NULL pointer if P does not appear as a
@@ -3673,7 +3691,7 @@ sqlite3_file *sqlite3_database_file_object(const char*);
**
** The sqlite3_free_filename(Y) routine releases a memory allocation
** previously obtained from sqlite3_create_filename(). Invoking
-** sqlite3_free_filename(Y) is a NULL pointer is a harmless no-op.
+** sqlite3_free_filename(Y) where Y is a NULL pointer is a harmless no-op.
**
** If the Y parameter to sqlite3_free_filename(Y) is anything other
** than a NULL pointer or a pointer previously acquired from
@@ -5479,7 +5497,7 @@ void sqlite3_value_free(sqlite3_value*);
**
** ^(The amount of space allocated by sqlite3_aggregate_context(C,N) is
** determined by the N parameter on first successful call. Changing the
-** value of N in any subsequents call to sqlite3_aggregate_context() within
+** value of N in any subsequent call to sqlite3_aggregate_context() within
** the same aggregate function instance will not resize the memory
** allocation.)^ Within the xFinal callback, it is customary to set
** N=0 in calls to sqlite3_aggregate_context(C,N) so that no
@@ -6258,7 +6276,7 @@ void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*);
** ^In the case of an update, this is the [rowid] after the update takes place.
**
** ^(The update hook is not invoked when internal system tables are
-** modified (i.e. sqlite_master and sqlite_sequence).)^
+** modified (i.e. sqlite_sequence).)^
** ^The update hook is not invoked when [WITHOUT ROWID] tables are modified.
**
** ^In the current implementation, the update hook
@@ -7360,7 +7378,7 @@ int sqlite3_vfs_unregister(sqlite3_vfs*);
** <ul>
** <li> SQLITE_MUTEX_FAST
** <li> SQLITE_MUTEX_RECURSIVE
-** <li> SQLITE_MUTEX_STATIC_MASTER
+** <li> SQLITE_MUTEX_STATIC_MAIN
** <li> SQLITE_MUTEX_STATIC_MEM
** <li> SQLITE_MUTEX_STATIC_OPEN
** <li> SQLITE_MUTEX_STATIC_PRNG
@@ -7562,7 +7580,7 @@ int sqlite3_mutex_notheld(sqlite3_mutex*);
*/
#define SQLITE_MUTEX_FAST 0
#define SQLITE_MUTEX_RECURSIVE 1
-#define SQLITE_MUTEX_STATIC_MASTER 2
+#define SQLITE_MUTEX_STATIC_MAIN 2
#define SQLITE_MUTEX_STATIC_MEM 3 /* sqlite3_malloc() */
#define SQLITE_MUTEX_STATIC_MEM2 4 /* NOT USED */
#define SQLITE_MUTEX_STATIC_OPEN 4 /* sqlite3BtreeOpen() */
@@ -7577,6 +7595,10 @@ int sqlite3_mutex_notheld(sqlite3_mutex*);
#define SQLITE_MUTEX_STATIC_VFS2 12 /* For use by extension VFS */
#define SQLITE_MUTEX_STATIC_VFS3 13 /* For use by application VFS */
+/* Legacy compatibility: */
+#define SQLITE_MUTEX_STATIC_MASTER 2
+
+
/*
** CAPI3REF: Retrieve the mutex for a database connection
** METHOD: sqlite3
@@ -9372,7 +9394,7 @@ int sqlite3_db_cacheflush(sqlite3*);
**
** ^The preupdate hook only fires for changes to real database tables; the
** preupdate hook is not invoked for changes to [virtual tables] or to
-** system tables like sqlite_master or sqlite_stat1.
+** system tables like sqlite_sequence or sqlite_stat1.
**
** ^The second parameter to the preupdate callback is a pointer to
** the [database connection] that registered the preupdate hook.
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index c668e6bee..82dcc9de2 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -190,10 +190,10 @@
** WAL mode depends on atomic aligned 32-bit loads and stores in a few
** places. The following macros try to make this explicit.
*/
-#ifndef __has_feature
-# define __has_feature(x) 0 /* compatibility with non-clang compilers */
+#ifndef __has_extension
+# define __has_extension(x) 0 /* compatibility with non-clang compilers */
#endif
-#if GCC_VERSION>=4007000 || __has_feature(c_atomic)
+#if GCC_VERSION>=4007000 || __has_extension(c_atomic)
# define AtomicLoad(PTR) __atomic_load_n((PTR),__ATOMIC_RELAXED)
# define AtomicStore(PTR,VAL) __atomic_store_n((PTR),(VAL),__ATOMIC_RELAXED)
#else
@@ -902,6 +902,7 @@ typedef INT16_TYPE LogEst;
** compilers.
*/
#define LARGEST_INT64 (0xffffffff|(((i64)0x7fffffff)<<32))
+#define LARGEST_UINT64 (0xffffffff|(((u64)0xffffffff)<<32))
#define SMALLEST_INT64 (((i64)-1) - LARGEST_INT64)
/*
@@ -979,6 +980,16 @@ typedef INT16_TYPE LogEst;
#else
# define SELECTTRACE_ENABLED 0
#endif
+#if defined(SQLITE_ENABLE_SELECTTRACE)
+# define SELECTTRACE_ENABLED 1
+# define SELECTTRACE(K,P,S,X) \
+ if(sqlite3SelectTrace&(K)) \
+ sqlite3DebugPrintf("%u/%d/%p: ",(S)->selId,(P)->addrExplain,(S)),\
+ sqlite3DebugPrintf X
+#else
+# define SELECTTRACE(K,P,S,X)
+# define SELECTTRACE_ENABLED 0
+#endif
/*
** An instance of the following structure is used to store the busy-handler
@@ -994,26 +1005,27 @@ struct BusyHandler {
int (*xBusyHandler)(void *,int); /* The busy callback */
void *pBusyArg; /* First arg to busy callback */
int nBusy; /* Incremented with each busy call */
- u8 bExtraFileArg; /* Include sqlite3_file as callback arg */
};
/*
-** Name of the master database table. The master database table
-** is a special table that holds the names and attributes of all
-** user tables and indices.
+** Name of table that holds the database schema.
*/
-#define MASTER_NAME "sqlite_master"
-#define TEMP_MASTER_NAME "sqlite_temp_master"
+#define DFLT_SCHEMA_TABLE "sqlite_master"
+#define DFLT_TEMP_SCHEMA_TABLE "sqlite_temp_master"
+#define ALT_SCHEMA_TABLE "sqlite_schema"
+#define ALT_TEMP_SCHEMA_TABLE "sqlite_temp_schema"
+
/*
-** The root-page of the master database table.
+** The root-page of the schema table.
*/
-#define MASTER_ROOT 1
+#define SCHEMA_ROOT 1
/*
-** The name of the schema table.
+** The name of the schema table. The name is different for TEMP.
*/
-#define SCHEMA_TABLE(x) ((!OMIT_TEMPDB)&&(x==1)?TEMP_MASTER_NAME:MASTER_NAME)
+#define SCHEMA_TABLE(x) \
+ ((!OMIT_TEMPDB)&&(x==1)?DFLT_TEMP_SCHEMA_TABLE:DFLT_SCHEMA_TABLE)
/*
** A convenience macro that returns the number of elements in
@@ -1539,6 +1551,7 @@ struct sqlite3 {
BusyHandler busyHandler; /* Busy callback */
Db aDbStatic[2]; /* Static space for the 2 default backends */
Savepoint *pSavepoint; /* List of active savepoints */
+ int nAnalysisLimit; /* Number of index rows to ANALYZE */
int busyTimeout; /* Busy handler timeout, in msec */
int nSavepoint; /* Number of non-transaction savepoints */
int nStatement; /* Number of nested statement-transactions */
@@ -1546,7 +1559,7 @@ struct sqlite3 {
i64 nDeferredImmCons; /* Net deferred immediate constraints */
int *pnBytesFreed; /* If not NULL, increment this in DbFree() */
#ifdef SQLITE_ENABLE_UNLOCK_NOTIFY
- /* The following variables are all protected by the STATIC_MASTER
+ /* The following variables are all protected by the STATIC_MAIN
** mutex, not by sqlite3.mutex. They are used by code in notify.c.
**
** When X.pUnlockConnection==Y, that means that X is waiting for Y to
@@ -1588,7 +1601,7 @@ struct sqlite3 {
** SQLITE_CkptFullFSync == PAGER_CKPT_FULLFSYNC
** SQLITE_CacheSpill == PAGER_CACHE_SPILL
*/
-#define SQLITE_WriteSchema 0x00000001 /* OK to update SQLITE_MASTER */
+#define SQLITE_WriteSchema 0x00000001 /* OK to update SQLITE_SCHEMA */
#define SQLITE_LegacyFileFmt 0x00000002 /* Create new databases in format 1 */
#define SQLITE_FullColNames 0x00000004 /* Show full column names on SELECT */
#define SQLITE_FullFSync 0x00000008 /* Use full fsync on the backend */
@@ -1764,7 +1777,7 @@ struct FuncDestructor {
#define SQLITE_FUNC_LENGTH 0x0040 /* Built-in length() function */
#define SQLITE_FUNC_TYPEOF 0x0080 /* Built-in typeof() function */
#define SQLITE_FUNC_COUNT 0x0100 /* Built-in count(*) aggregate */
-#define SQLITE_FUNC_COALESCE 0x0200 /* Built-in coalesce() or ifnull() */
+/* 0x0200 -- available for reuse */
#define SQLITE_FUNC_UNLIKELY 0x0400 /* Built-in unlikely() function */
#define SQLITE_FUNC_CONSTANT 0x0800 /* Constant inputs give a constant output */
#define SQLITE_FUNC_MINMAX 0x1000 /* True for min() and max() aggregates */
@@ -1785,6 +1798,7 @@ struct FuncDestructor {
#define INLINEFUNC_expr_implies_expr 2
#define INLINEFUNC_expr_compare 3
#define INLINEFUNC_affinity 4
+#define INLINEFUNC_iif 5
#define INLINEFUNC_unlikely 99 /* Default case */
/*
@@ -2381,7 +2395,7 @@ struct UnpackedRecord {
** element.
**
** While parsing a CREATE TABLE or CREATE INDEX statement in order to
-** generate VDBE code (as opposed to parsing one read from an sqlite_master
+** generate VDBE code (as opposed to parsing one read from an sqlite_schema
** table as part of parsing an existing database schema), transient instances
** of this structure may be created. In this case the Index.tnum variable is
** used to store the address of a VDBE instruction, not a database page
@@ -2485,7 +2499,7 @@ struct Token {
** code for a SELECT that contains aggregate functions.
**
** If Expr.op==TK_AGG_COLUMN or TK_AGG_FUNCTION then Expr.pAggInfo is a
-** pointer to this structure. The Expr.iColumn field is the index in
+** pointer to this structure. The Expr.iAgg field is the index in
** AggInfo.aCol[] or AggInfo.aFunc[] of information needed to generate
** code for that node.
**
@@ -2505,26 +2519,33 @@ struct AggInfo {
ExprList *pGroupBy; /* The group by clause */
struct AggInfo_col { /* For each column used in source tables */
Table *pTab; /* Source table */
+ Expr *pCExpr; /* The original expression */
int iTable; /* Cursor number of the source table */
- int iColumn; /* Column number within the source table */
- int iSorterColumn; /* Column number in the sorting index */
int iMem; /* Memory location that acts as accumulator */
- Expr *pExpr; /* The original expression */
+ i16 iColumn; /* Column number within the source table */
+ i16 iSorterColumn; /* Column number in the sorting index */
} *aCol;
int nColumn; /* Number of used entries in aCol[] */
int nAccumulator; /* Number of columns that show through to the output.
** Additional columns are used only as parameters to
** aggregate functions */
struct AggInfo_func { /* For each aggregate function */
- Expr *pExpr; /* Expression encoding the function */
+ Expr *pFExpr; /* Expression encoding the function */
FuncDef *pFunc; /* The aggregate function implementation */
int iMem; /* Memory location that acts as accumulator */
int iDistinct; /* Ephemeral table used to enforce DISTINCT */
} *aFunc;
int nFunc; /* Number of entries in aFunc[] */
+ u32 selId; /* Select to which this AggInfo belongs */
+ AggInfo *pNext; /* Next in list of them all */
};
/*
+** Value for AggInfo.iAggMagic when the structure is valid
+*/
+#define AggInfoMagic 0x2059e99e
+
+/*
** The datatype ynVar is a signed integer, either 16-bit or 32-bit.
** Usually it is 16-bits. But if SQLITE_MAX_VARIABLE_NUMBER is greater
** than 32767 we have to make it 32-bit. 16-bit is preferred because
@@ -2700,7 +2721,7 @@ struct Expr {
#define EP_Static 0x8000000 /* Held in memory not obtained from malloc() */
#define EP_IsTrue 0x10000000 /* Always has boolean value of TRUE */
#define EP_IsFalse 0x20000000 /* Always has boolean value of FALSE */
-#define EP_FromDDL 0x40000000 /* Originates from sqlite_master */
+#define EP_FromDDL 0x40000000 /* Originates from sqlite_schema */
/* 0x80000000 // Available */
/*
@@ -2880,7 +2901,7 @@ struct SrcList {
unsigned isCorrelated :1; /* True if sub-query is correlated */
unsigned viaCoroutine :1; /* Implemented as a co-routine */
unsigned isRecursive :1; /* True for recursive reference in WITH */
- unsigned fromDDL :1; /* Comes from sqlite_master */
+ unsigned fromDDL :1; /* Comes from sqlite_schema */
} fg;
int iCursor; /* The VDBE cursor number used to access this table */
Expr *pOn; /* The ON clause of a join */
@@ -3001,7 +3022,7 @@ struct NameContext {
#define NC_HasWin 0x08000 /* One or more window functions seen */
#define NC_IsDDL 0x10000 /* Resolving names in a CREATE statement */
#define NC_InAggFunc 0x20000 /* True if analyzing arguments to an agg func */
-#define NC_FromDDL 0x40000 /* SQL text comes from sqlite_master */
+#define NC_FromDDL 0x40000 /* SQL text comes from sqlite_schema */
/*
** An instance of the following object describes a single ON CONFLICT
@@ -3104,6 +3125,7 @@ struct Select {
#define SF_WhereBegin 0x0080000 /* Really a WhereBegin() call. Debug Only */
#define SF_WinRewrite 0x0100000 /* Window function rewrite accomplished */
#define SF_View 0x0200000 /* SELECT statement is a view */
+#define SF_NoopOrderBy 0x0400000 /* ORDER BY is ignored for this query */
/*
** The results of a SELECT can be distributed in several ways, as defined
@@ -3322,6 +3344,7 @@ struct Parse {
Parse *pToplevel; /* Parse structure for main program (or NULL) */
Table *pTriggerTab; /* Table triggers are being coded for */
Parse *pParentParse; /* Parent parser if this parser is nested */
+ AggInfo *pAggList; /* List of all AggInfo objects */
int addrCrTab; /* Address of OP_CreateBtree opcode on CREATE TABLE */
u32 nQueryLoop; /* Est number of iterations of a query (10*log2(N)) */
u32 oldmask; /* Mask of old.* columns referenced */
@@ -3726,6 +3749,9 @@ int sqlite3WalkSelectFrom(Walker*, Select*);
int sqlite3ExprWalkNoop(Walker*, Expr*);
int sqlite3SelectWalkNoop(Walker*, Select*);
int sqlite3SelectWalkFail(Walker*, Select*);
+int sqlite3WalkerDepthIncrease(Walker*,Select*);
+void sqlite3WalkerDepthDecrease(Walker*,Select*);
+
#ifdef SQLITE_DEBUG
void sqlite3SelectWalkAssert2(Walker*, Select*);
#endif
@@ -4123,7 +4149,7 @@ void sqlite3DeleteColumnNames(sqlite3*,Table*);
int sqlite3ColumnsFromExprList(Parse*,ExprList*,i16*,Column**);
void sqlite3SelectAddColumnTypeAndCollation(Parse*,Table*,Select*,char);
Table *sqlite3ResultSetOfSelect(Parse*,Select*,char);
-void sqlite3OpenMasterTable(Parse *, int);
+void sqlite3OpenSchemaTable(Parse *, int);
Index *sqlite3PrimaryKeyIndex(Table*);
i16 sqlite3TableColumnToIndex(Index*, i16);
#ifdef SQLITE_OMIT_GENERATED_COLUMNS
@@ -4225,7 +4251,6 @@ int sqlite3Select(Parse*, Select*, SelectDest*);
Select *sqlite3SelectNew(Parse*,ExprList*,SrcList*,Expr*,ExprList*,
Expr*,ExprList*,u32,Expr*);
void sqlite3SelectDelete(sqlite3*, Select*);
-void sqlite3SelectReset(Parse*, Select*);
Table *sqlite3SrcListLookup(Parse*, SrcList*);
int sqlite3IsReadOnly(Parse*, Table*, int);
void sqlite3OpenTable(Parse*, int iCur, int iDb, Table*, int);
@@ -4286,6 +4311,7 @@ int sqlite3ExprCompareSkip(Expr*, Expr*, int);
int sqlite3ExprListCompare(ExprList*, ExprList*, int);
int sqlite3ExprImpliesExpr(Parse*,Expr*, Expr*, int);
int sqlite3ExprImpliesNonNullRow(Expr*,int);
+void sqlite3AggInfoPersistWalkerInit(Walker*,Parse*);
void sqlite3ExprAnalyzeAggregates(NameContext*, Expr*);
void sqlite3ExprAnalyzeAggList(NameContext*,ExprList*);
int sqlite3ExprCoveredByIndex(Expr*, int iCur, Index *pIdx);
@@ -4545,10 +4571,11 @@ extern const unsigned char sqlite3UpperToLower[];
extern const unsigned char sqlite3CtypeMap[];
extern SQLITE_WSD struct Sqlite3Config sqlite3Config;
extern FuncDefHash sqlite3BuiltinFunctions;
+extern u32 sqlite3SelectTrace;
#ifndef SQLITE_OMIT_WSD
extern int sqlite3PendingByte;
#endif
-#endif
+#endif /* SQLITE_AMALGAMATION */
#ifdef VDBE_PROFILE
extern sqlite3_uint64 sqlite3NProfileCnt;
#endif
@@ -4587,7 +4614,7 @@ void sqlite3RenameExprlistUnmap(Parse*, ExprList*);
CollSeq *sqlite3GetCollSeq(Parse*, u8, CollSeq *, const char*);
char sqlite3AffinityType(const char*, Column*);
void sqlite3Analyze(Parse*, Token*, Token*);
-int sqlite3InvokeBusyHandler(BusyHandler*, sqlite3_file*);
+int sqlite3InvokeBusyHandler(BusyHandler*);
int sqlite3FindDb(sqlite3*, Token*);
int sqlite3FindDbName(sqlite3 *, const char *);
int sqlite3AnalysisLoad(sqlite3*,int iDB);
@@ -4712,8 +4739,10 @@ void sqlite3AutoLoadExtensions(sqlite3*);
int sqlite3ReadOnlyShadowTables(sqlite3 *db);
#ifndef SQLITE_OMIT_VIRTUALTABLE
int sqlite3ShadowTableName(sqlite3 *db, const char *zName);
+ int sqlite3IsShadowTableOf(sqlite3*,Table*,const char*);
#else
# define sqlite3ShadowTableName(A,B) 0
+# define sqlite3IsShadowTableOf(A,B,C) 0
#endif
int sqlite3VtabEponymousTableInit(Parse*,Module*);
void sqlite3VtabEponymousTableClear(sqlite3*,Module*);
diff --git a/src/table.c b/src/table.c
index c79255f99..db60a827a 100644
--- a/src/table.c
+++ b/src/table.c
@@ -56,7 +56,7 @@ static int sqlite3_get_table_cb(void *pArg, int nCol, char **argv, char **colv){
if( p->nData + need > p->nAlloc ){
char **azNew;
p->nAlloc = p->nAlloc*2 + need;
- azNew = sqlite3_realloc64( p->azResult, sizeof(char*)*p->nAlloc );
+ azNew = sqlite3Realloc( p->azResult, sizeof(char*)*p->nAlloc );
if( azNew==0 ) goto malloc_failed;
p->azResult = azNew;
}
@@ -165,7 +165,7 @@ int sqlite3_get_table(
}
if( res.nAlloc>res.nData ){
char **azNew;
- azNew = sqlite3_realloc64( res.azResult, sizeof(char*)*res.nData );
+ azNew = sqlite3Realloc( res.azResult, sizeof(char*)*res.nData );
if( azNew==0 ){
sqlite3_free_table(&res.azResult[1]);
db->errCode = SQLITE_NOMEM;
diff --git a/src/tclsqlite.c b/src/tclsqlite.c
index 69da2ccd9..d80c25251 100644
--- a/src/tclsqlite.c
+++ b/src/tclsqlite.c
@@ -3699,6 +3699,7 @@ static int SQLITE_TCLAPI DbMain(
const char *zFile = 0;
const char *zVfs = 0;
int flags;
+ int bTranslateFileName = 1;
Tcl_DString translatedFilename;
int rc;
@@ -3796,6 +3797,10 @@ static int SQLITE_TCLAPI DbMain(
}else{
flags &= ~SQLITE_OPEN_URI;
}
+ }else if( strcmp(zArg, "-translatefilename")==0 ){
+ if( Tcl_GetBooleanFromObj(interp, objv[i], &bTranslateFileName) ){
+ return TCL_ERROR;
+ }
}else{
Tcl_AppendResult(interp, "unknown option: ", zArg, (char*)0);
return TCL_ERROR;
@@ -3805,9 +3810,13 @@ static int SQLITE_TCLAPI DbMain(
p = (SqliteDb*)Tcl_Alloc( sizeof(*p) );
memset(p, 0, sizeof(*p));
if( zFile==0 ) zFile = "";
- zFile = Tcl_TranslateFileName(interp, zFile, &translatedFilename);
+ if( bTranslateFileName ){
+ zFile = Tcl_TranslateFileName(interp, zFile, &translatedFilename);
+ }
rc = sqlite3_open_v2(zFile, &p->db, flags, zVfs);
- Tcl_DStringFree(&translatedFilename);
+ if( bTranslateFileName ){
+ Tcl_DStringFree(&translatedFilename);
+ }
if( p->db ){
if( SQLITE_OK!=sqlite3_errcode(p->db) ){
zErrMsg = sqlite3_mprintf("%s", sqlite3_errmsg(p->db));
diff --git a/src/test1.c b/src/test1.c
index 29207d51a..f94adf2d6 100644
--- a/src/test1.c
+++ b/src/test1.c
@@ -4630,7 +4630,7 @@ static int SQLITE_TCLAPI test_open_v2(
{ "SQLITE_OPEN_MAIN_JOURNAL", SQLITE_OPEN_MAIN_JOURNAL },
{ "SQLITE_OPEN_TEMP_JOURNAL", SQLITE_OPEN_TEMP_JOURNAL },
{ "SQLITE_OPEN_SUBJOURNAL", SQLITE_OPEN_SUBJOURNAL },
- { "SQLITE_OPEN_MASTER_JOURNAL", SQLITE_OPEN_MASTER_JOURNAL },
+ { "SQLITE_OPEN_SUPER_JOURNAL", SQLITE_OPEN_SUPER_JOURNAL },
{ "SQLITE_OPEN_NOMUTEX", SQLITE_OPEN_NOMUTEX },
{ "SQLITE_OPEN_FULLMUTEX", SQLITE_OPEN_FULLMUTEX },
{ "SQLITE_OPEN_SHAREDCACHE", SQLITE_OPEN_SHAREDCACHE },
@@ -7257,6 +7257,7 @@ static int SQLITE_TCLAPI tclLoadStaticExtensionCmd(
extern int sqlite3_eval_init(sqlite3*,char**,const sqlite3_api_routines*);
extern int sqlite3_explain_init(sqlite3*,char**,const sqlite3_api_routines*);
extern int sqlite3_fileio_init(sqlite3*,char**,const sqlite3_api_routines*);
+ extern int sqlite3_decimal_init(sqlite3*,char**,const sqlite3_api_routines*);
extern int sqlite3_fuzzer_init(sqlite3*,char**,const sqlite3_api_routines*);
extern int sqlite3_ieee_init(sqlite3*,char**,const sqlite3_api_routines*);
extern int sqlite3_nextchar_init(sqlite3*,char**,const sqlite3_api_routines*);
@@ -7282,6 +7283,7 @@ static int SQLITE_TCLAPI tclLoadStaticExtensionCmd(
{ "carray", sqlite3_carray_init },
{ "closure", sqlite3_closure_init },
{ "csv", sqlite3_csv_init },
+ { "decimal", sqlite3_decimal_init },
{ "eval", sqlite3_eval_init },
{ "explain", sqlite3_explain_init },
{ "fileio", sqlite3_fileio_init },
@@ -8164,7 +8166,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
#endif
#endif
#if defined(SQLITE_ENABLE_SELECTTRACE)
- extern int sqlite3SelectTrace;
+ extern u32 sqlite3SelectTrace;
#endif
for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){
diff --git a/src/test4.c b/src/test4.c
index 2ef5fe692..5da9cc488 100644
--- a/src/test4.c
+++ b/src/test4.c
@@ -32,7 +32,7 @@ extern const char *sqlite3ErrName(int);
*/
typedef struct Thread Thread;
struct Thread {
- /* The first group of fields are writable by the master and read-only
+ /* The first group of fields are writable by the leader and read-only
** to the thread. */
char *zFilename; /* Name of database file */
void (*xOp)(Thread*); /* next operation to do */
@@ -41,7 +41,7 @@ struct Thread {
int busy; /* True if this thread is in use */
/* The next group of fields are writable by the thread but read-only to the
- ** master. */
+ ** leader. */
int completed; /* Number of operations completed */
sqlite3 *db; /* Open database */
sqlite3_stmt *pStmt; /* Pending operation */
diff --git a/src/test8.c b/src/test8.c
index 2684f801f..f984c2e5f 100644
--- a/src/test8.c
+++ b/src/test8.c
@@ -341,7 +341,7 @@ static int echoDeclareVtab(
if( pVtab->zTableName ){
sqlite3_stmt *pStmt = 0;
rc = sqlite3_prepare(db,
- "SELECT sql FROM sqlite_master WHERE type = 'table' AND name = ?",
+ "SELECT sql FROM sqlite_schema WHERE type = 'table' AND name = ?",
-1, &pStmt, 0);
if( rc==SQLITE_OK ){
sqlite3_bind_text(pStmt, 1, pVtab->zTableName, -1, 0);
diff --git a/src/test_multiplex.c b/src/test_multiplex.c
index 3c9aa034c..cda83fd81 100644
--- a/src/test_multiplex.c
+++ b/src/test_multiplex.c
@@ -545,7 +545,7 @@ static int multiplexOpen(
rc = pSubOpen->pMethods->xFileSize(pSubOpen, &sz64);
if( rc==SQLITE_OK && zName ){
int bExists;
- if( flags & SQLITE_OPEN_MASTER_JOURNAL ){
+ if( flags & SQLITE_OPEN_SUPER_JOURNAL ){
pGroup->bEnabled = 0;
}else
if( sz64==0 ){
diff --git a/src/test_mutex.c b/src/test_mutex.c
index 8f43e5ad3..8bd9ff85a 100644
--- a/src/test_mutex.c
+++ b/src/test_mutex.c
@@ -30,7 +30,7 @@
extern const char *sqlite3ErrName(int);
static const char *aName[MAX_MUTEXES+1] = {
- "fast", "recursive", "static_master", "static_mem",
+ "fast", "recursive", "static_main", "static_mem",
"static_open", "static_prng", "static_lru", "static_pmem",
"static_app1", "static_app2", "static_app3", "static_vfs1",
"static_vfs2", "static_vfs3", 0
diff --git a/src/test_osinst.c b/src/test_osinst.c
index a008baba4..3e698c032 100644
--- a/src/test_osinst.c
+++ b/src/test_osinst.c
@@ -740,7 +740,7 @@ int sqlite3_vfslog_new(
zFile = (char *)&p->base.zName[nVfs+1];
pParent->xFullPathname(pParent, zLog, pParent->mxPathname, zFile);
- flags = SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|SQLITE_OPEN_MASTER_JOURNAL;
+ flags = SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|SQLITE_OPEN_SUPER_JOURNAL;
pParent->xDelete(pParent, zFile, 0);
rc = pParent->xOpen(pParent, zFile, p->pLog, flags, &flags);
if( rc==SQLITE_OK ){
@@ -893,7 +893,7 @@ static int vlogConnect(
pVfs->xFullPathname(pVfs, zFile, pVfs->mxPathname, p->zFile);
sqlite3_free(zFile);
- flags = SQLITE_OPEN_READWRITE|SQLITE_OPEN_MASTER_JOURNAL;
+ flags = SQLITE_OPEN_READWRITE|SQLITE_OPEN_SUPER_JOURNAL;
rc = pVfs->xOpen(pVfs, p->zFile, p->pFd, flags, &flags);
if( rc==SQLITE_OK ){
diff --git a/src/test_schema.c b/src/test_schema.c
index cdf085797..d2cae7f2a 100644
--- a/src/test_schema.c
+++ b/src/test_schema.c
@@ -192,18 +192,18 @@ static int schemaNext(sqlite3_vtab_cursor *cur){
}
/* Set zSql to the SQL to pull the list of tables from the
- ** sqlite_master (or sqlite_temp_master) table of the database
+ ** sqlite_schema (or sqlite_temp_schema) table of the database
** identified by the row pointed to by the SQL statement pCur->pDbList
** (iterating through a "PRAGMA database_list;" statement).
*/
if( sqlite3_column_int(pCur->pDbList, 0)==1 ){
zSql = sqlite3_mprintf(
- "SELECT name FROM sqlite_temp_master WHERE type='table'"
+ "SELECT name FROM sqlite_temp_schema WHERE type='table'"
);
}else{
sqlite3_stmt *pDbList = pCur->pDbList;
zSql = sqlite3_mprintf(
- "SELECT name FROM %Q.sqlite_master WHERE type='table'",
+ "SELECT name FROM %Q.sqlite_schema WHERE type='table'",
sqlite3_column_text(pDbList, 1)
);
}
diff --git a/src/test_sqllog.c b/src/test_sqllog.c
index 9b207cf07..9ae0e5068 100644
--- a/src/test_sqllog.c
+++ b/src/test_sqllog.c
@@ -118,7 +118,7 @@ struct SLConn {
/* This object is a singleton that keeps track of all data loggers.
*/
static struct SLGlobal {
- /* Protected by MUTEX_STATIC_MASTER */
+ /* Protected by MUTEX_STATIC_MAIN */
sqlite3_mutex *mutex; /* Recursive mutex */
int nConn; /* Size of aConn[] array */
@@ -467,28 +467,28 @@ static int sqllogTraceDb(sqlite3 *db){
*/
static void testSqllog(void *pCtx, sqlite3 *db, const char *zSql, int eType){
struct SLConn *p = 0;
- sqlite3_mutex *master = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER);
+ sqlite3_mutex *mainmtx = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MAIN);
assert( eType==0 || eType==1 || eType==2 );
assert( (eType==2)==(zSql==0) );
/* This is a database open command. */
if( eType==0 ){
- sqlite3_mutex_enter(master);
+ sqlite3_mutex_enter(mainmtx);
if( sqllogglobal.mutex==0 ){
sqllogglobal.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_RECURSIVE);
}
- sqlite3_mutex_leave(master);
+ sqlite3_mutex_leave(mainmtx);
sqlite3_mutex_enter(sqllogglobal.mutex);
if( sqllogglobal.bRec==0 && sqllogTraceDb(db) ){
- sqlite3_mutex_enter(master);
+ sqlite3_mutex_enter(mainmtx);
p = &sqllogglobal.aConn[sqllogglobal.nConn++];
p->fd = 0;
p->db = db;
p->iLog = sqllogglobal.iNextLog++;
- sqlite3_mutex_leave(master);
+ sqlite3_mutex_leave(mainmtx);
/* Open the log and take a copy of the main database file */
sqllogOpenlog(p);
@@ -507,7 +507,7 @@ static void testSqllog(void *pCtx, sqlite3 *db, const char *zSql, int eType){
/* A database handle close command */
if( eType==2 ){
- sqlite3_mutex_enter(master);
+ sqlite3_mutex_enter(mainmtx);
if( i<sqllogglobal.nConn ){
if( p->fd ) fclose(p->fd);
p->db = 0;
@@ -524,7 +524,7 @@ static void testSqllog(void *pCtx, sqlite3 *db, const char *zSql, int eType){
memmove(p, &p[1], nShift*sizeof(struct SLConn));
}
}
- sqlite3_mutex_leave(master);
+ sqlite3_mutex_leave(mainmtx);
/* An ordinary SQL command. */
}else if( i<sqllogglobal.nConn && p->fd ){
diff --git a/src/treeview.c b/src/treeview.c
index 45c0d748b..187f1a07d 100644
--- a/src/treeview.c
+++ b/src/treeview.c
@@ -582,8 +582,10 @@ void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){
#endif
}
if( pExpr->op==TK_AGG_FUNCTION ){
- sqlite3TreeViewLine(pView, "AGG_FUNCTION%d %Q%s",
- pExpr->op2, pExpr->u.zToken, zFlgs);
+ sqlite3TreeViewLine(pView, "AGG_FUNCTION%d %Q%s agg=%d[%d]/%p",
+ pExpr->op2, pExpr->u.zToken, zFlgs,
+ pExpr->pAggInfo ? pExpr->pAggInfo->selId : 0,
+ pExpr->iAgg, pExpr->pAggInfo);
}else if( pExpr->op2!=0 ){
const char *zOp2;
char zBuf[8];
@@ -615,7 +617,7 @@ void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){
break;
}
case TK_SELECT: {
- sqlite3TreeViewLine(pView, "SELECT-expr flags=0x%x", pExpr->flags);
+ sqlite3TreeViewLine(pView, "subquery-expr flags=0x%x", pExpr->flags);
sqlite3TreeViewSelect(pView, pExpr->x.pSelect, 0);
break;
}
diff --git a/src/trigger.c b/src/trigger.c
index 646d6942d..50de878dd 100644
--- a/src/trigger.c
+++ b/src/trigger.c
@@ -128,7 +128,7 @@ void sqlite3BeginTrigger(
** ^^^^^^^^
**
** To maintain backwards compatibility, ignore the database
- ** name on pTableName if we are reparsing out of SQLITE_MASTER.
+ ** name on pTableName if we are reparsing out of the schema table
*/
if( db->init.busy && iDb!=1 ){
sqlite3DbFree(db, pTableName->a[0].zDatabase);
@@ -318,21 +318,22 @@ void sqlite3FinishTrigger(
#endif
/* if we are not initializing,
- ** build the sqlite_master entry
+ ** build the sqlite_schema entry
*/
if( !db->init.busy ){
Vdbe *v;
char *z;
- /* Make an entry in the sqlite_master table */
+ /* Make an entry in the sqlite_schema table */
v = sqlite3GetVdbe(pParse);
if( v==0 ) goto triggerfinish_cleanup;
sqlite3BeginWriteOperation(pParse, 0, iDb);
z = sqlite3DbStrNDup(db, (char*)pAll->z, pAll->n);
testcase( z==0 );
sqlite3NestedParse(pParse,
- "INSERT INTO %Q.%s VALUES('trigger',%Q,%Q,0,'CREATE TRIGGER %q')",
- db->aDb[iDb].zDbSName, MASTER_NAME, zName,
+ "INSERT INTO %Q." DFLT_SCHEMA_TABLE
+ " VALUES('trigger',%Q,%Q,0,'CREATE TRIGGER %q')",
+ db->aDb[iDb].zDbSName, zName,
pTrig->table, z);
sqlite3DbFree(db, z);
sqlite3ChangeCookie(pParse, iDb);
@@ -639,8 +640,8 @@ void sqlite3DropTriggerPtr(Parse *pParse, Trigger *pTrigger){
*/
if( (v = sqlite3GetVdbe(pParse))!=0 ){
sqlite3NestedParse(pParse,
- "DELETE FROM %Q.%s WHERE name=%Q AND type='trigger'",
- db->aDb[iDb].zDbSName, MASTER_NAME, pTrigger->zName
+ "DELETE FROM %Q." DFLT_SCHEMA_TABLE " WHERE name=%Q AND type='trigger'",
+ db->aDb[iDb].zDbSName, pTrigger->zName
);
sqlite3ChangeCookie(pParse, iDb);
sqlite3VdbeAddOp4(v, OP_DropTrigger, iDb, 0, 0, pTrigger->zName, 0);
diff --git a/src/update.c b/src/update.c
index 7aa9fee51..4d86aab6e 100644
--- a/src/update.c
+++ b/src/update.c
@@ -46,17 +46,17 @@ static void updateVirtualTable(
** literal default values specified: a number, null or a string. (If a more
** complicated default expression value was provided, it is evaluated
** when the ALTER TABLE is executed and one of the literal values written
-** into the sqlite_master table.)
+** into the sqlite_schema table.)
**
** Therefore, the P4 parameter is only required if the default value for
** the column is a literal number, string or null. The sqlite3ValueFromExpr()
** function is capable of transforming these types of expressions into
** sqlite3_value objects.
**
-** If parameter iReg is not negative, code an OP_RealAffinity instruction
-** on register iReg. This is used when an equivalent integer value is
-** stored in place of an 8-byte floating point value in order to save
-** space.
+** If column as REAL affinity and the table is an ordinary b-tree table
+** (not a virtual table) then the value might have been stored as an
+** integer. In that case, add an OP_RealAffinity opcode to make sure
+** it has been converted into REAL.
*/
void sqlite3ColumnDefault(Vdbe *v, Table *pTab, int i, int iReg){
assert( pTab!=0 );
@@ -73,7 +73,7 @@ void sqlite3ColumnDefault(Vdbe *v, Table *pTab, int i, int iReg){
}
}
#ifndef SQLITE_OMIT_FLOATING_POINT
- if( pTab->aCol[i].affinity==SQLITE_AFF_REAL ){
+ if( pTab->aCol[i].affinity==SQLITE_AFF_REAL && !IsVirtual(pTab) ){
sqlite3VdbeAddOp1(v, OP_RealAffinity, iReg);
}
#endif
@@ -1234,7 +1234,7 @@ static void updateVirtualTable(
** the ephemeral table. */
sqlite3MultiWrite(pParse);
sqlite3VdbeAddOp3(v, OP_MakeRecord, regArg, nArg, regRec);
-#ifdef SQLITE_DEBUG
+#if defined(SQLITE_DEBUG) && !defined(SQLITE_ENABLE_NULL_TRIM)
/* Signal an assert() within OP_MakeRecord that it is allowed to
** accept no-change records with serial_type 10 */
sqlite3VdbeChangeP5(v, OPFLAG_NOCHNG_MAGIC);
diff --git a/src/utf.c b/src/utf.c
index f6c8e79e5..5f27babdf 100644
--- a/src/utf.c
+++ b/src/utf.c
@@ -284,6 +284,7 @@ SQLITE_NOINLINE int sqlite3VdbeMemTranslate(Mem *pMem, u8 desiredEnc){
c = *(zIn++);
c += (*(zIn++))<<8;
if( c>=0xd800 && c<0xe000 ){
+#ifdef SQLITE_REPLACE_INVALID_UTF
if( c>=0xdc00 || zIn>=zTerm ){
c = 0xfffd;
}else{
@@ -296,6 +297,13 @@ SQLITE_NOINLINE int sqlite3VdbeMemTranslate(Mem *pMem, u8 desiredEnc){
c = ((c&0x3ff)<<10) + (c2&0x3ff) + 0x10000;
}
}
+#else
+ if( zIn<zTerm ){
+ int c2 = (*zIn++);
+ c2 += ((*zIn++)<<8);
+ c = (c2&0x03FF) + ((c&0x003F)<<10) + (((c&0x03C0)+0x0040)<<10);
+ }
+#endif
}
WRITE_UTF8(z, c);
}
@@ -305,6 +313,7 @@ SQLITE_NOINLINE int sqlite3VdbeMemTranslate(Mem *pMem, u8 desiredEnc){
c = (*(zIn++))<<8;
c += *(zIn++);
if( c>=0xd800 && c<0xe000 ){
+#ifdef SQLITE_REPLACE_INVALID_UTF
if( c>=0xdc00 || zIn>=zTerm ){
c = 0xfffd;
}else{
@@ -317,6 +326,13 @@ SQLITE_NOINLINE int sqlite3VdbeMemTranslate(Mem *pMem, u8 desiredEnc){
c = ((c&0x3ff)<<10) + (c2&0x3ff) + 0x10000;
}
}
+#else
+ if( zIn<zTerm ){
+ int c2 = ((*zIn++)<<8);
+ c2 += (*zIn++);
+ c = (c2&0x03FF) + ((c&0x003F)<<10) + (((c&0x03C0)+0x0040)<<10);
+ }
+#endif
}
WRITE_UTF8(z, c);
}
@@ -326,9 +342,9 @@ SQLITE_NOINLINE int sqlite3VdbeMemTranslate(Mem *pMem, u8 desiredEnc){
*z = 0;
assert( (pMem->n+(desiredEnc==SQLITE_UTF8?1:2))<=len );
- c = pMem->flags;
+ c = MEM_Str|MEM_Term|(pMem->flags&(MEM_AffMask|MEM_Subtype));
sqlite3VdbeMemRelease(pMem);
- pMem->flags = MEM_Str|MEM_Term|(c&(MEM_AffMask|MEM_Subtype));
+ pMem->flags = c;
pMem->enc = desiredEnc;
pMem->z = (char*)zOut;
pMem->zMalloc = pMem->z;
diff --git a/src/util.c b/src/util.c
index 09520d1d6..9c462cc67 100644
--- a/src/util.c
+++ b/src/util.c
@@ -1141,8 +1141,7 @@ u8 sqlite3GetVarint32(const unsigned char *p, u32 *v){
u64 v64;
u8 n;
- p -= 2;
- n = sqlite3GetVarint(p, &v64);
+ n = sqlite3GetVarint(p-2, &v64);
assert( n>3 && n<=9 );
if( (v64 & SQLITE_MAX_U32)!=v64 ){
*v = 0xffffffff;
diff --git a/src/vacuum.c b/src/vacuum.c
index 5c230fbe1..50875d8d3 100644
--- a/src/vacuum.c
+++ b/src/vacuum.c
@@ -41,7 +41,7 @@ static int execSql(sqlite3 *db, char **pzErrMsg, const char *zSql){
assert( sqlite3_strnicmp(zSql,"SELECT",6)==0 );
/* The secondary SQL must be one of CREATE TABLE, CREATE INDEX,
** or INSERT. Historically there have been attacks that first
- ** corrupt the sqlite_master.sql field with other kinds of statements
+ ** corrupt the sqlite_schema.sql field with other kinds of statements
** then run VACUUM to get those statements to execute at inappropriate
** times. */
if( zSubSql
@@ -272,14 +272,14 @@ SQLITE_NOINLINE int sqlite3RunVacuum(
*/
db->init.iDb = nDb; /* force new CREATE statements into vacuum_db */
rc = execSqlF(db, pzErrMsg,
- "SELECT sql FROM \"%w\".sqlite_master"
+ "SELECT sql FROM \"%w\".sqlite_schema"
" WHERE type='table'AND name<>'sqlite_sequence'"
" AND coalesce(rootpage,1)>0",
zDbMain
);
if( rc!=SQLITE_OK ) goto end_of_vacuum;
rc = execSqlF(db, pzErrMsg,
- "SELECT sql FROM \"%w\".sqlite_master"
+ "SELECT sql FROM \"%w\".sqlite_schema"
" WHERE type='index'",
zDbMain
);
@@ -293,7 +293,7 @@ SQLITE_NOINLINE int sqlite3RunVacuum(
rc = execSqlF(db, pzErrMsg,
"SELECT'INSERT INTO vacuum_db.'||quote(name)"
"||' SELECT*FROM\"%w\".'||quote(name)"
- "FROM vacuum_db.sqlite_master "
+ "FROM vacuum_db.sqlite_schema "
"WHERE type='table'AND coalesce(rootpage,1)>0",
zDbMain
);
@@ -304,11 +304,11 @@ SQLITE_NOINLINE int sqlite3RunVacuum(
/* Copy the triggers, views, and virtual tables from the main database
** over to the temporary database. None of these objects has any
** associated storage, so all we have to do is copy their entries
- ** from the SQLITE_MASTER table.
+ ** from the schema table.
*/
rc = execSqlF(db, pzErrMsg,
- "INSERT INTO vacuum_db.sqlite_master"
- " SELECT*FROM \"%w\".sqlite_master"
+ "INSERT INTO vacuum_db.sqlite_schema"
+ " SELECT*FROM \"%w\".sqlite_schema"
" WHERE type IN('view','trigger')"
" OR(type='table'AND rootpage=0)",
zDbMain
@@ -377,7 +377,7 @@ end_of_vacuum:
db->nChange = saved_nChange;
db->nTotalChange = saved_nTotalChange;
db->mTrace = saved_mTrace;
- sqlite3BtreeSetPageSize(pMain, -1, -1, 1);
+ sqlite3BtreeSetPageSize(pMain, -1, 0, 1);
/* Currently there is an SQL level transaction open on the vacuum
** database. No locks are held on any other files (since the main file
diff --git a/src/vdbe.c b/src/vdbe.c
index 1f1d352cd..9705f9d03 100644
--- a/src/vdbe.c
+++ b/src/vdbe.c
@@ -671,9 +671,9 @@ int sqlite3VdbeExec(
u8 resetSchemaOnFault = 0; /* Reset schema after an error if positive */
u8 encoding = ENC(db); /* The database encoding */
int iCompare = 0; /* Result of last comparison */
- unsigned nVmStep = 0; /* Number of virtual machine steps */
+ u64 nVmStep = 0; /* Number of virtual machine steps */
#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
- unsigned nProgressLimit; /* Invoke xProgress() when nVmStep reaches this */
+ u64 nProgressLimit; /* Invoke xProgress() when nVmStep reaches this */
#endif
Mem *aMem = p->aMem; /* Copy of p->aMem */
Mem *pIn1 = 0; /* 1st input operand */
@@ -693,7 +693,7 @@ int sqlite3VdbeExec(
assert( 0 < db->nProgressOps );
nProgressLimit = db->nProgressOps - (iPrior % db->nProgressOps);
}else{
- nProgressLimit = 0xffffffff;
+ nProgressLimit = LARGEST_UINT64;
}
#endif
if( p->rc==SQLITE_NOMEM ){
@@ -702,6 +702,8 @@ int sqlite3VdbeExec(
goto no_mem;
}
assert( p->rc==SQLITE_OK || (p->rc&0xff)==SQLITE_BUSY );
+ testcase( p->rc!=SQLITE_OK );
+ p->rc = SQLITE_OK;
assert( p->bIsReader || p->readOnly!=0 );
p->iCurrentTime = 0;
assert( p->explain==0 );
@@ -903,7 +905,7 @@ check_for_interrupt:
assert( db->nProgressOps!=0 );
nProgressLimit += db->nProgressOps;
if( db->xProgress(db->pProgressArg) ){
- nProgressLimit = 0xffffffff;
+ nProgressLimit = LARGEST_UINT64;
rc = SQLITE_INTERRUPT;
goto abort_due_to_error;
}
@@ -2074,7 +2076,7 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
if( (flags1 | flags3)&MEM_Str ){
if( (flags1 & (MEM_Int|MEM_IntReal|MEM_Real|MEM_Str))==MEM_Str ){
applyNumericAffinity(pIn1,0);
- assert( flags3==pIn3->flags );
+ testcase( flags3==pIn3->flags );
flags3 = pIn3->flags;
}
if( (flags3 & (MEM_Int|MEM_IntReal|MEM_Real|MEM_Str))==MEM_Str ){
@@ -2920,6 +2922,17 @@ case OP_Affinity: {
** macros defined in sqliteInt.h.
**
** If P4 is NULL then all index fields have the affinity BLOB.
+**
+** The meaning of P5 depends on whether or not the SQLITE_ENABLE_NULL_TRIM
+** compile-time option is enabled:
+**
+** * If SQLITE_ENABLE_NULL_TRIM is enabled, then the P5 is the index
+** of the right-most table that can be null-trimmed.
+**
+** * If SQLITE_ENABLE_NULL_TRIM is omitted, then P5 has the value
+** OPFLAG_NOCHNG_MAGIC if the OP_MakeRecord opcode is allowed to
+** accept no-change records with serial_type 10. This value is
+** only used inside an assert() and does not affect the end result.
*/
case OP_MakeRecord: {
Mem *pRec; /* The new record */
@@ -3038,7 +3051,9 @@ case OP_MakeRecord: {
** Give such values a special internal-use-only serial-type of 10
** so that they can be passed through to xUpdate and have
** a true sqlite3_value_nochange(). */
+#ifndef SQLITE_ENABLE_NULL_TRIM
assert( pOp->p5==OPFLAG_NOCHNG_MAGIC || CORRUPT_DB );
+#endif
pRec->uTemp = 10;
}else{
pRec->uTemp = 0;
@@ -3187,13 +3202,16 @@ case OP_MakeRecord: {
break;
}
-/* Opcode: Count P1 P2 * * *
+/* Opcode: Count P1 P2 p3 * *
** Synopsis: r[P2]=count()
**
** Store the number of entries (an integer value) in the table or index
-** opened by cursor P1 in register P2
+** opened by cursor P1 in register P2.
+**
+** If P3==0, then an exact count is obtained, which involves visiting
+** every btree page of the table. But if P3 is non-zero, an estimate
+** is returned based on the current cursor position.
*/
-#ifndef SQLITE_OMIT_BTREECOUNT
case OP_Count: { /* out2 */
i64 nEntry;
BtCursor *pCrsr;
@@ -3201,14 +3219,17 @@ case OP_Count: { /* out2 */
assert( p->apCsr[pOp->p1]->eCurType==CURTYPE_BTREE );
pCrsr = p->apCsr[pOp->p1]->uc.pCursor;
assert( pCrsr );
- nEntry = 0; /* Not needed. Only used to silence a warning. */
- rc = sqlite3BtreeCount(db, pCrsr, &nEntry);
- if( rc ) goto abort_due_to_error;
+ if( pOp->p3 ){
+ nEntry = sqlite3BtreeRowCountEst(pCrsr);
+ }else{
+ nEntry = 0; /* Not needed. Only used to silence a warning. */
+ rc = sqlite3BtreeCount(db, pCrsr, &nEntry);
+ if( rc ) goto abort_due_to_error;
+ }
pOut = out2Prerelease(p, pOp);
pOut->u.i = nEntry;
goto check_for_interrupt;
}
-#endif
/* Opcode: Savepoint P1 * * P4 *
**
@@ -3608,7 +3629,7 @@ case OP_ReadCookie: { /* out2 */
break;
}
-/* Opcode: SetCookie P1 P2 P3 * *
+/* Opcode: SetCookie P1 P2 P3 * P5
**
** Write the integer value P3 into cookie number P2 of database P1.
** P2==1 is the schema version. P2==2 is the database format.
@@ -3617,6 +3638,11 @@ case OP_ReadCookie: { /* out2 */
** database file used to store temporary tables.
**
** A transaction must be started before executing this opcode.
+**
+** If P2 is the SCHEMA_VERSION cookie (cookie number 1) then the internal
+** schema version is set to P3-P5. The "PRAGMA schema_version=N" statement
+** has P5 set to 1, so that the internal schema version will be different
+** from the database schema version, resulting in a schema reset.
*/
case OP_SetCookie: {
Db *pDb;
@@ -3633,7 +3659,7 @@ case OP_SetCookie: {
rc = sqlite3BtreeUpdateMeta(pDb->pBt, pOp->p2, pOp->p3);
if( pOp->p2==BTREE_SCHEMA_VERSION ){
/* When the schema cookie changes, record the new cookie internally */
- pDb->pSchema->schema_cookie = pOp->p3;
+ pDb->pSchema->schema_cookie = pOp->p3 - pOp->p5;
db->mDbFlags |= DBFLAG_SchemaChange;
}else if( pOp->p2==BTREE_FILE_FORMAT ){
/* Record changes in the file format */
@@ -3942,7 +3968,7 @@ case OP_OpenEphemeral: {
rc = sqlite3BtreeCreateTable(pCx->pBtx, (int*)&pCx->pgnoRoot,
BTREE_BLOBKEY | pOp->p5);
if( rc==SQLITE_OK ){
- assert( pCx->pgnoRoot==MASTER_ROOT+1 );
+ assert( pCx->pgnoRoot==SCHEMA_ROOT+1 );
assert( pKeyInfo->db==db );
assert( pKeyInfo->enc==ENC(db) );
rc = sqlite3BtreeCursor(pCx->pBtx, pCx->pgnoRoot, BTREE_WRCSR,
@@ -3950,8 +3976,8 @@ case OP_OpenEphemeral: {
}
pCx->isTable = 0;
}else{
- pCx->pgnoRoot = MASTER_ROOT;
- rc = sqlite3BtreeCursor(pCx->pBtx, MASTER_ROOT, BTREE_WRCSR,
+ pCx->pgnoRoot = SCHEMA_ROOT;
+ rc = sqlite3BtreeCursor(pCx->pBtx, SCHEMA_ROOT, BTREE_WRCSR,
0, pCx->uc.pCursor);
pCx->isTable = 1;
}
@@ -4359,7 +4385,7 @@ seek_not_found:
** Synopsis: seekHit=P2
**
** Set the seekHit flag on cursor P1 to the value in P2.
-* The seekHit flag is used by the IfNoHope opcode.
+** The seekHit flag is used by the IfNoHope opcode.
**
** P1 must be a valid b-tree cursor. P2 must be a boolean value,
** either 0 or 1.
@@ -5646,12 +5672,19 @@ case OP_SorterInsert: { /* in2 */
break;
}
-/* Opcode: IdxDelete P1 P2 P3 * *
+/* Opcode: IdxDelete P1 P2 P3 * P5
** Synopsis: key=r[P2@P3]
**
** The content of P3 registers starting at register P2 form
** an unpacked index key. This opcode removes that entry from the
** index opened by cursor P1.
+**
+** If P5 is not zero, then raise an SQLITE_CORRUPT_INDEX error
+** if no matching index entry is found. This happens when running
+** an UPDATE or DELETE statement and the index entry to be updated
+** or deleted is not found. For some uses of IdxDelete
+** (example: the EXCEPT operator) it does not matter that no matching
+** entry is found. For those cases, P5 is zero.
*/
case OP_IdxDelete: {
VdbeCursor *pC;
@@ -5668,7 +5701,6 @@ case OP_IdxDelete: {
sqlite3VdbeIncrWriteCounter(p, pC);
pCrsr = pC->uc.pCursor;
assert( pCrsr!=0 );
- assert( pOp->p5==0 );
r.pKeyInfo = pC->pKeyInfo;
r.nField = (u16)pOp->p3;
r.default_rc = 0;
@@ -5678,6 +5710,9 @@ case OP_IdxDelete: {
if( res==0 ){
rc = sqlite3BtreeDelete(pCrsr, BTREE_AUXDELETE);
if( rc ) goto abort_due_to_error;
+ }else if( pOp->p5 ){
+ rc = SQLITE_CORRUPT_INDEX;
+ goto abort_due_to_error;
}
assert( pC->deferredMoveto==0 );
pC->cacheStatus = CACHE_STALE;
@@ -6049,7 +6084,7 @@ case OP_SqlExec: {
/* Opcode: ParseSchema P1 * * P4 *
**
-** Read and parse all entries from the SQLITE_MASTER table of database P1
+** Read and parse all entries from the schema table of database P1
** that match the WHERE clause P4. If P4 is a NULL pointer, then the
** entire schema for P1 is reparsed.
**
@@ -6058,7 +6093,7 @@ case OP_SqlExec: {
*/
case OP_ParseSchema: {
int iDb;
- const char *zMaster;
+ const char *zSchema;
char *zSql;
InitData initData;
@@ -6086,14 +6121,14 @@ case OP_ParseSchema: {
}else
#endif
{
- zMaster = MASTER_NAME;
+ zSchema = DFLT_SCHEMA_TABLE;
initData.db = db;
initData.iDb = iDb;
initData.pzErrMsg = &p->zErrMsg;
initData.mInitFlags = 0;
zSql = sqlite3MPrintf(db,
"SELECT*FROM\"%w\".%s WHERE %s ORDER BY rowid",
- db->aDb[iDb].zDbSName, zMaster, pOp->p4.z);
+ db->aDb[iDb].zDbSName, zSchema, pOp->p4.z);
if( zSql==0 ){
rc = SQLITE_NOMEM_BKPT;
}else{
@@ -6107,7 +6142,7 @@ case OP_ParseSchema: {
if( rc==SQLITE_OK && initData.nInitRow==0 ){
/* The OP_ParseSchema opcode with a non-NULL P4 argument should parse
** at least one SQL statement. Any less than that indicates that
- ** the sqlite_master table is corrupt. */
+ ** the sqlite_schema table is corrupt. */
rc = SQLITE_CORRUPT_BKPT;
}
sqlite3DbFreeNN(db, zSql);
@@ -7966,7 +8001,7 @@ vdbe_return:
while( nVmStep>=nProgressLimit && db->xProgress!=0 ){
nProgressLimit += db->nProgressOps;
if( db->xProgress(db->pProgressArg) ){
- nProgressLimit = 0xffffffff;
+ nProgressLimit = LARGEST_UINT64;
rc = SQLITE_INTERRUPT;
goto abort_due_to_error;
}
@@ -8000,8 +8035,6 @@ no_mem:
*/
abort_due_to_interrupt:
assert( AtomicLoad(&db->u1.isInterrupted) );
- rc = db->mallocFailed ? SQLITE_NOMEM_BKPT : SQLITE_INTERRUPT;
- p->rc = rc;
- sqlite3VdbeError(p, "%s", sqlite3ErrStr(rc));
+ rc = SQLITE_INTERRUPT;
goto abort_due_to_error;
}
diff --git a/src/vdbe.h b/src/vdbe.h
index 482331eff..38b43eb71 100644
--- a/src/vdbe.h
+++ b/src/vdbe.h
@@ -290,6 +290,9 @@ void sqlite3VdbeLinkSubProgram(Vdbe *, SubProgram *);
int sqlite3VdbeHasSubProgram(Vdbe*);
int sqlite3NotPureFunc(sqlite3_context*);
+#ifdef SQLITE_ENABLE_BYTECODE_VTAB
+int sqlite3VdbeBytecodeVtabInit(sqlite3*);
+#endif
/* Use SQLITE_ENABLE_COMMENTS to enable generation of extra comments on
** each VDBE opcode.
diff --git a/src/vdbeInt.h b/src/vdbeInt.h
index a256ed5bd..e46198312 100644
--- a/src/vdbeInt.h
+++ b/src/vdbeInt.h
@@ -31,7 +31,8 @@
** "explain" P4 display logic is enabled.
*/
#if !defined(SQLITE_OMIT_EXPLAIN) || !defined(NDEBUG) \
- || defined(VDBE_PROFILE) || defined(SQLITE_DEBUG)
+ || defined(VDBE_PROFILE) || defined(SQLITE_DEBUG) \
+ || defined(SQLITE_ENABLE_BYTECODE_VTAB)
# define VDBE_DISPLAY_P4 1
#else
# define VDBE_DISPLAY_P4 0
@@ -496,7 +497,14 @@ int sqlite2BtreeKeyCompare(BtCursor *, const void *, int, int, int *);
int sqlite3VdbeIdxKeyCompare(sqlite3*,VdbeCursor*,UnpackedRecord*,int*);
int sqlite3VdbeIdxRowid(sqlite3*, BtCursor*, i64*);
int sqlite3VdbeExec(Vdbe*);
-#ifndef SQLITE_OMIT_EXPLAIN
+#if !defined(SQLITE_OMIT_EXPLAIN) || defined(SQLITE_ENABLE_BYTECODE_VTAB)
+int sqlite3VdbeNextOpcode(Vdbe*,Mem*,int,int*,int*,Op**);
+char *sqlite3VdbeDisplayP4(sqlite3*,Op*);
+#endif
+#if defined(SQLITE_ENABLE_EXPLAIN_COMMENTS)
+char *sqlite3VdbeDisplayComment(sqlite3*,const Op*,const char*);
+#endif
+#if !defined(SQLITE_OMIT_EXPLAIN)
int sqlite3VdbeList(Vdbe*);
#endif
int sqlite3VdbeHalt(Vdbe*);
@@ -538,7 +546,7 @@ int sqlite3VdbeMemFinalize(Mem*, FuncDef*);
#ifndef SQLITE_OMIT_WINDOWFUNC
int sqlite3VdbeMemAggValue(Mem*, Mem*, FuncDef*);
#endif
-#ifndef SQLITE_OMIT_EXPLAIN
+#if !defined(SQLITE_OMIT_EXPLAIN) || defined(SQLITE_ENABLE_BYTECODE_VTAB)
const char *sqlite3OpcodeName(int);
#endif
int sqlite3VdbeMemGrow(Mem *pMem, int n, int preserve);
diff --git a/src/vdbeapi.c b/src/vdbeapi.c
index 4337a33a5..2126318e0 100644
--- a/src/vdbeapi.c
+++ b/src/vdbeapi.c
@@ -655,6 +655,13 @@ static int sqlite3Step(Vdbe *p){
if( p->pc<0 && p->expired ){
p->rc = SQLITE_SCHEMA;
rc = SQLITE_ERROR;
+ if( (p->prepFlags & SQLITE_PREPARE_SAVESQL)!=0 ){
+ /* If this statement was prepared using saved SQL and an
+ ** error has occurred, then return the error code in p->rc to the
+ ** caller. Set the error code in the database handle to the same value.
+ */
+ rc = sqlite3VdbeTransferError(p);
+ }
goto end_of_step;
}
if( p->pc<0 ){
@@ -710,35 +717,27 @@ static int sqlite3Step(Vdbe *p){
if( p->rc!=SQLITE_OK ){
rc = SQLITE_ERROR;
}
+ }else if( rc!=SQLITE_DONE && (p->prepFlags & SQLITE_PREPARE_SAVESQL)!=0 ){
+ /* If this statement was prepared using saved SQL and an
+ ** error has occurred, then return the error code in p->rc to the
+ ** caller. Set the error code in the database handle to the same value.
+ */
+ rc = sqlite3VdbeTransferError(p);
}
}
db->errCode = rc;
if( SQLITE_NOMEM==sqlite3ApiExit(p->db, p->rc) ){
p->rc = SQLITE_NOMEM_BKPT;
+ if( (p->prepFlags & SQLITE_PREPARE_SAVESQL)!=0 ) rc = p->rc;
}
end_of_step:
- /* At this point local variable rc holds the value that should be
- ** returned if this statement was compiled using the legacy
- ** sqlite3_prepare() interface. According to the docs, this can only
- ** be one of the values in the first assert() below. Variable p->rc
- ** contains the value that would be returned if sqlite3_finalize()
- ** were called on statement p.
- */
- assert( rc==SQLITE_ROW || rc==SQLITE_DONE || rc==SQLITE_ERROR
+ /* There are only a limited number of result codes allowed from the
+ ** statements prepared using the legacy sqlite3_prepare() interface */
+ assert( (p->prepFlags & SQLITE_PREPARE_SAVESQL)!=0
+ || rc==SQLITE_ROW || rc==SQLITE_DONE || rc==SQLITE_ERROR
|| (rc&0xff)==SQLITE_BUSY || rc==SQLITE_MISUSE
);
- assert( (p->rc!=SQLITE_ROW && p->rc!=SQLITE_DONE) || p->rc==p->rcApp );
- if( rc!=SQLITE_ROW
- && rc!=SQLITE_DONE
- && (p->prepFlags & SQLITE_PREPARE_SAVESQL)!=0
- ){
- /* If this statement was prepared using saved SQL and an
- ** error has occurred, then return the error code in p->rc to the
- ** caller. Set the error code in the database handle to the same value.
- */
- rc = sqlite3VdbeTransferError(p);
- }
return (rc&db->errMask);
}
@@ -1355,7 +1354,7 @@ static int vdbeUnbind(Vdbe *p, int i){
/* If the bit corresponding to this variable in Vdbe.expmask is set, then
** binding a new value to this variable invalidates the current query plan.
**
- ** IMPLEMENTATION-OF: R-48440-37595 If the specific value bound to host
+ ** IMPLEMENTATION-OF: R-57496-20354 If the specific value bound to a host
** parameter in the WHERE clause might influence the choice of query plan
** for a statement, then the statement will be automatically recompiled,
** as if there had been a schema change, on the first sqlite3_step() call
diff --git a/src/vdbeaux.c b/src/vdbeaux.c
index cfddc0f61..b0a25ad8d 100644
--- a/src/vdbeaux.c
+++ b/src/vdbeaux.c
@@ -1464,11 +1464,10 @@ static int translateP(char c, const Op *pOp){
** "PX@PY+1" -> "r[X..X+Y]" or "r[x]" if y is 0
** "PY..PY" -> "r[X..Y]" or "r[x]" if y<=x
*/
-static int displayComment(
+char *sqlite3VdbeDisplayComment(
+ sqlite3 *db, /* Optional - Oom error reporting only */
const Op *pOp, /* The opcode to be commented */
- const char *zP4, /* Previously obtained value for P4 */
- char *zTemp, /* Write result here */
- int nTemp /* Space available in zTemp[] */
+ const char *zP4 /* Previously obtained value for P4 */
){
const char *zOpName;
const char *zSynopsis;
@@ -1476,8 +1475,8 @@ static int displayComment(
int ii;
char zAlt[50];
StrAccum x;
- sqlite3StrAccumInit(&x, 0, zTemp, nTemp, 0);
+ sqlite3StrAccumInit(&x, 0, 0, 0, SQLITE_MAX_LENGTH);
zOpName = sqlite3OpcodeName(pOp->opcode);
nOpName = sqlite3Strlen30(zOpName);
if( zOpName[nOpName+1] ){
@@ -1544,10 +1543,12 @@ static int displayComment(
}else if( pOp->zComment ){
sqlite3_str_appendall(&x, pOp->zComment);
}
- sqlite3StrAccumFinish(&x);
- return x.nChar;
+ if( (x.accError & SQLITE_NOMEM)!=0 && db!=0 ){
+ sqlite3OomFault(db);
+ }
+ return sqlite3StrAccumFinish(&x);
}
-#endif /* SQLITE_DEBUG */
+#endif /* SQLITE_ENABLE_EXPLAIN_COMMENTS */
#if VDBE_DISPLAY_P4 && defined(SQLITE_ENABLE_CURSOR_HINTS)
/*
@@ -1628,11 +1629,11 @@ static void displayP4Expr(StrAccum *p, Expr *pExpr){
** Compute a string that describes the P4 parameter for an opcode.
** Use zTemp for any required temporary buffer space.
*/
-static char *displayP4(Op *pOp, char *zTemp, int nTemp){
- char *zP4 = zTemp;
+char *sqlite3VdbeDisplayP4(sqlite3 *db, Op *pOp){
+ char *zP4 = 0;
StrAccum x;
- assert( nTemp>=20 );
- sqlite3StrAccumInit(&x, 0, zTemp, nTemp, 0);
+
+ sqlite3StrAccumInit(&x, 0, 0, 0, SQLITE_MAX_LENGTH);
switch( pOp->p4type ){
case P4_KEYINFO: {
int j;
@@ -1716,36 +1717,32 @@ static char *displayP4(Op *pOp, char *zTemp, int nTemp){
int n = ai[0]; /* The first element of an INTARRAY is always the
** count of the number of elements to follow */
for(i=1; i<=n; i++){
- sqlite3_str_appendf(&x, ",%d", ai[i]);
+ sqlite3_str_appendf(&x, "%c%d", (i==1 ? '[' : ','), ai[i]);
}
- zTemp[0] = '[';
sqlite3_str_append(&x, "]", 1);
break;
}
case P4_SUBPROGRAM: {
- sqlite3_str_appendf(&x, "program");
+ zP4 = "program";
break;
}
case P4_DYNBLOB:
case P4_ADVANCE: {
- zTemp[0] = 0;
break;
}
case P4_TABLE: {
- sqlite3_str_appendf(&x, "%s", pOp->p4.pTab->zName);
+ zP4 = pOp->p4.pTab->zName;
break;
}
default: {
zP4 = pOp->p4.z;
- if( zP4==0 ){
- zP4 = zTemp;
- zTemp[0] = 0;
- }
}
}
- sqlite3StrAccumFinish(&x);
- assert( zP4!=0 );
- return zP4;
+ if( zP4 ) sqlite3_str_appendall(&x, zP4);
+ if( (x.accError & SQLITE_NOMEM)!=0 ){
+ sqlite3OomFault(db);
+ }
+ return sqlite3StrAccumFinish(&x);
}
#endif /* VDBE_DISPLAY_P4 */
@@ -1835,24 +1832,30 @@ void sqlite3VdbeLeave(Vdbe *p){
*/
void sqlite3VdbePrintOp(FILE *pOut, int pc, VdbeOp *pOp){
char *zP4;
- char zPtr[50];
- char zCom[100];
+ char *zCom;
+ sqlite3 dummyDb;
static const char *zFormat1 = "%4d %-13s %4d %4d %4d %-13s %.2X %s\n";
if( pOut==0 ) pOut = stdout;
- zP4 = displayP4(pOp, zPtr, sizeof(zPtr));
+ sqlite3BeginBenignMalloc();
+ dummyDb.mallocFailed = 1;
+ zP4 = sqlite3VdbeDisplayP4(&dummyDb, pOp);
#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
- displayComment(pOp, zP4, zCom, sizeof(zCom));
+ zCom = sqlite3VdbeDisplayComment(0, pOp, zP4);
#else
- zCom[0] = 0;
+ zCom = 0;
#endif
/* NB: The sqlite3OpcodeName() function is implemented by code created
** by the mkopcodeh.awk and mkopcodec.awk scripts which extract the
** information from the vdbe.c source text */
fprintf(pOut, zFormat1, pc,
- sqlite3OpcodeName(pOp->opcode), pOp->p1, pOp->p2, pOp->p3, zP4, pOp->p5,
- zCom
+ sqlite3OpcodeName(pOp->opcode), pOp->p1, pOp->p2, pOp->p3,
+ zP4 ? zP4 : "", pOp->p5,
+ zCom ? zCom : ""
);
fflush(pOut);
+ sqlite3_free(zP4);
+ sqlite3_free(zCom);
+ sqlite3EndBenignMalloc();
}
#endif
@@ -1943,6 +1946,121 @@ void sqlite3VdbeFrameMemDel(void *pArg){
pFrame->v->pDelFrame = pFrame;
}
+#if defined(SQLITE_ENABLE_BYTECODE_VTAB) || !defined(SQLITE_OMIT_EXPLAIN)
+/*
+** Locate the next opcode to be displayed in EXPLAIN or EXPLAIN
+** QUERY PLAN output.
+**
+** Return SQLITE_ROW on success. Return SQLITE_DONE if there are no
+** more opcodes to be displayed.
+*/
+int sqlite3VdbeNextOpcode(
+ Vdbe *p, /* The statement being explained */
+ Mem *pSub, /* Storage for keeping track of subprogram nesting */
+ int eMode, /* 0: normal. 1: EQP. 2: TablesUsed */
+ int *piPc, /* IN/OUT: Current rowid. Overwritten with next rowid */
+ int *piAddr, /* OUT: Write index into (*paOp)[] here */
+ Op **paOp /* OUT: Write the opcode array here */
+){
+ int nRow; /* Stop when row count reaches this */
+ int nSub = 0; /* Number of sub-vdbes seen so far */
+ SubProgram **apSub = 0; /* Array of sub-vdbes */
+ int i; /* Next instruction address */
+ int rc = SQLITE_OK; /* Result code */
+ Op *aOp = 0; /* Opcode array */
+ int iPc; /* Rowid. Copy of value in *piPc */
+
+ /* When the number of output rows reaches nRow, that means the
+ ** listing has finished and sqlite3_step() should return SQLITE_DONE.
+ ** nRow is the sum of the number of rows in the main program, plus
+ ** the sum of the number of rows in all trigger subprograms encountered
+ ** so far. The nRow value will increase as new trigger subprograms are
+ ** encountered, but p->pc will eventually catch up to nRow.
+ */
+ nRow = p->nOp;
+ if( pSub!=0 ){
+ if( pSub->flags&MEM_Blob ){
+ /* pSub is initiallly NULL. It is initialized to a BLOB by
+ ** the P4_SUBPROGRAM processing logic below */
+ nSub = pSub->n/sizeof(Vdbe*);
+ apSub = (SubProgram **)pSub->z;
+ }
+ for(i=0; i<nSub; i++){
+ nRow += apSub[i]->nOp;
+ }
+ }
+ iPc = *piPc;
+ while(1){ /* Loop exits via break */
+ i = iPc++;
+ if( i>=nRow ){
+ p->rc = SQLITE_OK;
+ rc = SQLITE_DONE;
+ break;
+ }
+ if( i<p->nOp ){
+ /* The rowid is small enough that we are still in the
+ ** main program. */
+ aOp = p->aOp;
+ }else{
+ /* We are currently listing subprograms. Figure out which one and
+ ** pick up the appropriate opcode. */
+ int j;
+ i -= p->nOp;
+ assert( apSub!=0 );
+ assert( nSub>0 );
+ for(j=0; i>=apSub[j]->nOp; j++){
+ i -= apSub[j]->nOp;
+ assert( i<apSub[j]->nOp || j+1<nSub );
+ }
+ aOp = apSub[j]->aOp;
+ }
+
+ /* When an OP_Program opcode is encounter (the only opcode that has
+ ** a P4_SUBPROGRAM argument), expand the size of the array of subprograms
+ ** kept in p->aMem[9].z to hold the new program - assuming this subprogram
+ ** has not already been seen.
+ */
+ if( pSub!=0 && aOp[i].p4type==P4_SUBPROGRAM ){
+ int nByte = (nSub+1)*sizeof(SubProgram*);
+ int j;
+ for(j=0; j<nSub; j++){
+ if( apSub[j]==aOp[i].p4.pProgram ) break;
+ }
+ if( j==nSub ){
+ p->rc = sqlite3VdbeMemGrow(pSub, nByte, nSub!=0);
+ if( p->rc!=SQLITE_OK ){
+ rc = SQLITE_ERROR;
+ break;
+ }
+ apSub = (SubProgram **)pSub->z;
+ apSub[nSub++] = aOp[i].p4.pProgram;
+ MemSetTypeFlag(pSub, MEM_Blob);
+ pSub->n = nSub*sizeof(SubProgram*);
+ nRow += aOp[i].p4.pProgram->nOp;
+ }
+ }
+ if( eMode==0 ) break;
+#ifdef SQLITE_ENABLE_BYTECODE_VTAB
+ if( eMode==2 ){
+ Op *pOp = aOp + i;
+ if( pOp->opcode==OP_OpenRead ) break;
+ if( pOp->opcode==OP_OpenWrite && (pOp->p5 & OPFLAG_P2ISREG)==0 ) break;
+ if( pOp->opcode==OP_ReopenIdx ) break;
+ }else
+#endif
+ {
+ assert( eMode==1 );
+ if( aOp[i].opcode==OP_Explain ) break;
+ if( aOp[i].opcode==OP_Init && iPc>1 ) break;
+ }
+ }
+ *piPc = iPc;
+ *piAddr = i;
+ *paOp = aOp;
+ return rc;
+}
+#endif /* SQLITE_ENABLE_BYTECODE_VTAB || !SQLITE_OMIT_EXPLAIN */
+
/*
** Delete a VdbeFrame object and its contents. VdbeFrame objects are
@@ -1983,16 +2101,14 @@ void sqlite3VdbeFrameDelete(VdbeFrame *p){
int sqlite3VdbeList(
Vdbe *p /* The VDBE */
){
- int nRow; /* Stop when row count reaches this */
- int nSub = 0; /* Number of sub-vdbes seen so far */
- SubProgram **apSub = 0; /* Array of sub-vdbes */
Mem *pSub = 0; /* Memory cell hold array of subprogs */
sqlite3 *db = p->db; /* The database connection */
int i; /* Loop counter */
int rc = SQLITE_OK; /* Return code */
Mem *pMem = &p->aMem[1]; /* First Mem of result set */
int bListSubprogs = (p->explain==1 || (db->flags & SQLITE_TriggerEQP)!=0);
- Op *pOp = 0;
+ Op *aOp; /* Array of opcodes */
+ Op *pOp; /* Current opcode */
assert( p->explain );
assert( p->magic==VDBE_MAGIC_RUN );
@@ -2012,14 +2128,6 @@ int sqlite3VdbeList(
return SQLITE_ERROR;
}
- /* When the number of output rows reaches nRow, that means the
- ** listing has finished and sqlite3_step() should return SQLITE_DONE.
- ** nRow is the sum of the number of rows in the main program, plus
- ** the sum of the number of rows in all trigger subprograms encountered
- ** so far. The nRow value will increase as new trigger subprograms are
- ** encountered, but p->pc will eventually catch up to nRow.
- */
- nRow = p->nOp;
if( bListSubprogs ){
/* The first 8 memory cells are used for the result set. So we will
** commandeer the 9th cell to use as storage for an array of pointers
@@ -2027,147 +2135,55 @@ int sqlite3VdbeList(
** cells. */
assert( p->nMem>9 );
pSub = &p->aMem[9];
- if( pSub->flags&MEM_Blob ){
- /* On the first call to sqlite3_step(), pSub will hold a NULL. It is
- ** initialized to a BLOB by the P4_SUBPROGRAM processing logic below */
- nSub = pSub->n/sizeof(Vdbe*);
- apSub = (SubProgram **)pSub->z;
- }
- for(i=0; i<nSub; i++){
- nRow += apSub[i]->nOp;
- }
+ }else{
+ pSub = 0;
}
- while(1){ /* Loop exits via break */
- i = p->pc++;
- if( i>=nRow ){
- p->rc = SQLITE_OK;
- rc = SQLITE_DONE;
- break;
- }
- if( i<p->nOp ){
- /* The output line number is small enough that we are still in the
- ** main program. */
- pOp = &p->aOp[i];
- }else{
- /* We are currently listing subprograms. Figure out which one and
- ** pick up the appropriate opcode. */
- int j;
- i -= p->nOp;
- assert( apSub!=0 );
- assert( nSub>0 );
- for(j=0; i>=apSub[j]->nOp; j++){
- i -= apSub[j]->nOp;
- assert( i<apSub[j]->nOp || j+1<nSub );
- }
- pOp = &apSub[j]->aOp[i];
- }
-
- /* When an OP_Program opcode is encounter (the only opcode that has
- ** a P4_SUBPROGRAM argument), expand the size of the array of subprograms
- ** kept in p->aMem[9].z to hold the new program - assuming this subprogram
- ** has not already been seen.
- */
- if( bListSubprogs && pOp->p4type==P4_SUBPROGRAM ){
- int nByte = (nSub+1)*sizeof(SubProgram*);
- int j;
- for(j=0; j<nSub; j++){
- if( apSub[j]==pOp->p4.pProgram ) break;
- }
- if( j==nSub ){
- p->rc = sqlite3VdbeMemGrow(pSub, nByte, nSub!=0);
- if( p->rc!=SQLITE_OK ){
- rc = SQLITE_ERROR;
- break;
- }
- apSub = (SubProgram **)pSub->z;
- apSub[nSub++] = pOp->p4.pProgram;
- pSub->flags |= MEM_Blob;
- pSub->n = nSub*sizeof(SubProgram*);
- nRow += pOp->p4.pProgram->nOp;
- }
- }
- if( p->explain<2 ) break;
- if( pOp->opcode==OP_Explain ) break;
- if( pOp->opcode==OP_Init && p->pc>1 ) break;
- }
+ /* Figure out which opcode is next to display */
+ rc = sqlite3VdbeNextOpcode(p, pSub, p->explain==2, &p->pc, &i, &aOp);
if( rc==SQLITE_OK ){
+ pOp = aOp + i;
if( AtomicLoad(&db->u1.isInterrupted) ){
p->rc = SQLITE_INTERRUPT;
rc = SQLITE_ERROR;
sqlite3VdbeError(p, sqlite3ErrStr(p->rc));
}else{
- char *zP4;
- if( p->explain==1 ){
- pMem->flags = MEM_Int;
- pMem->u.i = i; /* Program counter */
- pMem++;
-
- pMem->flags = MEM_Static|MEM_Str|MEM_Term;
- pMem->z = (char*)sqlite3OpcodeName(pOp->opcode); /* Opcode */
- assert( pMem->z!=0 );
- pMem->n = sqlite3Strlen30(pMem->z);
- pMem->enc = SQLITE_UTF8;
- pMem++;
- }
-
- pMem->flags = MEM_Int;
- pMem->u.i = pOp->p1; /* P1 */
- pMem++;
-
- pMem->flags = MEM_Int;
- pMem->u.i = pOp->p2; /* P2 */
- pMem++;
-
- pMem->flags = MEM_Int;
- pMem->u.i = pOp->p3; /* P3 */
- pMem++;
-
- if( sqlite3VdbeMemClearAndResize(pMem, 100) ){ /* P4 */
- assert( p->db->mallocFailed );
- return SQLITE_ERROR;
- }
- pMem->flags = MEM_Str|MEM_Term;
- zP4 = displayP4(pOp, pMem->z, pMem->szMalloc);
- if( zP4!=pMem->z ){
- pMem->n = 0;
- sqlite3VdbeMemSetStr(pMem, zP4, -1, SQLITE_UTF8, 0);
+ char *zP4 = sqlite3VdbeDisplayP4(db, pOp);
+ if( p->explain==2 ){
+ sqlite3VdbeMemSetInt64(pMem, pOp->p1);
+ sqlite3VdbeMemSetInt64(pMem+1, pOp->p2);
+ sqlite3VdbeMemSetInt64(pMem+2, pOp->p3);
+ sqlite3VdbeMemSetStr(pMem+3, zP4, -1, SQLITE_UTF8, sqlite3_free);
+ p->nResColumn = 4;
}else{
- assert( pMem->z!=0 );
- pMem->n = sqlite3Strlen30(pMem->z);
- pMem->enc = SQLITE_UTF8;
- }
- pMem++;
-
- if( p->explain==1 ){
- if( sqlite3VdbeMemClearAndResize(pMem, 4) ){
- assert( p->db->mallocFailed );
- return SQLITE_ERROR;
- }
- pMem->flags = MEM_Str|MEM_Term;
- pMem->n = 2;
- sqlite3_snprintf(3, pMem->z, "%.2x", pOp->p5); /* P5 */
- pMem->enc = SQLITE_UTF8;
- pMem++;
-
+ sqlite3VdbeMemSetInt64(pMem+0, i);
+ sqlite3VdbeMemSetStr(pMem+1, (char*)sqlite3OpcodeName(pOp->opcode),
+ -1, SQLITE_UTF8, SQLITE_STATIC);
+ sqlite3VdbeMemSetInt64(pMem+2, pOp->p1);
+ sqlite3VdbeMemSetInt64(pMem+3, pOp->p2);
+ sqlite3VdbeMemSetInt64(pMem+4, pOp->p3);
+ /* pMem+5 for p4 is done last */
+ sqlite3VdbeMemSetInt64(pMem+6, pOp->p5);
#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
- if( sqlite3VdbeMemClearAndResize(pMem, 500) ){
- assert( p->db->mallocFailed );
- return SQLITE_ERROR;
+ {
+ char *zCom = sqlite3VdbeDisplayComment(db, pOp, zP4);
+ sqlite3VdbeMemSetStr(pMem+7, zCom, -1, SQLITE_UTF8, sqlite3_free);
}
- pMem->flags = MEM_Str|MEM_Term;
- pMem->n = displayComment(pOp, zP4, pMem->z, 500);
- pMem->enc = SQLITE_UTF8;
#else
- pMem->flags = MEM_Null; /* Comment */
+ sqlite3VdbeMemSetNull(pMem+7);
#endif
+ sqlite3VdbeMemSetStr(pMem+5, zP4, -1, SQLITE_UTF8, sqlite3_free);
+ p->nResColumn = 8;
+ }
+ p->pResultSet = pMem;
+ if( db->mallocFailed ){
+ p->rc = SQLITE_NOMEM;
+ rc = SQLITE_ERROR;
+ }else{
+ p->rc = SQLITE_OK;
+ rc = SQLITE_ROW;
}
-
- p->nResColumn = 8 - 4*(p->explain-1);
- p->pResultSet = &p->aMem[1];
- p->rc = SQLITE_OK;
- rc = SQLITE_ROW;
}
}
return rc;
@@ -2613,13 +2629,13 @@ int sqlite3VdbeSetColName(
** A read or write transaction may or may not be active on database handle
** db. If a transaction is active, commit it. If there is a
** write-transaction spanning more than one database file, this routine
-** takes care of the master journal trickery.
+** takes care of the super-journal trickery.
*/
static int vdbeCommit(sqlite3 *db, Vdbe *p){
int i;
int nTrans = 0; /* Number of databases with an active write-transaction
** that are candidates for a two-phase commit using a
- ** master-journal */
+ ** super-journal */
int rc = SQLITE_OK;
int needXcommit = 0;
@@ -2632,7 +2648,7 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
/* Before doing anything else, call the xSync() callback for any
** virtual module tables written in this transaction. This has to
- ** be done before determining whether a master journal file is
+ ** be done before determining whether a super-journal file is
** required, as an xSync() callback may add an attached database
** to the transaction.
*/
@@ -2641,15 +2657,15 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
/* This loop determines (a) if the commit hook should be invoked and
** (b) how many database files have open write transactions, not
** including the temp database. (b) is important because if more than
- ** one database file has an open write transaction, a master journal
+ ** one database file has an open write transaction, a super-journal
** file is required for an atomic commit.
*/
for(i=0; rc==SQLITE_OK && i<db->nDb; i++){
Btree *pBt = db->aDb[i].pBt;
if( sqlite3BtreeIsInTrans(pBt) ){
- /* Whether or not a database might need a master journal depends upon
+ /* Whether or not a database might need a super-journal depends upon
** its journal mode (among other things). This matrix determines which
- ** journal modes use a master journal and which do not */
+ ** journal modes use a super-journal and which do not */
static const u8 aMJNeeded[] = {
/* DELETE */ 1,
/* PERSIST */ 1,
@@ -2687,7 +2703,7 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
/* The simple case - no more than one database file (not counting the
** TEMP database) has a transaction active. There is no need for the
- ** master-journal.
+ ** super-journal.
**
** If the return value of sqlite3BtreeGetFilename() is a zero length
** string, it means the main database is :memory: or a temp file. In
@@ -2721,61 +2737,62 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
}
/* The complex case - There is a multi-file write-transaction active.
- ** This requires a master journal file to ensure the transaction is
+ ** This requires a super-journal file to ensure the transaction is
** committed atomically.
*/
#ifndef SQLITE_OMIT_DISKIO
else{
sqlite3_vfs *pVfs = db->pVfs;
- char *zMaster = 0; /* File-name for the master journal */
+ char *zSuper = 0; /* File-name for the super-journal */
char const *zMainFile = sqlite3BtreeGetFilename(db->aDb[0].pBt);
- sqlite3_file *pMaster = 0;
+ sqlite3_file *pSuperJrnl = 0;
i64 offset = 0;
int res;
int retryCount = 0;
int nMainFile;
- /* Select a master journal file name */
+ /* Select a super-journal file name */
nMainFile = sqlite3Strlen30(zMainFile);
- zMaster = sqlite3MPrintf(db, "%s-mjXXXXXX9XXz%c%c", zMainFile, 0, 0);
- if( zMaster==0 ) return SQLITE_NOMEM_BKPT;
+ zSuper = sqlite3MPrintf(db, "%.4c%s%.16c", 0,zMainFile,0);
+ if( zSuper==0 ) return SQLITE_NOMEM_BKPT;
+ zSuper += 4;
do {
u32 iRandom;
if( retryCount ){
if( retryCount>100 ){
- sqlite3_log(SQLITE_FULL, "MJ delete: %s", zMaster);
- sqlite3OsDelete(pVfs, zMaster, 0);
+ sqlite3_log(SQLITE_FULL, "MJ delete: %s", zSuper);
+ sqlite3OsDelete(pVfs, zSuper, 0);
break;
}else if( retryCount==1 ){
- sqlite3_log(SQLITE_FULL, "MJ collide: %s", zMaster);
+ sqlite3_log(SQLITE_FULL, "MJ collide: %s", zSuper);
}
}
retryCount++;
sqlite3_randomness(sizeof(iRandom), &iRandom);
- sqlite3_snprintf(13, &zMaster[nMainFile], "-mj%06X9%02X",
+ sqlite3_snprintf(13, &zSuper[nMainFile], "-mj%06X9%02X",
(iRandom>>8)&0xffffff, iRandom&0xff);
- /* The antipenultimate character of the master journal name must
+ /* The antipenultimate character of the super-journal name must
** be "9" to avoid name collisions when using 8+3 filenames. */
- assert( zMaster[sqlite3Strlen30(zMaster)-3]=='9' );
- sqlite3FileSuffix3(zMainFile, zMaster);
- rc = sqlite3OsAccess(pVfs, zMaster, SQLITE_ACCESS_EXISTS, &res);
+ assert( zSuper[sqlite3Strlen30(zSuper)-3]=='9' );
+ sqlite3FileSuffix3(zMainFile, zSuper);
+ rc = sqlite3OsAccess(pVfs, zSuper, SQLITE_ACCESS_EXISTS, &res);
}while( rc==SQLITE_OK && res );
if( rc==SQLITE_OK ){
- /* Open the master journal. */
- rc = sqlite3OsOpenMalloc(pVfs, zMaster, &pMaster,
+ /* Open the super-journal. */
+ rc = sqlite3OsOpenMalloc(pVfs, zSuper, &pSuperJrnl,
SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|
- SQLITE_OPEN_EXCLUSIVE|SQLITE_OPEN_MASTER_JOURNAL, 0
+ SQLITE_OPEN_EXCLUSIVE|SQLITE_OPEN_SUPER_JOURNAL, 0
);
}
if( rc!=SQLITE_OK ){
- sqlite3DbFree(db, zMaster);
+ sqlite3DbFree(db, zSuper-4);
return rc;
}
/* Write the name of each database file in the transaction into the new
- ** master journal file. If an error occurs at this point close
- ** and delete the master journal file. All the individual journal files
- ** still have 'null' as the master journal pointer, so they will roll
+ ** super-journal file. If an error occurs at this point close
+ ** and delete the super-journal file. All the individual journal files
+ ** still have 'null' as the super-journal pointer, so they will roll
** back independently if a failure occurs.
*/
for(i=0; i<db->nDb; i++){
@@ -2786,59 +2803,59 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
continue; /* Ignore TEMP and :memory: databases */
}
assert( zFile[0]!=0 );
- rc = sqlite3OsWrite(pMaster, zFile, sqlite3Strlen30(zFile)+1, offset);
+ rc = sqlite3OsWrite(pSuperJrnl, zFile, sqlite3Strlen30(zFile)+1,offset);
offset += sqlite3Strlen30(zFile)+1;
if( rc!=SQLITE_OK ){
- sqlite3OsCloseFree(pMaster);
- sqlite3OsDelete(pVfs, zMaster, 0);
- sqlite3DbFree(db, zMaster);
+ sqlite3OsCloseFree(pSuperJrnl);
+ sqlite3OsDelete(pVfs, zSuper, 0);
+ sqlite3DbFree(db, zSuper-4);
return rc;
}
}
}
- /* Sync the master journal file. If the IOCAP_SEQUENTIAL device
+ /* Sync the super-journal file. If the IOCAP_SEQUENTIAL device
** flag is set this is not required.
*/
- if( 0==(sqlite3OsDeviceCharacteristics(pMaster)&SQLITE_IOCAP_SEQUENTIAL)
- && SQLITE_OK!=(rc = sqlite3OsSync(pMaster, SQLITE_SYNC_NORMAL))
+ if( 0==(sqlite3OsDeviceCharacteristics(pSuperJrnl)&SQLITE_IOCAP_SEQUENTIAL)
+ && SQLITE_OK!=(rc = sqlite3OsSync(pSuperJrnl, SQLITE_SYNC_NORMAL))
){
- sqlite3OsCloseFree(pMaster);
- sqlite3OsDelete(pVfs, zMaster, 0);
- sqlite3DbFree(db, zMaster);
+ sqlite3OsCloseFree(pSuperJrnl);
+ sqlite3OsDelete(pVfs, zSuper, 0);
+ sqlite3DbFree(db, zSuper-4);
return rc;
}
/* Sync all the db files involved in the transaction. The same call
- ** sets the master journal pointer in each individual journal. If
- ** an error occurs here, do not delete the master journal file.
+ ** sets the super-journal pointer in each individual journal. If
+ ** an error occurs here, do not delete the super-journal file.
**
** If the error occurs during the first call to
** sqlite3BtreeCommitPhaseOne(), then there is a chance that the
- ** master journal file will be orphaned. But we cannot delete it,
- ** in case the master journal file name was written into the journal
+ ** super-journal file will be orphaned. But we cannot delete it,
+ ** in case the super-journal file name was written into the journal
** file before the failure occurred.
*/
for(i=0; rc==SQLITE_OK && i<db->nDb; i++){
Btree *pBt = db->aDb[i].pBt;
if( pBt ){
- rc = sqlite3BtreeCommitPhaseOne(pBt, zMaster);
+ rc = sqlite3BtreeCommitPhaseOne(pBt, zSuper);
}
}
- sqlite3OsCloseFree(pMaster);
+ sqlite3OsCloseFree(pSuperJrnl);
assert( rc!=SQLITE_BUSY );
if( rc!=SQLITE_OK ){
- sqlite3DbFree(db, zMaster);
+ sqlite3DbFree(db, zSuper-4);
return rc;
}
- /* Delete the master journal file. This commits the transaction. After
+ /* Delete the super-journal file. This commits the transaction. After
** doing this the directory is synced again before any individual
** transaction files are deleted.
*/
- rc = sqlite3OsDelete(pVfs, zMaster, 1);
- sqlite3DbFree(db, zMaster);
- zMaster = 0;
+ rc = sqlite3OsDelete(pVfs, zSuper, 1);
+ sqlite3DbFree(db, zSuper-4);
+ zSuper = 0;
if( rc ){
return rc;
}
@@ -3285,7 +3302,11 @@ int sqlite3VdbeReset(Vdbe *p){
*/
if( p->pc>=0 ){
vdbeInvokeSqllog(p);
- sqlite3VdbeTransferError(p);
+ if( db->pErr || p->zErrMsg ){
+ sqlite3VdbeTransferError(p);
+ }else{
+ db->errCode = p->rc;
+ }
if( p->runOnlyOnce ) p->expired = 1;
}else if( p->rc && p->expired ){
/* The expired flag was set on the VDBE before the first call
@@ -3305,8 +3326,10 @@ int sqlite3VdbeReset(Vdbe *p){
for(i=0; i<p->nMem; i++) assert( p->aMem[i].flags==MEM_Undefined );
}
#endif
- sqlite3DbFree(db, p->zErrMsg);
- p->zErrMsg = 0;
+ if( p->zErrMsg ){
+ sqlite3DbFree(db, p->zErrMsg);
+ p->zErrMsg = 0;
+ }
p->pResultSet = 0;
#ifdef SQLITE_DEBUG
p->nWrite = 0;
diff --git a/src/vdbevtab.c b/src/vdbevtab.c
new file mode 100644
index 000000000..2fbee6257
--- /dev/null
+++ b/src/vdbevtab.c
@@ -0,0 +1,424 @@
+/*
+** 2020-03-23
+**
+** The author disclaims copyright to this source code. In place of
+** a legal notice, here is a blessing:
+**
+** May you do good and not evil.
+** May you find forgiveness for yourself and forgive others.
+** May you share freely, never taking more than you give.
+**
+*************************************************************************
+**
+** This file implements virtual-tables for examining the bytecode content
+** of a prepared statement.
+*/
+#include "sqliteInt.h"
+#if defined(SQLITE_ENABLE_BYTECODE_VTAB) && !defined(SQLITE_OMIT_VIRTUALTABLE)
+#include "vdbeInt.h"
+
+/* An instance of the bytecode() table-valued function.
+*/
+typedef struct bytecodevtab bytecodevtab;
+struct bytecodevtab {
+ sqlite3_vtab base; /* Base class - must be first */
+ sqlite3 *db; /* Database connection */
+ int bTablesUsed; /* 2 for tables_used(). 0 for bytecode(). */
+};
+
+/* A cursor for scanning through the bytecode
+*/
+typedef struct bytecodevtab_cursor bytecodevtab_cursor;
+struct bytecodevtab_cursor {
+ sqlite3_vtab_cursor base; /* Base class - must be first */
+ sqlite3_stmt *pStmt; /* The statement whose bytecode is displayed */
+ int iRowid; /* The rowid of the output table */
+ int iAddr; /* Address */
+ int needFinalize; /* Cursors owns pStmt and must finalize it */
+ int showSubprograms; /* Provide a listing of subprograms */
+ Op *aOp; /* Operand array */
+ char *zP4; /* Rendered P4 value */
+ const char *zType; /* tables_used.type */
+ const char *zSchema; /* tables_used.schema */
+ const char *zName; /* tables_used.name */
+ Mem sub; /* Subprograms */
+};
+
+/*
+** Create a new bytecode() table-valued function.
+*/
+static int bytecodevtabConnect(
+ sqlite3 *db,
+ void *pAux,
+ int argc, const char *const*argv,
+ sqlite3_vtab **ppVtab,
+ char **pzErr
+){
+ bytecodevtab *pNew;
+ int rc;
+ int isTabUsed = pAux!=0;
+ const char *azSchema[2] = {
+ /* bytecode() schema */
+ "CREATE TABLE x("
+ "addr INT,"
+ "opcode TEXT,"
+ "p1 INT,"
+ "p2 INT,"
+ "p3 INT,"
+ "p4 TEXT,"
+ "p5 INT,"
+ "comment TEXT,"
+ "subprog TEXT,"
+ "stmt HIDDEN"
+ ");",
+
+ /* Tables_used() schema */
+ "CREATE TABLE x("
+ "type TEXT,"
+ "schema TEXT,"
+ "name TEXT,"
+ "wr INT,"
+ "subprog TEXT,"
+ "stmt HIDDEN"
+ ");"
+ };
+
+ rc = sqlite3_declare_vtab(db, azSchema[isTabUsed]);
+ 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;
+ pNew->bTablesUsed = isTabUsed*2;
+ }
+ return rc;
+}
+
+/*
+** This method is the destructor for bytecodevtab objects.
+*/
+static int bytecodevtabDisconnect(sqlite3_vtab *pVtab){
+ bytecodevtab *p = (bytecodevtab*)pVtab;
+ sqlite3_free(p);
+ return SQLITE_OK;
+}
+
+/*
+** Constructor for a new bytecodevtab_cursor object.
+*/
+static int bytecodevtabOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
+ bytecodevtab *pVTab = (bytecodevtab*)p;
+ bytecodevtab_cursor *pCur;
+ pCur = sqlite3_malloc( sizeof(*pCur) );
+ if( pCur==0 ) return SQLITE_NOMEM;
+ memset(pCur, 0, sizeof(*pCur));
+ sqlite3VdbeMemInit(&pCur->sub, pVTab->db, 1);
+ *ppCursor = &pCur->base;
+ return SQLITE_OK;
+}
+
+/*
+** Clear all internal content from a bytecodevtab cursor.
+*/
+static void bytecodevtabCursorClear(bytecodevtab_cursor *pCur){
+ sqlite3_free(pCur->zP4);
+ pCur->zP4 = 0;
+ sqlite3VdbeMemRelease(&pCur->sub);
+ sqlite3VdbeMemSetNull(&pCur->sub);
+ if( pCur->needFinalize ){
+ sqlite3_finalize(pCur->pStmt);
+ }
+ pCur->pStmt = 0;
+ pCur->needFinalize = 0;
+ pCur->zType = 0;
+ pCur->zSchema = 0;
+ pCur->zName = 0;
+}
+
+/*
+** Destructor for a bytecodevtab_cursor.
+*/
+static int bytecodevtabClose(sqlite3_vtab_cursor *cur){
+ bytecodevtab_cursor *pCur = (bytecodevtab_cursor*)cur;
+ bytecodevtabCursorClear(pCur);
+ sqlite3_free(pCur);
+ return SQLITE_OK;
+}
+
+
+/*
+** Advance a bytecodevtab_cursor to its next row of output.
+*/
+static int bytecodevtabNext(sqlite3_vtab_cursor *cur){
+ bytecodevtab_cursor *pCur = (bytecodevtab_cursor*)cur;
+ bytecodevtab *pTab = (bytecodevtab*)cur->pVtab;
+ int rc;
+ if( pCur->zP4 ){
+ sqlite3_free(pCur->zP4);
+ pCur->zP4 = 0;
+ }
+ if( pCur->zName ){
+ pCur->zName = 0;
+ pCur->zType = 0;
+ pCur->zSchema = 0;
+ }
+ rc = sqlite3VdbeNextOpcode(
+ (Vdbe*)pCur->pStmt,
+ pCur->showSubprograms ? &pCur->sub : 0,
+ pTab->bTablesUsed,
+ &pCur->iRowid,
+ &pCur->iAddr,
+ &pCur->aOp);
+ if( rc!=SQLITE_OK ){
+ sqlite3VdbeMemSetNull(&pCur->sub);
+ pCur->aOp = 0;
+ }
+ return SQLITE_OK;
+}
+
+/*
+** Return TRUE if the cursor has been moved off of the last
+** row of output.
+*/
+static int bytecodevtabEof(sqlite3_vtab_cursor *cur){
+ bytecodevtab_cursor *pCur = (bytecodevtab_cursor*)cur;
+ return pCur->aOp==0;
+}
+
+/*
+** Return values of columns for the row at which the bytecodevtab_cursor
+** is currently pointing.
+*/
+static int bytecodevtabColumn(
+ sqlite3_vtab_cursor *cur, /* The cursor */
+ sqlite3_context *ctx, /* First argument to sqlite3_result_...() */
+ int i /* Which column to return */
+){
+ bytecodevtab_cursor *pCur = (bytecodevtab_cursor*)cur;
+ bytecodevtab *pVTab = (bytecodevtab*)cur->pVtab;
+ Op *pOp = pCur->aOp + pCur->iAddr;
+ if( pVTab->bTablesUsed ){
+ if( i==4 ){
+ i = 8;
+ }else{
+ if( i<=2 && pCur->zType==0 ){
+ Schema *pSchema;
+ HashElem *k;
+ int iDb = pOp->p3;
+ int iRoot = pOp->p2;
+ sqlite3 *db = pVTab->db;
+ pSchema = db->aDb[iDb].pSchema;
+ pCur->zSchema = db->aDb[iDb].zDbSName;
+ for(k=sqliteHashFirst(&pSchema->tblHash); k; k=sqliteHashNext(k)){
+ Table *pTab = (Table*)sqliteHashData(k);
+ if( !IsVirtual(pTab) && pTab->tnum==iRoot ){
+ pCur->zName = pTab->zName;
+ pCur->zType = "table";
+ break;
+ }
+ }
+ if( pCur->zName==0 ){
+ for(k=sqliteHashFirst(&pSchema->idxHash); k; k=sqliteHashNext(k)){
+ Index *pIdx = (Index*)sqliteHashData(k);
+ if( pIdx->tnum==iRoot ){
+ pCur->zName = pIdx->zName;
+ pCur->zType = "index";
+ }
+ }
+ }
+ }
+ i += 10;
+ }
+ }
+ switch( i ){
+ case 0: /* addr */
+ sqlite3_result_int(ctx, pCur->iAddr);
+ break;
+ case 1: /* opcode */
+ sqlite3_result_text(ctx, (char*)sqlite3OpcodeName(pOp->opcode),
+ -1, SQLITE_STATIC);
+ break;
+ case 2: /* p1 */
+ sqlite3_result_int(ctx, pOp->p1);
+ break;
+ case 3: /* p2 */
+ sqlite3_result_int(ctx, pOp->p2);
+ break;
+ case 4: /* p3 */
+ sqlite3_result_int(ctx, pOp->p3);
+ break;
+ case 5: /* p4 */
+ case 7: /* comment */
+ if( pCur->zP4==0 ){
+ pCur->zP4 = sqlite3VdbeDisplayP4(pVTab->db, pOp);
+ }
+ if( i==5 ){
+ sqlite3_result_text(ctx, pCur->zP4, -1, SQLITE_STATIC);
+ }else{
+#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
+ char *zCom = sqlite3VdbeDisplayComment(pVTab->db, pOp, pCur->zP4);
+ sqlite3_result_text(ctx, zCom, -1, sqlite3_free);
+#endif
+ }
+ break;
+ case 6: /* p5 */
+ sqlite3_result_int(ctx, pOp->p5);
+ break;
+ case 8: { /* subprog */
+ Op *aOp = pCur->aOp;
+ assert( aOp[0].opcode==OP_Init );
+ assert( aOp[0].p4.z==0 || strncmp(aOp[0].p4.z,"-" "- ",3)==0 );
+ if( pCur->iRowid==pCur->iAddr+1 ){
+ break; /* Result is NULL for the main program */
+ }else if( aOp[0].p4.z!=0 ){
+ sqlite3_result_text(ctx, aOp[0].p4.z+3, -1, SQLITE_STATIC);
+ }else{
+ sqlite3_result_text(ctx, "(FK)", 4, SQLITE_STATIC);
+ }
+ break;
+ }
+ case 10: /* tables_used.type */
+ sqlite3_result_text(ctx, pCur->zType, -1, SQLITE_STATIC);
+ break;
+ case 11: /* tables_used.schema */
+ sqlite3_result_text(ctx, pCur->zSchema, -1, SQLITE_STATIC);
+ break;
+ case 12: /* tables_used.name */
+ sqlite3_result_text(ctx, pCur->zName, -1, SQLITE_STATIC);
+ break;
+ case 13: /* tables_used.wr */
+ sqlite3_result_int(ctx, pOp->opcode==OP_OpenWrite);
+ 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 bytecodevtabRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
+ bytecodevtab_cursor *pCur = (bytecodevtab_cursor*)cur;
+ *pRowid = pCur->iRowid;
+ return SQLITE_OK;
+}
+
+/*
+** Initialize a cursor.
+**
+** idxNum==0 means show all subprograms
+** idxNum==1 means show only the main bytecode and omit subprograms.
+*/
+static int bytecodevtabFilter(
+ sqlite3_vtab_cursor *pVtabCursor,
+ int idxNum, const char *idxStr,
+ int argc, sqlite3_value **argv
+){
+ bytecodevtab_cursor *pCur = (bytecodevtab_cursor *)pVtabCursor;
+ bytecodevtab *pVTab = (bytecodevtab *)pVtabCursor->pVtab;
+ int rc = SQLITE_OK;
+
+ bytecodevtabCursorClear(pCur);
+ pCur->iRowid = 0;
+ pCur->iAddr = 0;
+ pCur->showSubprograms = idxNum==0;
+ assert( argc==1 );
+ if( sqlite3_value_type(argv[0])==SQLITE_TEXT ){
+ const char *zSql = (const char*)sqlite3_value_text(argv[0]);
+ if( zSql==0 ){
+ rc = SQLITE_NOMEM;
+ }else{
+ rc = sqlite3_prepare_v2(pVTab->db, zSql, -1, &pCur->pStmt, 0);
+ pCur->needFinalize = 1;
+ }
+ }else{
+ pCur->pStmt = (sqlite3_stmt*)sqlite3_value_pointer(argv[0],"stmt-pointer");
+ }
+ if( pCur->pStmt==0 ){
+ pVTab->base.zErrMsg = sqlite3_mprintf(
+ "argument to %s() is not a valid SQL statement",
+ pVTab->bTablesUsed ? "tables_used" : "bytecode"
+ );
+ rc = SQLITE_ERROR;
+ }else{
+ bytecodevtabNext(pVtabCursor);
+ }
+ return rc;
+}
+
+/*
+** We must have a single stmt=? constraint that will be passed through
+** into the xFilter method. If there is no valid stmt=? constraint,
+** then return an SQLITE_CONSTRAINT error.
+*/
+static int bytecodevtabBestIndex(
+ sqlite3_vtab *tab,
+ sqlite3_index_info *pIdxInfo
+){
+ int i;
+ int rc = SQLITE_CONSTRAINT;
+ struct sqlite3_index_constraint *p;
+ bytecodevtab *pVTab = (bytecodevtab*)tab;
+ int iBaseCol = pVTab->bTablesUsed ? 4 : 8;
+ pIdxInfo->estimatedCost = (double)100;
+ pIdxInfo->estimatedRows = 100;
+ pIdxInfo->idxNum = 0;
+ for(i=0, p=pIdxInfo->aConstraint; i<pIdxInfo->nConstraint; i++, p++){
+ if( p->usable==0 ) continue;
+ if( p->op==SQLITE_INDEX_CONSTRAINT_EQ && p->iColumn==iBaseCol+1 ){
+ rc = SQLITE_OK;
+ pIdxInfo->aConstraintUsage[i].omit = 1;
+ pIdxInfo->aConstraintUsage[i].argvIndex = 1;
+ }
+ if( p->op==SQLITE_INDEX_CONSTRAINT_ISNULL && p->iColumn==iBaseCol ){
+ pIdxInfo->aConstraintUsage[i].omit = 1;
+ pIdxInfo->idxNum = 1;
+ }
+ }
+ return rc;
+}
+
+/*
+** This following structure defines all the methods for the
+** virtual table.
+*/
+static sqlite3_module bytecodevtabModule = {
+ /* iVersion */ 0,
+ /* xCreate */ 0,
+ /* xConnect */ bytecodevtabConnect,
+ /* xBestIndex */ bytecodevtabBestIndex,
+ /* xDisconnect */ bytecodevtabDisconnect,
+ /* xDestroy */ 0,
+ /* xOpen */ bytecodevtabOpen,
+ /* xClose */ bytecodevtabClose,
+ /* xFilter */ bytecodevtabFilter,
+ /* xNext */ bytecodevtabNext,
+ /* xEof */ bytecodevtabEof,
+ /* xColumn */ bytecodevtabColumn,
+ /* xRowid */ bytecodevtabRowid,
+ /* xUpdate */ 0,
+ /* xBegin */ 0,
+ /* xSync */ 0,
+ /* xCommit */ 0,
+ /* xRollback */ 0,
+ /* xFindMethod */ 0,
+ /* xRename */ 0,
+ /* xSavepoint */ 0,
+ /* xRelease */ 0,
+ /* xRollbackTo */ 0,
+ /* xShadowName */ 0
+};
+
+
+int sqlite3VdbeBytecodeVtabInit(sqlite3 *db){
+ int rc;
+ rc = sqlite3_create_module(db, "bytecode", &bytecodevtabModule, 0);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_create_module(db, "tables_used", &bytecodevtabModule, &db);
+ }
+ return rc;
+}
+#elif defined(SQLITE_ENABLE_BYTECODE_VTAB)
+int sqlite3VdbeBytecodeVtabInit(sqlite3 *db){ return SQLITE_OK; }
+#endif /* SQLITE_ENABLE_BYTECODE_VTAB */
diff --git a/src/vtab.c b/src/vtab.c
index 013511cfb..b2c01f2fa 100644
--- a/src/vtab.c
+++ b/src/vtab.c
@@ -405,7 +405,7 @@ void sqlite3VtabBeginParse(
#ifndef SQLITE_OMIT_AUTHORIZATION
/* Creating a virtual table invokes the authorization callback twice.
** The first invocation, to obtain permission to INSERT a row into the
- ** sqlite_master table, has already been made by sqlite3StartTable().
+ ** sqlite_schema table, has already been made by sqlite3StartTable().
** The second call, to obtain permission to create the table, is made now.
*/
if( pTable->azModuleArg ){
@@ -446,9 +446,9 @@ void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){
/* If the CREATE VIRTUAL TABLE statement is being entered for the
** first time (in other words if the virtual table is actually being
- ** created now instead of just being read out of sqlite_master) then
+ ** created now instead of just being read out of sqlite_schema) then
** do additional initialization work and store the statement text
- ** in the sqlite_master table.
+ ** in the sqlite_schema table.
*/
if( !db->init.busy ){
char *zStmt;
@@ -466,19 +466,19 @@ void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){
zStmt = sqlite3MPrintf(db, "CREATE VIRTUAL TABLE %T", &pParse->sNameToken);
/* A slot for the record has already been allocated in the
- ** SQLITE_MASTER table. We just need to update that slot with all
+ ** schema table. We just need to update that slot with all
** the information we've collected.
**
** The VM register number pParse->regRowid holds the rowid of an
- ** entry in the sqlite_master table tht was created for this vtab
+ ** entry in the sqlite_schema table tht was created for this vtab
** by sqlite3StartTable().
*/
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
sqlite3NestedParse(pParse,
- "UPDATE %Q.%s "
+ "UPDATE %Q." DFLT_SCHEMA_TABLE " "
"SET type='table', name=%Q, tbl_name=%Q, rootpage=0, sql=%Q "
"WHERE rowid=#%d",
- db->aDb[iDb].zDbSName, MASTER_NAME,
+ db->aDb[iDb].zDbSName,
pTab->zName,
pTab->zName,
zStmt,
@@ -497,7 +497,7 @@ void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){
sqlite3VdbeAddOp2(v, OP_VCreate, iDb, iReg);
}
- /* If we are rereading the sqlite_master table create the in-memory
+ /* If we are rereading the sqlite_schema table create the in-memory
** record of the table. The xConnect() method is not called until
** the first time the virtual table is used in an SQL statement. This
** allows a schema that contains virtual tables to be loaded before
@@ -1177,7 +1177,7 @@ void sqlite3VtabMakeWritable(Parse *pParse, Table *pTab){
if( pTab==pToplevel->apVtabLock[i] ) return;
}
n = (pToplevel->nVtabLock+1)*sizeof(pToplevel->apVtabLock[0]);
- apVtabLock = sqlite3_realloc64(pToplevel->apVtabLock, n);
+ apVtabLock = sqlite3Realloc(pToplevel->apVtabLock, n);
if( apVtabLock ){
pToplevel->apVtabLock = apVtabLock;
pToplevel->apVtabLock[pToplevel->nVtabLock++] = pTab;
diff --git a/src/wal.c b/src/wal.c
index 3e4f4acfd..c6d4476e7 100644
--- a/src/wal.c
+++ b/src/wal.c
@@ -467,6 +467,9 @@ struct Wal {
#ifdef SQLITE_ENABLE_SNAPSHOT
WalIndexHdr *pSnapshot; /* Start transaction here if not NULL */
#endif
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+ sqlite3 *db;
+#endif
};
/*
@@ -565,7 +568,7 @@ static SQLITE_NOINLINE int walIndexPageRealloc(
if( pWal->nWiData<=iPage ){
sqlite3_int64 nByte = sizeof(u32*)*(iPage+1);
volatile u32 **apNew;
- apNew = (volatile u32 **)sqlite3_realloc64((void *)pWal->apWiData, nByte);
+ apNew = (volatile u32 **)sqlite3Realloc((void *)pWal->apWiData, nByte);
if( !apNew ){
*ppPage = 0;
return SQLITE_NOMEM_BKPT;
@@ -686,6 +689,10 @@ static void walChecksumBytes(
aOut[1] = s2;
}
+/*
+** If there is the possibility of concurrent access to the SHM file
+** from multiple threads and/or processes, then do a memory barrier.
+*/
static void walShmBarrier(Wal *pWal){
if( pWal->exclusiveMode!=WAL_HEAPMEMORY_MODE ){
sqlite3OsShmBarrier(pWal->pDbFd);
@@ -693,11 +700,24 @@ static void walShmBarrier(Wal *pWal){
}
/*
+** Add the SQLITE_NO_TSAN as part of the return-type of a function
+** definition as a hint that the function contains constructs that
+** might give false-positive TSAN warnings.
+**
+** See tag-20200519-1.
+*/
+#if defined(__clang__) && !defined(SQLITE_NO_TSAN)
+# define SQLITE_NO_TSAN __attribute__((no_sanitize_thread))
+#else
+# define SQLITE_NO_TSAN
+#endif
+
+/*
** Write the header information in pWal->hdr into the wal-index.
**
** The checksum on pWal->hdr is updated before it is written.
*/
-static void walIndexWriteHdr(Wal *pWal){
+static SQLITE_NO_TSAN void walIndexWriteHdr(Wal *pWal){
volatile WalIndexHdr *aHdr = walIndexHdr(pWal);
const int nCksum = offsetof(WalIndexHdr, aCksum);
@@ -705,6 +725,7 @@ static void walIndexWriteHdr(Wal *pWal){
pWal->hdr.isInit = 1;
pWal->hdr.iVersion = WALINDEX_MAX_VERSION;
walChecksumBytes(1, (u8*)&pWal->hdr, nCksum, 0, pWal->hdr.aCksum);
+ /* Possible TSAN false-positive. See tag-20200519-1 */
memcpy((void*)&aHdr[1], (const void*)&pWal->hdr, sizeof(WalIndexHdr));
walShmBarrier(pWal);
memcpy((void*)&aHdr[0], (const void*)&pWal->hdr, sizeof(WalIndexHdr));
@@ -840,7 +861,7 @@ static int walLockShared(Wal *pWal, int lockIdx){
SQLITE_SHM_LOCK | SQLITE_SHM_SHARED);
WALTRACE(("WAL%p: acquire SHARED-%s %s\n", pWal,
walLockName(lockIdx), rc ? "failed" : "ok"));
- VVA_ONLY( pWal->lockError = (u8)(rc!=SQLITE_OK && rc!=SQLITE_BUSY); )
+ VVA_ONLY( pWal->lockError = (u8)(rc!=SQLITE_OK && (rc&0xFF)!=SQLITE_BUSY); )
return rc;
}
static void walUnlockShared(Wal *pWal, int lockIdx){
@@ -856,7 +877,7 @@ static int walLockExclusive(Wal *pWal, int lockIdx, int n){
SQLITE_SHM_LOCK | SQLITE_SHM_EXCLUSIVE);
WALTRACE(("WAL%p: acquire EXCLUSIVE-%s cnt=%d %s\n", pWal,
walLockName(lockIdx), n, rc ? "failed" : "ok"));
- VVA_ONLY( pWal->lockError = (u8)(rc!=SQLITE_OK && rc!=SQLITE_BUSY); )
+ VVA_ONLY( pWal->lockError = (u8)(rc!=SQLITE_OK && (rc&0xFF)!=SQLITE_BUSY); )
return rc;
}
static void walUnlockExclusive(Wal *pWal, int lockIdx, int n){
@@ -1075,7 +1096,7 @@ static int walIndexAppend(Wal *pWal, u32 iFrame, u32 iPage){
if( (nCollide--)==0 ) return SQLITE_CORRUPT_BKPT;
}
sLoc.aPgno[idx] = iPage;
- sLoc.aHash[iKey] = (ht_slot)idx;
+ AtomicStore(&sLoc.aHash[iKey], (ht_slot)idx);
#ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT
/* Verify that the number of entries in the hash table exactly equals
@@ -1128,11 +1149,6 @@ static int walIndexRecover(Wal *pWal){
u32 aFrameCksum[2] = {0, 0};
int iLock; /* Lock offset to lock for checkpoint */
-#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
- int tmout = 0;
- sqlite3OsFileControl(pWal->pDbFd, SQLITE_FCNTL_LOCK_TIMEOUT, (void*)&tmout);
-#endif
-
/* Obtain an exclusive lock on all byte in the locking range not already
** locked by the caller. The caller is guaranteed to have locked the
** WAL_WRITE_LOCK byte, and may have also locked the WAL_CKPT_LOCK byte.
@@ -1681,6 +1697,89 @@ static int walIteratorInit(Wal *pWal, u32 nBackfill, WalIterator **pp){
return rc;
}
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+/*
+** Attempt to enable blocking locks. Blocking locks are enabled only if (a)
+** they are supported by the VFS, and (b) the database handle is configured
+** with a busy-timeout. Return 1 if blocking locks are successfully enabled,
+** or 0 otherwise.
+*/
+static int walEnableBlocking(Wal *pWal){
+ int res = 0;
+ if( pWal->db ){
+ int tmout = pWal->db->busyTimeout;
+ if( tmout ){
+ int rc;
+ rc = sqlite3OsFileControl(
+ pWal->pDbFd, SQLITE_FCNTL_LOCK_TIMEOUT, (void*)&tmout
+ );
+ res = (rc==SQLITE_OK);
+ }
+ }
+ return res;
+}
+
+/*
+** Disable blocking locks.
+*/
+static void walDisableBlocking(Wal *pWal){
+ int tmout = 0;
+ sqlite3OsFileControl(pWal->pDbFd, SQLITE_FCNTL_LOCK_TIMEOUT, (void*)&tmout);
+}
+
+/*
+** If parameter bLock is true, attempt to enable blocking locks, take
+** the WRITER lock, and then disable blocking locks. If blocking locks
+** cannot be enabled, no attempt to obtain the WRITER lock is made. Return
+** an SQLite error code if an error occurs, or SQLITE_OK otherwise. It is not
+** an error if blocking locks can not be enabled.
+**
+** If the bLock parameter is false and the WRITER lock is held, release it.
+*/
+int sqlite3WalWriteLock(Wal *pWal, int bLock){
+ int rc = SQLITE_OK;
+ assert( pWal->readLock<0 || bLock==0 );
+ if( bLock ){
+ assert( pWal->db );
+ if( walEnableBlocking(pWal) ){
+ rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1);
+ if( rc==SQLITE_OK ){
+ pWal->writeLock = 1;
+ }
+ walDisableBlocking(pWal);
+ }
+ }else if( pWal->writeLock ){
+ walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1);
+ pWal->writeLock = 0;
+ }
+ return rc;
+}
+
+/*
+** Set the database handle used to determine if blocking locks are required.
+*/
+void sqlite3WalDb(Wal *pWal, sqlite3 *db){
+ pWal->db = db;
+}
+
+/*
+** Take an exclusive WRITE lock. Blocking if so configured.
+*/
+static int walLockWriter(Wal *pWal){
+ int rc;
+ walEnableBlocking(pWal);
+ rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1);
+ walDisableBlocking(pWal);
+ return rc;
+}
+#else
+# define walEnableBlocking(x) 0
+# define walDisableBlocking(x)
+# define walLockWriter(pWal) walLockExclusive((pWal), WAL_WRITE_LOCK, 1)
+# define sqlite3WalDb(pWal, db)
+#endif /* ifdef SQLITE_ENABLE_SETLK_TIMEOUT */
+
+
/*
** Attempt to obtain the exclusive WAL lock defined by parameters lockIdx and
** n. If the attempt fails and parameter xBusy is not NULL, then it is a
@@ -1698,6 +1797,12 @@ static int walBusyLock(
do {
rc = walLockExclusive(pWal, lockIdx, n);
}while( xBusy && rc==SQLITE_BUSY && xBusy(pBusyArg) );
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+ if( rc==SQLITE_BUSY_TIMEOUT ){
+ walDisableBlocking(pWal);
+ rc = SQLITE_BUSY;
+ }
+#endif
return rc;
}
@@ -1735,7 +1840,7 @@ static void walRestartHdr(Wal *pWal, u32 salt1){
sqlite3Put4byte((u8*)&aSalt[0], 1 + sqlite3Get4byte((u8*)&aSalt[0]));
memcpy(&pWal->hdr.aSalt[1], &salt1, 4);
walIndexWriteHdr(pWal);
- pInfo->nBackfill = 0;
+ AtomicStore(&pInfo->nBackfill, 0);
pInfo->nBackfillAttempted = 0;
pInfo->aReadMark[1] = 0;
for(i=2; i<WAL_NREADER; i++) pInfo->aReadMark[i] = READMARK_NOT_USED;
@@ -1810,32 +1915,13 @@ static int walCheckpoint(
mxSafeFrame = pWal->hdr.mxFrame;
mxPage = pWal->hdr.nPage;
for(i=1; i<WAL_NREADER; i++){
- /* Thread-sanitizer reports that the following is an unsafe read,
- ** as some other thread may be in the process of updating the value
- ** of the aReadMark[] slot. The assumption here is that if that is
- ** happening, the other client may only be increasing the value,
- ** not decreasing it. So assuming either that either the "old" or
- ** "new" version of the value is read, and not some arbitrary value
- ** that would never be written by a real client, things are still
- ** safe.
- **
- ** Astute readers have pointed out that the assumption stated in the
- ** last sentence of the previous paragraph is not guaranteed to be
- ** true for all conforming systems. However, the assumption is true
- ** for all compilers and architectures in common use today (circa
- ** 2019-11-27) and the alternatives are both slow and complex, and
- ** so we will continue to go with the current design for now. If this
- ** bothers you, or if you really are running on a system where aligned
- ** 32-bit reads and writes are not atomic, then you can simply avoid
- ** the use of WAL mode, or only use WAL mode together with
- ** PRAGMA locking_mode=EXCLUSIVE and all will be well.
- */
- u32 y = pInfo->aReadMark[i];
+ u32 y = AtomicLoad(pInfo->aReadMark+i);
if( mxSafeFrame>y ){
assert( y<=pWal->hdr.mxFrame );
rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(i), 1);
if( rc==SQLITE_OK ){
- pInfo->aReadMark[i] = (i==1 ? mxSafeFrame : READMARK_NOT_USED);
+ u32 iMark = (i==1 ? mxSafeFrame : READMARK_NOT_USED);
+ AtomicStore(pInfo->aReadMark+i, iMark);
walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1);
}else if( rc==SQLITE_BUSY ){
mxSafeFrame = y;
@@ -1853,7 +1939,7 @@ static int walCheckpoint(
}
if( pIter
- && (rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(0),1))==SQLITE_OK
+ && (rc = walBusyLock(pWal,xBusy,pBusyArg,WAL_READ_LOCK(0),1))==SQLITE_OK
){
u32 nBackfill = pInfo->nBackfill;
@@ -1868,6 +1954,7 @@ static int walCheckpoint(
if( rc==SQLITE_OK ){
i64 nReq = ((i64)mxPage * szPage);
i64 nSize; /* Current size of database file */
+ sqlite3OsFileControl(pWal->pDbFd, SQLITE_FCNTL_CKPT_START, 0);
rc = sqlite3OsFileSize(pWal->pDbFd, &nSize);
if( rc==SQLITE_OK && nSize<nReq ){
sqlite3OsFileControlHint(pWal->pDbFd, SQLITE_FCNTL_SIZE_HINT, &nReq);
@@ -1895,6 +1982,7 @@ static int walCheckpoint(
rc = sqlite3OsWrite(pWal->pDbFd, zBuf, szPage, iOffset);
if( rc!=SQLITE_OK ) break;
}
+ sqlite3OsFileControl(pWal->pDbFd, SQLITE_FCNTL_CKPT_DONE, 0);
/* If work was actually accomplished... */
if( rc==SQLITE_OK ){
@@ -1907,11 +1995,7 @@ static int walCheckpoint(
}
}
if( rc==SQLITE_OK ){
- rc = sqlite3OsFileControl(pWal->pDbFd, SQLITE_FCNTL_CKPT_DONE, 0);
- if( rc==SQLITE_NOTFOUND ) rc = SQLITE_OK;
- }
- if( rc==SQLITE_OK ){
- pInfo->nBackfill = mxSafeFrame;
+ AtomicStore(&pInfo->nBackfill, mxSafeFrame);
}
}
@@ -2070,7 +2154,7 @@ int sqlite3WalClose(
** If the checksum cannot be verified return non-zero. If the header
** is read successfully and the checksum verified, return zero.
*/
-static int walIndexTryHdr(Wal *pWal, int *pChanged){
+static SQLITE_NO_TSAN int walIndexTryHdr(Wal *pWal, int *pChanged){
u32 aCksum[2]; /* Checksum on the header content */
WalIndexHdr h1, h2; /* Two copies of the header content */
WalIndexHdr volatile *aHdr; /* Header in shared memory */
@@ -2083,13 +2167,19 @@ static int walIndexTryHdr(Wal *pWal, int *pChanged){
** meaning it is possible that an inconsistent snapshot is read
** from the file. If this happens, return non-zero.
**
+ ** tag-20200519-1:
** There are two copies of the header at the beginning of the wal-index.
** When reading, read [0] first then [1]. Writes are in the reverse order.
** Memory barriers are used to prevent the compiler or the hardware from
- ** reordering the reads and writes.
+ ** reordering the reads and writes. TSAN and similar tools can sometimes
+ ** give false-positive warnings about these accesses because the tools do not
+ ** account for the double-read and the memory barrier. The use of mutexes
+ ** here would be problematic as the memory being accessed is potentially
+ ** shared among multiple processes and not all mutex implementions work
+ ** reliably in that environment.
*/
aHdr = walIndexHdr(pWal);
- memcpy(&h1, (void *)&aHdr[0], sizeof(h1));
+ memcpy(&h1, (void *)&aHdr[0], sizeof(h1)); /* Possible TSAN false-positive */
walShmBarrier(pWal);
memcpy(&h2, (void *)&aHdr[1], sizeof(h2));
@@ -2179,28 +2269,32 @@ static int walIndexReadHdr(Wal *pWal, int *pChanged){
/* If the first attempt failed, it might have been due to a race
** with a writer. So get a WRITE lock and try again.
*/
- assert( badHdr==0 || pWal->writeLock==0 );
if( badHdr ){
if( pWal->bShmUnreliable==0 && (pWal->readOnly & WAL_SHM_RDONLY) ){
if( SQLITE_OK==(rc = walLockShared(pWal, WAL_WRITE_LOCK)) ){
walUnlockShared(pWal, WAL_WRITE_LOCK);
rc = SQLITE_READONLY_RECOVERY;
}
- }else if( SQLITE_OK==(rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1)) ){
- pWal->writeLock = 1;
- if( SQLITE_OK==(rc = walIndexPage(pWal, 0, &page0)) ){
- badHdr = walIndexTryHdr(pWal, pChanged);
- if( badHdr ){
- /* If the wal-index header is still malformed even while holding
- ** a WRITE lock, it can only mean that the header is corrupted and
- ** needs to be reconstructed. So run recovery to do exactly that.
- */
- rc = walIndexRecover(pWal);
- *pChanged = 1;
+ }else{
+ int bWriteLock = pWal->writeLock;
+ if( bWriteLock || SQLITE_OK==(rc = walLockWriter(pWal)) ){
+ pWal->writeLock = 1;
+ if( SQLITE_OK==(rc = walIndexPage(pWal, 0, &page0)) ){
+ badHdr = walIndexTryHdr(pWal, pChanged);
+ if( badHdr ){
+ /* If the wal-index header is still malformed even while holding
+ ** a WRITE lock, it can only mean that the header is corrupted and
+ ** needs to be reconstructed. So run recovery to do exactly that.
+ */
+ rc = walIndexRecover(pWal);
+ *pChanged = 1;
+ }
+ }
+ if( bWriteLock==0 ){
+ pWal->writeLock = 0;
+ walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1);
}
}
- pWal->writeLock = 0;
- walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1);
}
}
@@ -2530,7 +2624,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
assert( pWal->nWiData>0 );
assert( pWal->apWiData[0]!=0 );
pInfo = walCkptInfo(pWal);
- if( !useWal && pInfo->nBackfill==pWal->hdr.mxFrame
+ if( !useWal && AtomicLoad(&pInfo->nBackfill)==pWal->hdr.mxFrame
#ifdef SQLITE_ENABLE_SNAPSHOT
&& (pWal->pSnapshot==0 || pWal->hdr.mxFrame==0)
#endif
@@ -2697,7 +2791,7 @@ int sqlite3WalSnapshotRecover(Wal *pWal){
rc = SQLITE_NOMEM;
}else{
u32 i = pInfo->nBackfillAttempted;
- for(i=pInfo->nBackfillAttempted; i>pInfo->nBackfill; i--){
+ for(i=pInfo->nBackfillAttempted; i>AtomicLoad(&pInfo->nBackfill); i--){
WalHashLoc sLoc; /* Hash table location */
u32 pgno; /* Page number in db file */
i64 iDbOff; /* Offset of db file entry */
@@ -2752,22 +2846,36 @@ int sqlite3WalSnapshotRecover(Wal *pWal){
int sqlite3WalBeginReadTransaction(Wal *pWal, int *pChanged){
int rc; /* Return code */
int cnt = 0; /* Number of TryBeginRead attempts */
-#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
- int tmout = 0;
-#endif
-
#ifdef SQLITE_ENABLE_SNAPSHOT
int bChanged = 0;
WalIndexHdr *pSnapshot = pWal->pSnapshot;
- if( pSnapshot && memcmp(pSnapshot, &pWal->hdr, sizeof(WalIndexHdr))!=0 ){
- bChanged = 1;
- }
#endif
-#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
- /* Disable blocking locks. They are not useful when trying to open a
- ** read-transaction, and blocking may cause deadlock anyway. */
- sqlite3OsFileControl(pWal->pDbFd, SQLITE_FCNTL_LOCK_TIMEOUT, (void*)&tmout);
+ assert( pWal->ckptLock==0 );
+
+#ifdef SQLITE_ENABLE_SNAPSHOT
+ if( pSnapshot ){
+ if( memcmp(pSnapshot, &pWal->hdr, sizeof(WalIndexHdr))!=0 ){
+ bChanged = 1;
+ }
+
+ /* It is possible that there is a checkpointer thread running
+ ** concurrent with this code. If this is the case, it may be that the
+ ** checkpointer has already determined that it will checkpoint
+ ** snapshot X, where X is later in the wal file than pSnapshot, but
+ ** has not yet set the pInfo->nBackfillAttempted variable to indicate
+ ** its intent. To avoid the race condition this leads to, ensure that
+ ** there is no checkpointer process by taking a shared CKPT lock
+ ** before checking pInfo->nBackfillAttempted. */
+ (void)walEnableBlocking(pWal);
+ rc = walLockShared(pWal, WAL_CKPT_LOCK);
+ walDisableBlocking(pWal);
+
+ if( rc!=SQLITE_OK ){
+ return rc;
+ }
+ pWal->ckptLock = 1;
+ }
#endif
do{
@@ -2778,16 +2886,6 @@ int sqlite3WalBeginReadTransaction(Wal *pWal, int *pChanged){
testcase( rc==SQLITE_PROTOCOL );
testcase( rc==SQLITE_OK );
-#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
- /* If they were disabled earlier and the read-transaction has been
- ** successfully opened, re-enable blocking locks. This is because the
- ** connection may attempt to upgrade to a write-transaction, which does
- ** benefit from using blocking locks. */
- if( rc==SQLITE_OK ){
- sqlite3OsFileControl(pWal->pDbFd, SQLITE_FCNTL_LOCK_TIMEOUT, (void*)&tmout);
- }
-#endif
-
#ifdef SQLITE_ENABLE_SNAPSHOT
if( rc==SQLITE_OK ){
if( pSnapshot && memcmp(pSnapshot, &pWal->hdr, sizeof(WalIndexHdr))!=0 ){
@@ -2809,48 +2907,42 @@ int sqlite3WalBeginReadTransaction(Wal *pWal, int *pChanged){
assert( pWal->readLock>0 || pWal->hdr.mxFrame==0 );
assert( pInfo->aReadMark[pWal->readLock]<=pSnapshot->mxFrame );
- /* It is possible that there is a checkpointer thread running
- ** concurrent with this code. If this is the case, it may be that the
- ** checkpointer has already determined that it will checkpoint
- ** snapshot X, where X is later in the wal file than pSnapshot, but
- ** has not yet set the pInfo->nBackfillAttempted variable to indicate
- ** its intent. To avoid the race condition this leads to, ensure that
- ** there is no checkpointer process by taking a shared CKPT lock
- ** before checking pInfo->nBackfillAttempted.
- **
- ** TODO: Does the aReadMark[] lock prevent a checkpointer from doing
- ** this already?
- */
- rc = walLockShared(pWal, WAL_CKPT_LOCK);
-
- if( rc==SQLITE_OK ){
- /* Check that the wal file has not been wrapped. Assuming that it has
- ** not, also check that no checkpointer has attempted to checkpoint any
- ** frames beyond pSnapshot->mxFrame. If either of these conditions are
- ** true, return SQLITE_ERROR_SNAPSHOT. Otherwise, overwrite pWal->hdr
- ** with *pSnapshot and set *pChanged as appropriate for opening the
- ** snapshot. */
- if( !memcmp(pSnapshot->aSalt, pWal->hdr.aSalt, sizeof(pWal->hdr.aSalt))
- && pSnapshot->mxFrame>=pInfo->nBackfillAttempted
- ){
- assert( pWal->readLock>0 );
- memcpy(&pWal->hdr, pSnapshot, sizeof(WalIndexHdr));
- *pChanged = bChanged;
- }else{
- rc = SQLITE_ERROR_SNAPSHOT;
- }
-
- /* Release the shared CKPT lock obtained above. */
- walUnlockShared(pWal, WAL_CKPT_LOCK);
- pWal->minFrame = 1;
+ /* Check that the wal file has not been wrapped. Assuming that it has
+ ** not, also check that no checkpointer has attempted to checkpoint any
+ ** frames beyond pSnapshot->mxFrame. If either of these conditions are
+ ** true, return SQLITE_ERROR_SNAPSHOT. Otherwise, overwrite pWal->hdr
+ ** with *pSnapshot and set *pChanged as appropriate for opening the
+ ** snapshot. */
+ if( !memcmp(pSnapshot->aSalt, pWal->hdr.aSalt, sizeof(pWal->hdr.aSalt))
+ && pSnapshot->mxFrame>=pInfo->nBackfillAttempted
+ ){
+ assert( pWal->readLock>0 );
+ memcpy(&pWal->hdr, pSnapshot, sizeof(WalIndexHdr));
+ *pChanged = bChanged;
+ }else{
+ rc = SQLITE_ERROR_SNAPSHOT;
}
+ /* A client using a non-current snapshot may not ignore any frames
+ ** from the start of the wal file. This is because, for a system
+ ** where (minFrame < iSnapshot < maxFrame), a checkpointer may
+ ** have omitted to checkpoint a frame earlier than minFrame in
+ ** the file because there exists a frame after iSnapshot that
+ ** is the same database page. */
+ pWal->minFrame = 1;
if( rc!=SQLITE_OK ){
sqlite3WalEndReadTransaction(pWal);
}
}
}
+
+ /* Release the shared CKPT lock obtained above. */
+ if( pWal->ckptLock ){
+ assert( pSnapshot );
+ walUnlockShared(pWal, WAL_CKPT_LOCK);
+ pWal->ckptLock = 0;
+ }
#endif
return rc;
}
@@ -2930,14 +3022,15 @@ int sqlite3WalFindFrame(
int iKey; /* Hash slot index */
int nCollide; /* Number of hash collisions remaining */
int rc; /* Error code */
+ u32 iH;
rc = walHashGet(pWal, iHash, &sLoc);
if( rc!=SQLITE_OK ){
return rc;
}
nCollide = HASHTABLE_NSLOT;
- for(iKey=walHash(pgno); sLoc.aHash[iKey]; iKey=walNextHash(iKey)){
- u32 iH = sLoc.aHash[iKey];
+ iKey = walHash(pgno);
+ while( (iH = AtomicLoad(&sLoc.aHash[iKey]))!=0 ){
u32 iFrame = iH + sLoc.iZero;
if( iFrame<=iLast && iFrame>=pWal->minFrame && sLoc.aPgno[iH]==pgno ){
assert( iFrame>iRead || CORRUPT_DB );
@@ -2946,6 +3039,7 @@ int sqlite3WalFindFrame(
if( (nCollide--)==0 ){
return SQLITE_CORRUPT_BKPT;
}
+ iKey = walNextHash(iKey);
}
if( iRead ) break;
}
@@ -3021,6 +3115,16 @@ Pgno sqlite3WalDbsize(Wal *pWal){
int sqlite3WalBeginWriteTransaction(Wal *pWal){
int rc;
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+ /* If the write-lock is already held, then it was obtained before the
+ ** read-transaction was even opened, making this call a no-op.
+ ** Return early. */
+ if( pWal->writeLock ){
+ assert( !memcmp(&pWal->hdr,(void *)walIndexHdr(pWal),sizeof(WalIndexHdr)) );
+ return SQLITE_OK;
+ }
+#endif
+
/* Cannot start a write transaction without first holding a read
** transaction. */
assert( pWal->readLock>=0 );
@@ -3597,45 +3701,52 @@ int sqlite3WalCheckpoint(
if( pWal->readOnly ) return SQLITE_READONLY;
WALTRACE(("WAL%p: checkpoint begins\n", pWal));
+ /* Enable blocking locks, if possible. If blocking locks are successfully
+ ** enabled, set xBusy2=0 so that the busy-handler is never invoked. */
+ sqlite3WalDb(pWal, db);
+ (void)walEnableBlocking(pWal);
+
/* IMPLEMENTATION-OF: R-62028-47212 All calls obtain an exclusive
- ** "checkpoint" lock on the database file. */
+ ** "checkpoint" lock on the database file.
+ ** EVIDENCE-OF: R-10421-19736 If any other process is running a
+ ** checkpoint operation at the same time, the lock cannot be obtained and
+ ** SQLITE_BUSY is returned.
+ ** EVIDENCE-OF: R-53820-33897 Even if there is a busy-handler configured,
+ ** it will not be invoked in this case.
+ */
rc = walLockExclusive(pWal, WAL_CKPT_LOCK, 1);
- if( rc ){
- /* EVIDENCE-OF: R-10421-19736 If any other process is running a
- ** checkpoint operation at the same time, the lock cannot be obtained and
- ** SQLITE_BUSY is returned.
- ** EVIDENCE-OF: R-53820-33897 Even if there is a busy-handler configured,
- ** it will not be invoked in this case.
- */
- testcase( rc==SQLITE_BUSY );
- testcase( xBusy!=0 );
- return rc;
- }
- pWal->ckptLock = 1;
+ testcase( rc==SQLITE_BUSY );
+ testcase( rc!=SQLITE_OK && xBusy2!=0 );
+ if( rc==SQLITE_OK ){
+ pWal->ckptLock = 1;
- /* IMPLEMENTATION-OF: R-59782-36818 The SQLITE_CHECKPOINT_FULL, RESTART and
- ** TRUNCATE modes also obtain the exclusive "writer" lock on the database
- ** file.
- **
- ** EVIDENCE-OF: R-60642-04082 If the writer lock cannot be obtained
- ** immediately, and a busy-handler is configured, it is invoked and the
- ** writer lock retried until either the busy-handler returns 0 or the
- ** lock is successfully obtained.
- */
- if( eMode!=SQLITE_CHECKPOINT_PASSIVE ){
- rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_WRITE_LOCK, 1);
- if( rc==SQLITE_OK ){
- pWal->writeLock = 1;
- }else if( rc==SQLITE_BUSY ){
- eMode2 = SQLITE_CHECKPOINT_PASSIVE;
- xBusy2 = 0;
- rc = SQLITE_OK;
+ /* IMPLEMENTATION-OF: R-59782-36818 The SQLITE_CHECKPOINT_FULL, RESTART and
+ ** TRUNCATE modes also obtain the exclusive "writer" lock on the database
+ ** file.
+ **
+ ** EVIDENCE-OF: R-60642-04082 If the writer lock cannot be obtained
+ ** immediately, and a busy-handler is configured, it is invoked and the
+ ** writer lock retried until either the busy-handler returns 0 or the
+ ** lock is successfully obtained.
+ */
+ if( eMode!=SQLITE_CHECKPOINT_PASSIVE ){
+ rc = walBusyLock(pWal, xBusy2, pBusyArg, WAL_WRITE_LOCK, 1);
+ if( rc==SQLITE_OK ){
+ pWal->writeLock = 1;
+ }else if( rc==SQLITE_BUSY ){
+ eMode2 = SQLITE_CHECKPOINT_PASSIVE;
+ xBusy2 = 0;
+ rc = SQLITE_OK;
+ }
}
}
+
/* Read the wal-index header. */
if( rc==SQLITE_OK ){
+ walDisableBlocking(pWal);
rc = walIndexReadHdr(pWal, &isChanged);
+ (void)walEnableBlocking(pWal);
if( isChanged && pWal->pDbFd->pMethods->iVersion>=3 ){
sqlite3OsUnfetch(pWal->pDbFd, 0, 0);
}
@@ -3667,11 +3778,19 @@ int sqlite3WalCheckpoint(
memset(&pWal->hdr, 0, sizeof(WalIndexHdr));
}
+ walDisableBlocking(pWal);
+ sqlite3WalDb(pWal, 0);
+
/* Release the locks. */
sqlite3WalEndWriteTransaction(pWal);
- walUnlockExclusive(pWal, WAL_CKPT_LOCK, 1);
- pWal->ckptLock = 0;
+ if( pWal->ckptLock ){
+ walUnlockExclusive(pWal, WAL_CKPT_LOCK, 1);
+ pWal->ckptLock = 0;
+ }
WALTRACE(("WAL%p: checkpoint %s\n", pWal, rc ? "failed" : "ok"));
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+ if( rc==SQLITE_BUSY_TIMEOUT ) rc = SQLITE_BUSY;
+#endif
return (rc==SQLITE_OK && eMode!=eMode2 ? SQLITE_BUSY : rc);
}
@@ -3788,7 +3907,10 @@ int sqlite3WalSnapshotGet(Wal *pWal, sqlite3_snapshot **ppSnapshot){
/* Try to open on pSnapshot when the next read-transaction starts
*/
-void sqlite3WalSnapshotOpen(Wal *pWal, sqlite3_snapshot *pSnapshot){
+void sqlite3WalSnapshotOpen(
+ Wal *pWal,
+ sqlite3_snapshot *pSnapshot
+){
pWal->pSnapshot = (WalIndexHdr*)pSnapshot;
}
diff --git a/src/wal.h b/src/wal.h
index 161060748..02e2bab36 100644
--- a/src/wal.h
+++ b/src/wal.h
@@ -146,5 +146,10 @@ int sqlite3WalFramesize(Wal *pWal);
/* Return the sqlite3_file object for the WAL file */
sqlite3_file *sqlite3WalFile(Wal *pWal);
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+int sqlite3WalWriteLock(Wal *pWal, int bLock);
+void sqlite3WalDb(Wal *pWal, sqlite3 *db);
+#endif
+
#endif /* ifndef SQLITE_OMIT_WAL */
#endif /* SQLITE_WAL_H */
diff --git a/src/walker.c b/src/walker.c
index 48d7ddbf3..7649036f5 100644
--- a/src/walker.c
+++ b/src/walker.c
@@ -207,3 +207,40 @@ int sqlite3WalkSelect(Walker *pWalker, Select *p){
}while( p!=0 );
return WRC_Continue;
}
+
+/* Increase the walkerDepth when entering a subquery, and
+** descrease when leaving the subquery.
+*/
+int sqlite3WalkerDepthIncrease(Walker *pWalker, Select *pSelect){
+ UNUSED_PARAMETER(pSelect);
+ pWalker->walkerDepth++;
+ return WRC_Continue;
+}
+void sqlite3WalkerDepthDecrease(Walker *pWalker, Select *pSelect){
+ UNUSED_PARAMETER(pSelect);
+ pWalker->walkerDepth--;
+}
+
+
+/*
+** No-op routine for the parse-tree walker.
+**
+** When this routine is the Walker.xExprCallback then expression trees
+** are walked without any actions being taken at each node. Presumably,
+** when this routine is used for Walker.xExprCallback then
+** Walker.xSelectCallback is set to do something useful for every
+** subquery in the parser tree.
+*/
+int sqlite3ExprWalkNoop(Walker *NotUsed, Expr *NotUsed2){
+ UNUSED_PARAMETER2(NotUsed, NotUsed2);
+ return WRC_Continue;
+}
+
+/*
+** No-op routine for the parse-tree walker for SELECT statements.
+** subquery in the parser tree.
+*/
+int sqlite3SelectWalkNoop(Walker *NotUsed, Select *NotUsed2){
+ UNUSED_PARAMETER2(NotUsed, NotUsed2);
+ return WRC_Continue;
+}
diff --git a/src/where.c b/src/where.c
index ad309006d..a7df4b9b8 100644
--- a/src/where.c
+++ b/src/where.c
@@ -3028,6 +3028,7 @@ static int whereLoopAddBtree(
pNew->nOut = rSize;
pNew->u.btree.pIndex = pProbe;
b = indexMightHelpWithOrderBy(pBuilder, pProbe, pSrc->iCursor);
+
/* The ONEPASS_DESIRED flags never occurs together with ORDER BY */
assert( (pWInfo->wctrlFlags & WHERE_ONEPASS_DESIRED)==0 || b==0 );
if( pProbe->idxType==SQLITE_IDXTYPE_IPK ){
@@ -3057,6 +3058,7 @@ static int whereLoopAddBtree(
if( b
|| !HasRowid(pTab)
|| pProbe->pPartIdxWhere!=0
+ || pSrc->fg.isIndexedBy
|| ( m==0
&& pProbe->bUnordered==0
&& (pProbe->szIdxRow<pTab->szTabRow)
diff --git a/src/window.c b/src/window.c
index db495d832..602af784a 100644
--- a/src/window.c
+++ b/src/window.c
@@ -803,6 +803,7 @@ static int selectWindowRewriteExprCb(Walker *pWalker, Expr *pExpr){
p->pSub = sqlite3ExprListAppend(pParse, p->pSub, pDup);
}
if( p->pSub ){
+ int f = pExpr->flags & EP_Collate;
assert( ExprHasProperty(pExpr, EP_Static)==0 );
ExprSetProperty(pExpr, EP_Static);
sqlite3ExprDelete(pParse->db, pExpr);
@@ -813,6 +814,7 @@ static int selectWindowRewriteExprCb(Walker *pWalker, Expr *pExpr){
pExpr->iColumn = (iCol<0 ? p->pSub->nExpr-1: iCol);
pExpr->iTable = p->pWin->iEphCsr;
pExpr->y.pTab = p->pTab;
+ pExpr->flags = f;
}
if( pParse->db->mallocFailed ) return WRC_Abort;
break;
@@ -895,13 +897,19 @@ static ExprList *exprListAppendList(
int i;
int nInit = pList ? pList->nExpr : 0;
for(i=0; i<pAppend->nExpr; i++){
- int iDummy;
Expr *pDup = sqlite3ExprDup(pParse->db, pAppend->a[i].pExpr, 0);
assert( pDup==0 || !ExprHasProperty(pDup, EP_MemToken) );
- if( bIntToNull && pDup && sqlite3ExprIsInteger(pDup, &iDummy) ){
- pDup->op = TK_NULL;
- pDup->flags &= ~(EP_IntValue|EP_IsTrue|EP_IsFalse);
- pDup->u.zToken = 0;
+ if( bIntToNull && pDup ){
+ int iDummy;
+ Expr *pSub;
+ for(pSub=pDup; ExprHasProperty(pSub, EP_Skip); pSub=pSub->pLeft){
+ assert( pSub );
+ }
+ if( sqlite3ExprIsInteger(pSub, &iDummy) ){
+ pSub->op = TK_NULL;
+ pSub->flags &= ~(EP_IntValue|EP_IsTrue|EP_IsFalse);
+ pSub->u.zToken = 0;
+ }
}
pList = sqlite3ExprListAppend(pParse, pList, pDup);
if( pList ) pList->a[nInit+i].sortFlags = pAppend->a[i].sortFlags;
@@ -911,6 +919,23 @@ static ExprList *exprListAppendList(
}
/*
+** When rewriting a query, if the new subquery in the FROM clause
+** contains TK_AGG_FUNCTION nodes that refer to an outer query,
+** then we have to increase the Expr->op2 values of those nodes
+** due to the extra subquery layer that was added.
+**
+** See also the incrAggDepth() routine in resolve.c
+*/
+static int sqlite3WindowExtraAggFuncDepth(Walker *pWalker, Expr *pExpr){
+ if( pExpr->op==TK_AGG_FUNCTION
+ && pExpr->op2>=pWalker->walkerDepth
+ ){
+ pExpr->op2++;
+ }
+ return WRC_Continue;
+}
+
+/*
** If the SELECT statement passed as the second argument does not invoke
** any SQL window functions, this function is a no-op. Otherwise, it
** rewrites the SELECT statement so that window function xStep functions
@@ -930,15 +955,19 @@ int sqlite3WindowRewrite(Parse *pParse, Select *p){
ExprList *pSort = 0;
ExprList *pSublist = 0; /* Expression list for sub-query */
- Window *pMWin = p->pWin; /* Master window object */
+ Window *pMWin = p->pWin; /* Main window object */
Window *pWin; /* Window object iterator */
Table *pTab;
+ Walker w;
+
u32 selFlags = p->selFlags;
pTab = sqlite3DbMallocZero(db, sizeof(Table));
if( pTab==0 ){
return sqlite3ErrorToParser(db, SQLITE_NOMEM);
}
+ sqlite3AggInfoPersistWalkerInit(&w, pParse);
+ sqlite3WalkSelect(&w, p);
p->pSrc = 0;
p->pWhere = 0;
@@ -1016,6 +1045,9 @@ int sqlite3WindowRewrite(Parse *pParse, Select *p){
pSub = sqlite3SelectNew(
pParse, pSublist, pSrc, pWhere, pGroupBy, pHaving, pSort, 0, 0
);
+ SELECTTRACE(1,pParse,pSub,
+ ("New window-function subquery in FROM clause of (%u/%p)\n",
+ p->selId, p));
p->pSrc = sqlite3SrcListAppend(pParse, 0, 0, 0);
if( p->pSrc ){
Table *pTab2;
@@ -1034,6 +1066,11 @@ int sqlite3WindowRewrite(Parse *pParse, Select *p){
pTab->tabFlags |= TF_Ephemeral;
p->pSrc->a[0].pTab = pTab;
pTab = pTab2;
+ memset(&w, 0, sizeof(w));
+ w.xExprCallback = sqlite3WindowExtraAggFuncDepth;
+ w.xSelectCallback = sqlite3WalkerDepthIncrease;
+ w.xSelectCallback2 = sqlite3WalkerDepthDecrease;
+ sqlite3WalkSelect(&w, pSub);
}
}else{
sqlite3SelectDelete(db, pSub);
@@ -1047,7 +1084,6 @@ int sqlite3WindowRewrite(Parse *pParse, Select *p){
assert( pParse->db->mallocFailed );
sqlite3ErrorToParser(pParse->db, SQLITE_NOMEM);
}
- sqlite3SelectReset(pParse, p);
}
return rc;
}
diff --git a/test/aggnested.test b/test/aggnested.test
index d712c840f..dcb1f95c9 100644
--- a/test/aggnested.test
+++ b/test/aggnested.test
@@ -17,6 +17,7 @@
set testdir [file dirname $argv0]
source $testdir/tester.tcl
+set testprefix aggnested
do_test aggnested-1.1 {
db eval {
@@ -259,6 +260,52 @@ do_execsql_test aggnested-4.4 {
SELECT max((SELECT a FROM (SELECT count(*) AS a FROM ty) AS s)) FROM tx;
} {3}
+#--------------------------------------------------------------------------
+#
+reset_db
+do_execsql_test 5.0 {
+ CREATE TABLE x1(a, b);
+ INSERT INTO x1 VALUES(1, 2);
+ CREATE TABLE x2(x);
+ INSERT INTO x2 VALUES(NULL), (NULL), (NULL);
+}
+
+# At one point, aggregate "total()" in the query below was being processed
+# as part of the outer SELECT, not as part of the sub-select with no FROM
+# clause.
+do_execsql_test 5.1 {
+ SELECT ( SELECT total( (SELECT b FROM x1) ) ) FROM x2;
+} {2.0 2.0 2.0}
+
+do_execsql_test 5.2 {
+ SELECT ( SELECT total( (SELECT 2 FROM x1) ) ) FROM x2;
+} {2.0 2.0 2.0}
+
+do_execsql_test 5.3 {
+ CREATE TABLE t1(a);
+ CREATE TABLE t2(b);
+}
+
+do_execsql_test 5.4 {
+ SELECT(
+ SELECT max(b) LIMIT (
+ SELECT total( (SELECT a FROM t1) )
+ )
+ )
+ FROM t2;
+} {{}}
+
+do_execsql_test 5.5 {
+ CREATE TABLE a(b);
+ WITH c AS(SELECT a)
+ SELECT(SELECT(SELECT group_concat(b, b)
+ LIMIT(SELECT 0.100000 *
+ AVG(DISTINCT(SELECT 0 FROM a ORDER BY b, b, b))))
+ FROM a GROUP BY b,
+ b, b) FROM a EXCEPT SELECT b FROM a ORDER BY b,
+ b, b;
+}
+
diff --git a/test/alter.test b/test/alter.test
index 0ec485ef8..43d2a6d5a 100644
--- a/test/alter.test
+++ b/test/alter.test
@@ -840,6 +840,7 @@ do_test alter-13.3 {
do_test alter-14.1 {
catchsql {
CREATE TABLE t3651(a UNIQUE);
+ INSERT INTO t3651 VALUES(5);
ALTER TABLE t3651 ADD COLUMN b UNIQUE;
}
} {1 {Cannot add a UNIQUE column}}
diff --git a/test/alter3.test b/test/alter3.test
index b16a7f305..30bc1cbba 100644
--- a/test/alter3.test
+++ b/test/alter3.test
@@ -116,6 +116,7 @@ do_test alter3-1.99 {
do_test alter3-2.1 {
execsql {
CREATE TABLE t1(a, b);
+ INSERT INTO t1 VALUES(1,2);
}
catchsql {
ALTER TABLE t1 ADD c PRIMARY KEY;
diff --git a/test/alter4.test b/test/alter4.test
index 92f33e7a3..3aca7df33 100644
--- a/test/alter4.test
+++ b/test/alter4.test
@@ -123,6 +123,7 @@ do_test alter4-1.99 {
do_test alter4-2.1 {
execsql {
CREATE TABLE temp.t1(a, b);
+ INSERT INTO t1 VALUES(1,2);
}
catchsql {
ALTER TABLE t1 ADD c PRIMARY KEY;
@@ -397,6 +398,7 @@ do_test alter4-10.1 {
reset_db
do_execsql_test alter4-11.0 {
CREATE TABLE t1(c INTEGER PRIMARY KEY, d);
+ INSERT INTO t1(c,d) VALUES(1,2);
PRAGMA foreign_keys = on;
ALTER TABLE t1 ADD COLUMN e;
}
diff --git a/test/altertab.test b/test/altertab.test
index c99010d29..435620d1e 100644
--- a/test/altertab.test
+++ b/test/altertab.test
@@ -658,5 +658,23 @@ do_catchsql_test 21.3 {
ALTER TABLE a RENAME TO e;
} {1 {error in view c: 1st ORDER BY term does not match any column in the result set}}
+# After forum thread https://sqlite.org/forum/forumpost/ddbe1c7efa
+# Ensure that PRAGMA schema_version=N causes a full schema reload.
+#
+reset_db
+do_execsql_test 22.0 {
+ CREATE TABLE t1(a INT, b TEXT NOT NULL);
+ INSERT INTO t1 VALUES(1,2),('a','b');
+ BEGIN;
+ PRAGMA writable_schema=ON;
+ UPDATE sqlite_schema SET sql='CREATE TABLE t1(a INT, b TEXT)' WHERE name LIKE 't1';
+ PRAGMA schema_version=1234;
+ COMMIT;
+ PRAGMA integrity_check;
+} {ok}
+do_execsql_test 22.1 {
+ ALTER TABLE t1 ADD COLUMN c INT DEFAULT 78;
+ SELECT * FROM t1;
+} {1 2 78 a b 78}
finish_test
diff --git a/test/atrc.c b/test/atrc.c
index c6e4ce3d0..673f12cc4 100644
--- a/test/atrc.c
+++ b/test/atrc.c
@@ -75,7 +75,7 @@ int rename_all_tables(
int cnt = 0;
rc = sqlite3_prepare_v2(db,
- "SELECT name FROM sqlite_master WHERE type='table'"
+ "SELECT name FROM sqlite_schema WHERE type='table'"
" AND name NOT LIKE 'sqlite_%';",
-1, &pStmt, 0);
if( rc ) return rc;
diff --git a/test/busy2.test b/test/busy2.test
new file mode 100644
index 000000000..e1f8eeeff
--- /dev/null
+++ b/test/busy2.test
@@ -0,0 +1,132 @@
+# 2020 June 30
+#
+# 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 test the busy handler
+#
+
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+source $testdir/lock_common.tcl
+set testprefix busy2
+
+do_multiclient_test tn {
+ do_test 1.$tn.0 {
+ sql2 {
+ CREATE TABLE t1(a, b);
+ PRAGMA journal_mode = wal;
+ INSERT INTO t1 VALUES('A', 'B');
+ }
+ } {wal}
+
+ do_test 1.$tn.1 {
+ code1 { db timeout 1000 }
+ sql1 { SELECT * FROM t1 }
+ } {A B}
+
+ do_test 1.$tn.2 {
+ sql2 {
+ BEGIN;
+ INSERT INTO t1 VALUES('C', 'D');
+ }
+ } {}
+
+ do_test 1.$tn.3 {
+ set us [lindex [time { catch { sql1 { BEGIN EXCLUSIVE } } }] 0]
+ expr {$us>950000 && $us<1500000}
+ } {1}
+
+ do_test 1.$tn.4 {
+ sql2 {
+ COMMIT
+ }
+ } {}
+}
+
+#-------------------------------------------------------------------------
+
+do_multiclient_test tn {
+ # Make the db a WAL mode db. And add a table and a row to it. Then open
+ # a second connection within process 1. Process 1 now has connections
+ # [db] and [db1.2], process 2 has connection [db2] only.
+ #
+ # Configure all connections to use a 1000 ms timeout.
+ #
+ do_test 2.$tn.0 {
+ sql1 {
+ PRAGMA journal_mode = wal;
+ CREATE TABLE t1(a, b);
+ INSERT INTO t1 VALUES(1, 2);
+ }
+ code2 {
+ db2 timeout 1000
+ }
+ code1 {
+ sqlite3 db1.2 test.db
+ db1.2 timeout 1000
+ db timeout 1000
+ db1.2 eval {SELECT * FROM t1}
+ }
+ } {1 2}
+
+ # Take a read lock with [db] in process 1.
+ #
+ do_test 2.$tn.1 {
+ sql1 {
+ BEGIN;
+ SELECT * FROM t1;
+ }
+ } {1 2}
+
+ # Insert a row using [db2] in process 2. Then try a passive checkpoint.
+ # It fails to checkpoint the final frame (due to the readlock taken by
+ # [db]), and returns in less than 250ms.
+ do_test 2.$tn.2 {
+ sql2 { INSERT INTO t1 VALUES(3, 4) }
+ set us [lindex [time {
+ set res [code2 { db2 eval { PRAGMA wal_checkpoint } }]
+ }] 0]
+ list [expr $us < 250000] $res
+ } {1 {0 4 3}}
+
+ # Now try a FULL checkpoint with [db2]. It returns SQLITE_BUSY. And takes
+ # over 950ms to do so.
+ do_test 2.$tn.3 {
+ set us [lindex [time {
+ set res [code2 { db2 eval { PRAGMA wal_checkpoint = FULL } }]
+ }] 0]
+ list [expr $us > 950000] $res
+ } {1 {1 4 3}}
+
+ # Passive checkpoint with [db1.2] (process 1). No SQLITE_BUSY, returns
+ # in under 250ms.
+ do_test 2.$tn.4 {
+ set us [lindex [time {
+ set res [code1 { db1.2 eval { PRAGMA wal_checkpoint } }]
+ }] 0]
+ list [expr $us < 250000] $res
+ } {1 {0 4 3}}
+
+ # Full checkpoint with [db1.2] (process 1). SQLITE_BUSY returned in
+ # a bit over 950ms.
+ do_test 2.$tn.5 {
+ set us [lindex [time {
+ set res [code1 { db1.2 eval { PRAGMA wal_checkpoint = FULL } }]
+ }] 0]
+ list [expr $us > 950000] $res
+ } {1 {1 4 3}}
+
+ code1 {
+ db1.2 close
+ }
+}
+
+finish_test
+
diff --git a/test/corruptL.test b/test/corruptL.test
index 67d308abc..6a2fa94fc 100644
--- a/test/corruptL.test
+++ b/test/corruptL.test
@@ -1182,5 +1182,114 @@ do_catchsql_test 14.2 {
ALTER TABLE t1 RENAME TO alkjalkjdfiiiwuer987lkjwer82mx97sf98788s9789s;
} {1 {database disk image is malformed}}
+#-------------------------------------------------------------------------
+reset_db
+do_test 15.0 {
+ sqlite3 db {}
+ db deserialize [decode_hexdb {
+| size 28672 pagesize 4096 filename crash-3afa1ca9e9c1bd.db
+| page 1 offset 0
+| 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3.
+| 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 07 .....@ ........
+| 32: 00 00 00 00 00 00 00 00 00 00 00 06 00 00 00 04 ................
+| 48: 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 ................
+| 96: 00 00 00 00 0d 00 00 00 06 0e 88 00 0f b8 0f 6d ...............m
+| 112: 0f 3a 0f 0b 0e d5 0e 88 01 00 00 00 00 00 00 00 .:..............
+| 3712: 00 00 00 00 00 00 00 00 4b 06 06 17 25 25 01 5b ........K...%%.[
+| 3728: 74 61 62 6c 65 73 71 6c 69 74 65 5f 73 74 61 74 tablesqlite_stat
+| 3744: 31 73 71 6c 69 74 65 5f 73 74 61 74 31 07 43 52 1sqlite_stat1.CR
+| 3760: 45 41 54 45 20 54 41 42 4c 45 20 73 71 6c 69 74 EATE TABLE sqlit
+| 3776: 65 5f 73 74 61 74 31 28 74 62 6c 2c 69 64 78 2c e_stat1(tbl,idx,
+| 3792: 73 74 61 74 29 34 05 06 17 13 11 01 53 69 6e 64 stat)4......Sind
+| 3808: 65 78 63 31 63 63 31 06 43 52 45 41 54 45 20 55 exc1cc1.CREATE U
+| 3824: 4e 49 51 55 45 20 49 4e 44 45 58 20 63 31 63 20 NIQUE INDEX c1c
+| 3840: 4f 4e 20 63 31 28 63 2c 20 62 29 2d 04 06 17 13 ON c1(c, b)-....
+| 3856: 11 01 45 69 6e 64 65 78 63 31 64 63 31 05 43 52 ..Eindexc1dc1.CR
+| 3872: 45 41 54 45 20 49 4e 44 45 58 20 63 31 64 20 4f EATE INDEX c1d O
+| 3888: 4e 20 63 31 28 64 2c 20 62 29 31 03 06 17 13 11 N c1(d, b)1.....
+| 3904: 01 4d 69 6e 64 65 78 62 31 63 62 31 05 43 52 45 .Mindexb1cb1.CRE
+| 3920: 41 54 45 20 55 4e 49 51 55 45 20 49 4e 44 45 58 ATE UNIQUE INDEX
+| 3936: 20 62 31 63 20 4f 4e 20 62 31 28 63 29 49 02 06 b1c ON b1(c)I..
+| 3952: 17 11 11 0f 7f 74 61 62 6c 65 63 31 63 31 03 43 .....tablec1c1.C
+| 3968: 52 45 41 54 45 20 54 41 42 4c 45 20 63 31 28 61 REATE TABLE c1(a
+| 3984: 20 49 4e 54 20 50 52 49 4d 41 52 59 20 4b 45 59 INT PRIMARY KEY
+| 4000: 2c 20 62 2c 20 63 2c 20 64 29 20 57 49 54 48 4f , b, c, d) WITHO
+| 4016: 55 54 20 52 4f 57 49 44 46 01 06 17 11 11 01 79 UT ROWIDF......y
+| 4032: 74 61 62 6c 65 62 31 62 31 02 43 52 45 41 54 45 tableb1b1.CREATE
+| 4048: 20 54 41 42 4c 45 20 62 31 28 61 20 49 4e 54 20 TABLE b1(a INT
+| 4064: 50 52 49 4d 41 52 59 20 4b 45 59 2c 20 62 2c 20 PRIMARY KEY, b,
+| 4080: 63 29 20 57 49 54 48 4f 55 54 20 52 4f 57 49 44 c) WITHOUT ROWID
+| page 2 offset 4096
+| 0: 0a 00 00 00 07 0f ca 00 0f fa 0f f2 0f ea 0f e2 ................
+| 16: 0f da 00 00 00 01 00 00 00 00 00 00 00 00 00 00 ................
+| 4032: 00 00 00 00 00 00 00 00 00 00 07 04 01 0f 01 06 ................
+| 4048: 67 07 07 04 01 0f 01 06 66 06 07 04 01 0f 01 05 g.......f.......
+| 4064: 65 05 07 04 01 0f 01 04 64 04 07 04 01 0f 01 03 e.......d.......
+| 4080: 63 03 07 04 01 0f 01 02 62 0f 05 04 09 0f 09 61 c.......b......a
+| page 3 offset 8192
+| 0: 0a 00 00 00 07 0f bd 00 0f f9 0f ef 0f e5 0f db ................
+| 16: 0f d1 0f c7 0f bd 00 00 00 00 01 00 00 00 00 00 ................
+| 4016: 00 00 00 00 00 00 00 00 00 00 00 00 00 09 05 01 ................
+| 4032: 0f 01 01 07 61 07 07 09 05 01 0f 01 01 06 61 06 ....a.........a.
+| 4048: 06 09 05 01 0f 01 01 05 61 05 05 09 05 01 0f 01 ........a.......
+| 4064: 01 04 61 04 04 09 05 01 0f 01 01 03 61 03 03 09 ..a.........a...
+| 4080: 05 01 0f 01 01 02 61 0f 02 06 05 09 0f 09 09 61 ......a........a
+| page 4 offset 12288
+| 0: 0a 00 00 00 07 0f d8 00 0f fc 0f f0 0f ea 0f e4 ................
+| 16: 0f de 0f d8 0f f6 00 00 00 00 00 00 00 00 00 00 ................
+| 4048: 00 00 00 00 00 00 00 00 05 03 01 01 07 07 05 03 ................
+| 4064: 01 01 06 06 05 03 01 01 05 05 05 03 01 01 04 04 ................
+| 4080: 05 03 01 01 03 03 05 03 01 01 0f 02 03 03 09 09 ................
+| page 5 offset 16384
+| 0: 0a 00 00 00 07 0f ca 00 0f fa 0f f2 0f ea 0f 00 ................
+| 4032: 00 00 00 00 00 00 00 00 00 00 07 04 01 0f 01 07 ................
+| 4048: 61 07 07 04 01 0f 01 06 61 06 07 04 01 0f 01 05 a.......a.......
+| 4064: 61 05 07 04 01 1f 01 04 61 04 07 04 01 0f 01 03 a.......a.......
+| 4080: 61 03 07 04 01 0f 01 02 61 02 05 04 09 0f 09 61 a.......a......a
+| page 6 offset 20480
+| 0: 0a 00 00 00 07 0f ca 00 0f fa 0f ea 0f e2 00 00 ................
+| 4032: 00 00 00 00 00 00 00 00 00 00 07 04 01 0f 01 07 ................
+| 4048: 61 07 07 04 01 0f 01 06 61 06 07 04 01 0f 01 05 a.......a.......
+| 4064: 61 05 07 04 01 0f 01 04 61 04 07 04 01 0f 01 03 a.......a.......
+| 4080: 61 03 07 04 01 0f 01 0f 61 02 05 04 09 0f 09 61 a.......a......a
+| page 7 offset 24576
+| 0: 0d 00 00 00 05 0f 1c 00 0f f0 0f e0 0f d3 0f c5 ................
+| 16: 0f b8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+| 4016: 00 00 00 00 00 00 00 00 0b 05 04 11 11 13 62 31 ..............b1
+| 4032: 62 31 37 20 31 0c 04 04 11 13 13 62 31 62 31 63 b17 1......b1b1c
+| 4048: 37 20 31 0b 03 04 11 11 13 63 31 63 31 37 20 31 7 1......c1c17 1
+| 4064: 0e 02 04 11 13 07 63 31 63 31 64 37 20 31 20 31 ......c1c1d7 1 1
+| 4080: 0e 01 04 11 13 17 63 31 63 31 63 37 20 31 00 00 ......c1c1c7 1..
+| end crash-3afa1ca9e9c1bd.db
+}]} {}
+
+do_execsql_test 15.1 {
+ UPDATE c1 SET c= NOT EXISTS(SELECT 1 FROM c1 ORDER BY (SELECT 1 FROM c1 ORDER BY a)) +10 WHERE d BETWEEN 4 AND 7;
+} {}
+
+#-------------------------------------------------------------------------
+reset_db
+do_execsql_test 16.0 {
+ CREATE TABLE t1(w, x, y, z, UNIQUE(w, x), UNIQUE(y, z));
+ INSERT INTO t1 VALUES(1, 1, 1, 1);
+
+ CREATE TABLE t1idx(x, y, i INTEGER, PRIMARY KEY(x)) WITHOUT ROWID;
+ INSERT INTO t1idx VALUES(10, NULL, 5);
+
+ PRAGMA writable_schema = 1;
+ UPDATE sqlite_master SET rootpage = (
+ SELECT rootpage FROM sqlite_master WHERE name='t1idx'
+ ) WHERE type = 'index';
+}
+
+db close
+sqlite3 db test.db
+
+do_catchsql_test 16.1 {
+ PRAGMA writable_schema = ON;
+ INSERT INTO t1(rowid, w, x, y, z) VALUES(5, 10, 11, 10, NULL);
+} {1 {database disk image is malformed}}
+
finish_test
+
diff --git a/test/cost.test b/test/cost.test
index 2922a0a05..592973ab5 100644
--- a/test/cost.test
+++ b/test/cost.test
@@ -230,10 +230,10 @@ do_test 9.2 {
set L [list a=? b=? c=? d=? e=? f=? g=? h=? i=? j=?]
foreach {tn nTerm nRow} {
1 1 10
- 2 2 9
+ 2 2 10
3 3 8
4 4 7
- 5 5 6
+ 5 5 7
6 6 5
7 7 5
8 8 5
diff --git a/test/count.test b/test/count.test
index 862b62ab1..250eb669b 100644
--- a/test/count.test
+++ b/test/count.test
@@ -196,4 +196,42 @@ do_catchsql_test count-6.1 {
SELECT count(DISTINCT) FROM t6 GROUP BY x;
} {1 {DISTINCT aggregates must have exactly one argument}}
+# 2020-05-08.
+# The count() optimization should honor the NOT INDEXED clause
+#
+reset_db
+do_execsql_test count-7.1 {
+ CREATE TABLE t1(a INTEGER PRIMARY KEY, b INT, c VARCHAR(1000));
+ CREATE INDEX t1b ON t1(b);
+ INSERT INTO t1(a,b,c) values(1,2,'count.test cases for NOT INDEXED');
+ ANALYZE;
+ UPDATE sqlite_stat1 SET stat='1000000 10' WHERE idx='t1b';
+ ANALYZE sqlite_master;
+}
+do_eqp_test count-7.2 {
+ SELECT count(1) FROM t1;
+} {
+ QUERY PLAN
+ `--SCAN TABLE t1 USING COVERING INDEX t1b
+}
+do_eqp_test count-7.3 {
+ SELECT count(1) FROM t1 NOT INDEXED
+} {
+ QUERY PLAN
+ `--SCAN TABLE t1
+}
+do_eqp_test count-7.3 {
+ SELECT count(*) FROM t1;
+} {
+ QUERY PLAN
+ `--SCAN TABLE t1 USING COVERING INDEX t1b
+}
+do_eqp_test count-7.4 {
+ SELECT count(*) FROM t1 NOT INDEXED
+} {
+ QUERY PLAN
+ `--SCAN TABLE t1
+}
+
+
finish_test
diff --git a/test/cursorhint.test b/test/cursorhint.test
index ae86120fa..a3397b867 100644
--- a/test/cursorhint.test
+++ b/test/cursorhint.test
@@ -69,7 +69,7 @@ do_test 1.2 {
p5_of_opcode db OpenRead {
SELECT * FROM t1 CROSS JOIN t2 WHERE a=x
}
-} {00 00}
+} {0 0}
# Do the same test the other way around.
#
@@ -82,7 +82,7 @@ do_test 2.2 {
p5_of_opcode db OpenRead {
SELECT * FROM t2 CROSS JOIN t1 WHERE a=x
}
-} {00 00}
+} {0 0}
# Various expressions captured by CursorHint
#
@@ -117,7 +117,7 @@ do_test 4.2 {
p5_of_opcode db OpenRead {
SELECT * FROM t1 WHERE b>11;
}
-} {02 00}
+} {2 0}
do_test 4.3asc {
p4_of_opcode db CursorHint {
SELECT c FROM t1 WHERE b<11 ORDER BY b ASC;
@@ -132,7 +132,7 @@ do_test 4.4 {
p5_of_opcode db OpenRead {
SELECT c FROM t1 WHERE b<11;
}
-} {00}
+} {0}
do_test 4.5asc {
p4_of_opcode db CursorHint {
diff --git a/test/dbfuzz2.c b/test/dbfuzz2.c
index 804222ce4..e35162937 100644
--- a/test/dbfuzz2.c
+++ b/test/dbfuzz2.c
@@ -54,7 +54,7 @@
*/
static const char *azSql[] = {
"PRAGMA integrity_check;",
- "SELECT * FROM sqlite_master;",
+ "SELECT * FROM sqlite_schema;",
"SELECT sum(length(name)) FROM dbstat;",
"UPDATE t1 SET b=a, a=b WHERE a<b;",
"ALTER TABLE t1 RENAME TO alkjalkjdfiiiwuer987lkjwer82mx97sf98788s9789s;",
diff --git a/test/decimal.test b/test/decimal.test
new file mode 100644
index 000000000..6fb15340f
--- /dev/null
+++ b/test/decimal.test
@@ -0,0 +1,142 @@
+# 2017 December 9
+#
+# 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.
+#
+#***********************************************************************
+#
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+set testprefix decimal
+
+if {[catch {load_static_extension db decimal} error]} {
+ puts "Skipping zipfile tests, hit load error: $error"
+ finish_test; return
+}
+
+do_execsql_test 1000 {
+ SELECT decimal(1);
+} {1}
+do_execsql_test 1010 {
+ SELECT decimal(1.0);
+} {1.0}
+do_execsql_test 1020 {
+ SELECT decimal(0001.0);
+} {1.0}
+do_execsql_test 1030 {
+ SELECT decimal(+0001.0);
+} {1.0}
+do_execsql_test 1040 {
+ SELECT decimal(-0001.0);
+} {-1.0}
+do_execsql_test 1050 {
+ SELECT decimal(1.0e72);
+} {1000000000000000000000000000000000000000000000000000000000000000000000000}
+# 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123
+do_execsql_test 1060 {
+ SELECT decimal(1.0e-72);
+} {0.0000000000000000000000000000000000000000000000000000000000000000000000010}
+# 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123
+do_execsql_test 1070 {
+ SELECT decimal(-123e-4);
+} {-0.0123}
+do_execsql_test 1080 {
+ SELECT decimal(+123e+4);
+} {1230000.0}
+
+
+do_execsql_test 2000 {
+ CREATE TABLE t1(seq INTEGER PRIMARY KEY, val TEXT);
+ INSERT INTO t1 VALUES
+ (1, '-9999e99'),
+ (2, '-9998.000e+99'),
+ (3, '-9999.0'),
+ (4, '-1'),
+ (5, '-9999e-20'),
+ (6, '0'),
+ (7, '1e-30'),
+ (8, '1e-29'),
+ (9, '1'),
+ (10,'1.00000000000000001'),
+ (11,'+1.00001'),
+ (12,'99e+99');
+ SELECT *, '|'
+ FROM t1 AS a, t1 AS b
+ WHERE a.seq<b.seq
+ AND decimal_cmp(a.val,b.val)>=0;
+} {}
+do_execsql_test 2010 {
+ SELECT *, '|'
+ FROM t1 AS a, t1 AS b
+ WHERE a.seq<>b.seq
+ AND decimal_cmp(a.val,b.val)==0;
+} {}
+do_execsql_test 2020 {
+ SELECT *, '|'
+ FROM t1 AS a, t1 AS b
+ WHERE a.seq>b.seq
+ AND decimal_cmp(a.val,b.val)<=0;
+} {}
+do_execsql_test 2030 {
+ SELECT seq FROM t1 ORDER BY val COLLATE decimal;
+} {1 2 3 4 5 6 7 8 9 10 11 12}
+do_execsql_test 2040 {
+ SELECT seq FROM t1 ORDER BY val COLLATE decimal DESC;
+} {12 11 10 9 8 7 6 5 4 3 2 1}
+
+do_execsql_test 3000 {
+ CREATE TABLE t3(seq INTEGER PRIMARY KEY, val TEXT);
+ WITH RECURSIVE c(x) AS (VALUES(1) UNION SELECT x+1 FROM c WHERE x<10)
+ INSERT INTO t3(seq, val) SELECT x, x FROM c;
+ WITH RECURSIVE c(x) AS (VALUES(1) UNION SELECT x+1 FROM c WHERE x<5)
+ INSERT INTO t3(seq, val) SELECT x+10, x*1000 FROM c;
+ SELECT decimal(val) FROM t3 ORDER BY seq;
+} {1 2 3 4 5 6 7 8 9 10 1000 2000 3000 4000 5000}
+do_execsql_test 3020 {
+ SELECT decimal_add(val,'0.5') FROM t3 WHERE seq>5 ORDER BY seq
+} {6.5 7.5 8.5 9.5 10.5 1000.5 2000.5 3000.5 4000.5 5000.5}
+do_execsql_test 3030 {
+ SELECT decimal_add(val,'-10') FROM t3 ORDER BY seq;
+} {-9 -8 -7 -6 -5 -4 -3 -2 -1 0 990 1990 2990 3990 4990}
+
+do_execsql_test 4000 {
+ SELECT decimal_sum(val) FROM t3;
+} {15055}
+do_execsql_test 4010 {
+ SELECT decimal_sum(decimal_add(val,val||'e+10')) FROM t3;
+} {150550000015055}
+do_execsql_test 4010 {
+ SELECT decimal_sum(decimal_add(val||'e+20',decimal_add(val,val||'e-20')))
+ FROM t3;
+} {1505500000000000000015055.00000000000000015055}
+
+do_execsql_test 5000 {
+ WITH RECURSIVE c(x,y,z) AS (
+ VALUES(0,'1','1')
+ UNION ALL
+ SELECT x+1, decimal_mul(y,'2'), decimal_mul(z,'0.5')
+ FROM c WHERE x<32
+ )
+ SELECT count(*) FROM c WHERE decimal_mul(y,z)='1';
+} {33}
+
+do_execsql_test 5100 {
+ SELECT decimal_mul('1234.00','2.00');
+} {2468.00}
+do_execsql_test 5101 {
+ SELECT decimal_mul('1234.00','2.0000');
+} {2468.00}
+do_execsql_test 5102 {
+ SELECT decimal_mul('1234.0000','2.000');
+} {2468.000}
+do_execsql_test 5103 {
+ SELECT decimal_mul('1234.0000','2');
+} {2468}
+
+
+finish_test
diff --git a/test/distinct.test b/test/distinct.test
index 9957ac388..f6f3c6cdc 100644
--- a/test/distinct.test
+++ b/test/distinct.test
@@ -51,8 +51,8 @@ proc do_temptables_test {tn sql temptables} {
set ret ""
db eval "EXPLAIN [set sql]" {
if {$opcode == "OpenEphemeral" || $opcode == "SorterOpen"} {
- if {$p5 != "08" && $p5!="00"} { error "p5 = $p5" }
- if {$p5 == "08"} {
+ if {$p5!=8 && $p5!=0} { error "p5 = $p5" }
+ if {$p5==8} {
lappend ret hash
} else {
lappend ret btree
diff --git a/test/e_expr.test b/test/e_expr.test
index 94e66afec..8dd75079b 100644
--- a/test/e_expr.test
+++ b/test/e_expr.test
@@ -1139,7 +1139,7 @@ sqlite3 db test.db
#-------------------------------------------------------------------------
# Test cases for the testable statements related to the CASE expression.
#
-# EVIDENCE-OF: R-15199-61389 There are two basic forms of the CASE
+# EVIDENCE-OF: R-57495-24088 There are two fundamental forms of the CASE
# expression: those with a base expression and those without.
#
do_execsql_test e_expr-20.1 {
@@ -1235,11 +1235,11 @@ db nullvalue {}
# evaluating WHEN terms.
#
do_execsql_test e_expr-21.4.1 {
- SELECT CASE WHEN NULL THEN 'A' WHEN 1 THEN 'B' END
-} {B}
+ SELECT CASE WHEN NULL THEN 'A' WHEN 1 THEN 'B' END, iif(NULL,8,99);
+} {B 99}
do_execsql_test e_expr-21.4.2 {
- SELECT CASE WHEN 0 THEN 'A' WHEN NULL THEN 'B' ELSE 'C' END
-} {C}
+ SELECT CASE WHEN 0 THEN 'A' WHEN NULL THEN 'B' ELSE 'C' END, iif(0,8,99);
+} {C 99}
# EVIDENCE-OF: R-38620-19499 In a CASE with a base expression, the base
# expression is evaluated just once and the result is compared against
@@ -1952,39 +1952,39 @@ foreach {tn expr} {
# 'english' and '0' are all considered to be false.
#
do_execsql_test e_expr-37.1 {
- SELECT CASE WHEN NULL THEN 'true' ELSE 'false' END;
-} {false}
+ SELECT CASE WHEN NULL THEN 'true' ELSE 'false' END, iif(NULL,'true','false');
+} {false false}
do_execsql_test e_expr-37.2 {
- SELECT CASE WHEN 0.0 THEN 'true' ELSE 'false' END;
-} {false}
+ SELECT CASE WHEN 0.0 THEN 'true' ELSE 'false' END, iif(0.0,'true','false');
+} {false false}
do_execsql_test e_expr-37.3 {
- SELECT CASE WHEN 0 THEN 'true' ELSE 'false' END;
-} {false}
+ SELECT CASE WHEN 0 THEN 'true' ELSE 'false' END, iif(0,'true','false');
+} {false false}
do_execsql_test e_expr-37.4 {
- SELECT CASE WHEN 'engligh' THEN 'true' ELSE 'false' END;
-} {false}
+ SELECT CASE WHEN 'engligh' THEN 'true' ELSE 'false' END, iif('engligh','true','false');
+} {false false}
do_execsql_test e_expr-37.5 {
- SELECT CASE WHEN '0' THEN 'true' ELSE 'false' END;
-} {false}
+ SELECT CASE WHEN '0' THEN 'true' ELSE 'false' END, iif('0','true','false');
+} {false false}
# EVIDENCE-OF: R-55532-10108 Values 1, 1.0, 0.1, -0.1 and '1english' are
# considered to be true.
#
do_execsql_test e_expr-37.6 {
- SELECT CASE WHEN 1 THEN 'true' ELSE 'false' END;
-} {true}
+ SELECT CASE WHEN 1 THEN 'true' ELSE 'false' END, iif(1,'true','false');
+} {true true}
do_execsql_test e_expr-37.7 {
- SELECT CASE WHEN 1.0 THEN 'true' ELSE 'false' END;
-} {true}
+ SELECT CASE WHEN 1.0 THEN 'true' ELSE 'false' END, iif(1.0,'true','false');
+} {true true}
do_execsql_test e_expr-37.8 {
- SELECT CASE WHEN 0.1 THEN 'true' ELSE 'false' END;
-} {true}
+ SELECT CASE WHEN 0.1 THEN 'true' ELSE 'false' END, iif(0.1,'true','false');
+} {true true}
do_execsql_test e_expr-37.9 {
- SELECT CASE WHEN -0.1 THEN 'true' ELSE 'false' END;
-} {true}
+ SELECT CASE WHEN -0.1 THEN 'true' ELSE 'false' END, iif(-0.1,'true','false');
+} {true true}
do_execsql_test e_expr-37.10 {
- SELECT CASE WHEN '1english' THEN 'true' ELSE 'false' END;
-} {true}
+ SELECT CASE WHEN '1english' THEN 'true' ELSE 'false' END, iif('1engl','true','false');
+} {true true}
finish_test
diff --git a/test/e_fkey.test b/test/e_fkey.test
index 8d465abf3..3636bef87 100644
--- a/test/e_fkey.test
+++ b/test/e_fkey.test
@@ -2507,7 +2507,7 @@ proc test_efkey_6 {tn zAlter isError} {
drop_all_tables
do_test e_fkey-56.$tn.1 "
- execsql { CREATE TABLE tbl(a, b) }
+ execsql { CREATE TABLE tbl(a, b); INSERT INTO tbl VALUES(1, 2); }
[list catchsql $zAlter]
" [lindex {{0 {}} {1 {Cannot add a REFERENCES column with non-NULL default value}}} $isError]
@@ -2771,7 +2771,7 @@ do_test e_fkey-60.6 {
#
do_test e_fkey-61.1.1 {
drop_all_tables
- execsql { CREATE TABLE t1(a, b) }
+ execsql { CREATE TABLE t1(a, b) ; INSERT INTO t1 VALUES(1, 2) }
catchsql { ALTER TABLE t1 ADD COLUMN c DEFAULT 'xxx' REFERENCES t2 }
} {1 {Cannot add a REFERENCES column with non-NULL default value}}
do_test e_fkey-61.1.2 {
diff --git a/test/filter1.test b/test/filter1.test
index ee17099d9..7b2cf9cc3 100644
--- a/test/filter1.test
+++ b/test/filter1.test
@@ -204,4 +204,22 @@ do_execsql_test 6.3 {
SELECT (SELECT COUNT(a) FROM t2) FROM t1;
} {2}
+#-------------------------------------------------------------------------
+reset_db
+do_execsql_test 7.0 {
+ CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
+ INSERT INTO t1 VALUES(321, 100000);
+ INSERT INTO t1 VALUES(111, 110000);
+ INSERT INTO t1 VALUES(444, 120000);
+ INSERT INTO t1 VALUES(222, 130000);
+}
+
+do_execsql_test 7.1 {
+ SELECT max(a), max(a) FILTER (WHERE b<12345), b FROM t1;
+} {
+ 444 {} 120000
+}
+
+
+
finish_test
diff --git a/test/fkey2.test b/test/fkey2.test
index e7fa7b645..015c43cbd 100644
--- a/test/fkey2.test
+++ b/test/fkey2.test
@@ -955,6 +955,7 @@ ifcapable altertable {
execsql {
CREATE TABLE t1(a PRIMARY KEY);
CREATE TABLE t2(a, b);
+ INSERT INTO t2 VALUES(1,2);
}
catchsql { ALTER TABLE t2 ADD COLUMN c REFERENCES t1 }
} {0 {}}
@@ -1046,6 +1047,7 @@ ifcapable altertable {
execsql {
CREATE TEMP TABLE t1(a PRIMARY KEY);
CREATE TEMP TABLE t2(a, b);
+ INSERT INTO temp.t2 VALUES(1,2);
}
catchsql { ALTER TABLE t2 ADD COLUMN c REFERENCES t1 }
} {0 {}}
@@ -1130,6 +1132,7 @@ ifcapable altertable {
ATTACH ':memory:' AS aux;
CREATE TABLE aux.t1(a PRIMARY KEY);
CREATE TABLE aux.t2(a, b);
+ INSERT INTO aux.t2(a,b) VALUES(1,2);
}
catchsql { ALTER TABLE t2 ADD COLUMN c REFERENCES t1 }
} {0 {}}
diff --git a/test/fkey5.test b/test/fkey5.test
index 3c44cd319..0c0d206b4 100644
--- a/test/fkey5.test
+++ b/test/fkey5.test
@@ -430,4 +430,59 @@ do_catchsql_test 11.1 {
PRAGMA foreign_key_check;
} {1 {foreign key mismatch - "c11" referencing "tt"}}
+# 2020-07-03 Bug in foreign_key_check discovered while working on the
+# forum reports that pragma_foreign_key_check does not accept an argument:
+# If two separate schemas seem to reference one another, that causes
+# problems for foreign_key_check.
+#
+reset_db
+do_execsql_test 12.0 {
+ ATTACH ':memory:' as aux;
+ CREATE TABLE aux.t1(a INTEGER PRIMARY KEY, b TEXT REFERENCES t2);
+ CREATE TABLE main.t2(x TEXT PRIMARY KEY, y INT);
+ INSERT INTO main.t2 VALUES('abc',11),('def',22),('xyz',99);
+ INSERT INTO aux.t1 VALUES(5,'abc'),(7,'xyz'),(9,'oops');
+ PRAGMA foreign_key_check=t1;
+} {t1 5 t2 0 t1 7 t2 0 t1 9 t2 0}
+do_execsql_test 12.1 {
+ CREATE TABLE aux.t2(x TEXT PRIMARY KEY, y INT);
+ INSERT INTO aux.t2 VALUES('abc',11),('def',22),('xyz',99);
+ PRAGMA foreign_key_check=t1;
+} {t1 9 t2 0}
+
+# 2020-07-03: the pragma_foreign_key_check virtual table should
+# accept arguments for the table name and/or schema name.
+#
+do_execsql_test 13.0 {
+ SELECT *, 'x' FROM pragma_foreign_key_check('t1');
+} {t1 9 t2 0 x}
+do_catchsql_test 13.1 {
+ SELECT *, 'x' FROM pragma_foreign_key_check('t1','main');
+} {1 {no such table: main.t1}}
+do_execsql_test 13.2 {
+ SELECT *, 'x' FROM pragma_foreign_key_check('t1','aux');
+} {t1 9 t2 0 x}
+
+reset_db
+do_execsql_test 13.10 {
+ PRAGMA foreign_keys=OFF;
+ CREATE TABLE t1(a INTEGER PRIMARY KEY, b TEXT REFERENCES t2);
+ CREATE TABLE t2(x TEXT PRIMARY KEY, y INT);
+ CREATE TABLE t3(w TEXT, z INT REFERENCES t1);
+ INSERT INTO t2 VALUES('abc',11),('def',22),('xyz',99);
+ INSERT INTO t1 VALUES(5,'abc'),(7,'xyz'),(9,'oops');
+ INSERT INTO t3 VALUES(11,7),(22,19);
+} {}
+do_execsql_test 13.11 {
+ SELECT x.*, '|'
+ FROM sqlite_schema, pragma_foreign_key_check(name) AS x
+ WHERE type='table'
+ ORDER BY x."table";
+} {t1 9 t2 0 | t3 2 t1 0 |}
+do_execsql_test 13.12 {
+ SELECT *, '|'
+ FROM pragma_foreign_key_check AS x
+ ORDER BY x."table";
+} {t1 9 t2 0 | t3 2 t1 0 |}
+
finish_test
diff --git a/test/fordelete.test b/test/fordelete.test
index 9a382d97f..39c0c3585 100644
--- a/test/fordelete.test
+++ b/test/fordelete.test
@@ -48,7 +48,7 @@ proc analyze_delete_program {sql} {
set obj $T($root)
set O($obj) ""
- if {"0x$R(p5)" & 0x08} {
+ if {$R(p5) & 0x08} {
set O($obj) *
} else {
set O($obj) ""
diff --git a/test/fts3corrupt2.test b/test/fts3corrupt2.test
index 40783facf..58643534f 100644
--- a/test/fts3corrupt2.test
+++ b/test/fts3corrupt2.test
@@ -16,6 +16,7 @@ source $testdir/tester.tcl
ifcapable !fts3 { finish_test ; return }
set ::testprefix fts3corrupt2
+sqlite3_fts3_may_be_corrupt 1
set data [list]
lappend data {*}{
@@ -107,5 +108,4 @@ foreach c {50 100 150 200 250} {
-
finish_test
diff --git a/test/fts3corrupt4.test b/test/fts3corrupt4.test
index 89853833c..90a7c7d4c 100644
--- a/test/fts3corrupt4.test
+++ b/test/fts3corrupt4.test
@@ -5847,4 +5847,439 @@ do_catchsql_test 37.1 {
INSERT INTO f VALUES (0,x'00');
} {1 {database disk image is malformed}}
+#-------------------------------------------------------------------------
+#
+reset_db
+do_test 38.0 {
+ sqlite3 db {}
+ db deserialize [decode_hexdb {
+.open --hexdb
+| size 24576 pagesize 4096 filename crash-1cc4f8a70485ce.db
+| page 1 offset 0
+| 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3.
+| 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 00 .....@ ........
+| 96: 00 00 00 00 0d 0e b1 00 06 0d a4 00 0f 8d 0f 21 ...............!
+| 112: 0e b9 0d c8 0e 7e 0d a4 00 00 00 00 00 00 00 00 .....~..........
+| 3488: 00 00 00 00 22 07 06 17 11 11 01 31 74 61 62 6c ...........1tabl
+| 3504: 65 74 32 74 32 07 43 52 45 41 54 45 20 54 41 42 et2t2.CREATE TAB
+| 3520: 4c 45 20 74 32 28 78 29 81 33 05 07 17 1f 1f 01 LE t2(x).3......
+| 3536: 82 35 74 61 62 6c 65 74 31 5f 73 65 67 64 69 72 .5tablet1_segdir
+| 3552: 74 31 5f 73 65 67 64 69 72 05 43 52 45 41 54 45 t1_segdir.CREATE
+| 3568: 20 54 41 42 4c 45 20 27 74 31 5f 73 65 67 64 69 TABLE 't1_segdi
+| 3584: 72 27 28 6c 65 76 65 6c 20 49 4e 54 45 47 45 52 r'(level INTEGER
+| 3600: 2c 69 64 78 20 49 4e 54 45 47 45 52 2c 73 74 61 ,idx INTEGER,sta
+| 3616: 72 74 5f 62 6c 6f 63 6b 20 49 4e 54 45 47 45 52 rt_block INTEGER
+| 3632: 2c 6c 65 61 76 65 73 5f 65 6e 64 5f 62 6c 6f 63 ,leaves_end_bloc
+| 3648: 6b 20 49 4e 54 45 47 45 52 2c 65 6e 64 5f 62 6c k INTEGER,end_bl
+| 3664: 6f 63 6b 20 49 4e 54 45 47 45 62 2c 72 6f 6f 74 ock INTEGEb,root
+| 3680: 20 42 4c 4f 42 2c 50 52 49 4d 41 52 59 20 4b 45 BLOB,PRIMARY KE
+| 3696: 59 28 6c 65 76 65 6c 2c 20 69 64 78 29 29 31 06 Y(level, idx))1.
+| 3712: 06 17 45 1f 01 00 69 6e 64 65 78 73 71 6c 69 74 ..E...indexsqlit
+| 3728: 65 5f 61 75 74 6f 69 6e 64 65 78 5f 74 31 5f 73 e_autoindex_t1_s
+| 3744: 65 67 64 69 72 5f 31 74 31 5f 73 65 67 64 69 72 egdir_1t1_segdir
+| 3760: 06 0f c7 00 08 00 00 00 00 66 04 07 17 23 23 01 .........f...##.
+| 3776: 81 13 74 61 62 6c 65 74 31 5f 73 65 67 6d 65 6e ..tablet1_segmen
+| 3792: 74 73 74 31 5f 73 65 67 6d 65 6e 74 73 04 43 52 tst1_segments.CR
+| 3808: 45 41 54 45 20 54 41 42 4c 45 20 27 74 31 5f 73 EATE TABLE 't1_s
+| 3824: 65 67 6d 65 6e 74 73 27 28 62 6c 6f 63 6b 69 64 egments'(blockid
+| 3840: 20 49 4e 54 45 47 45 52 20 50 52 49 4d 41 52 59 INTEGER PRIMARY
+| 3856: 20 4b 45 59 2c 20 62 6c 6f 63 6b 20 42 4c 4f 42 KEY, block BLOB
+| 3872: 29 6a 03 07 17 21 21 01 81 1f 74 61 62 6c 65 74 )j...!!...tablet
+| 3888: 31 5f 63 6f 6e 74 65 6e 74 74 31 5f 63 6f 6e 74 1_contentt1_cont
+| 3904: 65 6e 74 03 43 52 45 41 54 45 20 54 41 42 4c 45 ent.CREATE TABLE
+| 3920: 20 27 74 31 5f 63 6f 6e 74 65 6e 74 27 28 64 6f 't1_content'(do
+| 3936: 63 69 64 20 49 4e 54 45 47 45 52 20 50 52 49 4d cid INTEGER PRIM
+| 3952: 41 52 59 20 4b 45 59 2c 20 27 63 30 61 27 2c 20 ARY KEY, 'c0a',
+| 3968: 27 63 31 62 27 2c 20 27 63 32 63 27 29 38 02 06 'c1b', 'c2c')8..
+| 3984: 17 11 11 08 5f 74 61 62 6c 65 74 31 74 31 43 52 ...._tablet1t1CR
+| 4000: 45 41 54 45 20 56 49 52 54 55 41 4c 20 54 41 42 EATE VIRTUAL TAB
+| 4016: 4c 45 20 74 31 20 55 53 49 4e 47 20 66 74 73 33 LE t1 USING fts3
+| 4032: 28 61 2c 62 2c 63 29 00 00 00 00 00 00 00 00 00 (a,b,c).........
+| page 3 offset 8192
+| 0: 0d 00 00 00 25 0b 48 00 0f d8 0f af 0f 86 0f 74 ....%.H........t
+| 16: 0f 61 0f 4e 0f 2f 0f 0f 0e ef 0e d7 0e be 0e a5 .a.N./..........
+| 32: 0e 8d 0e 74 0e 5b 0e 40 0e 24 0e 08 0d ef 00 00 ...t.[.@.$......
+| 2880: 00 00 00 00 00 00 00 00 81 3f 25 06 00 82 7e f0 .........?%...~.
+| 2896: 00 43 4f 4d 50 49 4c 45 52 3d 67 63 63 2d 35 2e .COMPILER=gcc-5.
+| 2912: 34 23 00 20 42 30 31 36 2f 36 30 39 20 44 45 42 4#. B016/609 DEB
+| 2928: 55 47 20 45 4e 41 42 4c 45 20 44 42 53 54 41 54 UG ENABLE DBSTAT
+| 2944: 20 56 54 41 42 20 45 4e 42 92 4c 45 20 46 54 53 VTAB ENB.LE FTS
+| 2960: 34 20 45 4e 41 42 4c 45 20 46 54 53 35 20 45 4e 4 ENABLE FTS5 EN
+| 2976: 41 42 4c 45 20 47 45 4f 50 4f 4c 59 20 45 4e 41 ABLE GEOPOLY ENA
+| 2992: 42 5c 45 1f 4a 53 4f 4e 31 20 45 4e 41 42 4c 45 B.E.JSON1 ENABLE
+| 3008: 20 4d 45 4d 53 59 53 35 20 45 4e 41 42 4c 45 20 MEMSYS5 ENABLE
+| 3024: 52 54 52 45 45 20 4d 41 58 20 4d 45 4d 4f 52 59 RTREE MAX MEMORY
+| 3040: 3d 35 30 30 30 30 30 30 30 20 4f 4d 49 54 20 4c =50000000 OMIT L
+| 3056: 4f 41 44 20 45 58 54 45 4e 53 49 4f 4e 20 54 48 OAD EXTENSION TH
+| 3072: 52 45 41 44 53 41 46 45 3d 30 18 24 05 00 25 0f READSAFE=0.$..%.
+| 3088: 19 54 48 52 45 41 44 53 41 46 45 3d 30 58 42 49 .THREADSAFE=0XBI
+| 3104: 4e 41 52 59 18 23 05 00 25 0f 19 54 48 52 45 41 NARY.#..%..THREA
+| 3120: 44 53 41 46 45 3d 30 88 4e 4f 43 41 53 45 17 22 DSAFE=0.NOCASE..
+| 3136: 05 00 25 0f 17 54 48 52 45 41 44 53 41 46 45 3d ..%..THREADSAFE=
+| 3152: 30 58 52 54 52 49 4d 1f 21 05 00 33 0f 19 4f 4d 0XRTRIM.!..3..OM
+| 3168: 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 53 49 4f IT LOAD EXTENSIO
+| 3184: 4e 58 42 49 4e 41 52 59 1f 20 05 00 33 0f 19 4f NXBINARY. ..3..O
+| 3200: 4d 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 53 49 MIT LOAD EXTENSI
+| 3216: 4f 4e 58 4e 4f 43 41 53 45 1e 1f 05 00 33 0f 17 ONXNOCASE....3..
+| 3232: 4f 4d 49 54 20 4c 4f 41 54 20 45 58 54 45 4e 53 OMIT LOAT EXTENS
+| 3248: 49 4f 4e 58 52 54 52 49 4d 1f 1e 04 00 33 0f 19 IONXRTRIM....3..
+| 3264: 82 41 58 20 4d 45 4d 4f 52 59 3d 35 30 30 30 30 .AX MEMORY=50000
+| 3280: 30 30 30 58 42 49 4e 41 52 59 1f 1d 05 00 33 0f 000XBINARY....3.
+| 3296: 19 4d 41 58 20 4d 45 4d 4f 52 59 3d 35 30 30 30 .MAX MEMORY=5000
+| 3312: 30 30 30 30 58 4e 4f 43 41 53 45 1e 1c 05 00 33 0000XNOCASE....3
+| 3328: 0f 17 4d 41 58 20 4d 45 4d fa 52 59 3d 35 30 20 ..MAX MEM.RY=50
+| 3344: 30 30 30 30 30 58 52 54 52 49 4d 18 1b 05 00 25 00000XRTRIM....%
+| 3360: 0f 19 45 4e 41 42 4c 45 20 52 54 52 45 45 58 42 ..ENABLE RTREEXB
+| 3376: 49 4e 41 52 59 18 1a 05 00 25 0f 19 45 4e 41 42 INARY....%..ENAB
+| 3392: 4c 45 20 52 54 52 45 45 58 4e 4f 43 41 53 45 17 LE RTREEXNOCASE.
+| 3408: 19 05 00 25 0f 17 45 4e 42 42 4c 45 20 52 54 52 ...%..ENBBLE RTR
+| 3424: 45 45 58 52 54 52 49 4d 1a 18 05 00 29 0f 19 45 EEXRTRIM....)..E
+| 3440: 4e 41 42 4c 45 20 4d 45 4d 53 59 53 35 58 42 49 NABLE MEMSYS5XBI
+| 3456: 4e 41 52 59 1a 17 05 00 29 0f 19 45 4e 41 42 3c NARY....)..ENAB<
+| 3472: 45 20 4d 45 4d 53 59 53 35 58 4e 4f 43 41 53 45 E MEMSYS5XNOCASE
+| 3488: 19 16 05 00 29 0f 17 45 4e 41 42 4c 45 20 4d 45 ....)..ENABLE ME
+| 3504: 4d 53 59 53 35 58 52 54 52 49 4d 18 15 05 00 25 MSYS5XRTRIM....%
+| 3520: 0f 19 45 4e 41 42 4c 45 20 4a 53 4f 4e 31 58 42 ..ENABLE JSON1XB
+| 3536: 49 4e 41 52 59 18 14 05 00 25 0f 19 45 4e 41 42 INARY....%..ENAB
+| 3552: 4c 45 20 4a 53 4f 4e 31 58 4e 4f 43 41 53 45 17 LE JSON1XNOCASE.
+| 3568: 13 05 00 25 0f 17 45 4e 41 42 4c 45 20 4a 53 4f ...%..ENABLE JSO
+| 3584: 4e 31 58 52 54 52 49 4d 95 12 05 00 29 0f 19 45 N1XRTRIM....)..E
+| 3600: 4e 31 42 4c 45 20 47 45 4e 50 4f 4c 59 58 42 49 N1BLE GENPOLYXBI
+| 3616: 4e 41 52 59 1a 11 05 00 29 0f 19 45 3e f2 1e 4c NARY....)..E>..L
+| 3632: 45 20 47 45 4f 50 4f 4c 59 58 4e 4f 43 41 53 45 E GEOPOLYXNOCASE
+| 3648: 19 10 05 00 29 0f 17 45 4e 41 42 4c 45 20 47 45 ....)..ENABLE GE
+| 3664: 4f 50 4f 4c 59 58 52 54 52 49 4d 17 0f 05 00 23 OPOLYXRTRIM....#
+| 3680: 0f 19 45 4e 41 42 4c 45 20 46 54 53 35 58 42 49 ..ENABLE FTS5XBI
+| 3696: 4e 41 52 59 17 0e 05 00 23 0f 19 45 4e 41 42 3c NARY....#..ENAB<
+| 3712: 45 20 46 54 53 35 58 4e 4f 43 41 53 45 16 0d 05 E FTS5XNOCASE...
+| 3728: 00 23 0f 17 45 4e 41 42 4c 45 20 46 54 53 35 58 .#..ENABLE FTS5X
+| 3744: 5d 24 52 49 4d 17 0c 05 00 23 0f 19 45 4e 41 42 ]$RIM....#..ENAB
+| 3760: 4c 45 20 46 54 53 34 58 42 49 4e 41 52 59 17 0b LE FTS4XBINARY..
+| 3776: 05 00 23 0f 19 45 4e 41 42 4c 45 20 46 54 53 35 ..#..ENABLE FTS5
+| 3792: 58 4e 4f 43 40 53 45 16 0a 05 00 23 0f 17 45 4e XNOC@SE....#..EN
+| 3808: 41 42 4c 45 20 46 54 53 34 58 52 54 52 49 4d 1e ABLE FTS4XRTRIM.
+| 3824: 09 05 00 31 0f 19 45 4e 41 42 4c 45 20 44 42 53 ...1..ENABLE DBS
+| 3840: 54 41 54 20 56 54 41 42 58 42 49 4e 41 52 59 1e TAT VTABXBINARY.
+| 3856: 08 05 00 31 0f 19 45 4e 41 42 4c 45 20 44 42 53 ...1..ENABLE DBS
+| 3872: 54 41 54 20 56 54 41 42 58 4e 4f 43 41 53 45 1d TAT VTABXNOCASE.
+| 3888: 07 05 00 31 0f 17 45 4e 41 42 4b 45 20 44 42 53 ...1..ENABKE DBS
+| 3904: 54 41 54 20 56 53 41 42 58 52 54 62 49 4d 11 06 TAT VSABXRTbIM..
+| 3920: 05 00 17 0f 19 44 45 42 54 47 58 42 49 4e 41 52 .....DEBTGXBINAR
+| 3936: 59 11 05 05 00 17 0f 19 44 45 42 55 47 58 4e 4f Y.......DEBUGXNO
+| 3952: 43 41 53 45 10 04 05 00 17 0f 17 44 45 42 55 47 CASE.......DEBUG
+| 3968: 68 52 54 52 49 4d 27 03 05 00 43 0f 19 43 4f 4d hRTRIM'...C..COM
+| 3984: 50 49 4c 45 52 3d 67 63 63 2d 35 2e 34 2e 30 20 PILER=gcc-5.4.0
+| 4000: 32 30 31 36 30 36 30 39 58 42 49 4e 41 52 59 27 20160609XBINARY'
+| 4016: 02 05 00 43 0f 19 43 4f 4d 50 49 4c 45 52 3d 67 ...C..COMPILER=g
+| 4032: 63 63 2d 35 2e 34 2e 30 20 32 30 31 36 30 36 30 cc-5.4.0 2016060
+| 4048: 39 58 4f 4f 43 41 53 45 26 01 05 00 43 0f 17 43 9XOOCASE&...C..C
+| 4064: 4f 4d 50 49 4c 45 52 3d 67 63 63 2d 35 2e 34 2e OMPILER=gcc-5.4.
+| 4080: 30 20 32 30 31 36 30 36 30 39 58 52 54 52 49 4d 0 20160609XRTRIM
+| page 4 offset 12288
+| 0: 0d 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+| page 5 offset 16384
+| 0: 0d 00 00 00 02 0b a0 00 0c ad 0b a0 00 00 00 00 ................
+| 2976: 82 0a 02 08 08 09 08 08 17 84 06 30 20 32 35 33 ...........0 253
+| 2992: 00 01 30 04 25 06 1b 00 00 08 32 30 31 36 8c 36 ..0.%.....2016.6
+| 3008: 30 39 03 25 07 00 00 01 34 03 25 05 00 00 01 35 09.%....4.%....5
+| 3024: 03 25 04 00 01 07 30 30 30 30 30 30 30 03 25 1a .%....0000000.%.
+| 3040: 00 00 08 63 6f 5d 70 69 6c 65 72 03 25 02 00 00 ...co]piler.%...
+| 3056: 06 64 62 73 74 61 74 03 25 0a 00 01 04 65 62 75 .dbstat.%....ebu
+| 3072: 67 03 25 08 00 00 06 65 6e 61 62 6c 65 09 25 09 g.%....enable.%.
+| 3088: 05 04 04 04 04 04 00 01 08 78 74 65 7e 73 69 6f .........xte~sio
+| 3104: 6e 03 25 1d 00 00 04 66 74 73 34 03 25 0d 00 03 n.%....fts4.%...
+| 3120: 01 35 03 25 0f 00 00 03 67 63 63 03 25 03 00 01 .5.%....gcc.%...
+| 3136: 06 65 6f 70 7f 6c 79 03 25 11 00 00 05 6a 73 6f .eop.ly.%....jso
+| 3152: 6e 31 03 25 14 00 e8 04 6c 6f 61 64 03 25 1c 00 n1.%....load.%..
+| 3168: 00 03 6d 61 78 03 25 18 00 01 05 65 6d 6f 72 79 ..max.%....emory
+| 3184: 03 25 19 00 03 04 73 79 73 35 03 25 15 00 00 04 .%....sys5.%....
+| 3200: 6f 6d 69 74 03 25 1b 00 00 05 72 74 72 65 65 03 omit.%....rtree.
+| 3216: 25 17 00 00 0a 74 68 72 65 61 64 73 61 66 65 03 %....threadsafe.
+| 3232: 25 1e 00 00 04 76 74 61 62 03 25 0b 00 86 50 01 %....vtab.%...P.
+| 3248: 08 08 08 08 08 17 8d 12 30 20 38 33 35 00 01 30 ........0 835..0
+| 3264: 12 01 06 00 01 06 00 01 06 00 1f 03 00 01 03 00 ................
+| 3280: 01 03 00 00 08 32 30 31 36 30 36 30 39 09 01 07 .....20160609...
+| 3296: 00 01 07 00 01 07 00 00 01 34 09 01 05 00 01 05 .........4......
+| 3312: 00 01 05 00 00 01 35 09 01 04 00 01 04 00 01 04 ......5.........
+| 3328: 00 01 07 30 30 30 30 30 30 30 09 1c 04 00 01 04 ...0000000......
+| 3344: 00 01 04 00 00 06 62 69 6e 61 72 79 3c 03 01 02 ......binary<...
+| 3360: 02 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 ................
+| 3376: 00 03 01 02 c2 00 03 01 02 02 00 03 01 04 82 00 ................
+| 3392: 03 01 02 02 00 03 01 02 02 00 03 01 02 02 00 03 ................
+| 3408: 01 02 02 00 03 01 02 02 00 00 08 63 6f 6d 70 69 ...........compi
+| 3424: 6c 65 72 09 01 02 00 01 02 00 01 02 00 00 06 64 ler............d
+| 3440: 62 73 74 61 74 09 07 03 00 01 03 00 01 03 00 01 bstat...........
+| 3456: 04 65 62 75 67 09 04 02 00 01 02 00 01 02 00 00 .ebug...........
+| 3472: 06 65 6e 60 62 6c 65 3f 07 02 00 01 02 92 e1 a4 .en`ble?........
+| 3488: ff fc a2 8c 95 b2 3f 01 01 f0 f1 02 00 57 02 00 ......?......W..
+| 3504: 01 02 00 01 02 00 01 02 00 01 02 00 01 02 10 01 ................
+| 3520: 02 00 01 02 00 01 02 00 01 02 01 01 02 00 01 02 ................
+| 3536: 00 01 02 00 00 f2 00 01 08 78 74 65 6e 73 69 6f .........xtensio
+| 3552: 6e 09 1f 04 00 01 04 00 01 04 00 00 04 66 74 73 n............fts
+| 3568: 34 09 0a 03 00 01 03 00 01 03 00 03 01 35 09 0d 4............5..
+| 3584: 03 00 01 03 00 01 03 00 00 03 67 63 63 09 01 03 ..........gcc...
+| 3600: 00 01 03 00 01 03 00 01 06 65 5f 70 6f 6c 79 09 .........e_poly.
+| 3616: 10 03 00 01 03 00 01 03 00 00 b3 6a 73 6f 6e 31 ...........json1
+| 3632: 09 13 03 00 01 03 00 01 03 00 00 04 6c 6f 61 64 ............load
+| 3648: 09 1f 03 00 01 03 00 01 03 00 00 03 6d 61 78 09 ............max.
+| 3664: 1c 02 00 01 02 00 01 02 00 01 05 65 6d 6f 72 79 ...........emory
+| 3680: 09 1c 03 00 01 03 00 01 03 00 03 04 73 79 73 35 ............sys5
+| 3696: 09 16 03 00 01 03 00 01 03 cc 00 06 6e 6f 63 61 ............noca
+| 3712: 73 65 3c 02 01 02 02 00 03 01 02 02 00 03 01 02 se<.............
+| 3728: 02 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 ................
+| 3744: 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 00 ................
+| 3760: 03 01 02 02 00 03 01 02 02 00 03 01 02 02 00 00 ................
+| 3776: 04 6f 6d 69 74 09 1f 02 00 01 02 00 01 02 00 00 .omit...........
+| 3792: 05 72 74 62 65 65 09 19 03 00 01 03 00 01 03 00 .rtbee..........
+| 3808: 03 02 69 6d 3c 01 01 02 02 00 03 01 02 02 00 03 ..im<...........
+| 3824: 01 02 02 00 03 01 02 02 00 03 01 02 02 00 03 01 ................
+| 3840: 02 02 00 03 01 02 02 00 03 01 02 02 00 03 01 02 ................
+| 3856: 02 00 03 01 02 02 00 03 01 02 01 00 03 01 02 02 ................
+| 3872: 00 00 0a 74 68 72 65 61 64 73 61 66 65 09 22 02 ...threadsafe...
+| 3888: 00 01 02 00 02 02 00 00 04 76 74 61 62 09 07 04 .........vtab...
+| 3904: 00 01 03 00 01 04 00 00 01 78 b4 01 01 01 01 02 .........x......
+| 3920: 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 ................
+| 3936: 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 01 ................
+| 3952: 01 01 02 00 01 01 01 02 00 01 01 01 02 00 01 01 ................
+| 3968: 01 02 00 01 01 01 02 00 01 01 01 02 00 01 01 01 ................
+| 3984: 02 01 01 01 01 02 00 01 01 01 02 00 01 01 01 02 ................
+| 4000: 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 ................
+| 4016: 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 01 ................
+| 4032: 01 01 02 00 01 01 01 da 00 00 f1 01 02 00 01 01 ................
+| 4048: 01 02 00 01 01 01 01 ff ff 01 01 02 00 01 01 01 ................
+| 4064: 02 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 ................
+| 4080: 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 ................
+| page 6 offset 20480
+| 0: 0a 00 00 00 02 0f f5 00 0f fb 0f f5 01 00 00 00 ................
+| 4080: 00 00 00 00 00 05 04 08 09 01 02 04 04 08 08 09 ................
+| end crash-1cc4f8a70485ce.db
+}]} {}
+
+do_execsql_test 38.1 {
+ UPDATE t1 SET b=a;
+}
+
+do_catchsql_test 38.2 {
+ SELECT b FROM t1 WHERE a MATCH 'e*e*e*e*e*e*e*e*e*e*e*e*e*e*e*e*'
+} {1 {database disk image is malformed}}
+
+#-------------------------------------------------------------------------
+reset_db
+set saved $sqlite_fts3_enable_parentheses
+set sqlite_fts3_enable_parentheses 1
+do_execsql_test 39.0 {
+ CREATE VIRTUAL TABLE t0 USING fts3(
+ col0 INTEGER PRIMARY KEY,
+ col1 VARCHAR(8),
+ col2 BINARY,
+ col3 BINARY
+ );
+ INSERT INTO t0_content VALUES(1,1,'1234','aaaa','bbbb');
+ INSERT INTO t0_segdir VALUES(0,0,0,0,'0 42',X'000131030782000103323334050101010200000461616161050101020200000462626262050101030200');
+}
+
+do_test 39.1 {
+ catch {
+ db eval { SELECT rowid FROM t0 WHERE t0 MATCH '1 NEAR 1' }
+ }
+} 0
+
+do_test 39.2 {
+ catch {
+ db eval {
+ SELECT matchinfo(t0,'yxy') FROM t0 WHERE t0 MATCH x'2b0a312b0a312a312a2a0b5d0a0b0b0a312a0a0b0b0a312a0b310a392a0b0a27312a2a0b5d0a312a0b310a31315d0b310a312a316d2a0b313b15bceaa50a312a0b0a27312a2a0b5d0a312a0b310a312b0b2a310a312a0b2a0b2a0b2e5d0a0bff313336e34a2a312a0b0a3c310b0a0b4b4b0b4b2a4bec40322b2a0b310a0a312a0a0a0a0a0a0a0a0a0b310a312a2a2a0b5d0a0b0b0a312a0b310a312a0b0a4e4541530b310a5df5ced70a0a0a0a0a4f520a0a0a0a0a0a0a312a0b0a4e4541520b310a5d616161610a0a0a0a4f520a0a0a0a0a0a312b0a312a312a0a0a0a0a0a0a004a0b0a310b220a0b0a310a4a22310a0b0a7e6fe0e0e030e0e0e0e0e01176e02000e0e0e0e0e01131320226310a0b0a310a4a22310a0b0a310a766f8b8b4ee0e0300ae0090909090909090909090909090909090909090909090909090909090909090947aaaa540b09090909090909090909090909090909090909090909090909090909090909fae0e0f2f22164e0e0f273e07fefefef7d6dfafafafa6d6d6d6d';
+ }
+ }
+} 0
+set sqlite_fts3_enable_parentheses $saved
+
+#-------------------------------------------------------------------------
+reset_db
+set saved $sqlite_fts3_enable_parentheses
+set sqlite_fts3_enable_parentheses 1
+
+do_execsql_test 40.1 {
+
+ CREATE VIRTUAL TABLE t0 USING fts3(col0 INTEGER PRIMARY KEY, col1, col2 ,col3 );
+ INSERT INTO t0_segdir VALUES(0,0,0,0,'0 42',
+ X'0001310301020001033233340500010102000004616161bc050101020200000462626262050101030200'
+ );
+}
+
+do_execsql_test 40.2 {
+ SELECT 0==matchinfo(t0,'sx') FROM t0 WHERE t0 MATCH '1* 2 3 4 5 6 OR 1';
+} 0
+
+set sqlite_fts3_enable_parentheses $saved
+
+#-------------------------------------------------------------------------
+reset_db
+do_execsql_test 41.1 {
+ CREATE VIRTUAL TABLE t1 USING fts3(a,b,c);
+ INSERT INTO t1_segdir VALUES(0,0,0,0,'0 835',X'000130120106000106000106001f030001030001030000083230313630363039090107000107000107000001340901050001050001050000013509010400010400010400010730303030303030091c0400010400010400000662696e6172793c0301020200030102020003010202000301020200030102020003010202000301020200030102020003010202000301020200030102020003010202000008636f3870696c657209010200010200010200000664627374617409070300010300010300010465627567090402000102000102000006656e61626c653f07020001020001020001020001020001020001020001020001020001030001010002020001020001020001020001120001020001020001020001020001020001087874656e73696f6e091f0400010400010400000466747334090a0300010300010400030135090d03000103000103000003676363090103000103000103000106656f706f6c790910030001030001030000056a736f6e310913030001030001030000046c6f6164091f030001030001030000036d6178091c02000102000102000105656d6f7279091c03000103000103000304737973350916030001030001030000066e6f636173653c02010202000301020200030102020003010202000301020200030102020003010202000301020200030102020003010202000301020200030102020000046f6d6974091f020001020001020000057274726565091903000103000103000302696d3c010102020003010202000301020200030102020003010202000301020200030102020003010202000301020200030102020003010202000301020200000a746872656164736166650922020001020001020000047674616209070400010400010400000178b401010101020001010102000101010200010101020001010102000101010200010101020001010102000101010200010101020001010102000101010200010101020001010102000101010200010101020001010102000101010200010101020001010102000101010200010101020001010102000101010200010101020001010102000101010200010101020001010102000101010200010101020001010102000101010200010101020001010102000101010200');
+}
+
+do_execsql_test 41.2 {
+ SELECT offsets(t1) FROM t1 WHERE t1 MATCH 'rtree ner "json1^enable"';
+}
+
+#-------------------------------------------------------------------------
+do_execsql_test 42.1 {
+ CREATE VIRTUAL TABLE f USING fts3(a, b);
+}
+do_execsql_test 42.2 {
+ INSERT INTO f_segdir VALUES(0,2,1111,0,0,X'00');
+ INSERT INTO f_segdir VALUES(0,3,0 ,0,0,X'00013003010200');
+}
+do_execsql_test 42.3 {
+ INSERT INTO f(f) VALUES ('merge=107,2');
+}
+
+#-------------------------------------------------------------------------
+reset_db
+set saved $sqlite_fts3_enable_parentheses
+set sqlite_fts3_enable_parentheses 1
+do_execsql_test 43.1 {
+ CREATE VIRTUAL TABLE def USING fts3(xyz);
+ INSERT INTO def_segdir VALUES(0,0,0,0,0, X'0001310301c9000103323334050d81');
+} {}
+
+do_execsql_test 43.2 {
+ SELECT rowid FROM def WHERE def MATCH '1 NEAR 1'
+} {1}
+
+set sqlite_fts3_enable_parentheses $saved
+
+#-------------------------------------------------------------------------
+reset_db
+do_execsql_test 44.1 {
+ CREATE VIRTUAL TABLE t0 USING fts3(col0 INTEGER PRIMARY KEY,col1 VARCHAR(8),col2 BINARY,col3 BINARY);
+ INSERT INTO t0_content VALUES(0,NULL,NULL,NULL,NULL);
+ INSERT INTO t0_segdir VALUES(0,0,0,0,'0 42',X'00013103010200010332333405010201ba00000461616161050101020200000462626262050101030200');
+}
+
+do_execsql_test 44.2 {
+ SELECT matchinfo(t0, t0) IS NULL FROM t0 WHERE t0 MATCH '1*'
+} {0}
+
+#-------------------------------------------------------------------------
+#
+reset_db
+do_test 45.0 {
+ sqlite3 db {}
+ db deserialize [decode_hexdb {
+.open --hexdb
+| size 24576 pagesize 4096 filename crash-65c98512cc9e49.db
+| page 1 offset 0
+| 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3.
+| 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 06 .....@ ........
+| 96: 00 00 00 00 0d 0e fc 00 06 0d bc 00 0f ca 0f 6c ...............l
+| 112: 0f 04 0e 13 0e c9 0d bc 00 00 00 00 00 00 00 00 ................
+| 3504: 00 00 00 00 00 00 00 00 00 00 00 00 55 06 07 17 ............U...
+| 3520: 1b 1b 01 81 01 74 61 62 6c 65 78 31 5f 73 74 61 .....tablex1_sta
+| 3536: 74 78 31 5f 73 74 61 74 06 43 52 45 41 54 45 20 tx1_stat.CREATE
+| 3552: 54 41 42 4c 45 20 27 78 31 5f 73 74 61 74 27 28 TABLE 'x1_stat'(
+| 3568: 69 64 20 49 4e 54 45 47 45 52 20 50 52 49 4d 41 id INTEGER PRIMA
+| 3584: 52 59 20 4b 45 59 2c 20 76 61 6c 75 65 20 42 4c RY KEY, value BL
+| 3600: 41 82 29 81 33 04 07 17 1f 1f 01 82 35 74 61 62 A.).3.......5tab
+| 3616: 6c 65 78 31 5f 73 65 67 64 69 72 78 31 5f 73 65 lex1_segdirx1_se
+| 3632: 67 64 69 72 04 43 52 45 41 54 45 20 54 41 42 4c gdir.CREATE TABL
+| 3648: 45 20 27 78 31 5f 73 65 67 64 69 72 27 28 6c 65 E 'x1_segdir'(le
+| 3664: 76 65 6c 20 49 4e 54 45 47 45 52 2c 69 64 78 20 vel INTEGER,idx
+| 3680: 49 4e 54 45 47 45 52 2c 73 74 61 72 74 5f 62 6c INTEGER,start_bl
+| 3696: 6f 63 6b 20 49 4e 54 45 47 45 52 2c 6c 65 61 76 ock INTEGER,leav
+| 3712: 65 73 5f 65 6e 64 5f 62 6c 6f 63 6b 20 49 4e 54 es_end_block INT
+| 3728: 45 47 45 52 2c 65 6e 64 5f 62 6c 6f 63 6b 20 49 EGER,end_block I
+| 3744: 4e 54 45 47 45 52 2c 72 6f 6f 74 20 42 4c 4f 42 NTEGER,root BLOB
+| 3760: 2c 50 52 49 4d 41 52 59 20 4b 45 59 28 6c 65 76 ,PRIMARY KEY(lev
+| 3776: 65 6c 2c 20 69 64 78 29 29 31 05 06 17 45 1f 01 el, idx))1...E..
+| 3792: 00 69 6e 64 65 78 73 71 6c 69 74 65 5f 61 75 74 .indexsqlite_aut
+| 3808: 6f 69 6e 64 65 78 5f 78 31 5f 73 65 67 64 69 72 oindex_x1_segdir
+| 3824: 5f 31 78 31 5f 73 65 67 64 69 72 05 00 00 00 08 _1x1_segdir.....
+| 3840: 60 00 00 00 66 03 07 17 23 23 01 81 13 74 61 62 `...f...##...tab
+| 3856: 6c 65 78 31 5f 73 65 67 6d 65 6e 74 73 78 31 5f lex1_segmentsx1_
+| 3872: 73 65 67 6d 65 6e 74 73 03 43 52 45 41 54 45 20 segments.CREATE
+| 3888: 54 41 42 4c 45 20 27 78 31 5f 73 65 67 6d 65 6e TABLE 'x1_segmen
+| 3904: 74 73 27 28 62 6c 6f 63 6b 69 64 20 49 4e 54 45 ts'(blockid INTE
+| 3920: 47 45 52 20 50 52 49 4d 41 52 59 20 4b 45 59 2c GER PRIMARY KEY,
+| 3936: 20 62 6c 6f 63 6b 20 42 4c 4f 42 29 5c 02 07 17 block BLOB)....
+| 3952: 21 21 01 81 03 74 61 62 6c 65 78 31 5f 63 6f 6e !!...tablex1_con
+| 3968: 74 65 6e 74 78 31 5f 63 6f 6e 74 65 6e 74 02 43 tentx1_content.C
+| 3984: 52 45 41 54 45 20 54 41 42 4c 45 20 27 78 31 5f REATE TABLE 'x1_
+| 4000: 63 6f 6e 74 65 6e 74 27 28 64 6f 63 69 64 20 49 content'(docid I
+| 4016: 4e 54 45 47 45 52 20 50 52 49 4d 41 52 59 20 4b NTEGER PRIMARY K
+| 4032: 45 59 2c 20 27 63 30 78 27 29 34 01 06 17 11 11 EY, 'c0x')4.....
+| 4048: 08 57 74 61 62 6c 65 78 31 78 31 43 52 45 41 54 .Wtablex1x1CREAT
+| 4064: 45 20 56 49 52 54 55 41 4c 20 54 41 42 4c 45 20 E VIRTUAL TABLE
+| 4080: 78 31 20 55 53 49 4e 47 20 66 74 73 33 28 78 29 x1 USING fts3(x)
+| page 2 offset 4096
+| 0: 0d 00 00 00 11 0f 77 f0 0f f8 0f f0 0f e8 0f e0 ......w.........
+| 16: 0f d8 0f d0 0f c8 0f c0 00 00 00 00 00 00 00 00 ................
+| 3952: 00 00 00 00 00 00 00 00 06 11 03 00 13 77 78 79 .............wxy
+| 3968: 06 10 03 00 13 74 75 76 06 0f 03 00 13 71 33 73 .....tuv.....q3s
+| 3984: 06 0e 03 00 13 6e 6f 70 06 0d 03 00 13 6b 6c 6d .....nop.....klm
+| 4000: 06 0c 03 04 c3 68 69 6a 06 0b 03 00 13 65 66 67 .....hij.....efg
+| 4016: 06 0a 03 00 13 62 63 64 06 09 03 00 13 79 7a 61 .....bcd.....yza
+| 4032: 06 08 03 00 13 76 77 78 06 07 03 00 13 73 74 75 .....vwx.....stu
+| 4048: 06 06 03 00 13 70 71 72 06 05 03 00 13 6d 6e 6f .....pqr.....mno
+| 4064: 06 03 03 00 13 6a 6b 6c 06 03 03 00 13 67 68 69 .....jkl.....ghi
+| 4080: 06 02 02 00 03 64 65 66 06 01 03 00 13 61 52 63 .....def.....aRc
+| page 3 offset 8192
+| 0: 0d 00 00 00 03 0f a7 00 0f b5 0f a7 0f fa 01 00 ................
+| 4000: 00 00 00 00 00 00 00 0c 02 03 00 1e 00 03 6b 6c ..............kl
+| 4016: 6d 03 0d 02 00 43 01 04 00 81 0a 00 03 61 62 63 m....C.......abc
+| 4032: 03 0b 32 00 00 03 62 63 64 03 0a 02 00 00 03 64 ..2...bcd......d
+| 4048: 69 26 03 02 02 00 00 03 65 66 67 03 0b 02 00 00 i&......efg.....
+| 4064: 03 67 68 69 03 03 02 00 00 03 68 69 6a 03 0c 02 .ghi......hij...
+| 4080: 00 00 03 6a 6a 2c 03 04 02 00 03 81 00 03 00 00 ...jj,..........
+| page 4 offset 12288
+| 0: 0d 0f 3a 00 05 0f 25 00 0f 9e 0f 88 0f 43 0f 25 ..:...%......C.%
+| 16: 0f 72 00 00 00 00 00 00 00 00 00 00 00 00 00 00 .r..............
+| 3856: 00 00 00 00 00 00 00 00 00 56 01 08 08 13 1e 03 .........V......
+| 3872: 30 20 39 00 03 13 05 07 08 08 18 08 13 1e 30 20 0 9...........0
+| 3888: 39 00 03 77 78 79 03 11 02 00 0f 6c 00 09 01 08 9..wxy.....l....
+| 3904: 08 15 54 27 04 07 09 01 08 08 15 42 02 30 20 33 ..T'.......B.0 3
+| 3920: 36 00 03 6e 6f 70 03 0e 02 00 00 03 71 72 73 03 6..nop......qrs.
+| 3936: 0f 02 00 00 03 74 75 76 03 10 02 00 0f cf b1 06 .....tuv........
+| 3952: 01 08 14 06 07 01 08 09 01 1b 14 02 02 31 32 38 .............128
+| 3968: 20 2d 37 32 10 01 01 6b 14 03 07 09 09 08 08 15 -72...k........
+| 3984: 1e 30 20 33 36 00 03 79 7a 61 03 09 02 00 2f 02 .0 36..yza..../.
+| 4000: 07 09 08 08 08 15 54 30 20 33 36 00 03 6d 6e 6f ......T0 36..mno
+| 4016: 03 05 02 00 00 03 70 71 72 03 06 02 00 00 03 73 ......pqr......s
+| 4032: 74 75 03 07 02 00 00 03 76 77 78 03 08 02 00 00 tu......vwx.....
+| 4048: 00 00 4a 08 08 08 15 54 30 20 33 36 00 03 61 62 ..J....T0 36..ab
+| 4064: 63 03 01 02 00 00 03 64 65 66 03 02 02 00 00 03 c......def......
+| 4080: 67 68 69 03 03 67 00 00 03 6a 6b 6c 03 04 02 00 ghi..g...jkl....
+| page 5 offset 16384
+| 0: 0a 0f e7 00 05 0f da 00 0f e1 0f fa 0f f4 0f ed ................
+| 16: 0f da 0f 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+| 4048: 00 00 00 00 00 00 00 1a 01 03 06 04 01 08 01 02 ................
+| 4064: 06 05 04 08 08 01 05 00 00 00 06 01 03 06 04 09 ................
+| 4080: 02 01 02 04 05 04 09 09 01 03 05 04 09 08 01 02 ................
+| page 6 offset 20480
+| 0: 0d 00 10 00 01 0f f9 00 0f f9 00 00 00 00 00 00 ................
+| 4080: 00 00 00 00 00 00 00 00 00 05 01 03 00 10 01 03 ................
+| end crash-65c98512cc9e49.db
+}]} {}
+
+do_catchsql_test 45.2 {
+ INSERT INTO x1(x1) VALUES( 'merge=1' )
+} {1 {database disk image is malformed}}
+
+#-------------------------------------------------------------------------
+reset_db
+set saved $sqlite_fts3_enable_parentheses
+set sqlite_fts3_enable_parentheses 1
+do_execsql_test 46.1 {
+ CREATE VIRTUAL TABLE t0 USING fts3(a INTEGER PRIMARY KEY,b,c,d);
+ INSERT INTO t0_segdir VALUES(0,0,0,0,'0 42',X'0001310301c9000103323334050d8000f200000461616161050101020200000462626262050101030200');
+} {}
+
+do_catchsql_test 46.2 {
+ SELECT * FROM t0
+ WHERE t0 MATCH x'2b0a312b0a312a312a2a0b5d0a0b0b0a312a0a0b0b0a312a0b310a392a0b0a27312a2a0b5d0a312a0b310a31315d0b310a312a316d2a0b313b15bceaa50a312a0b0a27312a2a0b5d0a312a0b310a312b0b2a310a312a0b2a0b2a0b2e5d0a0bff313336e34a2a312a0b0a3c310b0a0b4b4b0b4b2a4bec40322b2a0b310a0a312a0a0a0a0a0a0a0a0a0b310a312a2a2a0b5d0a0b0b0a312a0b310a312a0b0a4e4541530b310a5df5ced70a0a0a0a0a4f520a0a0a0a0a0a0a312a0b0a4e4541520b310a5d616161610a0a0a0a4f520a0a0a0a0a0a312b0a312a312a0a0a0a0a0a0a004a0b0a310b220a0b0a310a4a22310a0b0a7e6fe0e0e030e0e0e0e0e01176e02000e0e0e0e0e01131320226310a0b0a310a4a22310a0b0a310a766f8b8b4ee0e0300ae0090909090909090909090909090909090909090909090909090909090909090947aaaa540b09090909090909090909090909090909090909090909090909090909090909fae0e0f2f22164e0e0f273e07fefefef7d6dfafafafa6d6d6d6d';
+} {1 {database disk image is malformed}}
+
+set sqlite_fts3_enable_parentheses $saved
+
finish_test
diff --git a/test/fts3corrupt6.test b/test/fts3corrupt6.test
new file mode 100644
index 000000000..9e22bdf68
--- /dev/null
+++ b/test/fts3corrupt6.test
@@ -0,0 +1,60 @@
+# 2020 June 8
+#
+# The author disclaims copyright to this source code. In place of
+# a legal notice, here is a blessing:
+#
+# May you do good and not evil.
+# May you find forgiveness for yourself and forgive others.
+# May you share freely, never taking more than you give.
+#
+#*************************************************************************
+# This file implements regression tests for SQLite library. The
+# focus of this script is testing the FTS3 module.
+#
+# $Id: fts3aa.test,v 1.1 2007/08/20 17:38:42 shess Exp $
+#
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+source $testdir/fts3_common.tcl
+set testprefix fts3corrupt6
+
+# If SQLITE_ENABLE_FTS3 is defined, omit this file.
+ifcapable !fts3 {
+ finish_test
+ return
+}
+
+set ::saved_sqlite_fts3_enable_parentheses $::sqlite_fts3_enable_parentheses
+set sqlite_fts3_enable_parentheses 1
+sqlite3_fts3_may_be_corrupt 1
+database_may_be_corrupt
+
+do_execsql_test 1.0 {
+ BEGIN TRANSACTION;
+ CREATE TABLE t_content(col0 INTEGER);
+ PRAGMA writable_schema=ON;
+ CREATE VIRTUAL TABLE t0 USING fts3(col0 INTEGER PRIMARY KEY,col1 VARCHAR(8),col2 BINARY,col3 BINARY);
+ INSERT INTO t0_content VALUES(0,NULL,NULL,NULL,NULL);
+ INSERT INTO t0_segdir VALUES(0,0,0,0,'0 42',X'000131030102000103323334050101010200000461616161050101020200000462626262050101030200');
+ COMMIT;
+}
+
+do_execsql_test 1.1 {
+ SELECT 0+matchinfo(t0,'yxyyxy') FROM t0 WHERE t0 MATCH CAST( x'2b0a312b0a312a312a2a0b5d0a0b0b0a312a0a0b0b0a312a0b310a392a0b0a27312a2a0b5d0a312a0b310a31315d0b310a312a316d2a0b313b15bceaa50a312a0b0a27312a2a0b5d0a312a0b310a312b0b2a310a312a0b2a0b2a0b2e5d0a0bff313336e34a2a312a0b0a3c310b0a0b4b4b0b4b2a4bec40322b2a0b310a0a312a0a0a0a0a0a0a0a0a0b310a312a2a2a0b5d0a0b0b0a312a0b310a312a0b0a4e4541530b310a5df5ced70a0a0a0a0a4f520a0a0a0a0a0a0a312a0b0a4e4541520b310a5d616161610a0a0a0a4f520a0a0a0a0a0a312b0a312a312a0a0a0a0a0a0a004a0b0a310b220a0b0a310a4a22310a0b0a7e6fe0e0e030e0e0e0e0e01176e02000e0e0e0e0e01131320226310a0b0a310a4a22310a0b0a310a766f8b8b4ee0e0300ae0090909090909090909090909090909090909090909090909090909090909090947aaaa540b09090909090909090909090909090909090909090909090909090909090909fae0e0f2f22164e0e0f273e07fefefef7d6dfafafafa6d6d6d6d' AS TEXT);
+} {0}
+
+do_execsql_test 1.2 {
+ CREATE VIRTUAL TABLE t1 USING fts3(col0 INTEGER PRIMARY KEY,col1 VARCHAR(8),col2 BINARY,col3 BINARY);
+ INSERT INTO t1_content VALUES(0,NULL,NULL,NULL,NULL);
+ INSERT INTO t1_segdir VALUES(0,0,0,0,'0 42',X'000131030102000103323334050101010200000461616161050101020200000462626262050101030200');
+}
+
+do_execsql_test 1.3 {
+ SELECT 42+matchinfo(t1,'yxyyxy') FROM t1 WHERE t1 MATCH x'2b0a312b0a312a312a2a0b5d0a0b0b0a312a0a0b0b0a312a0b310a392a0b0a27312a2a0b5d0a312a0b310a31315d0b310a312a316d2a0b313b15bceaa50a312a0b0a27312a2a0b5d0a312a0b310a312b0b2a310a312a0b2a0b2a0b2e5d0a0bff313336e34a2a312a0b0a3c310b0a0b4b4b0b4b2a4bec40322b2a0b310a0a312a0a0a0a0a0a0a0a0a0b310a312a2a2a0b5d0a0b0b0a312a0b310a312a0b0a4e4541530b310a5df5ced70a0a0a0a0a4f520a0a0a0a0a0a0a312a0b0a4e4541520b310a5d616161610a0a0a0a4f520a0a0a0a0a0a312b0a312a312a0a0a0a0a0a0a004a0b0a310b220a0b0a310a4a22310a0b0a7e6fe0e0e030e0e0e0e0e01176e02000e0e0e0e0e01131320226310a0b0a310a4a22310a0b0a310a766f8b8b4ee0e0300ae0090909090909090909090909090909090909090909090909090909090909090947aaaa540b09090909090909090909090909090909090909090909090909090909090909fae0e0f2f22164e0e0f273e07fefefef7d6dfafafafa6d6d6d6d';
+} {42}
+
+set sqlite_fts3_enable_parentheses $saved_sqlite_fts3_enable_parentheses
+finish_test
+
+
diff --git a/test/fts3matchinfo2.test b/test/fts3matchinfo2.test
new file mode 100644
index 000000000..670e1079f
--- /dev/null
+++ b/test/fts3matchinfo2.test
@@ -0,0 +1,35 @@
+# 2020-05-14
+#
+# The author disclaims copyright to this source code. In place of
+# a legal notice, here is a blessing:
+#
+# May you do good and not evil.
+# May you find forgiveness for yourself and forgive others.
+# May you share freely, never taking more than you give.
+#
+#***********************************************************************
+# This file implements regression tests for the FTS3 module. The focus
+# of this file is tables created with the "matchinfo=fts3" option.
+#
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+
+# If SQLITE_ENABLE_FTS3 is not defined, omit this file.
+ifcapable !fts3 { finish_test ; return }
+
+set sqlite_fts3_enable_parentheses 1
+
+# Crash case found by cyg0810 at gmail.com 2020-05-14. Reported to
+# chromium (which is not vulnerable) who kindly referred it to us.
+#
+do_execsql_test 1.0 {
+ CREATE TABLE t_content(col0 INTEGER);
+ CREATE VIRTUAL TABLE t0 USING fts3(col0 INTEGER PRIMARY KEY,col1 VARCHAR(8),col2 BINARY,col3 BINARY);
+ INSERT INTO t0 VALUES (1, '1234','aaaa','bbbb');
+ SELECT hex(matchinfo(t0,'yxy')) FROM t0 WHERE t0 MATCH x'2b0a312b0a312a312a2a0b5d0a0b0b0a312a0a0b0b0a312a0b310a392a0b0a27312a2a0b5d0a312a0b310a31315d0b310a312a316d2a0b313b15bceaa50a312a0b0a27312a2a0b5d0a312a0b310a312b0b2a310a312a0b2a0b2a0b2e5d0a0bff313336e34a2a312a0b0a3c310b0a0b4b4b0b4b2a4bec40322b2a0b310a0a312a0a0a0a0a0a0a0a0a0b310a312a2a2a0b5d0a0b0b0a312a0b310a312a0b0a4e4541530b310a5df5ced70a0a0a0a0a4f520a0a0a0a0a0a0a312a0b0a4e4541520b310a5d616161610a0a0a0a4f520a0a0a0a0a0a312b0a312a312a0a0a0a0a0a0a004a0b0a310b220a0b0a310a4a22310a0b0a7e6fe0e0e030e0e0e0e0e01176e02000e0e0e0e0e01131320226310a0b0a310a4a22310a0b0a310a766f8b8b4ee0e0300ae0090909090909090909090909090909090909090909090909090909090909090947aaaa540b09090909090909090909090909090909090909090909090909090909090909fae0e0f2f22164e0e0f273e07fefefef7d6dfafafafa6d6d6d6d';
+} {/000000.*0000000/}
+
+
+set sqlite_fts3_enable_parentheses 0
+finish_test
diff --git a/test/fts3snippet.test b/test/fts3snippet.test
index 749aa4e0b..ae022b68a 100644
--- a/test/fts3snippet.test
+++ b/test/fts3snippet.test
@@ -588,18 +588,5 @@ do_execsql_test 5.1 {
{[a70] [a71] [a72]}
}
-#-------------------------------------------------------------------------
-# Request a snippet from a query with more than 64 phrases.
-#
-reset_db
-do_execsql_test 6.0 {
- CREATE VIRTUAL TABLE f USING fts3(b);
- INSERT INTO f VALUES ( x'746e6e6d64612e082a011065616e656d655a616c702a2f65732e0f42014001380230018218');
-}
-
-do_execsql_test 6.1 {
- SELECT length(snippet(f))>0 FROM f WHERE b MATCH x'1065616e656d655a616c702a2f65732e0f42014001380230018218021001081e0a3d746e6e6d64612e082a010f42014001380230018218021001081e0a3d746e6e6d64612e082a011065616e656d655a616c702a2f65732e0f42014001380230018218021001081e0a3d746e6e6d64612e082a011065616e656d655a616c702a2f65732e0f42014001380230018218021001081e0a3d746e6e6d64612e082a011065616e656d655a616c702a2f0a3d746e6e6d64612e082a011065616e656d655a616c702a2f65732e0f42014001018218021001081e0a3d746e6e6d64612e082a011065616e656d655a616c702a018218021001081e0a3d746e6e6d64612e082a011065616e656d655a616c2a2f65732e0f42014001380230018218021001081e0a3d746e6e6d64612e082a011065616e656d655a616c702a2f65732e0f42014001380230018218021001081e0a3d746e6e6d64612e082a011065616e656d655a616c702a2f65732e0f42014001380230018218021001081e0a3d746e6e6d64612e082a011065616e656d655a616c702a2f65732e0f42014001380230018218021001081e0a3d746e6e6d64612e0f42';
-} {1}
-
set sqlite_fts3_enable_parentheses 0
finish_test
diff --git a/test/fts3snippet2.test b/test/fts3snippet2.test
new file mode 100644
index 000000000..fc3994189
--- /dev/null
+++ b/test/fts3snippet2.test
@@ -0,0 +1,60 @@
+# 2020-05-14
+#
+# 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.
+#
+#*************************************************************************
+#
+# The tests in this file test the FTS3 auxillary functions offsets(),
+# snippet() and matchinfo() work. At time of writing, running this file
+# provides full coverage of fts3_snippet.c.
+#
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+set testprefix fts3snippet
+
+# If SQLITE_ENABLE_FTS3 is not defined, omit this file.
+ifcapable !fts3 { finish_test ; return }
+source $testdir/fts3_common.tcl
+
+set sqlite_fts3_enable_parentheses 1
+#-------------------------------------------------------------------------
+# Request a snippet from a query with more than 64 phrases.
+#
+reset_db
+do_execsql_test 1.0 {
+ CREATE VIRTUAL TABLE f USING fts3(b);
+ INSERT INTO f VALUES ( x'746e6e6d64612e082a011065616e656d655a616c702a2f65732e0f42014001380230018218');
+}
+
+do_execsql_test 1.1 {
+ SELECT length(snippet(f))>0 FROM f WHERE b MATCH x'1065616e656d655a616c702a2f65732e0f42014001380230018218021001081e0a3d746e6e6d64612e082a010f42014001380230018218021001081e0a3d746e6e6d64612e082a011065616e656d655a616c702a2f65732e0f42014001380230018218021001081e0a3d746e6e6d64612e082a011065616e656d655a616c702a2f65732e0f42014001380230018218021001081e0a3d746e6e6d64612e082a011065616e656d655a616c702a2f0a3d746e6e6d64612e082a011065616e656d655a616c702a2f65732e0f42014001018218021001081e0a3d746e6e6d64612e082a011065616e656d655a616c702a018218021001081e0a3d746e6e6d64612e082a011065616e656d655a616c2a2f65732e0f42014001380230018218021001081e0a3d746e6e6d64612e082a011065616e656d655a616c702a2f65732e0f42014001380230018218021001081e0a3d746e6e6d64612e082a011065616e656d655a616c702a2f65732e0f42014001380230018218021001081e0a3d746e6e6d64612e082a011065616e656d655a616c702a2f65732e0f42014001380230018218021001081e0a3d746e6e6d64612e0f42';
+} {1}
+
+reset_db
+do_execsql_test 2.0 {
+ CREATE VIRTUAL TABLE t0 USING fts3(col0 INTEGER PRIMARY KEY,col1 VARCHAR(8),col2 BINARY,col3 BINARY);
+ INSERT INTO t0 VALUES (1, '1234','aaaa','bbbb');
+ SELECT snippet(t0) FROM t0 WHERE t0 MATCH x'0a4d4d4d4d320a4f52d70a310a310a4e4541520a0a31f6ce0a4f520a0a310a310a310a4f520a75fc2a242424' ;
+} {<b>1</b>}
+
+reset_db
+do_execsql_test 2.1 {
+ CREATE VIRTUAL TABLE t0 USING fts3(
+ col0 INTEGER PRIMARY KEY,col1 VARCHAR(8),col2 BINARY,col3 BINARY
+ );
+ INSERT INTO t0 VALUES ('one', '1234','aaaa','bbbb');
+}
+do_execsql_test 2.2 {
+ SELECT snippet(t0) FROM t0 WHERE t0 MATCH
+ '(def AND (one NEAR abc)) OR one'
+} {<b>one</b>}
+
+set sqlite_fts3_enable_parentheses 0
+finish_test
+
diff --git a/test/fuzzdata8.db b/test/fuzzdata8.db
index 944393dbf..d45392ac7 100644
--- a/test/fuzzdata8.db
+++ b/test/fuzzdata8.db
Binary files differ
diff --git a/test/gencol1.test b/test/gencol1.test
index 5276d9694..43f48dff7 100644
--- a/test/gencol1.test
+++ b/test/gencol1.test
@@ -560,4 +560,30 @@ do_catchsql_test gencol1-19.10 {
INSERT INTO t0(c1) VALUES(0.16334143182538696), (0);
} {1 {UNIQUE constraint failed: t0.c0}}
+# 2020-06-29 forum bug report.
+# https://sqlite.org/forum/forumpost/73b9a8ccfb
+#
+do_execsql_test gencol1-20.1 {
+ CREATE TEMPORARY TABLE tab (
+ prim DATE PRIMARY KEY,
+ a INTEGER,
+ comp INTEGER AS (a),
+ b INTEGER,
+ x INTEGER
+ );
+ -- Add some data
+ INSERT INTO tab (prim, a, b) VALUES ('2001-01-01', 0, 0);
+ -- Check that each column is 0 like I expect
+ SELECT * FROM tab;
+} {2001-01-01 0 0 0 {}}
+do_execsql_test gencol1-20.2 {
+ -- Do an UPSERT on the b column
+ INSERT INTO tab (prim, b)
+ VALUES ('2001-01-01',5)
+ ON CONFLICT(prim) DO UPDATE SET b=excluded.b;
+ -- Now b is NULL rather than 5
+ SELECT * FROM tab;
+} {2001-01-01 0 0 5 {}}
+
+
finish_test
diff --git a/test/ieee754.test b/test/ieee754.test
index bf0676429..bd806d2cf 100644
--- a/test/ieee754.test
+++ b/test/ieee754.test
@@ -23,8 +23,8 @@ foreach {id float rep} {
3 0.5 1,-1
4 1.5 3,-1
5 0.0 0,-1075
- 6 4.9406564584124654e-324 4503599627370497,-1075
- 7 2.2250738585072009e-308 9007199254740991,-1075
+ 6 4.9406564584124654e-324 1,-1074
+ 7 2.2250738585072009e-308 4503599627370495,-1074
8 2.2250738585072014e-308 1,-1022
} {
do_test ieee754-100-$id-1 {
diff --git a/test/index7.test b/test/index7.test
index f57792e4c..084e8c3c7 100644
--- a/test/index7.test
+++ b/test/index7.test
@@ -339,5 +339,17 @@ do_execsql_test index7-7.1 {
SELECT * FROM t6 WHERE y IS TRUE ORDER BY x;
} {1 1}
+# 2020-05-27. tag-20200527-1.
+# Incomplete stat1 information on a table with few rows should still use the
+# index.
+reset_db
+do_execsql_test index7-8.1 {
+ CREATE TABLE t1(x INTEGER PRIMARY KEY, y);
+ CREATE INDEX t1y ON t1(y) WHERE y IS NOT NULL;
+ INSERT INTO t1(x) VALUES(1),(2);
+ ANALYZE;
+ EXPLAIN QUERY PLAN SELECT 1 FROM t1 WHERE y=5;
+} {/SEARCH TABLE t1 USING COVERING INDEX t1y/}
+
finish_test
diff --git a/test/indexedby.test b/test/indexedby.test
index 8624b10c7..18f7bb8fa 100644
--- a/test/indexedby.test
+++ b/test/indexedby.test
@@ -95,7 +95,7 @@ do_test indexedby-2.4 {
# an error.
do_test indexedby-2.4.1 {
catchsql { SELECT b FROM t1 INDEXED BY i1 WHERE b = 'two' }
-} {1 {no query solution}}
+} {0 {}}
do_test indexedby-2.5 {
catchsql { SELECT * FROM t1 INDEXED BY i5 WHERE a = 'one' AND b = 'two'}
@@ -135,10 +135,10 @@ do_eqp_test indexedby-3.3 {
} {SEARCH TABLE t1 USING INDEX i2 (b=?)}
do_test indexedby-3.4 {
catchsql { SELECT * FROM t1 INDEXED BY i2 WHERE a = 'one' }
-} {1 {no query solution}}
+} {0 {}}
do_test indexedby-3.5 {
catchsql { SELECT * FROM t1 INDEXED BY i2 ORDER BY a }
-} {1 {no query solution}}
+} {0 {}}
do_test indexedby-3.6 {
catchsql { SELECT * FROM t1 INDEXED BY i1 WHERE a = 'one' }
} {0 {}}
@@ -154,7 +154,7 @@ do_eqp_test indexedby-3.9 {
} {SEARCH TABLE t3 USING INDEX sqlite_autoindex_t3_1 (e=?)}
do_test indexedby-3.10 {
catchsql { SELECT * FROM t3 INDEXED BY sqlite_autoindex_t3_1 WHERE f = 10 }
-} {1 {no query solution}}
+} {0 {}}
do_test indexedby-3.11 {
catchsql { SELECT * FROM t3 INDEXED BY sqlite_autoindex_t3_2 WHERE f = 10 }
} {1 {no such index: sqlite_autoindex_t3_2}}
@@ -172,19 +172,19 @@ do_eqp_test indexedby-4.2 {
SELECT * FROM t1 INDEXED BY i1, t2 WHERE a = c
} {
QUERY PLAN
- |--SCAN TABLE t2
- `--SEARCH TABLE t1 USING INDEX i1 (a=?)
+ |--SCAN TABLE t1 USING INDEX i1
+ `--SEARCH TABLE t2 USING INDEX i3 (c=?)
}
do_test indexedby-4.3 {
catchsql {
SELECT * FROM t1 INDEXED BY i1, t2 INDEXED BY i3 WHERE a=c
}
-} {1 {no query solution}}
+} {0 {}}
do_test indexedby-4.4 {
catchsql {
SELECT * FROM t2 INDEXED BY i3, t1 INDEXED BY i1 WHERE a=c
}
-} {1 {no query solution}}
+} {0 {}}
# Test embedding an INDEXED BY in a CREATE VIEW statement. This block
# also tests that nothing bad happens if an index refered to by
@@ -205,7 +205,7 @@ do_test indexedby-5.4 {
# Recreate index i1 in such a way as it cannot be used by the view query.
execsql { CREATE INDEX i1 ON t1(b) }
catchsql { SELECT * FROM v2 }
-} {1 {no query solution}}
+} {0 {}}
do_test indexedby-5.5 {
# Drop and recreate index i1 again. This time, create it so that it can
# be used by the query.
@@ -245,7 +245,7 @@ do_eqp_test indexedby-7.5 {
} {SEARCH TABLE t1 USING INDEX i2 (b=?)}
do_test indexedby-7.6 {
catchsql { DELETE FROM t1 INDEXED BY i2 WHERE a = 5}
-} {1 {no query solution}}
+} {0 {}}
# Test that "INDEXED BY" can be used in an UPDATE statement.
#
@@ -266,7 +266,7 @@ do_eqp_test indexedby-8.5 {
} {SEARCH TABLE t1 USING INDEX i2 (b=?)}
do_test indexedby-8.6 {
catchsql { UPDATE t1 INDEXED BY i2 SET rowid=rowid+1 WHERE a = 5}
-} {1 {no query solution}}
+} {0 {}}
# Test that bug #3560 is fixed.
#
@@ -284,10 +284,10 @@ do_test indexedby-9.2 {
joinme as j indexed by joinme_id_text_idx
on ( m.id = j.id_int)
}
-} {1 {no query solution}}
+} {0 {}}
do_test indexedby-9.3 {
catchsql { select * from maintable, joinme INDEXED by joinme_id_text_idx }
-} {1 {no query solution}}
+} {0 {}}
# Make sure we can still create tables, indices, and columns whose name
# is "indexed".
diff --git a/test/istrue.test b/test/istrue.test
index d2768b379..b2f5b8d22 100644
--- a/test/istrue.test
+++ b/test/istrue.test
@@ -172,4 +172,33 @@ do_execsql_test istrue-710 {
SELECT 0.0 IS FALSE COLLATE BINARY;
} {1 1 1 1 1 1 1 1 1}
+# 2020-06-12 bug report from Chromium
+# https://bugs.chromium.org/p/chromium/issues/detail?id=1094247
+do_catchsql_test istrue-800 {
+ SELECT 9 IN (false.false);
+} {1 {no such column: false.false}}
+do_execsql_test istrue-810 {
+ CREATE TABLE t8(a INT, true INT, false INT, d INT);
+ INSERT INTO t8(a,true,false,d) VALUES(5,6,7,8),(4,3,2,1),('a','b','c','d');
+ SELECT * FROM t8 ORDER BY false;
+} {4 3 2 1 5 6 7 8 a b c d}
+do_catchsql_test istrue-820 {
+ SELECT 9 IN (false.false) FROM t8;
+} {1 {no such column: false.false}}
+do_execsql_test istrue-830 {
+ CREATE TABLE false(true INT, false INT, x INT CHECK (5 IN (false.false)));
+} {}
+do_execsql_test istrue-840 {
+ INSERT INTO False VALUES(4,5,6);
+} {}
+do_catchsql_test istrue-841 {
+ INSERT INTO False VALUES(5,6,7);
+} {1 {CHECK constraint failed: false}}
+do_execsql_test istrue-850 {
+ SELECT 9 IN (false.false) FROM false;
+} {0}
+do_execsql_test istrue-851 {
+ SELECT 5 IN (false.false) FROM false;
+} {1}
+
finish_test
diff --git a/test/kvtest.c b/test/kvtest.c
index 8c73caf1d..04dc01045 100644
--- a/test/kvtest.c
+++ b/test/kvtest.c
@@ -907,7 +907,7 @@ static int runMain(int argc, char **argv){
if( eType==PATH_DB ){
/* Recover any prior crashes prior to starting the timer */
sqlite3_open(zDb, &db);
- sqlite3_exec(db, "SELECT rowid FROM sqlite_master LIMIT 1", 0, 0, 0);
+ sqlite3_exec(db, "SELECT rowid FROM sqlite_schema LIMIT 1", 0, 0, 0);
sqlite3_close(db);
db = 0;
}
diff --git a/test/mutex1.test b/test/mutex1.test
index f567a0d93..aac04bf49 100644
--- a/test/mutex1.test
+++ b/test/mutex1.test
@@ -38,7 +38,7 @@ proc mutex_counters {varname} {
#-------------------------------------------------------------------------
# Tests mutex1-1.* test that sqlite3_config() returns SQLITE_MISUSE if
# is called at the wrong time. And that the first time sqlite3_initialize
-# is called it obtains the 'static_master' mutex 3 times and a recursive
+# is called it obtains the 'static_main' mutex 3 times and a recursive
# mutex (sqlite3Config.pInitMutex) twice. Subsequent calls are no-ops
# that do not require any mutexes.
#
@@ -75,7 +75,7 @@ do_test mutex1-1.6 {
do_test mutex1-1.7 {
mutex_counters counters
- # list $counters(total) $counters(static_master)
+ # list $counters(total) $counters(static_main)
expr {$counters(total)>0}
} {1}
@@ -86,7 +86,7 @@ do_test mutex1-1.8 {
do_test mutex1-1.9 {
mutex_counters counters
- list $counters(total) $counters(static_master)
+ list $counters(total) $counters(static_main)
} {0 0}
#-------------------------------------------------------------------------
@@ -103,13 +103,13 @@ ifcapable threadsafe1&&shared_cache {
singlethread {}
multithread {
fast static_app1 static_app2 static_app3
- static_lru static_master static_mem static_open
+ static_lru static_main static_mem static_open
static_prng static_pmem static_vfs1 static_vfs2
static_vfs3
}
serialized {
fast recursive static_app1 static_app2
- static_app3 static_lru static_master static_mem
+ static_app3 static_lru static_main static_mem
static_open static_prng static_pmem static_vfs1
static_vfs2 static_vfs3
}
diff --git a/test/optfuzz-db01.c b/test/optfuzz-db01.c
index 1cd3867e1..e11f15cc2 100644
--- a/test/optfuzz-db01.c
+++ b/test/optfuzz-db01.c
@@ -945,4 +945,3 @@ unsigned char data001[] = {
78, 32,116, 49, 32, 79, 78, 32, 40,116, 49, 46, 97, 61, 53, 48, 45, 99, 48,
46,120, 41,
};
-
diff --git a/test/permutations.test b/test/permutations.test
index d8ec9e4a5..ba7fa2be8 100644
--- a/test/permutations.test
+++ b/test/permutations.test
@@ -171,6 +171,12 @@ test_suite "veryquick" -prefix "" -description {
*fts5corrupt* *fts5big* *fts5aj*
]
+test_suite "shell" -prefix "" -description {
+ Run tests of the command-line shell
+} -files [
+ test_set [glob $testdir/shell*.test]
+]
+
test_suite "extraquick" -prefix "" -description {
"Extra" quick test suite. Runs in a few minutes on a workstation.
This test suite is the same as the "veryquick" tests, except that
diff --git a/test/printf.test b/test/printf.test
index d099da8fa..445470fc0 100644
--- a/test/printf.test
+++ b/test/printf.test
@@ -538,9 +538,11 @@ do_test printf-2.1.2.8 {
do_test printf-2.1.2.9 {
sqlite3_mprintf_double {abc: %d %d (%1.1g) :xyz} 1 1 1.0e-20
} {abc: 1 1 (1e-20) :xyz}
-do_test printf-2.1.2.10 {
- sqlite3_mprintf_double {abc: %*.*f} 2000000000 1000000000 1.0e-20
-} {}
+if {$SQLITE_MAX_LENGTH<=[expr 1000*1000*1000]} {
+ do_test printf-2.1.2.10 {
+ sqlite3_mprintf_double {abc: %*.*f} 2000000000 1000000000 1.0e-20
+ } {}
+}
do_test printf-2.1.3.1 {
sqlite3_mprintf_double {abc: (%*.*f) :xyz} 1 1 1.0
} {abc: (1.0) :xyz}
@@ -3777,4 +3779,11 @@ foreach ::iRepeat {0 1} {
}
}
+# 2020-05-23
+# ticket 23439ea582241138
+#
+do_execsql_test printf-16.1 {
+ SELECT printf('%.*g',2147483647,0.01);
+} {0.01}
+
finish_test
diff --git a/test/select3.test b/test/select3.test
index 50039c551..fec8ba4a5 100644
--- a/test/select3.test
+++ b/test/select3.test
@@ -314,4 +314,13 @@ do_execsql_test select3-9.100 {
SELECT * FROM t0 GROUP BY c0;
} {1.0 1.0}
+reset_db
+do_execsql_test select3.10.100 {
+ CREATE TABLE t1(a, b);
+ CREATE TABLE t2(c, d);
+ SELECT max(t1.a),
+ (SELECT 'xyz' FROM (SELECT * FROM t2 WHERE 0) WHERE t1.b=1)
+ FROM t1;
+} {{} {}}
+
finish_test
diff --git a/test/selectA.test b/test/selectA.test
index 838e5f432..7ca0096b1 100644
--- a/test/selectA.test
+++ b/test/selectA.test
@@ -1446,5 +1446,26 @@ do_execsql_test 6.1 {
SELECT * FROM (SELECT a FROM t1 UNION SELECT b FROM t2) WHERE a=a;
} {12345}
+# 2020-06-15 ticket 8f157e8010b22af0
+#
+reset_db
+do_execsql_test 7.1 {
+ CREATE TABLE t1(c1); INSERT INTO t1 VALUES(12),(123),(1234),(NULL),('abc');
+ CREATE TABLE t2(c2); INSERT INTO t2 VALUES(44),(55),(123);
+ CREATE TABLE t3(c3,c4); INSERT INTO t3 VALUES(66,1),(123,2),(77,3);
+ CREATE VIEW t4 AS SELECT c3 FROM t3;
+ CREATE VIEW t5 AS SELECT c3 FROM t3 ORDER BY c4;
+}
+do_execsql_test 7.2 {
+ SELECT * FROM t1, t2 WHERE c1=(SELECT 123 INTERSECT SELECT c2 FROM t4) AND c1=123;
+} {123 123}
+do_execsql_test 7.3 {
+ SELECT * FROM t1, t2 WHERE c1=(SELECT 123 INTERSECT SELECT c2 FROM t5) AND c1=123;
+} {123 123}
+do_execsql_test 7.4 {
+ CREATE TABLE a(b);
+ CREATE VIEW c(d) AS SELECT b FROM a ORDER BY b;
+ SELECT sum(d) OVER( PARTITION BY(SELECT 0 FROM c JOIN a WHERE b =(SELECT b INTERSECT SELECT d FROM c) AND b = 123)) FROM c;
+} {}
finish_test
diff --git a/test/shell1.test b/test/shell1.test
index c142ea724..49af3aa35 100644
--- a/test/shell1.test
+++ b/test/shell1.test
@@ -199,10 +199,10 @@ do_test shell1-2.2.4 {
} {0 {}}
do_test shell1-2.2.5 {
catchcmd "test.db" ".mode \"insert FOO"
-} {1 {Error: mode should be one of: ascii column csv html insert line list quote tabs tcl}}
+} {1 {Error: mode should be one of: ascii box column csv html insert json line list markdown quote table tabs tcl}}
do_test shell1-2.2.6 {
catchcmd "test.db" ".mode \'insert FOO"
-} {1 {Error: mode should be one of: ascii column csv html insert line list quote tabs tcl}}
+} {1 {Error: mode should be one of: ascii box column csv html insert json line list markdown quote table tabs tcl}}
# check multiple tokens, and quoted tokens
do_test shell1-2.3.1 {
@@ -230,7 +230,7 @@ do_test shell1-2.3.7 {
# check quoted args are unquoted
do_test shell1-2.4.1 {
catchcmd "test.db" ".mode FOO"
-} {1 {Error: mode should be one of: ascii column csv html insert line list quote tabs tcl}}
+} {1 {Error: mode should be one of: ascii box column csv html insert json line list markdown quote table tabs tcl}}
do_test shell1-2.4.2 {
catchcmd "test.db" ".mode csv"
} {0 {}}
@@ -430,7 +430,7 @@ do_test shell1-3.13.1 {
} {0 {current output mode: list}}
do_test shell1-3.13.2 {
catchcmd "test.db" ".mode FOO"
-} {1 {Error: mode should be one of: ascii column csv html insert line list quote tabs tcl}}
+} {1 {Error: mode should be one of: ascii box column csv html insert json line list markdown quote table tabs tcl}}
do_test shell1-3.13.3 {
catchcmd "test.db" ".mode csv"
} {0 {}}
@@ -463,10 +463,10 @@ do_test shell1-3.13.11 {
# don't allow partial mode type matches
do_test shell1-3.13.12 {
catchcmd "test.db" ".mode l"
-} {1 {Error: mode should be one of: ascii column csv html insert line list quote tabs tcl}}
+} {1 {Error: mode should be one of: ascii box column csv html insert json line list markdown quote table tabs tcl}}
do_test shell1-3.13.13 {
catchcmd "test.db" ".mode li"
-} {1 {Error: mode should be one of: ascii column csv html insert line list quote tabs tcl}}
+} {1 {Error: mode should be one of: ascii box column csv html insert json line list markdown quote table tabs tcl}}
do_test shell1-3.13.14 {
catchcmd "test.db" ".mode lin"
} {0 {}}
@@ -709,11 +709,11 @@ do_test shell1-3.26.4 {
# this should be treated the same as a '1' width for col 1 and 2
} {0 {}}
do_test shell1-3.26.5 {
- catchcmd "test.db" ".mode column\n.width 10 -10\nSELECT 'abcdefg', 123456;"
+ catchcmd "test.db" ".mode column\n.header off\n.width 10 -10\nSELECT 'abcdefg', 123456;"
# this should be treated the same as a '1' width for col 1 and 2
} {0 {abcdefg 123456}}
do_test shell1-3.26.6 {
- catchcmd "test.db" ".mode column\n.width -10 10\nSELECT 'abcdefg', 123456;"
+ catchcmd "test.db" ".mode column\n.header off\n.width -10 10\nSELECT 'abcdefg', 123456;"
# this should be treated the same as a '1' width for col 1 and 2
} {0 { abcdefg 123456 }}
diff --git a/test/speedtest1.c b/test/speedtest1.c
index 68ca5788c..723c8cffb 100644
--- a/test/speedtest1.c
+++ b/test/speedtest1.c
@@ -7,7 +7,7 @@ static const char zHelp[] =
"Usage: %s [--options] DATABASE\n"
"Options:\n"
" --autovacuum Enable AUTOVACUUM mode\n"
- " --cachesize N Set the cache size to N\n"
+ " --cachesize N Set the cache size to N\n"
" --exclusive Enable locking_mode=EXCLUSIVE\n"
" --explain Like --sqlonly but with added EXPLAIN keywords\n"
" --heap SZ MIN Memory allocator uses SZ bytes & min allocation MIN\n"
@@ -15,11 +15,13 @@ static const char zHelp[] =
" --journal M Set the journal_mode to M\n"
" --key KEY Set the encryption key to KEY\n"
" --lookaside N SZ Configure lookaside for N slots of SZ bytes each\n"
+ " --memdb Use an in-memory database\n"
" --mmap SZ MMAP the first SZ bytes of the database file\n"
" --multithread Set multithreaded mode\n"
" --nomemstat Disable memory statistics\n"
" --nosync Set PRAGMA synchronous=OFF\n"
" --notnull Add NOT NULL constraints to table columns\n"
+ " --output FILE Store SQL output in FILE\n"
" --pagesize N Set the page size to N\n"
" --pcache N SZ Configure N pages of pagecache each of size SZ bytes\n"
" --primarykey Use PRIMARY KEY instead of UNIQUE where appropriate\n"
@@ -41,7 +43,6 @@ static const char zHelp[] =
" --without-rowid Use WITHOUT ROWID where appropriate\n"
;
-
#include "sqlite3.h"
#include <assert.h>
#include <stdio.h>
@@ -61,6 +62,20 @@ static const char zHelp[] =
# define sqlite3_int64 sqlite_int64
#endif
+typedef sqlite3_uint64 u64;
+
+/*
+** State structure for a Hash hash in progress
+*/
+typedef struct HashContext HashContext;
+struct HashContext {
+ unsigned char isInit; /* True if initialized */
+ unsigned char i, j; /* State variables */
+ unsigned char s[256]; /* State variables */
+ unsigned char r[32]; /* Result */
+};
+
+
/* All global state is held in this structure */
static struct Global {
sqlite3 *db; /* The open database connection */
@@ -80,8 +95,13 @@ static struct Global {
const char *zNN; /* Might be NOT NULL */
const char *zPK; /* Might be UNIQUE or PRIMARY KEY */
unsigned int x, y; /* Pseudo-random number generator state */
+ u64 nResByte; /* Total number of result bytes */
int nResult; /* Size of the current result */
char zResult[3000]; /* Text of the current result */
+#ifndef SPEEDTEST_OMIT_HASH
+ FILE *hashFile; /* Store all hash results in this file */
+ HashContext hash; /* Hash of all output */
+#endif
} g;
/* Return " TEMP" or "", as appropriate for creating a table.
@@ -90,7 +110,6 @@ static const char *isTemp(int N){
return g.eTemp>=N ? " TEMP" : "";
}
-
/* Print an error message and exit */
static void fatal_error(const char *zMsg, ...){
va_list ap;
@@ -100,6 +119,72 @@ static void fatal_error(const char *zMsg, ...){
exit(1);
}
+#ifndef SPEEDTEST_OMIT_HASH
+/****************************************************************************
+** Hash algorithm used to verify that compilation is not miscompiled
+** in such a was as to generate an incorrect result.
+*/
+
+/*
+** Initialize a new hash. iSize determines the size of the hash
+** in bits and should be one of 224, 256, 384, or 512. Or iSize
+** can be zero to use the default hash size of 256 bits.
+*/
+static void HashInit(void){
+ unsigned int k;
+ g.hash.i = 0;
+ g.hash.j = 0;
+ for(k=0; k<256; k++) g.hash.s[k] = k;
+}
+
+/*
+** Make consecutive calls to the HashUpdate function to add new content
+** to the hash
+*/
+static void HashUpdate(
+ const unsigned char *aData,
+ unsigned int nData
+){
+ unsigned char t;
+ unsigned char i = g.hash.i;
+ unsigned char j = g.hash.j;
+ unsigned int k;
+ if( g.hashFile ) fwrite(aData, 1, nData, g.hashFile);
+ for(k=0; k<nData; k++){
+ j += g.hash.s[i] + aData[k];
+ t = g.hash.s[j];
+ g.hash.s[j] = g.hash.s[i];
+ g.hash.s[i] = t;
+ i++;
+ }
+ g.hash.i = i;
+ g.hash.j = j;
+}
+
+/*
+** After all content has been added, invoke HashFinal() to compute
+** the final hash. The hash result is stored in g.hash.r[].
+*/
+static void HashFinal(void){
+ unsigned int k;
+ unsigned char t, i, j;
+ i = g.hash.i;
+ j = g.hash.j;
+ for(k=0; k<32; k++){
+ i++;
+ t = g.hash.s[i];
+ j += t;
+ g.hash.s[i] = g.hash.s[j];
+ g.hash.s[j] = t;
+ t += g.hash.s[i];
+ g.hash.r[k] = g.hash.s[t];
+ }
+}
+
+/* End of the Hash hashing logic
+*****************************************************************************/
+#endif /* SPEEDTEST_OMIT_HASH */
+
/*
** Return the value of a hexadecimal digit. Return -1 if the input
** is not a hex digit.
@@ -324,6 +409,21 @@ void speedtest1_final(void){
printf(" TOTAL%.*s %4d.%03ds\n", NAMEWIDTH-5, zDots,
(int)(g.iTotal/1000), (int)(g.iTotal%1000));
}
+ if( g.bVerify ){
+#ifndef SPEEDTEST_OMIT_HASH
+ int i;
+#endif
+ printf("Verification Hash: %llu ", g.nResByte);
+#ifndef SPEEDTEST_OMIT_HASH
+ HashUpdate((const unsigned char*)"\n", 1);
+ HashFinal();
+ for(i=0; i<24; i++){
+ printf("%02x", g.hash.r[i]);
+ }
+ if( g.hashFile && g.hashFile!=stdout ) fclose(g.hashFile);
+#endif
+ printf("\n");
+ }
}
/* Print an SQL statement to standard output */
@@ -372,6 +472,36 @@ void speedtest1_exec(const char *zFormat, ...){
speedtest1_shrink_memory();
}
+/* Run SQL and return the first column of the first row as a string. The
+** returned string is obtained from sqlite_malloc() and must be freed by
+** the caller.
+*/
+char *speedtest1_once(const char *zFormat, ...){
+ va_list ap;
+ char *zSql;
+ sqlite3_stmt *pStmt;
+ char *zResult = 0;
+ va_start(ap, zFormat);
+ zSql = sqlite3_vmprintf(zFormat, ap);
+ va_end(ap);
+ if( g.bSqlOnly ){
+ printSql(zSql);
+ }else{
+ int rc = sqlite3_prepare_v2(g.db, zSql, -1, &pStmt, 0);
+ if( rc ){
+ fatal_error("SQL error: %s\n", sqlite3_errmsg(g.db));
+ }
+ if( sqlite3_step(pStmt)==SQLITE_ROW ){
+ const char *z = (const char*)sqlite3_column_text(pStmt, 0);
+ if( z ) zResult = sqlite3_mprintf("%s", z);
+ }
+ sqlite3_finalize(pStmt);
+ }
+ sqlite3_free(zSql);
+ speedtest1_shrink_memory();
+ return zResult;
+}
+
/* Prepare an SQL statement */
void speedtest1_prepare(const char *zFormat, ...){
va_list ap;
@@ -404,6 +534,39 @@ void speedtest1_run(void){
const char *z = (const char*)sqlite3_column_text(g.pStmt, i);
if( z==0 ) z = "nil";
len = (int)strlen(z);
+#ifndef SPEEDTEST_OMIT_HASH
+ if( g.bVerify ){
+ int eType = sqlite3_column_type(g.pStmt, i);
+ unsigned char zPrefix[2];
+ zPrefix[0] = '\n';
+ zPrefix[1] = "-IFTBN"[eType];
+ if( g.nResByte ){
+ HashUpdate(zPrefix, 2);
+ }else{
+ HashUpdate(zPrefix+1, 1);
+ }
+ if( eType==SQLITE_FLOAT ){
+ /* Omit the value of floating-point results from the verification
+ ** hash. The only thing we record is the fact that the result was
+ ** a floating-point value. */
+ g.nResByte += 2;
+ }else if( eType==SQLITE_BLOB ){
+ int nBlob = sqlite3_column_bytes(g.pStmt, i);
+ int iBlob;
+ unsigned char zChar[2];
+ const unsigned char *aBlob = sqlite3_column_blob(g.pStmt, i);
+ for(iBlob=0; iBlob<nBlob; iBlob++){
+ zChar[0] = "0123456789abcdef"[aBlob[iBlob]>>4];
+ zChar[1] = "0123456789abcdef"[aBlob[iBlob]&15];
+ HashUpdate(zChar,2);
+ }
+ g.nResByte += nBlob*2 + 2;
+ }else{
+ HashUpdate((unsigned char*)z, len);
+ g.nResByte += len + 2;
+ }
+ }
+#endif
if( g.nResult+len<sizeof(g.zResult)-2 ){
if( g.nResult>0 ) g.zResult[g.nResult++] = ' ';
memcpy(g.zResult + g.nResult, z, len+1);
@@ -1987,7 +2150,8 @@ int main(int argc, char **argv){
int showStats = 0; /* True for --stats */
int nThread = 0; /* --threads value */
int mmapSize = 0; /* How big of a memory map to use */
- const char *zTSet = "main"; /* Which --testset torun */
+ int memDb = 0; /* --memdb. Use an in-memory database */
+ char *zTSet = "main"; /* Which --testset torun */
int doTrace = 0; /* True for --trace */
const char *zEncoding = 0; /* --utf16be or --utf16le */
const char *zDbName = 0; /* Name of the test database */
@@ -2000,7 +2164,7 @@ int main(int argc, char **argv){
int rc; /* API return code */
/* Display the version of SQLite being tested */
- printf("-- Speedtest1 for SQLite %s %.50s\n",
+ printf("-- Speedtest1 for SQLite %s %.48s\n",
sqlite3_libversion(), sqlite3_sourceid());
/* Process command-line arguments */
@@ -2042,6 +2206,8 @@ int main(int argc, char **argv){
nLook = integerValue(argv[i+1]);
szLook = integerValue(argv[i+2]);
i += 2;
+ }else if( strcmp(z,"memdb")==0 ){
+ memDb = 1;
#if SQLITE_VERSION_NUMBER>=3006000
}else if( strcmp(z,"multithread")==0 ){
sqlite3_config(SQLITE_CONFIG_MULTITHREAD);
@@ -2057,6 +2223,22 @@ int main(int argc, char **argv){
noSync = 1;
}else if( strcmp(z,"notnull")==0 ){
g.zNN = "NOT NULL";
+ }else if( strcmp(z,"output")==0 ){
+#ifdef SPEEDTEST_OMIT_HASH
+ fatal_error("The --output option is not supported with"
+ " -DSPEEDTEST_OMIT_HASH\n");
+#else
+ if( i>=argc-1 ) fatal_error("missing argument on %s\n", argv[i]);
+ i++;
+ if( strcmp(argv[i],"-")==0 ){
+ g.hashFile = stdout;
+ }else{
+ g.hashFile = fopen(argv[i], "wb");
+ if( g.hashFile==0 ){
+ fatal_error("cannot open \"%s\" for writing\n", argv[i]);
+ }
+ }
+#endif
}else if( strcmp(z,"pagesize")==0 ){
if( i>=argc-1 ) fatal_error("missing argument on %s\n", argv[i]);
pageSize = integerValue(argv[++i]);
@@ -2110,6 +2292,9 @@ int main(int argc, char **argv){
zEncoding = "utf16be";
}else if( strcmp(z,"verify")==0 ){
g.bVerify = 1;
+#ifndef SPEEDTEST_OMIT_HASH
+ HashInit();
+#endif
}else if( strcmp(z,"without-rowid")==0 ){
g.zWR = "WITHOUT ROWID";
g.zPK = "PRIMARY KEY";
@@ -2151,13 +2336,13 @@ int main(int argc, char **argv){
sqlite3_initialize();
/* Open the database and the input file */
- if( sqlite3_open(zDbName, &g.db) ){
+ if( sqlite3_open(memDb ? ":memory:" : zDbName, &g.db) ){
fatal_error("Cannot open database file: %s\n", zDbName);
}
#if SQLITE_VERSION_NUMBER>=3006001
if( nLook>0 && szLook>0 ){
pLook = malloc( nLook*szLook );
- rc = sqlite3_db_config(g.db, SQLITE_DBCONFIG_LOOKASIDE, pLook, szLook,nLook);
+ rc = sqlite3_db_config(g.db, SQLITE_DBCONFIG_LOOKASIDE,pLook,szLook,nLook);
if( rc ) fatal_error("lookaside configuration failed: %d\n", rc);
}
#endif
@@ -2167,6 +2352,9 @@ int main(int argc, char **argv){
#ifndef SQLITE_OMIT_DEPRECATED
if( doTrace ) sqlite3_trace(g.db, traceCallback, 0);
#endif
+ if( memDb>0 ){
+ speedtest1_exec("PRAGMA temp_store=memory");
+ }
if( mmapSize>0 ){
speedtest1_exec("PRAGMA mmap_size=%d", mmapSize);
}
@@ -2197,30 +2385,68 @@ int main(int argc, char **argv){
}
if( g.bExplain ) printf(".explain\n.echo on\n");
- if( strcmp(zTSet,"main")==0 ){
- testset_main();
- }else if( strcmp(zTSet,"debug1")==0 ){
- testset_debug1();
- }else if( strcmp(zTSet,"orm")==0 ){
- testset_orm();
- }else if( strcmp(zTSet,"cte")==0 ){
- testset_cte();
- }else if( strcmp(zTSet,"fp")==0 ){
- testset_fp();
- }else if( strcmp(zTSet,"trigger")==0 ){
- testset_trigger();
- }else if( strcmp(zTSet,"rtree")==0 ){
+ do{
+ char *zThisTest = zTSet;
+ char *zComma = strchr(zThisTest,',');
+ if( zComma ){
+ *zComma = 0;
+ zTSet = zComma+1;
+ }else{
+ zTSet = "";
+ }
+ if( g.iTotal>0 || zComma!=0 ){
+ printf(" Begin testset \"%s\"\n", zThisTest);
+ }
+ if( strcmp(zThisTest,"main")==0 ){
+ testset_main();
+ }else if( strcmp(zThisTest,"debug1")==0 ){
+ testset_debug1();
+ }else if( strcmp(zThisTest,"orm")==0 ){
+ testset_orm();
+ }else if( strcmp(zThisTest,"cte")==0 ){
+ testset_cte();
+ }else if( strcmp(zThisTest,"fp")==0 ){
+ testset_fp();
+ }else if( strcmp(zThisTest,"trigger")==0 ){
+ testset_trigger();
+ }else if( strcmp(zThisTest,"rtree")==0 ){
#ifdef SQLITE_ENABLE_RTREE
- testset_rtree(6, 147);
+ testset_rtree(6, 147);
#else
- fatal_error("compile with -DSQLITE_ENABLE_RTREE to enable "
- "the R-Tree tests\n");
+ fatal_error("compile with -DSQLITE_ENABLE_RTREE to enable "
+ "the R-Tree tests\n");
#endif
- }else{
- fatal_error("unknown testset: \"%s\"\n"
- "Choices: cte debug1 fp main orm rtree trigger\n",
- zTSet);
- }
+ }else{
+ fatal_error("unknown testset: \"%s\"\n"
+ "Choices: cte debug1 fp main orm rtree trigger\n",
+ zThisTest);
+ }
+ if( zTSet[0] ){
+ char *zSql, *zObj;
+ speedtest1_begin_test(999, "Reset the database");
+ while( 1 ){
+ zObj = speedtest1_once(
+ "SELECT name FROM main.sqlite_master"
+ " WHERE sql LIKE 'CREATE %%TABLE%%'");
+ if( zObj==0 ) break;
+ zSql = sqlite3_mprintf("DROP TABLE main.\"%w\"", zObj);
+ speedtest1_exec(zSql);
+ sqlite3_free(zSql);
+ sqlite3_free(zObj);
+ }
+ while( 1 ){
+ zObj = speedtest1_once(
+ "SELECT name FROM temp.sqlite_master"
+ " WHERE sql LIKE 'CREATE %%TABLE%%'");
+ if( zObj==0 ) break;
+ zSql = sqlite3_mprintf("DROP TABLE main.\"%w\"", zObj);
+ speedtest1_exec(zSql);
+ sqlite3_free(zSql);
+ sqlite3_free(zObj);
+ }
+ speedtest1_end_test();
+ }
+ }while( zTSet[0] );
speedtest1_final();
if( showStats ){
diff --git a/test/stat.test b/test/stat.test
index 105169df1..5eb7d6f76 100644
--- a/test/stat.test
+++ b/test/stat.test
@@ -59,7 +59,7 @@ if {[wal_is_capable]} {
PRAGMA journal_mode = delete;
SELECT name, path, pageno, pagetype, ncell, payload, unused, mx_payload
FROM stat;
- } {wal delete sqlite_master / 1 leaf 0 0 916 0}
+ } {wal delete sqlite_schema / 1 leaf 0 0 916 0}
}
do_test stat-1.0 {
@@ -85,9 +85,9 @@ do_test stat-1.2 {
do_test stat-1.3 {
execsql {
SELECT name, path, pageno, pagetype, ncell, payload, unused, mx_payload
- FROM stat WHERE name = 'sqlite_master';
+ FROM stat WHERE name = 'sqlite_schema';
}
-} {sqlite_master / 1 leaf 2 77 831 40}
+} {sqlite_schema / 1 leaf 2 77 831 40}
do_test stat-1.4 {
execsql {
DROP TABLE t1;
@@ -108,7 +108,7 @@ do_execsql_test stat-2.1 {
INSERT INTO t3 SELECT a_string(110+rowid), a_string(221+rowid) FROM t3
ORDER BY rowid;
SELECT name, path, pageno, pagetype, ncell, payload, unused, mx_payload
- FROM stat WHERE name != 'sqlite_master' ORDER BY name;
+ FROM stat WHERE name != 'sqlite_schema' ORDER BY name;
} [list \
sqlite_autoindex_t3_1 / 3 internal 3 368 623 125 \
sqlite_autoindex_t3_1 /000/ 8 leaf 8 946 46 123 \
@@ -138,7 +138,7 @@ do_execsql_test stat-2.1agg {
SELECT * FROM dbstat WHERE aggregate=TRUE ORDER BY name;
} [list \
sqlite_autoindex_t3_1 {} 5 {} 32 3898 1065 132 {} 5120 \
- sqlite_master {} 1 {} 2 84 824 49 {} 1024 \
+ sqlite_schema {} 1 {} 2 84 824 49 {} 1024 \
t3 {} 17 {} 47 11188 5815 370 {} 17408 \
]
@@ -158,7 +158,7 @@ do_execsql_test stat-3.1 {
CREATE INDEX i4 ON t4(x);
INSERT INTO t4(rowid, x) VALUES(2, a_string(7777));
SELECT name, path, pageno, pagetype, ncell, payload, unused, mx_payload
- FROM stat WHERE name != 'sqlite_master' ORDER BY name;
+ FROM stat WHERE name != 'sqlite_schema' ORDER BY name;
} [list \
i4 / 3 leaf 1 103 905 7782 \
i4 /000+000000 4 overflow 0 1020 0 0 \
@@ -183,7 +183,7 @@ do_execsql_test stat-3.2 {
SELECT *, '|' FROM dbstat WHERE aggregate=TRUE ORDER BY name;
} [list \
i4 {} 9 {} 1 7782 1386 7782 {} 9216 | \
- sqlite_master {} 1 {} 2 74 834 40 {} 1024 | \
+ sqlite_schema {} 1 {} 2 74 834 40 {} 1024 | \
t4 {} 8 {} 1 7780 367 7780 {} 8192 | \
]
@@ -221,11 +221,11 @@ do_execsql_test stat-5.1 {
do_execsql_test stat-5.20 {
SELECT name, quote(path), pageno, quote(pagetype), ncell, payload,
unused, mx_payload, '|' FROM dbstat('main',1);
-} {sqlite_master NULL 1 NULL 1 34 878 34 | tx NULL 1 NULL 0 0 1016 0 |}
+} {sqlite_schema NULL 1 NULL 1 34 878 34 | tx NULL 1 NULL 0 0 1016 0 |}
do_execsql_test stat-5.21 {
SELECT name, quote(path), pageno, quote(pagetype), ncell, payload,
unused, mx_payload, '|' FROM dbstat('aux1',1);
-} {sqlite_master NULL 1 NULL 1 34 878 34 | t1 NULL 3 NULL 2 3033 5 1517 |}
+} {sqlite_schema NULL 1 NULL 1 34 878 34 | t1 NULL 3 NULL 2 3033 5 1517 |}
do_catchsql_test stat-6.1 {
@@ -247,27 +247,27 @@ do_execsql_test 7.1 {
do_execsql_test 7.1.1 {
SELECT * FROM dbstat('123');
} {
- sqlite_master / 1 leaf 1 37 875 37 0 1024
+ sqlite_schema / 1 leaf 1 37 875 37 0 1024
x1 / 2 leaf 1 4 1008 4 1024 1024
}
do_execsql_test 7.1.2 {
SELECT * FROM dbstat(123);
} {
- sqlite_master / 1 leaf 1 37 875 37 0 1024
+ sqlite_schema / 1 leaf 1 37 875 37 0 1024
x1 / 2 leaf 1 4 1008 4 1024 1024
}
do_execsql_test 7.1.3 {
CREATE VIRTUAL TABLE x2 USING dbstat('123');
SELECT * FROM x2;
} {
- sqlite_master / 1 leaf 1 37 875 37 0 1024
+ sqlite_schema / 1 leaf 1 37 875 37 0 1024
x1 / 2 leaf 1 4 1008 4 1024 1024
}
do_execsql_test 7.1.4 {
CREATE VIRTUAL TABLE x3 USING dbstat(123);
SELECT * FROM x3;
} {
- sqlite_master / 1 leaf 1 37 875 37 0 1024
+ sqlite_schema / 1 leaf 1 37 875 37 0 1024
x1 / 2 leaf 1 4 1008 4 1024 1024
}
@@ -280,7 +280,7 @@ do_execsql_test 7.2 {
do_execsql_test 7.2.1 {
SELECT * FROM dbstat('123corp');
} {
- sqlite_master / 1 leaf 1 37 875 37 0 1024
+ sqlite_schema / 1 leaf 1 37 875 37 0 1024
x1 / 2 leaf 1 4 1008 4 1024 1024
}
do_catchsql_test 7.2.2 {
@@ -290,7 +290,7 @@ do_execsql_test 7.2.3 {
CREATE VIRTUAL TABLE x2 USING dbstat('123corp');
SELECT * FROM x2;
} {
- sqlite_master / 1 leaf 1 37 875 37 0 1024
+ sqlite_schema / 1 leaf 1 37 875 37 0 1024
x1 / 2 leaf 1 4 1008 4 1024 1024
}
do_catchsql_test 7.2.4 {
diff --git a/test/tkt-3fe897352e.test b/test/tkt-3fe897352e.test
index fa70ac765..bc2b2033e 100644
--- a/test/tkt-3fe897352e.test
+++ b/test/tkt-3fe897352e.test
@@ -33,28 +33,28 @@ do_test tkt-3fe89-1.1 {
INSERT INTO t1 VALUES(hex_to_utf16be('D800'));
SELECT hex(x) FROM t1;
}
-} {EFBFBD}
+} {EDA080}
do_test tkt-3fe89-1.2 {
db eval {
DELETE FROM t1;
INSERT INTO t1 VALUES(hex_to_utf16le('00D8'));
SELECT hex(x) FROM t1;
}
-} {EFBFBD}
+} {EDA080}
do_test tkt-3fe89-1.3 {
db eval {
DELETE FROM t1;
INSERT INTO t1 VALUES(hex_to_utf16be('DFFF'));
SELECT hex(x) FROM t1;
}
-} {EFBFBD}
+} {EDBFBF}
do_test tkt-3fe89-1.4 {
db eval {
DELETE FROM t1;
INSERT INTO t1 VALUES(hex_to_utf16le('FFDF'));
SELECT hex(x) FROM t1;
}
-} {EFBFBD}
+} {EDBFBF}
finish_test
diff --git a/test/tt3_stress.c b/test/tt3_stress.c
index cdfab9c09..be917b732 100644
--- a/test/tt3_stress.c
+++ b/test/tt3_stress.c
@@ -41,7 +41,7 @@ static char *stress_thread_2(int iTid, void *pArg){
Sqlite db = {0}; /* SQLite database connection */
while( !timetostop(&err) ){
opendb(&err, &db, "test.db", 0);
- sql_script(&err, &db, "SELECT * FROM sqlite_master;");
+ sql_script(&err, &db, "SELECT * FROM sqlite_schema;");
clear_error(&err, SQLITE_LOCKED);
closedb(&err, &db);
}
@@ -266,7 +266,7 @@ static char *stress2_workload19(int iTid, void *pArg){
const char *zDb = (const char*)pArg;
while( !timetostop(&err) ){
opendb(&err, &db, zDb, 0);
- sql_script(&err, &db, "SELECT * FROM sqlite_master;");
+ sql_script(&err, &db, "SELECT * FROM sqlite_schema;");
clear_error(&err, SQLITE_LOCKED);
closedb(&err, &db);
}
@@ -362,7 +362,3 @@ static void stress2(int nMs){
sqlite3_enable_shared_cache(0);
print_and_free_err(&err);
}
-
-
-
-
diff --git a/test/wal.test b/test/wal.test
index a003b6ad2..acc278008 100644
--- a/test/wal.test
+++ b/test/wal.test
@@ -43,6 +43,7 @@ proc sqlite3_wal {args} {
[lindex $args 0] eval { PRAGMA journal_mode = wal }
[lindex $args 0] eval { PRAGMA synchronous = normal }
[lindex $args 0] function blob blob
+ db timeout 1000
}
proc log_deleted {logfile} {
diff --git a/test/walsetlk.test b/test/walsetlk.test
new file mode 100644
index 000000000..66513ad2d
--- /dev/null
+++ b/test/walsetlk.test
@@ -0,0 +1,198 @@
+# 2020 May 06
+#
+# 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.
+#
+#***********************************************************************
+#
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+source $testdir/lock_common.tcl
+set testprefix walsetlk
+
+ifcapable !wal {finish_test ; return }
+db timeout 1000
+
+#-------------------------------------------------------------------------
+# 1.*: Test that nothing goes wrong if recovery is forced while opening
+# a write transaction or performing a checkpoint with blocking locks.
+#
+
+do_execsql_test 1.0 {
+ CREATE TABLE t1(x, y);
+ PRAGMA journal_mode = wal;
+ INSERT INTO t1 VALUES(1, 2);
+ INSERT INTO t1 VALUES(3, 4);
+ INSERT INTO t1 VALUES(5, 6);
+ INSERT INTO t1 VALUES(7, 8);
+} {wal}
+
+sqlite3 db2 test.db
+db2 timeout 1000
+
+do_execsql_test -db db2 1.1 {
+ SELECT * FROM t1
+} {1 2 3 4 5 6 7 8}
+
+set fd [open test.db-shm r+]
+puts $fd "blahblahblahblah"
+flush $fd
+
+do_execsql_test 1.2 {
+ BEGIN;
+ INSERT INTO t1 VALUES(9, 10);
+}
+
+do_execsql_test -db db2 1.3 {
+ SELECT * FROM t1
+} {1 2 3 4 5 6 7 8}
+
+do_test 1.4 {
+ list [catch {db2 eval { BEGIN EXCLUSIVE }} msg] $msg
+} {1 {database is locked}}
+
+do_execsql_test 1.5 { COMMIT }
+do_execsql_test -db db2 1.6 {
+ SELECT * FROM t1
+} {1 2 3 4 5 6 7 8 9 10}
+
+puts $fd "blahblahblahblah"
+flush $fd
+
+do_execsql_test -db db2 1.7 {
+ PRAGMA wal_checkpoint = TRUNCATE
+} {0 0 0}
+
+do_test 1.8 {
+ file size test.db-wal
+} 0
+
+close $fd
+db close
+db2 close
+#-------------------------------------------------------------------------
+
+do_multiclient_test tn {
+ do_test 2.$tn.1 {
+ sql1 {
+ PRAGMA journal_mode = wal;
+ CREATE TABLE t1(s, v);
+ INSERT INTO t1 VALUES(1, 2);
+ INSERT INTO t1 VALUES(3, 4);
+ INSERT INTO t1 VALUES(5, 6);
+ }
+ code1 { db timeout 2000 }
+ } {}
+
+ do_test 2.$tn.2 {
+ sql2 {
+ BEGIN;
+ INSERT INTO t1 VALUES(7, 8);
+ }
+ } {}
+
+ do_test 2.$tn.3 {
+ set us [lindex [time { catch {db eval "BEGIN EXCLUSIVE"} }] 0]
+ expr $us>1000000 && $us<4000000
+ } {1}
+
+ do_test 2.$tn.4 {
+ sql2 { COMMIT }
+ sql1 { SELECT * FROM t1 }
+ } {1 2 3 4 5 6 7 8}
+
+ do_test 2.$tn.5 {
+ sql2 {
+ BEGIN;
+ INSERT INTO t1 VALUES(9, 10);
+ }
+ } {}
+
+ do_test 2.$tn.6 {
+ set us [lindex [time { catch {db eval "PRAGMA wal_checkpoint=RESTART"} }] 0]
+ expr $us>1000000 && $us<4000000
+ } {1}
+
+ do_test 2.$tn.7 {
+ sql2 {
+ COMMIT;
+ BEGIN;
+ SELECT * FROM t1;
+ }
+ } {1 2 3 4 5 6 7 8 9 10}
+
+ do_test 2.$tn.8 {
+ set us [lindex [time { catch {db eval "PRAGMA wal_checkpoint=RESTART"} }] 0]
+ expr $us>1000000 && $us<4000000
+ } {1}
+
+ do_test 2.$tn.9 {
+ sql3 {
+ INSERT INTO t1 VALUES(11, 12);
+ }
+ sql2 {
+ COMMIT;
+ BEGIN;
+ SELECT * FROM t1;
+ }
+ sql3 {
+ INSERT INTO t1 VALUES(13, 14);
+ }
+ } {}
+
+ do_test 2.$tn.10 {
+ set us [lindex [time { catch {db eval "PRAGMA wal_checkpoint=RESTART"} }] 0]
+ expr $us>1000000 && $us<4000000
+ } {1}
+
+ do_test 2.$tn.11 {
+ sql3 {
+ BEGIN;
+ SELECT * FROM t1;
+ }
+ sql1 { INSERT INTO t1 VALUES(15, 16); }
+ } {}
+
+ do_test 2.$tn.12 {
+ set us [lindex [time { catch {db eval "PRAGMA wal_checkpoint=RESTART"} }] 0]
+ expr $us>1000000 && $us<4000000
+ } {1}
+
+ do_test 2.$tn.13 {
+ sql2 {
+ COMMIT;
+ BEGIN;
+ SELECT * FROM t1;
+ }
+ sql1 { INSERT INTO t1 VALUES(17, 18); }
+ } {}
+
+ do_test 2.$tn.14 {
+ set us [lindex [time { catch {db eval "PRAGMA wal_checkpoint=RESTART"} }] 0]
+ expr $us>1000000 && $us<4000000
+ } {1}
+
+}
+
+#-------------------------------------------------------------------------
+reset_db
+sqlite3 db2 test.db
+db2 timeout 1000
+do_execsql_test 3.0 {
+ PRAGMA journal_mode = wal;
+ CREATE TABLE x1(x, y);
+ BEGIN;
+ INSERT INTO x1 VALUES(1, 2);
+} {wal}
+
+do_test 3.1 {
+ list [catch { db2 eval {BEGIN EXCLUSIVE} } msg] $msg
+} {1 {database is locked}}
+
+finish_test
+
diff --git a/test/where.test b/test/where.test
index 26bf3a040..9b072da67 100644
--- a/test/where.test
+++ b/test/where.test
@@ -1496,8 +1496,8 @@ do_execsql_test where-25.0 {
INSERT INTO t2 VALUES(3, 'three', 'iii');
PRAGMA writable_schema = 1;
- UPDATE sqlite_master SET rootpage = (
- SELECT rootpage FROM sqlite_master WHERE name = 'i2'
+ UPDATE sqlite_schema SET rootpage = (
+ SELECT rootpage FROM sqlite_schema WHERE name = 'i2'
) WHERE name = 'i1';
}
db close
@@ -1524,8 +1524,8 @@ do_execsql_test where-25.3 {
INSERT INTO t2 VALUES(3, 'three', 'iii');
PRAGMA writable_schema = 1;
- UPDATE sqlite_master SET rootpage = (
- SELECT rootpage FROM sqlite_master WHERE name = 'i2'
+ UPDATE sqlite_schema SET rootpage = (
+ SELECT rootpage FROM sqlite_schema WHERE name = 'i2'
) WHERE name = 'i1';
}
db close
diff --git a/test/where9.test b/test/where9.test
index b27460936..0f770dfee 100644
--- a/test/where9.test
+++ b/test/where9.test
@@ -426,7 +426,7 @@ do_test where9-4.5 {
AND (c=31031 OR d IS NULL)
ORDER BY +a
}
-} {1 {no query solution}}
+} {0 {92 93 97}}
do_test where9-4.6 {
count_steps {
SELECT a FROM t1 NOT INDEXED
@@ -442,7 +442,7 @@ do_test where9-4.7 {
AND (c=31031 OR d IS NULL)
ORDER BY +a
}
-} {1 {no query solution}}
+} {0 {92 93 97}}
do_test where9-4.8 {
catchsql {
SELECT a FROM t1 INDEXED BY t1d
@@ -450,7 +450,7 @@ do_test where9-4.8 {
AND (c=31031 OR d IS NULL)
ORDER BY +a
}
-} {1 {no query solution}}
+} {0 {92 93 97}}
# The (c=31031 OR d IS NULL) clause is preferred over b>1000 because
# the former is an equality test which is expected to return fewer rows.
@@ -776,7 +776,7 @@ do_test where9-6.8.1 {
OR (b NOT NULL AND c IS NULL AND d NOT NULL)
OR (b NOT NULL AND c NOT NULL AND d IS NULL)
}
-} {1 {no query solution}}
+} {0 {}}
do_test where9-6.8.2 {
catchsql {
UPDATE t1 INDEXED BY t1b SET a=a+100
@@ -784,7 +784,7 @@ do_test where9-6.8.2 {
OR (b NOT NULL AND c IS NULL AND d NOT NULL)
OR (b NOT NULL AND c NOT NULL AND d IS NULL)
}
-} {1 {no query solution}}
+} {0 {}}
set solution_possible 0
ifcapable stat4 {
@@ -818,7 +818,7 @@ if $solution_possible {
OR (b NOT NULL AND c IS NULL AND d NOT NULL)
OR (b NOT NULL AND c NOT NULL AND d IS NULL)
}
- } {1 {no query solution}}
+ } {0 {}}
do_test where9-6.8.4 {
catchsql {
DELETE FROM t1 INDEXED BY t1b
@@ -826,7 +826,7 @@ if $solution_possible {
OR (b NOT NULL AND c IS NULL AND d NOT NULL)
OR (b NOT NULL AND c NOT NULL AND d IS NULL)
}
- } {1 {no query solution}}
+ } {0 {}}
}
############################################################################
# Test cases where terms inside an OR series are combined with AND terms
diff --git a/test/whereG.test b/test/whereG.test
index 9d4cde7b4..c6ae3ce32 100644
--- a/test/whereG.test
+++ b/test/whereG.test
@@ -317,4 +317,15 @@ do_execsql_test 9.10 {
SELECT coalesce(max(quote(a)),10) FROM t1 GROUP BY a;
} {NULL '' 'X'}
+# 2020-06-14: assert() changed back into testcase()
+# ticket 9fb26d37cefaba40
+#
+reset_db
+do_execsql_test 10.1 {
+ CREATE TABLE a(b TEXT); INSERT INTO a VALUES(0),(4),(9);
+ CREATE TABLE c(d NUM);
+ CREATE VIEW f(g, h) AS SELECT b, 0 FROM a UNION SELECT d, d FROM c;
+ SELECT g = g FROM f GROUP BY h;
+} {1}
+
finish_test
diff --git a/test/win32longpath.test b/test/win32longpath.test
index 9e9ed359c..01b4af70a 100644
--- a/test/win32longpath.test
+++ b/test/win32longpath.test
@@ -24,7 +24,8 @@ do_test 1.0 {
} win32
db close
-set path [file nativename [get_pwd]]
+set rawPath [get_pwd]
+set path [file nativename $rawPath]
sqlite3 db [file join $path test.db] -vfs win32-longpath
do_test 1.1 {
@@ -45,16 +46,32 @@ do_test 1.2 {
} {1 2 3 4}
set longPath(1) \\\\?\\$path\\[pid]
+set uriPath(1a) %5C%5C%3F%5C$path\\[pid]
+set uriPath(1b) %5C%5C%3F%5C$rawPath/[pid]
+
make_win32_dir $longPath(1)
set longPath(2) $longPath(1)\\[string repeat X 255]
+set uriPath(2a) $uriPath(1a)\\[string repeat X 255]
+set uriPath(2b) $uriPath(1b)/[string repeat X 255]
+
make_win32_dir $longPath(2)
set longPath(3) $longPath(2)\\[string repeat Y 255]
+set uriPath(3a) $uriPath(2a)\\[string repeat Y 255]
+set uriPath(3b) $uriPath(2b)/[string repeat Y 255]
+
make_win32_dir $longPath(3)
set fileName $longPath(3)\\test.db
+set uri(1a) file:$uriPath(3a)\\test.db
+set uri(1b) file:$uriPath(3b)/test.db
+set uri(1c) file:///$uriPath(3a)\\test.db
+set uri(1d) file:///$uriPath(3b)/test.db
+set uri(1e) file://localhost/$uriPath(3a)\\test.db
+set uri(1f) file://localhost/$uriPath(3b)/test.db
+
do_test 1.3 {
list [catch {sqlite3 db2 [string range $fileName 4 end]} msg] $msg
} {1 {unable to open database file}}
@@ -100,6 +117,18 @@ do_test 1.6 {
db3 close
# puts " Database exists \{[exists_win32_path $fileName]\}"
+foreach tn {1a 1b 1c 1d 1e 1f} {
+ sqlite3 db3 $uri($tn) -vfs win32-longpath -uri 1 -translatefilename 0
+
+ do_test 1.7.$tn {
+ db3 eval {
+ SELECT x FROM t1 ORDER BY x;
+ }
+ } {5 6 7 8 9 10 11 12}
+
+ db3 close
+}
+
do_delete_win32_file $fileName
# puts " Files remaining \{[find_win32_file $longPath(3)\\*]\}"
diff --git a/test/window1.test b/test/window1.test
index e8e4bc2c4..dbaf4388f 100644
--- a/test/window1.test
+++ b/test/window1.test
@@ -1663,4 +1663,342 @@ do_catchsql_test 51.1 {
sum(b) OVER(PARTITION BY min(DISTINCT c), c ORDER BY b)));
} {1 {row value misused}}
+#-------------------------------------------------------------------------
+reset_db
+do_execsql_test 52.1 {
+ CREATE TABLE t1(a, b, c);
+ INSERT INTO t1 VALUES('AA','bb',356);
+ INSERT INTO t1 VALUES('CC','aa',158);
+ INSERT INTO t1 VALUES('BB','aa',399);
+ INSERT INTO t1 VALUES('FF','bb',938);
+}
+
+do_execsql_test 52.2 {
+ SELECT
+ count() OVER win1,
+ sum(c) OVER win2,
+ first_value(c) OVER win2,
+ count(a) OVER (ORDER BY b)
+ FROM t1
+ WINDOW
+ win1 AS (ORDER BY a),
+ win2 AS (PARTITION BY 6 ORDER BY a
+ RANGE BETWEEN 5 PRECEDING AND 0 PRECEDING );
+} {
+ 1 356 356 4
+ 2 399 399 2
+ 3 158 158 2
+ 4 938 938 4
+}
+
+do_execsql_test 52.3 {
+SELECT
+ count() OVER (),
+ sum(c) OVER win2,
+ first_value(c) OVER win2,
+ count(a) OVER (ORDER BY b)
+FROM t1
+WINDOW
+ win1 AS (ORDER BY a),
+ win2 AS (PARTITION BY 6 COLLATE binary ORDER BY a
+ RANGE BETWEEN 5 PRECEDING AND 0 PRECEDING );
+} {
+ 4 356 356 4
+ 4 399 399 2
+ 4 158 158 2
+ 4 938 938 4
+}
+
+do_execsql_test 52.4 {
+ SELECT
+ count() OVER win1,
+ sum(c) OVER win2,
+ first_value(c) OVER win2,
+ count(a) OVER (ORDER BY b)
+ FROM t1
+ WINDOW
+ win1 AS (ORDER BY a),
+ win2 AS (PARTITION BY 6 COLLATE binary ORDER BY a
+ RANGE BETWEEN 5 PRECEDING AND 0 PRECEDING );
+} {
+ 1 356 356 4
+ 2 399 399 2
+ 3 158 158 2
+ 4 938 938 4
+}
+
+# 2020-05-23
+# ticket 7a5279a25c57adf1
+#
+reset_db
+do_execsql_test 53.0 {
+ CREATE TABLE a(c UNIQUE);
+ INSERT INTO a VALUES(4),(0),(9),(-9);
+ SELECT a.c
+ FROM a
+ JOIN a AS b ON a.c=4
+ JOIN a AS e ON a.c=e.c
+ WHERE a.c=(SELECT (SELECT coalesce(lead(2) OVER(),0) + sum(d.c))
+ FROM a AS d
+ WHERE a.c);
+} {4 4 4 4}
+
+#-------------------------------------------------------------------------
+reset_db
+do_execsql_test 54.1 {
+ CREATE TABLE t1(a VARCHAR(20), b FLOAT);
+ INSERT INTO t1 VALUES('1',10.0);
+}
+
+do_catchsql_test 54.2 {
+ SELECT * FROM (
+ SELECT sum(b) OVER() AS c FROM t1
+ UNION
+ SELECT b AS c FROM t1
+ ) WHERE c>10;
+} {0 {}}
+
+do_execsql_test 54.3 {
+ INSERT INTO t1 VALUES('2',5.0);
+ INSERT INTO t1 VALUES('3',15.0);
+}
+
+do_catchsql_test 54.4 {
+ SELECT * FROM (
+ SELECT sum(b) OVER() AS c FROM t1
+ UNION
+ SELECT b AS c FROM t1
+ ) WHERE c>10;
+} {0 {15.0 30.0}}
+
+# 2020-06-05 ticket c8d3b9f0a750a529
+reset_db
+do_execsql_test 55.1 {
+ CREATE TABLE a(b);
+ SELECT
+ (SELECT b FROM a
+ GROUP BY b
+ HAVING (SELECT COUNT()OVER() + lead(b)OVER(ORDER BY SUM(DISTINCT b) + b))
+ )
+ FROM a
+ UNION
+ SELECT 99
+ ORDER BY 1;
+} {99}
+
+#------------------------------------------------------------------------
+reset_db
+do_execsql_test 56.1 {
+ CREATE TABLE t1(a, b INTEGER);
+ CREATE TABLE t2(c, d);
+}
+do_catchsql_test 56.2 {
+ SELECT avg(b) FROM t1
+ UNION ALL
+ SELECT min(c) OVER () FROM t2
+ ORDER BY nosuchcolumn;
+} {1 {1st ORDER BY term does not match any column in the result set}}
+
+reset_db
+do_execsql_test 57.1 {
+ CREATE TABLE t4(a, b, c, d, e);
+}
+
+do_catchsql_test 57.2 {
+ SELECT b FROM t4
+ UNION
+ SELECT a FROM t4
+ ORDER BY (
+ SELECT sum(x) OVER() FROM (
+ SELECT c AS x FROM t4
+ UNION
+ SELECT d FROM t4
+ ORDER BY (SELECT e FROM t4)
+ )
+ );
+} {1 {1st ORDER BY term does not match any column in the result set}}
+
+# 2020-06-06 various dbsqlfuzz finds and
+# ticket 0899cf62f597d7e7
+#
+reset_db
+do_execsql_test 57.1 {
+ CREATE TABLE t1(a, b, c);
+ INSERT INTO t1 VALUES(NULL,NULL,NULL);
+ SELECT
+ sum(a),
+ min(b) OVER (),
+ count(c) OVER (ORDER BY b)
+ FROM t1;
+} {{} {} 0}
+do_execsql_test 57.2 {
+ CREATE TABLE v0 ( v1 INTEGER PRIMARY KEY ) ;
+ INSERT INTO v0 VALUES ( 10 ) ;
+ SELECT DISTINCT v1, lead(v1) OVER() FROM v0 GROUP BY v1 ORDER BY 2;
+} {10 {}}
+do_catchsql_test 57.3 {
+ DROP TABLE t1;
+ CREATE TABLE t1(a);
+ INSERT INTO t1(a) VALUES(22);
+ CREATE TABLE t3(y);
+ INSERT INTO t3(y) VALUES(5),(11),(-9);
+ SELECT (
+ SELECT max(y) OVER( ORDER BY (SELECT x FROM (SELECT sum(y) AS x FROM t1)))
+ )
+ FROM t3;
+} {1 {misuse of aggregate: sum()}}
+
+# 2020-06-06 ticket 1f6f353b684fc708
+reset_db
+do_execsql_test 58.1 {
+ CREATE TABLE a(a, b, c);
+ INSERT INTO a VALUES(1, 2, 3);
+ INSERT INTO a VALUES(4, 5, 6);
+ SELECT sum(345+b) OVER (ORDER BY b),
+ sum(avg(678)) OVER (ORDER BY c) FROM a;
+} {347 678.0}
+
+# 2020-06-06 ticket e5504e987e419fb0
+do_catchsql_test 59.1 {
+ DROP TABLE IF EXISTS t1;
+ CREATE TABLE t1(x INTEGER PRIMARY KEY);
+ INSERT INTO t1 VALUES (123);
+ SELECT
+ ntile( (SELECT sum(x)) ) OVER(ORDER BY x),
+ min(x) OVER(ORDER BY x)
+ FROM t1;
+} {1 {misuse of aggregate: sum()}}
+
+# 2020-06-07 ticket f7d890858f361402
+do_execsql_test 60.1 {
+ DROP TABLE IF EXISTS t1;
+ CREATE TABLE t1 (x INTEGER PRIMARY KEY);
+ INSERT INTO t1 VALUES (99);
+ SELECT EXISTS(SELECT count(*) OVER() FROM t1 ORDER BY sum(x) OVER());
+} {1}
+
+# 2020-06-07 test case generated by dbsqlfuzz showing how an AggInfo
+# object might be referenced after the sqlite3Select() call that created
+# it returns. This proves the need to persist all AggInfo objects until
+# the Parse object is destroyed.
+#
+reset_db
+do_execsql_test 61.1 {
+CREATE TABLE t1(a);
+INSERT INTO t1 VALUES(5),(NULL),('seventeen');
+SELECT (SELECT max(x)OVER(ORDER BY x) % min(x)OVER(ORDER BY CASE x WHEN 889 THEN x WHEN x THEN x END)) FROM (SELECT (SELECT sum(CAST(a IN(SELECT (SELECT max(x)OVER(ORDER BY CASE x WHEN 889 THEN 299 WHEN 863 THEN 863 END)) FROM (SELECT (SELECT sum(CAST((SELECT (SELECT max(x)OVER(ORDER BY x) / min(x)OVER(ORDER BY CASE x WHEN 889 THEN 299 WHEN -true THEN 863 END)) FROM (SELECT (SELECT sum(CAST(a IN(SELECT (SELECT max(x) & sum ( a )OVER(ORDER BY CASE x WHEN -8 THEN 299 WHEN 863 THEN 863 END)) FROM (SELECT (SELECT sum(CAST(a AS )) FROM t1) AS x FROM t1)) AS t1 )) FROM t1) AS x FROM t1)) AS x )) FROM t1) AS x FROM t1)) AS real)) FROM t1) AS x FROM t1);
+} {{} {} {}}
+
+#-------------------------------------------------------------------------
+reset_db
+do_execsql_test 62.1 {
+ CREATE TABLE t1(a VARCHAR(20), b FLOAT);
+ INSERT INTO t1 VALUES('1',10.0);
+}
+
+do_execsql_test 62.2 {
+ SELECT * FROM (
+ SELECT sum(b) OVER() AS c FROM t1
+ UNION
+ SELECT b AS c FROM t1
+ ) WHERE c>10;
+}
+
+do_execsql_test 62.3 {
+ INSERT INTO t1 VALUES('2',5.0);
+ INSERT INTO t1 VALUES('3',15.0);
+}
+
+do_execsql_test 62.4 {
+ SELECT * FROM (
+ SELECT sum(b) OVER() AS c FROM t1
+ UNION
+ SELECT b AS c FROM t1
+ ) WHERE c>10;
+} {15.0 30.0}
+
+#-------------------------------------------------------------------------
+reset_db
+do_execsql_test 63.1 {
+ CREATE TABLE t1(b, x);
+ CREATE TABLE t2(c, d);
+ CREATE TABLE t3(e, f);
+}
+
+do_execsql_test 63.2 {
+ SELECT max(b) OVER(
+ ORDER BY SUM(
+ (SELECT c FROM t2 UNION SELECT x ORDER BY c)
+ )
+ ) FROM t1;
+} {{}}
+
+do_execsql_test 63.3 {
+ SELECT sum(b) over(
+ ORDER BY (
+ SELECT max(b) OVER(
+ ORDER BY sum(
+ (SELECT x AS c UNION SELECT 1234 ORDER BY c)
+ )
+ ) AS e
+ ORDER BY e
+ )
+ )
+ FROM t1;
+} {{}}
+
+#-------------------------------------------------------------------------
+reset_db
+do_execsql_test 64.1 {
+ CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
+ INSERT INTO t1 VALUES(1, 'abcd');
+ INSERT INTO t1 VALUES(2, 'BCDE');
+ INSERT INTO t1 VALUES(3, 'cdef');
+ INSERT INTO t1 VALUES(4, 'DEFG');
+}
+
+do_execsql_test 64.2 {
+ SELECT rowid, max(b COLLATE nocase)||''
+ FROM t1
+ GROUP BY rowid
+ ORDER BY max(b COLLATE nocase)||'';
+} {1 abcd 2 BCDE 3 cdef 4 DEFG}
+
+do_execsql_test 64.3 {
+ SELECT count() OVER (), rowid, max(b COLLATE nocase)||''
+ FROM t1
+ GROUP BY rowid
+ ORDER BY max(b COLLATE nocase)||'';
+} {4 1 abcd 4 2 BCDE 4 3 cdef 4 4 DEFG}
+
+do_execsql_test 64.4 {
+ SELECT count() OVER (), rowid, max(b COLLATE nocase)
+ FROM t1
+ GROUP BY rowid
+ ORDER BY max(b COLLATE nocase);
+} {4 1 abcd 4 2 BCDE 4 3 cdef 4 4 DEFG}
+
+#-------------------------------------------------------------------------
+reset_db
+do_execsql_test 65.1 {
+ CREATE TABLE t1(c1);
+ INSERT INTO t1 VALUES('abcd');
+}
+do_execsql_test 65.2 {
+ SELECT max(c1 COLLATE nocase) IN (SELECT 'aBCd') FROM t1;
+} {1}
+
+do_execsql_test 65.3 {
+ SELECT
+ count() OVER (),
+ group_concat(c1 COLLATE nocase) IN (SELECT 'aBCd') FROM t1;
+} {1 1}
+
+do_execsql_test 65.4 {
+ SELECT COUNT() OVER () LIKE lead(102030) OVER(
+ ORDER BY sum('abcdef' COLLATE nocase) IN (SELECT 54321)
+ )
+ FROM t1;
+} {{}}
+
finish_test
diff --git a/test/window9.test b/test/window9.test
index 46d746c4f..c342a4d79 100644
--- a/test/window9.test
+++ b/test/window9.test
@@ -255,7 +255,7 @@ do_execsql_test 8.2 {
do_catchsql_test 8.3 {
SELECT min( max((SELECT x FROM v1)) ) OVER()
-} {1 {misuse of aggregate: max()}}
+} {0 0}
do_execsql_test 8.4 {
SELECT(
@@ -263,6 +263,6 @@ do_execsql_test 8.4 {
SELECT sum( avg((SELECT x FROM v1)) ) OVER()
)
FROM v1;
-} {0.0}
+} {0.0 0.0}
finish_test
diff --git a/test/without_rowid3.test b/test/without_rowid3.test
index 24ef2304d..eae7e3c85 100644
--- a/test/without_rowid3.test
+++ b/test/without_rowid3.test
@@ -921,6 +921,7 @@ ifcapable altertable {
execsql {
CREATE TABLE t1(a PRIMARY KEY) WITHOUT rowid;
CREATE TABLE t2(a, b);
+ INSERT INTO t2(a,b) VALUES(1,2);
}
catchsql { ALTER TABLE t2 ADD COLUMN c REFERENCES t1 }
} {0 {}}
@@ -941,7 +942,7 @@ ifcapable altertable {
PRAGMA foreign_keys = off;
ALTER TABLE t2 ADD COLUMN h DEFAULT 'text' REFERENCES t1;
PRAGMA foreign_keys = on;
- SELECT sql FROM sqlite_master WHERE name='t2';
+ SELECT sql FROM sqlite_schema WHERE name='t2';
}
} {{CREATE TABLE t2(a, b, c REFERENCES t1, d DEFAULT NULL REFERENCES t1, e REFERENCES t1 DEFAULT NULL, h DEFAULT 'text' REFERENCES t1)}}
@@ -975,7 +976,7 @@ ifcapable altertable {
WITHOUT rowid;
CREATE TABLE t3(a REFERENCES t1, b REFERENCES t2, c REFERENCES t1);
}
- execsql { SELECT sql FROM sqlite_master WHERE type = 'table'}
+ execsql { SELECT sql FROM sqlite_schema WHERE type = 'table'}
} [list \
{CREATE TABLE t1(a PRIMARY KEY, b REFERENCES t1) WITHOUT rowid} \
{CREATE TABLE t2(a PRIMARY KEY, b REFERENCES t1, c REFERENCES t2)
@@ -984,7 +985,7 @@ ifcapable altertable {
]
do_test without_rowid3-14.2.2.2 {
execsql { ALTER TABLE t1 RENAME TO t4 }
- execsql { SELECT sql FROM sqlite_master WHERE type = 'table'}
+ execsql { SELECT sql FROM sqlite_schema WHERE type = 'table'}
} [list \
{CREATE TABLE "t4"(a PRIMARY KEY, b REFERENCES "t4") WITHOUT rowid} \
{CREATE TABLE t2(a PRIMARY KEY, b REFERENCES "t4", c REFERENCES t2)
@@ -1015,6 +1016,7 @@ ifcapable altertable {
execsql {
CREATE TEMP TABLE t1(a PRIMARY KEY) WITHOUT rowid;
CREATE TEMP TABLE t2(a, b);
+ INSERT INTO temp.t2(a,b) VALUES(1,2);
}
catchsql { ALTER TABLE t2 ADD COLUMN c REFERENCES t1 }
} {0 {}}
@@ -1035,7 +1037,7 @@ ifcapable altertable {
PRAGMA foreign_keys = off;
ALTER TABLE t2 ADD COLUMN h DEFAULT 'text' REFERENCES t1;
PRAGMA foreign_keys = on;
- SELECT sql FROM temp.sqlite_master WHERE name='t2';
+ SELECT sql FROM temp.sqlite_schema WHERE name='t2';
}
} {{CREATE TABLE t2(a, b, c REFERENCES t1, d DEFAULT NULL REFERENCES t1, e REFERENCES t1 DEFAULT NULL, h DEFAULT 'text' REFERENCES t1)}}
@@ -1061,7 +1063,7 @@ ifcapable altertable {
WITHOUT rowid;
CREATE TEMP TABLE t3(a REFERENCES t1, b REFERENCES t2, c REFERENCES t1);
}
- execsql { SELECT sql FROM sqlite_temp_master WHERE type = 'table'}
+ execsql { SELECT sql FROM sqlite_temp_schema WHERE type = 'table'}
} [list \
{CREATE TABLE t1(a PRIMARY KEY, b REFERENCES t1) WITHOUT rowid} \
{CREATE TABLE t2(a PRIMARY KEY, b REFERENCES t1, c REFERENCES t2)
@@ -1070,7 +1072,7 @@ ifcapable altertable {
]
do_test without_rowid3-14.2tmp.2.2 {
execsql { ALTER TABLE t1 RENAME TO t4 }
- execsql { SELECT sql FROM temp.sqlite_master WHERE type = 'table'}
+ execsql { SELECT sql FROM temp.sqlite_schema WHERE type = 'table'}
} [list \
{CREATE TABLE "t4"(a PRIMARY KEY, b REFERENCES "t4") WITHOUT rowid} \
{CREATE TABLE t2(a PRIMARY KEY, b REFERENCES "t4", c REFERENCES t2)
@@ -1102,6 +1104,7 @@ ifcapable altertable {
ATTACH ':memory:' AS aux;
CREATE TABLE aux.t1(a PRIMARY KEY) WITHOUT rowid;
CREATE TABLE aux.t2(a, b);
+ INSERT INTO aux.t2(a,b) VALUES(1,2);
}
catchsql { ALTER TABLE t2 ADD COLUMN c REFERENCES t1 }
} {0 {}}
@@ -1122,7 +1125,7 @@ ifcapable altertable {
PRAGMA foreign_keys = off;
ALTER TABLE t2 ADD COLUMN h DEFAULT 'text' REFERENCES t1;
PRAGMA foreign_keys = on;
- SELECT sql FROM aux.sqlite_master WHERE name='t2';
+ SELECT sql FROM aux.sqlite_schema WHERE name='t2';
}
} {{CREATE TABLE t2(a, b, c REFERENCES t1, d DEFAULT NULL REFERENCES t1, e REFERENCES t1 DEFAULT NULL, h DEFAULT 'text' REFERENCES t1)}}
@@ -1148,7 +1151,7 @@ ifcapable altertable {
WITHOUT rowid;
CREATE TABLE aux.t3(a REFERENCES t1, b REFERENCES t2, c REFERENCES t1);
}
- execsql { SELECT sql FROM aux.sqlite_master WHERE type = 'table'}
+ execsql { SELECT sql FROM aux.sqlite_schema WHERE type = 'table'}
} [list \
{CREATE TABLE t1(a PRIMARY KEY, b REFERENCES t1) WITHOUT rowid} \
{CREATE TABLE t2(a PRIMARY KEY, b REFERENCES t1, c REFERENCES t2)
@@ -1157,7 +1160,7 @@ ifcapable altertable {
]
do_test without_rowid3-14.2aux.2.2 {
execsql { ALTER TABLE t1 RENAME TO t4 }
- execsql { SELECT sql FROM aux.sqlite_master WHERE type = 'table'}
+ execsql { SELECT sql FROM aux.sqlite_schema WHERE type = 'table'}
} [list \
{CREATE TABLE "t4"(a PRIMARY KEY, b REFERENCES "t4") WITHOUT rowid} \
{CREATE TABLE t2(a PRIMARY KEY, b REFERENCES "t4", c REFERENCES t2)
diff --git a/tool/dbhash.c b/tool/dbhash.c
index 7696ddbde..78685dcd6 100644
--- a/tool/dbhash.c
+++ b/tool/dbhash.c
@@ -440,7 +440,7 @@ int main(int argc, char **argv){
fprintf(stderr, "cannot open database file '%s'\n", zDb);
continue;
}
- rc = sqlite3_exec(g.db, "SELECT * FROM sqlite_master", 0, 0, &zErrMsg);
+ rc = sqlite3_exec(g.db, "SELECT * FROM sqlite_schema", 0, 0, &zErrMsg);
if( rc || zErrMsg ){
sqlite3_close(g.db);
g.db = 0;
@@ -454,7 +454,7 @@ int main(int argc, char **argv){
/* Hash table content */
if( !omitContent ){
pStmt = db_prepare(
- "SELECT name FROM sqlite_master\n"
+ "SELECT name FROM sqlite_schema\n"
" WHERE type='table' AND sql NOT LIKE 'CREATE VIRTUAL%%'\n"
" AND name NOT LIKE 'sqlite_%%'\n"
" AND name LIKE '%q'\n"
@@ -476,7 +476,7 @@ int main(int argc, char **argv){
/* Hash the database schema */
if( !omitSchema ){
hash_one_query(
- "SELECT type, name, tbl_name, sql FROM sqlite_master\n"
+ "SELECT type, name, tbl_name, sql FROM sqlite_schema\n"
" WHERE tbl_name LIKE '%q'\n"
" ORDER BY name COLLATE nocase;\n",
zLike
diff --git a/tool/fast_vacuum.c b/tool/fast_vacuum.c
index 6a50dcc68..5ca0271dc 100644
--- a/tool/fast_vacuum.c
+++ b/tool/fast_vacuum.c
@@ -150,7 +150,7 @@ int main(int argc, char **argv){
*/
/* The vacuum will occur inside of a transaction. Set writable_schema
- ** to ON so that we can directly update the sqlite_master table in the
+ ** to ON so that we can directly update the sqlite_schema table in the
** zTempDb database.
*/
execSql(db, "PRAGMA writable_schema=ON");
@@ -162,16 +162,16 @@ int main(int argc, char **argv){
*/
execExecSql(db,
"SELECT 'CREATE TABLE vacuum_db.' || substr(sql,14) "
- " FROM sqlite_master WHERE type='table' AND name!='sqlite_sequence'"
+ " FROM sqlite_schema WHERE type='table' AND name!='sqlite_sequence'"
" AND rootpage>0"
);
execExecSql(db,
"SELECT 'CREATE INDEX vacuum_db.' || substr(sql,14)"
- " FROM sqlite_master WHERE sql LIKE 'CREATE INDEX %'"
+ " FROM sqlite_schema WHERE sql LIKE 'CREATE INDEX %'"
);
execExecSql(db,
"SELECT 'CREATE UNIQUE INDEX vacuum_db.' || substr(sql,21) "
- " FROM sqlite_master WHERE sql LIKE 'CREATE UNIQUE INDEX %'"
+ " FROM sqlite_schema WHERE sql LIKE 'CREATE UNIQUE INDEX %'"
);
/* Loop through the tables in the main database. For each, do
@@ -181,7 +181,7 @@ int main(int argc, char **argv){
execExecSql(db,
"SELECT 'INSERT INTO vacuum_db.' || quote(name) "
"|| ' SELECT * FROM main.' || quote(name) "
- "FROM main.sqlite_master "
+ "FROM main.sqlite_schema "
"WHERE type = 'table' AND name!='sqlite_sequence' "
" AND rootpage>0"
);
@@ -190,12 +190,12 @@ int main(int argc, char **argv){
*/
execExecSql(db,
"SELECT 'DELETE FROM vacuum_db.' || quote(name) "
- "FROM vacuum_db.sqlite_master WHERE name='sqlite_sequence'"
+ "FROM vacuum_db.sqlite_schema WHERE name='sqlite_sequence'"
);
execExecSql(db,
"SELECT 'INSERT INTO vacuum_db.' || quote(name) "
"|| ' SELECT * FROM main.' || quote(name) "
- "FROM vacuum_db.sqlite_master WHERE name=='sqlite_sequence'"
+ "FROM vacuum_db.sqlite_schema WHERE name=='sqlite_sequence'"
);
/* Copy the triggers, views, and virtual tables from the main database
@@ -204,9 +204,9 @@ int main(int argc, char **argv){
** from the SQLITE_MASTER table.
*/
execSql(db,
- "INSERT INTO vacuum_db.sqlite_master "
+ "INSERT INTO vacuum_db.sqlite_schema "
" SELECT type, name, tbl_name, rootpage, sql"
- " FROM main.sqlite_master"
+ " FROM main.sqlite_schema"
" WHERE type='view' OR type='trigger'"
" OR (type='table' AND rootpage=0)"
);
diff --git a/tool/index_usage.c b/tool/index_usage.c
index 451fa65c3..9bd3c9fdc 100644
--- a/tool/index_usage.c
+++ b/tool/index_usage.c
@@ -104,7 +104,7 @@ int main(int argc, char **argv){
printf("Cannot open \"%s\" for reading: %s\n", argv[1], sqlite3_errmsg(db));
goto errorOut;
}
- rc = sqlite3_prepare_v2(db, "SELECT * FROM sqlite_master", -1, &pStmt, 0);
+ rc = sqlite3_prepare_v2(db, "SELECT * FROM sqlite_schema", -1, &pStmt, 0);
if( rc ){
printf("Cannot read the schema from \"%s\" - %s\n", argv[1],
sqlite3_errmsg(db));
@@ -126,7 +126,7 @@ int main(int argc, char **argv){
}
rc = sqlite3_exec(db,
"INSERT INTO temp.idxu(tbl,idx,cnt)"
- " SELECT tbl_name, name, 0 FROM sqlite_master"
+ " SELECT tbl_name, name, 0 FROM sqlite_schema"
" WHERE type='index' AND sql IS NOT NULL", 0, 0, 0);
/* Open the LOG database */
@@ -205,9 +205,9 @@ int main(int argc, char **argv){
rc = sqlite3_prepare_v2(db,
"SELECT tbl, idx, cnt, "
" (SELECT group_concat(name,',') FROM pragma_index_info(idx))"
- " FROM temp.idxu, main.sqlite_master"
- " WHERE temp.idxu.tbl=main.sqlite_master.tbl_name"
- " AND temp.idxu.idx=main.sqlite_master.name"
+ " FROM temp.idxu, main.sqlite_schema"
+ " WHERE temp.idxu.tbl=main.sqlite_schema.tbl_name"
+ " AND temp.idxu.idx=main.sqlite_schema.name"
" ORDER BY cnt DESC, tbl, idx",
-1, &pStmt, 0);
if( rc ){
diff --git a/tool/lemon.c b/tool/lemon.c
index 8dcf65179..40e4e2894 100644
--- a/tool/lemon.c
+++ b/tool/lemon.c
@@ -423,6 +423,7 @@ struct lemon {
int nlookaheadtab; /* Number of entries in yy_lookahead[] */
int tablesize; /* Total table size of all tables in bytes */
int basisflag; /* Print only basis configurations */
+ int printPreprocessed; /* Show preprocessor output on stdout */
int has_fallback; /* True if any %fallback is seen in the grammar */
int nolinenosflag; /* True if #line statements should not be printed */
char *argv0; /* Name of the program */
@@ -1636,12 +1637,14 @@ int main(int argc, char **argv)
static int nolinenosflag = 0;
static int noResort = 0;
static int sqlFlag = 0;
+ static int printPP = 0;
static struct s_options options[] = {
{OPT_FLAG, "b", (char*)&basisflag, "Print only the basis in report."},
{OPT_FLAG, "c", (char*)&compress, "Don't compress the action table."},
{OPT_FSTR, "d", (char*)&handle_d_option, "Output directory. Default '.'"},
{OPT_FSTR, "D", (char*)handle_D_option, "Define an %ifdef macro."},
+ {OPT_FLAG, "E", (char*)&printPP, "Print input file after preprocessing."},
{OPT_FSTR, "f", 0, "Ignored. (Placeholder for -f compiler options.)"},
{OPT_FLAG, "g", (char*)&rpflag, "Print grammar without actions."},
{OPT_FSTR, "I", 0, "Ignored. (Placeholder for '-I' compiler options.)"},
@@ -1686,11 +1689,12 @@ int main(int argc, char **argv)
lem.filename = OptArg(0);
lem.basisflag = basisflag;
lem.nolinenosflag = nolinenosflag;
+ lem.printPreprocessed = printPP;
Symbol_new("$");
/* Parse the input file */
Parse(&lem);
- if( lem.errorcnt ) exit(lem.errorcnt);
+ if( lem.printPreprocessed || lem.errorcnt ) exit(lem.errorcnt);
if( lem.nrule==0 ){
fprintf(stderr,"Empty grammar.\n");
exit(1);
@@ -2779,13 +2783,108 @@ static void parseonetoken(struct pstate *psp)
}
}
+/* The text in the input is part of the argument to an %ifdef or %ifndef.
+** Evaluate the text as a boolean expression. Return true or false.
+*/
+static int eval_preprocessor_boolean(char *z, int lineno){
+ int neg = 0;
+ int res = 0;
+ int okTerm = 1;
+ int i;
+ for(i=0; z[i]!=0; i++){
+ if( ISSPACE(z[i]) ) continue;
+ if( z[i]=='!' ){
+ if( !okTerm ) goto pp_syntax_error;
+ neg = !neg;
+ continue;
+ }
+ if( z[i]=='|' && z[i+1]=='|' ){
+ if( okTerm ) goto pp_syntax_error;
+ if( res ) return 1;
+ i++;
+ okTerm = 1;
+ continue;
+ }
+ if( z[i]=='&' && z[i+1]=='&' ){
+ if( okTerm ) goto pp_syntax_error;
+ if( !res ) return 0;
+ i++;
+ okTerm = 1;
+ continue;
+ }
+ if( z[i]=='(' ){
+ int k;
+ int n = 1;
+ if( !okTerm ) goto pp_syntax_error;
+ for(k=i+1; z[k]; k++){
+ if( z[k]==')' ){
+ n--;
+ if( n==0 ){
+ z[k] = 0;
+ res = eval_preprocessor_boolean(&z[i+1], -1);
+ z[k] = ')';
+ if( res<0 ){
+ i = i-res;
+ goto pp_syntax_error;
+ }
+ i = k;
+ break;
+ }
+ }else if( z[k]=='(' ){
+ n++;
+ }else if( z[k]==0 ){
+ i = k;
+ goto pp_syntax_error;
+ }
+ }
+ if( neg ){
+ res = !res;
+ neg = 0;
+ }
+ okTerm = 0;
+ continue;
+ }
+ if( ISALPHA(z[i]) ){
+ int j, k, n;
+ if( !okTerm ) goto pp_syntax_error;
+ for(k=i+1; ISALNUM(z[k]) || z[k]=='_'; k++){}
+ n = k - i;
+ res = 0;
+ for(j=0; j<nDefine; j++){
+ if( strncmp(azDefine[j],&z[i],n)==0 && azDefine[j][n]==0 ){
+ res = 1;
+ break;
+ }
+ }
+ i = k-1;
+ if( neg ){
+ res = !res;
+ neg = 0;
+ }
+ okTerm = 0;
+ continue;
+ }
+ goto pp_syntax_error;
+ }
+ return res;
+
+pp_syntax_error:
+ if( lineno>0 ){
+ fprintf(stderr, "%%if syntax error on line %d.\n", lineno);
+ fprintf(stderr, " %.*s <-- syntax error here\n", i+1, z);
+ exit(1);
+ }else{
+ return -(i+1);
+ }
+}
+
/* Run the preprocessor over the input file text. The global variables
** azDefine[0] through azDefine[nDefine-1] contains the names of all defined
** macros. This routine looks for "%ifdef" and "%ifndef" and "%endif" and
** comments them out. Text in between is also commented out as appropriate.
*/
static void preprocess_input(char *z){
- int i, j, k, n;
+ int i, j, k;
int exclude = 0;
int start = 0;
int lineno = 1;
@@ -2801,21 +2900,33 @@ static void preprocess_input(char *z){
}
}
for(j=i; z[j] && z[j]!='\n'; j++) z[j] = ' ';
- }else if( (strncmp(&z[i],"%ifdef",6)==0 && ISSPACE(z[i+6]))
- || (strncmp(&z[i],"%ifndef",7)==0 && ISSPACE(z[i+7])) ){
+ }else if( strncmp(&z[i],"%else",5)==0 && ISSPACE(z[i+5]) ){
+ if( exclude==1){
+ exclude = 0;
+ for(j=start; j<i; j++) if( z[j]!='\n' ) z[j] = ' ';
+ }else if( exclude==0 ){
+ exclude = 1;
+ start = i;
+ start_lineno = lineno;
+ }
+ for(j=i; z[j] && z[j]!='\n'; j++) z[j] = ' ';
+ }else if( strncmp(&z[i],"%ifdef ",7)==0
+ || strncmp(&z[i],"%if ",4)==0
+ || strncmp(&z[i],"%ifndef ",8)==0 ){
if( exclude ){
exclude++;
}else{
- for(j=i+7; ISSPACE(z[j]); j++){}
- for(n=0; z[j+n] && !ISSPACE(z[j+n]); n++){}
- exclude = 1;
- for(k=0; k<nDefine; k++){
- if( strncmp(azDefine[k],&z[j],n)==0 && lemonStrlen(azDefine[k])==n ){
- exclude = 0;
- break;
- }
- }
- if( z[i+3]=='n' ) exclude = !exclude;
+ int isNot;
+ int iBool;
+ for(j=i; z[j] && !ISSPACE(z[j]); j++){}
+ iBool = j;
+ isNot = (j==i+7);
+ while( z[j] && z[j]!='\n' ){ j++; }
+ k = z[j];
+ z[j] = 0;
+ exclude = eval_preprocessor_boolean(&z[iBool], lineno);
+ z[j] = k;
+ if( !isNot ) exclude = !exclude;
if( exclude ){
start = i;
start_lineno = lineno;
@@ -2883,6 +2994,10 @@ void Parse(struct lemon *gp)
/* Make an initial pass through the file to handle %ifdef and %ifndef */
preprocess_input(filebuf);
+ if( gp->printPreprocessed ){
+ printf("%s\n", filebuf);
+ return;
+ }
/* Now scan the text of the input file */
lineno = 1;
diff --git a/tool/mkautoconfamal.sh b/tool/mkautoconfamal.sh
index 7cd7da35f..eacd9fa51 100644
--- a/tool/mkautoconfamal.sh
+++ b/tool/mkautoconfamal.sh
@@ -2,8 +2,8 @@
# This script is used to build the amalgamation autoconf package.
# It assumes the following:
#
-# 1. The files "sqlite3.c", "sqlite3.h" and "sqlite3ext.h"
-# are available in the current directory.
+# 1. The files "sqlite3.c", "sqlite3.h", "sqlite3ext.h", "shell.c",
+# and "sqlite3rc.h" are available in the current directory.
#
# 2. Variable $TOP is set to the full path of the root directory
# of the SQLite source tree.
@@ -49,6 +49,7 @@ cp -R $TOP/autoconf $TMPSPACE
cp sqlite3.c $TMPSPACE
cp sqlite3.h $TMPSPACE
cp sqlite3ext.h $TMPSPACE
+cp sqlite3rc.h $TMPSPACE
cp $TOP/sqlite3.1 $TMPSPACE
cp $TOP/sqlite3.pc.in $TMPSPACE
cp shell.c $TMPSPACE
diff --git a/tool/mkpragmatab.tcl b/tool/mkpragmatab.tcl
index 7c8ffd353..7c1576563 100644
--- a/tool/mkpragmatab.tcl
+++ b/tool/mkpragmatab.tcl
@@ -289,7 +289,7 @@ set pragma_def {
IF: !defined(SQLITE_OMIT_FOREIGN_KEY)
NAME: foreign_key_check
- FLAG: NeedSchema Result0
+ FLAG: NeedSchema Result0 Result1 SchemaOpt
COLS: table rowid parent fkid
IF: !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER)
@@ -382,6 +382,9 @@ set pragma_def {
NAME: threads
FLAG: Result0
+ NAME: analysis_limit
+ FLAG: Result0
+
NAME: optimize
FLAG: Result1 NeedSchema
diff --git a/tool/mksqlite3c.tcl b/tool/mksqlite3c.tcl
index 2f9bd866b..36663ff3b 100644
--- a/tool/mksqlite3c.tcl
+++ b/tool/mksqlite3c.tcl
@@ -183,7 +183,7 @@ proc copy_file {filename} {
}
set declpattern ^$declpattern\$
while {![eof $in]} {
- set line [gets $in]
+ set line [string trimright [gets $in]]
incr ln
if {[regexp {^\s*#\s*include\s+["<]([^">]+)[">]} $line all hdr]} {
if {[info exists available_hdr($hdr)]} {
@@ -341,6 +341,7 @@ foreach file {
vdbe.c
vdbeblob.c
vdbesort.c
+ vdbevtab.c
memjournal.c
walker.c
diff --git a/tool/mksqlite3h.tcl b/tool/mksqlite3h.tcl
index 216bd4e60..9078a1575 100644
--- a/tool/mksqlite3h.tcl
+++ b/tool/mksqlite3h.tcl
@@ -107,7 +107,7 @@ foreach file $filelist {
}
while {![eof $in]} {
- set line [gets $in]
+ set line [string trimright [gets $in]]
# File sqlite3rtree.h contains a line "#include <sqlite3.h>". Omit this
# line when copying sqlite3rtree.h into sqlite3.h.
diff --git a/tool/offsets.c b/tool/offsets.c
index 8e098e71c..26ee9fcef 100644
--- a/tool/offsets.c
+++ b/tool/offsets.c
@@ -75,7 +75,7 @@ static void ofstRootAndColumn(
ofstError(p, "cannot open database file \"%s\"", zFile);
goto rootAndColumn_exit;
}
- zSql = sqlite3_mprintf("SELECT rootpage FROM sqlite_master WHERE name=%Q",
+ zSql = sqlite3_mprintf("SELECT rootpage FROM sqlite_schema WHERE name=%Q",
zTable);
rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
if( rc ) ofstError(p, "%s: [%s]", sqlite3_errmsg(db), zSql);
diff --git a/tool/showdb.c b/tool/showdb.c
index fe4e9aca0..b79cc1eff 100644
--- a/tool/showdb.c
+++ b/tool/showdb.c
@@ -999,7 +999,7 @@ static void page_usage_report(const char *zPrg, const char *zDbName){
page_usage_freelist(decodeInt32(a+32));
page_usage_ptrmap(a);
sqlite3_free(a);
- page_usage_btree(1, 0, 0, "sqlite_master");
+ page_usage_btree(1, 0, 0, "sqlite_schema");
sqlite3_exec(db, "PRAGMA writable_schema=ON", 0, 0, 0);
for(j=0; j<2; j++){
sqlite3_snprintf(sizeof(zQuery), zQuery,
@@ -1055,7 +1055,7 @@ static void ptrmap_coverage_report(const char *zDbName){
usable = g.pagesize - aHdr[20];
perPage = usable/5;
sqlite3_free(aHdr);
- printf("%5d: root of sqlite_master\n", 1);
+ printf("%5d: root of sqlite_schema\n", 1);
for(pgno=2; pgno<=g.mxPage; pgno += perPage+1){
printf("%5d: PTRMAP page covering %d..%d\n", pgno,
pgno+1, pgno+perPage);
diff --git a/tool/showlocks.c b/tool/showlocks.c
index 752c535cc..4159a71f8 100644
--- a/tool/showlocks.c
+++ b/tool/showlocks.c
@@ -24,23 +24,58 @@
static int showLocksInRange(int fd, off_t lwr, off_t upr){
int cnt = 0;
struct flock x;
+ struct lockRange {
+ off_t lwr;
+ off_t upr;
+ } *aPending = 0;
+ int nAlloc = 1;
+ int nPending = 0;
+ int nDone = 0;
- x.l_type = F_WRLCK;
- x.l_whence = SEEK_SET;
- x.l_start = lwr;
- x.l_len = upr-lwr;
- fcntl(fd, F_GETLK, &x);
- if( x.l_type==F_UNLCK ) return 0;
- printf("start: %-12d len: %-5d pid: %-5d type: %s\n",
- (int)x.l_start, (int)x.l_len,
- x.l_pid, x.l_type==F_WRLCK ? "WRLCK" : "RDLCK");
- cnt++;
- if( x.l_start>lwr ){
- cnt += showLocksInRange(fd, lwr, x.l_start-1);
+ nPending = 1;
+ aPending = malloc( sizeof(aPending[0]) );
+ if( aPending==0 ){
+ fprintf(stderr, "out of memory\n");
+ exit(1);
}
- if( x.l_start+x.l_len<upr ){
- cnt += showLocksInRange(fd, x.l_start+x.l_len+1, upr);
+ aPending[0].lwr = lwr;
+ aPending[0].upr = upr;
+
+ for(nDone=0; nDone<nPending; nDone++){
+ lwr = aPending[nDone].lwr;
+ upr = aPending[nDone].upr;
+ if( lwr>=upr ) continue;
+ x.l_type = F_WRLCK;
+ x.l_whence = SEEK_SET;
+ x.l_start = lwr;
+ x.l_len = upr - lwr;
+ fcntl(fd, F_GETLK, &x);
+ if( x.l_type==F_UNLCK ) continue;
+ printf("start: %-12d len: %-5d pid: %-5d type: %s\n",
+ (int)x.l_start, (int)x.l_len,
+ x.l_pid, x.l_type==F_WRLCK ? "WRLCK" : "RDLCK");
+ cnt++;
+ if( nPending+2 > nAlloc ){
+ nAlloc = nAlloc*2 + 2;
+ aPending = realloc(aPending, sizeof(aPending[0])*nAlloc );
+ }
+ if( aPending==0 ){
+ fprintf(stderr, "unable to realloc for %d bytes\n",
+ (int)sizeof(aPending[0])*(nPending+2));
+ exit(1);
+ }
+ if( lwr<x.l_start ){
+ aPending[nPending].lwr = lwr;
+ aPending[nPending].upr = x.l_start;
+ nPending++;
+ }
+ if( x.l_start+x.l_len<=upr ){
+ aPending[nPending].lwr = x.l_start + x.l_len;
+ aPending[nPending].upr = upr;
+ nPending++;
+ }
}
+ free(aPending);
return cnt;
}
diff --git a/tool/spaceanal.tcl b/tool/spaceanal.tcl
index 3b33f8868..e026a90ef 100644
--- a/tool/spaceanal.tcl
+++ b/tool/spaceanal.tcl
@@ -16,7 +16,7 @@ proc is_without_rowid {tname} {
db eval "PRAGMA index_list = '$t'" o {
if {$o(origin) == "pk"} {
set n $o(name)
- if {0==[db one { SELECT count(*) FROM sqlite_master WHERE name=$n }]} {
+ if {0==[db one { SELECT count(*) FROM sqlite_schema WHERE name=$n }]} {
return 1
}
}
@@ -160,7 +160,7 @@ if {![db exists {SELECT 1 FROM pragma_compile_options
exit 1
}
-db eval {SELECT count(*) FROM sqlite_master}
+db eval {SELECT count(*) FROM sqlite_schema}
set pageSize [expr {wide([db one {PRAGMA page_size}])}]
if {$flags(-pageinfo)} {
@@ -245,8 +245,8 @@ db eval {DROP TABLE temp.stat}
set isCompressed 0
set compressOverhead 0
set depth 0
-set sql { SELECT name, tbl_name FROM sqlite_master WHERE rootpage>0 }
-foreach {name tblname} [concat sqlite_master sqlite_master [db eval $sql]] {
+set sql { SELECT name, tbl_name FROM sqlite_schema WHERE rootpage>0 }
+foreach {name tblname} [concat sqlite_schema sqlite_schema [db eval $sql]] {
set is_index [expr {$name!=$tblname}]
set is_without_rowid [is_without_rowid $name]
@@ -560,7 +560,7 @@ proc autovacuum_overhead {filePages pageSize} {
# nautoindex: Number of indices created automatically.
# nmanindex: Number of indices created manually.
# user_payload: Number of bytes of payload in table btrees
-# (not including sqlite_master)
+# (not including sqlite_schema)
# user_percent: $user_payload as a percentage of total file size.
### The following, setting $file_bytes based on the actual size of the file
@@ -590,15 +590,15 @@ set file_pgcnt2 [expr {$inuse_pgcnt+$free_pgcnt2+$av_pgcnt}]
# Account for the lockbyte page
if {$file_pgcnt2*$pageSize>1073742335} {incr file_pgcnt2}
-set ntable [db eval {SELECT count(*)+1 FROM sqlite_master WHERE type='table'}]
-set nindex [db eval {SELECT count(*) FROM sqlite_master WHERE type='index'}]
-set sql {SELECT count(*) FROM sqlite_master WHERE name LIKE 'sqlite_autoindex%'}
+set ntable [db eval {SELECT count(*)+1 FROM sqlite_schema WHERE type='table'}]
+set nindex [db eval {SELECT count(*) FROM sqlite_schema WHERE type='index'}]
+set sql {SELECT count(*) FROM sqlite_schema WHERE name LIKE 'sqlite_autoindex%'}
set nautoindex [db eval $sql]
set nmanindex [expr {$nindex-$nautoindex}]
# set total_payload [mem eval "SELECT sum(payload) FROM space_used"]
set user_payload [mem one {SELECT int(sum(payload)) FROM space_used
- WHERE NOT is_index AND name NOT LIKE 'sqlite_master'}]
+ WHERE NOT is_index AND name NOT LIKE 'sqlite_schema'}]
set user_percent [percent $user_payload $file_bytes]
# Output the summary statistics calculated above.
diff --git a/tool/speed-check.sh b/tool/speed-check.sh
index 414e4b448..1be7c9e5d 100644
--- a/tool/speed-check.sh
+++ b/tool/speed-check.sh
@@ -79,6 +79,10 @@ while test "$1" != ""; do
;;
--legacy)
doWal=0
+ CC_OPTS="$CC_OPTS -DSPEEDTEST_OMIT_HASH"
+ ;;
+ --verify)
+ SPEEDTEST_OPTS="$SPEEDTEST_OPTS --verify"
;;
--wal)
doWal=1
diff --git a/tool/sqldiff.c b/tool/sqldiff.c
index 9f5b6fe6d..3590e2c06 100644
--- a/tool/sqldiff.c
+++ b/tool/sqldiff.c
@@ -416,7 +416,7 @@ static void dump_table(const char *zTab, FILE *out){
const char *zSep; /* Separator string */
Str ins; /* Beginning of the INSERT statement */
- pStmt = db_prepare("SELECT sql FROM aux.sqlite_master WHERE name=%Q", zTab);
+ pStmt = db_prepare("SELECT sql FROM aux.sqlite_schema WHERE name=%Q", zTab);
if( SQLITE_ROW==sqlite3_step(pStmt) ){
fprintf(out, "%s;\n", sqlite3_column_text(pStmt,0));
}
@@ -466,7 +466,7 @@ static void dump_table(const char *zTab, FILE *out){
sqlite3_finalize(pStmt);
strFree(&ins);
} /* endif !g.bSchemaOnly */
- pStmt = db_prepare("SELECT sql FROM aux.sqlite_master"
+ pStmt = db_prepare("SELECT sql FROM aux.sqlite_schema"
" WHERE type='index' AND tbl_name=%Q AND sql IS NOT NULL",
zTab);
while( SQLITE_ROW==sqlite3_step(pStmt) ){
@@ -639,10 +639,10 @@ static void diff_one_table(const char *zTab, FILE *out){
/* Drop indexes that are missing in the destination */
pStmt = db_prepare(
- "SELECT name FROM main.sqlite_master"
+ "SELECT name FROM main.sqlite_schema"
" WHERE type='index' AND tbl_name=%Q"
" AND sql IS NOT NULL"
- " AND sql NOT IN (SELECT sql FROM aux.sqlite_master"
+ " AND sql NOT IN (SELECT sql FROM aux.sqlite_schema"
" WHERE type='index' AND tbl_name=%Q"
" AND sql IS NOT NULL)",
zTab, zTab);
@@ -700,10 +700,10 @@ static void diff_one_table(const char *zTab, FILE *out){
/* Create indexes that are missing in the source */
pStmt = db_prepare(
- "SELECT sql FROM aux.sqlite_master"
+ "SELECT sql FROM aux.sqlite_schema"
" WHERE type='index' AND tbl_name=%Q"
" AND sql IS NOT NULL"
- " AND sql NOT IN (SELECT sql FROM main.sqlite_master"
+ " AND sql NOT IN (SELECT sql FROM main.sqlite_schema"
" WHERE type='index' AND tbl_name=%Q"
" AND sql IS NOT NULL)",
zTab, zTab);
@@ -728,7 +728,7 @@ end_diff_one_table:
*/
static void checkSchemasMatch(const char *zTab){
sqlite3_stmt *pStmt = db_prepare(
- "SELECT A.sql=B.sql FROM main.sqlite_master A, aux.sqlite_master B"
+ "SELECT A.sql=B.sql FROM main.sqlite_schema A, aux.sqlite_schema B"
" WHERE A.name=%Q AND B.name=%Q", zTab, zTab
);
if( SQLITE_ROW==sqlite3_step(pStmt) ){
@@ -1757,7 +1757,7 @@ const char *gobble_token(const char *zIn, char *zBuf, int nBuf){
** module_name(SQL)
**
** The only argument should be an SQL statement of the type that may appear
-** in the sqlite_master table. If the statement is a "CREATE VIRTUAL TABLE"
+** in the sqlite_schema table. If the statement is a "CREATE VIRTUAL TABLE"
** statement, then the value returned is the name of the module that it
** uses. Otherwise, if the statement is not a CVT, NULL is returned.
*/
@@ -1816,32 +1816,32 @@ const char *all_tables_sql(){
assert( rc==SQLITE_OK );
return
- "SELECT name FROM main.sqlite_master\n"
+ "SELECT name FROM main.sqlite_schema\n"
" WHERE type='table' AND (\n"
" module_name(sql) IS NULL OR \n"
" module_name(sql) IN (SELECT module FROM temp.tblmap)\n"
" ) AND name NOT IN (\n"
" SELECT a.name || b.postfix \n"
- "FROM main.sqlite_master AS a, temp.tblmap AS b \n"
+ "FROM main.sqlite_schema AS a, temp.tblmap AS b \n"
"WHERE module_name(a.sql) = b.module\n"
" )\n"
"UNION \n"
- "SELECT name FROM aux.sqlite_master\n"
+ "SELECT name FROM aux.sqlite_schema\n"
" WHERE type='table' AND (\n"
" module_name(sql) IS NULL OR \n"
" module_name(sql) IN (SELECT module FROM temp.tblmap)\n"
" ) AND name NOT IN (\n"
" SELECT a.name || b.postfix \n"
- "FROM aux.sqlite_master AS a, temp.tblmap AS b \n"
+ "FROM aux.sqlite_schema AS a, temp.tblmap AS b \n"
"WHERE module_name(a.sql) = b.module\n"
" )\n"
" ORDER BY name";
}else{
return
- "SELECT name FROM main.sqlite_master\n"
+ "SELECT name FROM main.sqlite_schema\n"
" WHERE type='table' AND sql NOT LIKE 'CREATE VIRTUAL%%'\n"
" UNION\n"
- "SELECT name FROM aux.sqlite_master\n"
+ "SELECT name FROM aux.sqlite_schema\n"
" WHERE type='table' AND sql NOT LIKE 'CREATE VIRTUAL%%'\n"
" ORDER BY name";
}
@@ -1955,7 +1955,7 @@ int main(int argc, char **argv){
if( rc ){
cmdlineError("cannot open database file \"%s\"", zDb1);
}
- rc = sqlite3_exec(g.db, "SELECT * FROM sqlite_master", 0, 0, &zErrMsg);
+ rc = sqlite3_exec(g.db, "SELECT * FROM sqlite_schema", 0, 0, &zErrMsg);
if( rc || zErrMsg ){
cmdlineError("\"%s\" does not appear to be a valid SQLite database", zDb1);
}
@@ -1974,7 +1974,7 @@ int main(int argc, char **argv){
if( rc || zErrMsg ){
cmdlineError("cannot attach database \"%s\"", zDb2);
}
- rc = sqlite3_exec(g.db, "SELECT * FROM aux.sqlite_master", 0, 0, &zErrMsg);
+ rc = sqlite3_exec(g.db, "SELECT * FROM aux.sqlite_schema", 0, 0, &zErrMsg);
if( rc || zErrMsg ){
cmdlineError("\"%s\" does not appear to be a valid SQLite database", zDb2);
}
diff --git a/vsixtest/App.xaml.cpp b/vsixtest/App.xaml.cpp
index da8f327fa..c90604a83 100644
--- a/vsixtest/App.xaml.cpp
+++ b/vsixtest/App.xaml.cpp
@@ -117,4 +117,4 @@ void App::OnSuspending(Object^ sender, SuspendingEventArgs^ e)
void App::OnNavigationFailed(Platform::Object ^sender, Windows::UI::Xaml::Navigation::NavigationFailedEventArgs ^e)
{
throw ref new FailureException("Failed to load Page " + e->SourcePageType.Name);
-} \ No newline at end of file
+}