diff --git a/Makefile.in b/Makefile.in
index a63052c86c..ba9ea19f3e 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -1053,7 +1053,7 @@ parse.h: parse.c
parse.c: $(TOP)/src/parse.y lemon$(BEXE)
cp $(TOP)/src/parse.y .
- ./lemon$(BEXE) $(OPT_FEATURE_FLAGS) $(OPTS) parse.y
+ ./lemon$(BEXE) $(OPT_FEATURE_FLAGS) $(OPTS) -S parse.y
sqlite3.h: $(TOP)/src/sqlite.h.in $(TOP)/manifest mksourceid$(BEXE) $(TOP)/VERSION
$(TCLSH_CMD) $(TOP)/tool/mksqlite3h.tcl $(TOP) >sqlite3.h
@@ -1178,10 +1178,10 @@ FTS5_SRC = \
$(TOP)/ext/fts5/fts5_varint.c \
$(TOP)/ext/fts5/fts5_vocab.c \
-fts5parse.c: $(TOP)/ext/fts5/fts5parse.y lemon
+fts5parse.c: $(TOP)/ext/fts5/fts5parse.y lemon$(BEXE)
cp $(TOP)/ext/fts5/fts5parse.y .
rm -f fts5parse.h
- ./lemon$(BEXE) $(OPTS) fts5parse.y
+ ./lemon$(BEXE) $(OPTS) -S fts5parse.y
fts5parse.h: fts5parse.c
@@ -1243,10 +1243,6 @@ fuzztest: fuzzcheck$(TEXE) $(FUZZDATA) sessionfuzz$(TEXE) $(TOP)/test/sessionfuz
./fuzzcheck$(TEXE) $(FUZZDATA)
./sessionfuzz$(TEXE) run $(TOP)/test/sessionfuzz-data1.db
-fastfuzztest: fuzzcheck$(TEXE) $(FUZZDATA) sessionfuzz$(TEXE) $(TOP)/test/sessionfuzz-data1.db
- ./fuzzcheck$(TEXE) --limit-mem 100M $(FUZZDATA)
- ./sessionfuzz$(TEXE) run $(TOP)/test/sessionfuzz-data1.db
-
valgrindfuzz: fuzzcheck$(TEXT) $(FUZZDATA) sessionfuzz$(TEXE) $(TOP)/test/sessionfuzz-data1.db
valgrind ./fuzzcheck$(TEXE) --cell-size-check --limit-mem 10M --timeout 600 $(FUZZDATA)
valgrind ./sessionfuzz$(TEXE) run $(TOP)/test/sessionfuzz-data1.db
@@ -1264,7 +1260,7 @@ quicktest: ./testfixture$(TEXE)
# This is the common case. Run many tests that do not take too long,
# including fuzzcheck, sqlite3_analyzer, and sqldiff tests.
#
-test: fastfuzztest sourcetest $(TESTPROGS) tcltest
+test: fuzztest sourcetest $(TESTPROGS) tcltest
# Run a test using valgrind. This can take a really long time
# because valgrind is so much slower than a native machine.
diff --git a/Makefile.msc b/Makefile.msc
index 9fb776b5ce..7de25e463d 100644
--- a/Makefile.msc
+++ b/Makefile.msc
@@ -248,6 +248,12 @@ OPTIMIZATIONS = 2
SESSION = 0
!ENDIF
+# Set this to non-0 to enable support for the rbu extension.
+#
+!IFNDEF RBU
+RBU = 0
+!ENDIF
+
# Set the source code file to be used by executables and libraries when
# they need the amalgamation.
#
@@ -364,6 +370,13 @@ OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_SESSION=1
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_PREUPDATE_HOOK=1
!ENDIF
+# Should the rbu extension be enabled? If so, add compilation options
+# to enable it.
+#
+!IF $(RBU)!=0
+OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_RBU=1
+!ENDIF
+
# These are the "extended" SQLite compilation options used when compiling for
# the Windows 10 platform.
#
@@ -1743,7 +1756,7 @@ $(SQLITE3DLL): $(LIBOBJ) $(LIBRESOBJS) $(CORE_LINK_DEP)
sqlite3.def: libsqlite3.lib
echo EXPORTS > sqlite3.def
dumpbin /all libsqlite3.lib \
- | $(TCLSH_CMD) $(TOP)\tool\replace.tcl include "^\s+1 _?(sqlite3(?:session|changeset|changegroup|rebaser)?_[^@]*)(?:@\d+)?$$" \1 \
+ | $(TCLSH_CMD) $(TOP)\tool\replace.tcl include "^\s+1 _?(sqlite3(?:session|changeset|changegroup|rebaser|rbu)?_[^@]*)(?:@\d+)?$$" \1 \
| sort >> sqlite3.def
# <>
@@ -2142,7 +2155,7 @@ 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 .
- .\lemon.exe $(REQ_FEATURE_FLAGS) $(OPT_FEATURE_FLAGS) $(EXT_FEATURE_FLAGS) $(OPTS) 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
$(TCLSH_CMD) $(TOP)\tool\mksqlite3h.tcl $(TOP:\=/) > $(SQLITE3H) $(MKSQLITE3H_ARGS)
@@ -2302,7 +2315,7 @@ LSM1_SRC = \
fts5parse.c: $(TOP)\ext\fts5\fts5parse.y lemon.exe
copy $(TOP)\ext\fts5\fts5parse.y .
del /Q fts5parse.h 2>NUL
- .\lemon.exe $(REQ_FEATURE_FLAGS) $(OPT_FEATURE_FLAGS) $(EXT_FEATURE_FLAGS) $(OPTS) fts5parse.y
+ .\lemon.exe $(REQ_FEATURE_FLAGS) $(OPT_FEATURE_FLAGS) $(EXT_FEATURE_FLAGS) $(OPTS) -S fts5parse.y
fts5parse.h: fts5parse.c
@@ -2405,9 +2418,6 @@ queryplantest: testfixture.exe shell
fuzztest: fuzzcheck.exe
.\fuzzcheck.exe $(FUZZDATA)
-fastfuzztest: fuzzcheck.exe
- .\fuzzcheck.exe --limit-mem 100M $(FUZZDATA)
-
# Minimal testing that runs in less than 3 minutes (on a fast machine)
#
quicktest: testfixture.exe sourcetest
@@ -2417,7 +2427,7 @@ quicktest: testfixture.exe sourcetest
# This is the common case. Run many tests that do not take too long,
# including fuzzcheck, sqlite3_analyzer, and sqldiff tests.
#
-test: $(TESTPROGS) sourcetest fastfuzztest
+test: $(TESTPROGS) sourcetest fuzztest
@set PATH=$(LIBTCLPATH);$(PATH)
.\testfixture.exe $(TOP)\test\veryquick.test $(TESTOPTS)
diff --git a/VERSION b/VERSION
index 1cfe511a3e..d9351e5882 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-3.30.0
+3.31.0
diff --git a/autoconf/Makefile.msc b/autoconf/Makefile.msc
index 2a7042efb0..37a3c1b18a 100644
--- a/autoconf/Makefile.msc
+++ b/autoconf/Makefile.msc
@@ -210,6 +210,12 @@ OPTIMIZATIONS = 2
SESSION = 0
!ENDIF
+# Set this to non-0 to enable support for the rbu extension.
+#
+!IFNDEF RBU
+RBU = 0
+!ENDIF
+
# Set the source code file to be used by executables and libraries when
# they need the amalgamation.
#
@@ -282,7 +288,6 @@ 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_INTROSPECTION_PRAGMAS=1
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_DESERIALIZE=1
!ENDIF
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_COLUMN_METADATA=1
@@ -296,6 +301,13 @@ OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_SESSION=1
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_PREUPDATE_HOOK=1
!ENDIF
+# Should the rbu extension be enabled? If so, add compilation options
+# to enable it.
+#
+!IF $(RBU)!=0
+OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_RBU=1
+!ENDIF
+
# These are the "extended" SQLite compilation options used when compiling for
# the Windows 10 platform.
#
@@ -978,7 +990,7 @@ Replace.exe:
sqlite3.def: Replace.exe $(LIBOBJ)
echo EXPORTS > sqlite3.def
dumpbin /all $(LIBOBJ) \
- | .\Replace.exe "^\s+/EXPORT:_?(sqlite3(?:session|changeset|changegroup|rebaser)?_[^@,]*)(?:@\d+|,DATA)?$$" $$1 true \
+ | .\Replace.exe "^\s+/EXPORT:_?(sqlite3(?:session|changeset|changegroup|rebaser|rbu)?_[^@,]*)(?:@\d+|,DATA)?$$" $$1 true \
| sort >> sqlite3.def
$(SQLITE3EXE): shell.c $(SHELL_CORE_DEP) $(LIBRESOBJS) $(SHELL_CORE_SRC) $(SQLITE3H)
diff --git a/autoconf/configure.ac b/autoconf/configure.ac
index 82ab43dfa8..167626d59e 100644
--- a/autoconf/configure.ac
+++ b/autoconf/configure.ac
@@ -161,7 +161,7 @@ AC_ARG_ENABLE(rtree, [AS_HELP_STRING(
[--enable-rtree], [include rtree support [default=yes]])],
[], [enable_rtree=yes])
if test x"$enable_rtree" = "xyes"; then
- BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_ENABLE_RTREE"
+ BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_ENABLE_RTREE -DSQLITE_ENABLE_GEOPOLY"
fi
#-----------------------------------------------------------------------
diff --git a/configure b/configure
index d2806c20c4..1d1a5d2423 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.30.0.
+# Generated by GNU Autoconf 2.69 for sqlite 3.31.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.30.0'
-PACKAGE_STRING='sqlite 3.30.0'
+PACKAGE_VERSION='3.31.0'
+PACKAGE_STRING='sqlite 3.31.0'
PACKAGE_BUGREPORT=''
PACKAGE_URL=''
@@ -906,6 +906,7 @@ enable_amalgamation
enable_load_extension
enable_memsys5
enable_memsys3
+enable_all
enable_fts3
enable_fts4
enable_fts5
@@ -1466,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.30.0 to adapt to many kinds of systems.
+\`configure' configures sqlite 3.31.0 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1531,7 +1532,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
- short | recursive ) echo "Configuration of sqlite 3.30.0:";;
+ short | recursive ) echo "Configuration of sqlite 3.31.0:";;
esac
cat <<\_ACEOF
@@ -1559,6 +1560,7 @@ Optional Features:
Disable loading of external extensions
--enable-memsys5 Enable MEMSYS5
--enable-memsys3 Enable MEMSYS3
+ --enable-all Enable FTS4, FTS5, Geopoly, JSON, RTree, Sessions
--enable-fts3 Enable the FTS3 extension
--enable-fts4 Enable the FTS4 extension
--enable-fts5 Enable the FTS5 extension
@@ -1657,7 +1659,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
-sqlite configure 3.30.0
+sqlite configure 3.31.0
generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc.
@@ -2076,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.30.0, which was
+It was created by sqlite $as_me 3.31.0, which was
generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@
@@ -3934,13 +3936,13 @@ if ${lt_cv_nm_interface+:} false; then :
else
lt_cv_nm_interface="BSD nm"
echo "int some_variable = 0;" > conftest.$ac_ext
- (eval echo "\"\$as_me:3937: $ac_compile\"" >&5)
+ (eval echo "\"\$as_me:3939: $ac_compile\"" >&5)
(eval "$ac_compile" 2>conftest.err)
cat conftest.err >&5
- (eval echo "\"\$as_me:3940: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
+ (eval echo "\"\$as_me:3942: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
(eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
cat conftest.err >&5
- (eval echo "\"\$as_me:3943: output\"" >&5)
+ (eval echo "\"\$as_me:3945: output\"" >&5)
cat conftest.out >&5
if $GREP 'External.*some_variable' conftest.out > /dev/null; then
lt_cv_nm_interface="MS dumpbin"
@@ -5146,7 +5148,7 @@ ia64-*-hpux*)
;;
*-*-irix6*)
# Find out which ABI we are using.
- echo '#line 5149 "configure"' > conftest.$ac_ext
+ echo '#line 5151 "configure"' > conftest.$ac_ext
if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
(eval $ac_compile) 2>&5
ac_status=$?
@@ -6671,11 +6673,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:6674: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:6676: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
- echo "$as_me:6678: \$? = $ac_status" >&5
+ echo "$as_me:6680: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output.
@@ -7010,11 +7012,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:7013: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:7015: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
- echo "$as_me:7017: \$? = $ac_status" >&5
+ echo "$as_me:7019: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output.
@@ -7115,11 +7117,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:7118: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:7120: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
- echo "$as_me:7122: \$? = $ac_status" >&5
+ echo "$as_me:7124: \$? = $ac_status" >&5
if (exit $ac_status) && test -s out/conftest2.$ac_objext
then
# The compiler can only warn and ignore the option if not recognized
@@ -7170,11 +7172,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:7173: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:7175: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
- echo "$as_me:7177: \$? = $ac_status" >&5
+ echo "$as_me:7179: \$? = $ac_status" >&5
if (exit $ac_status) && test -s out/conftest2.$ac_objext
then
# The compiler can only warn and ignore the option if not recognized
@@ -9550,7 +9552,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
-#line 9553 "configure"
+#line 9555 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -9646,7 +9648,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
-#line 9649 "configure"
+#line 9651 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -11450,6 +11452,15 @@ else
$as_echo "no" >&6; }
fi
+########
+# The --enable-extensions argument is short-hand to enable
+# multiple extensions.
+# Check whether --enable-all was given.
+if test "${enable_all+set}" = set; then :
+ enableval=$enable_all;
+fi
+
+
#########
# See whether we should enable Full Text Search extensions
# Check whether --enable-fts3 was given.
@@ -11465,7 +11476,7 @@ if test "${enable_fts4+set}" = set; then :
enableval=$enable_fts4;
fi
-if test "${enable_fts4}" = "yes" ; then
+if test "${enable_fts4}" = "yes" -o "${enable_all}" = "yes" ; then
OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_FTS4"
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing log" >&5
$as_echo_n "checking for library containing log... " >&6; }
@@ -11529,7 +11540,7 @@ if test "${enable_fts5+set}" = set; then :
enableval=$enable_fts5;
fi
-if test "${enable_fts5}" = "yes" ; then
+if test "${enable_fts5}" = "yes" -o "${enable_all}" = "yes" ; then
OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_FTS5"
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing log" >&5
$as_echo_n "checking for library containing log... " >&6; }
@@ -11596,7 +11607,7 @@ if test "${enable_json1+set}" = set; then :
enableval=$enable_json1;
fi
-if test "${enable_json1}" = "yes" ; then
+if test "${enable_json1}" = "yes" -o "${enable_all}" = "yes" ; then
OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_JSON1"
fi
@@ -11621,7 +11632,7 @@ else
enable_geopoly=no
fi
-if test "${enable_geopoly}" = "yes" ; then
+if test "${enable_geopoly}" = "yes" -o "${enable_all}" = "yes" ; then
OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_GEOPOLY"
enable_rtree=yes
fi
@@ -11644,7 +11655,7 @@ if test "${enable_session+set}" = set; then :
enableval=$enable_session;
fi
-if test "${enable_session}" = "yes" ; then
+if test "${enable_session}" = "yes" -o "${enable_all}" = "yes" ; then
OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_SESSION"
OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_PREUPDATE_HOOK"
fi
@@ -12232,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.30.0, which was
+This file was extended by sqlite $as_me 3.31.0, which was
generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -12298,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.30.0
+sqlite config.status 3.31.0
configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\"
diff --git a/configure.ac b/configure.ac
index 9cf87adcad..ef70a4f0d1 100644
--- a/configure.ac
+++ b/configure.ac
@@ -613,6 +613,12 @@ else
AC_MSG_RESULT([no])
fi
+########
+# The --enable-extensions argument is short-hand to enable
+# multiple extensions.
+AC_ARG_ENABLE(all, AC_HELP_STRING([--enable-all],
+ [Enable FTS4, FTS5, Geopoly, JSON, RTree, Sessions]))
+
#########
# See whether we should enable Full Text Search extensions
AC_ARG_ENABLE(fts3, AC_HELP_STRING([--enable-fts3],
@@ -622,13 +628,13 @@ if test "${enable_fts3}" = "yes" ; then
fi
AC_ARG_ENABLE(fts4, AC_HELP_STRING([--enable-fts4],
[Enable the FTS4 extension]))
-if test "${enable_fts4}" = "yes" ; then
+if test "${enable_fts4}" = "yes" -o "${enable_all}" = "yes" ; then
OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_FTS4"
AC_SEARCH_LIBS([log],[m])
fi
AC_ARG_ENABLE(fts5, AC_HELP_STRING([--enable-fts5],
[Enable the FTS5 extension]))
-if test "${enable_fts5}" = "yes" ; then
+if test "${enable_fts5}" = "yes" -o "${enable_all}" = "yes" ; then
OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_FTS5"
AC_SEARCH_LIBS([log],[m])
fi
@@ -636,7 +642,7 @@ fi
#########
# See whether we should enable JSON1
AC_ARG_ENABLE(json1, AC_HELP_STRING([--enable-json1],[Enable the JSON1 extension]))
-if test "${enable_json1}" = "yes" ; then
+if test "${enable_json1}" = "yes" -o "${enable_all}" = "yes" ; then
OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_JSON1"
fi
@@ -654,7 +660,7 @@ fi
AC_ARG_ENABLE(geopoly, AC_HELP_STRING([--enable-geopoly],
[Enable the GEOPOLY extension]),
[enable_geopoly=yes],[enable_geopoly=no])
-if test "${enable_geopoly}" = "yes" ; then
+if test "${enable_geopoly}" = "yes" -o "${enable_all}" = "yes" ; then
OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_GEOPOLY"
enable_rtree=yes
fi
@@ -671,7 +677,7 @@ fi
# See whether we should enable the SESSION extension
AC_ARG_ENABLE(session, AC_HELP_STRING([--enable-session],
[Enable the SESSION extension]))
-if test "${enable_session}" = "yes" ; then
+if test "${enable_session}" = "yes" -o "${enable_all}" = "yes" ; then
OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_SESSION"
OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_PREUPDATE_HOOK"
fi
diff --git a/doc/trusted-schema.md b/doc/trusted-schema.md
new file mode 100644
index 0000000000..d431fd49a3
--- /dev/null
+++ b/doc/trusted-schema.md
@@ -0,0 +1,142 @@
+# The new-security-options branch
+
+## The problem that the [new-security-options](/timeline?r=new-security-options) branch tries to solve
+
+An attacker might modify the schema of an SQLite database by adding
+structures that cause code to run when some other application opens and
+reads the database. For example, the attacker might replace a table
+definition with a view. Or the attacker might add triggers to tables
+or views, or add new CHECK constraints or generated columns or indexes
+with expressions in the index list or in the WHERE clause. If the
+added features invoke SQL functions or virtual tables with side effects,
+that might cause harm to the system if run by a high-privilege victim.
+Or, the added features might exfiltrate information if the database is
+read by a high-privilege victim.
+
+The changes in this branch strive to make it easier for high-privilege
+applications to safely read SQLite database files that might have been
+maliciously corrupted by an attacker.
+
+## Overview of changes in [new-security-options](/timeline?r=new-security-options)
+
+The basic idea is to tag every SQL function and virtual table with one
+of three risk levels:
+
+ 1. Innocuous
+ 2. Normal
+ 3. Direct-Only
+
+Innocuous functions/vtabs are safe and can be used at any time.
+Direct-only elements, in contrast, might have cause side-effects and
+should only be used from top-level SQL, not from within triggers or views nor
+in elements of the schema such as CHECK constraint, DEFAULT values,
+generated columns, index expressions, or in the WHERE clause of a
+partial index that are potentially under the control of an attacker.
+Normal elements behave like Innocuous if TRUSTED\_SCHEMA=on
+and behave like direct-only if TRUSTED\_SCHEMA=off.
+
+Application-defined functions and virtual tables go in as Normal unless
+the application takes deliberate steps to change the risk level.
+
+For backwards compatibility, the default is TRUSTED\_SCHEMA=on. Documentation
+will be updated to recommend applications turn TRUSTED\_SCHEMA to off.
+
+An innocuous function or virtual table is one that can only read content
+from the database file in which it resides, and can only alter the database
+in which it resides. Most SQL functions are innocuous. For example, there
+is no harm in an attacker running the abs() function.
+
+Direct-only elements that have side-effects that go outside the database file
+in which it lives, or return information from outside of the database file.
+Examples of direct-only elements include:
+
+ 1. The fts3\_tokenizer() function
+ 2. The writefile() function
+ 3. The readfile() function
+ 4. The zipvfs virtual table
+ 5. The csv virtual table
+
+We do not want an attacker to be able to add these kinds of things to
+the database schema and possibly trick a high-privilege application
+from performing any of these actions. Therefore, functions and vtabs
+with side-effects are marked as Direct-Only.
+
+Legacy applications might add other risky functions or vtabs. Those will
+go in as "Normal" by default. For optimal security, we want those risky
+app-defined functions and vtabs to be direct-only, but making that the
+default might break some legacy applications. Hence, all app-defined
+functions and vtabs go in as Normal, but the application can switch them
+over to "Direct-Only" behavior using a single pragma.
+
+The restrictions on the use of functions and virtual tables do not apply
+to TEMP. A TEMP VIEW or a TEMP TRIGGER can use any valid SQL function
+or virtual table. The idea is that TEMP views and triggers must be
+directly created by the application and are thus under the control of the
+application. TEMP views and triggers cannot be created by an attacker who
+corrupts the schema of a persistent database file. Hence TEMP views and
+triggers are safe.
+
+## Specific changes
+
+ 1. New sqlite3\_db\_config() option SQLITE\_DBCONFIG\_TRUSTED\_SCHEMA for
+ turning TRUSTED\_SCHEMA on and off. It defaults to ON.
+
+ 2. Compile-time option -DSQLITE\_TRUSTED\_SCHEMA=0 causes the default
+ TRUSTED\_SCHEMA setting to be off.
+
+ 3. New pragma "PRAGMA trusted\_schema=(ON\|OFF);". This provides access
+ to the TRUSTED_SCHEMA setting for application coded using scripting
+ languages or other secondary languages where they are unable to make
+ calls to sqlite3\_db\_config().
+
+ 4. New options for the "enc" parameter to sqlite3\_create\_function() and
+ its kin:
+
+ - _SQLITE\_INNOCUOUS_ → tags the new functions as Innocuous
+
- _SQLITE\_DIRECTONLY_ → tags the new functions as Direct-Only
+
+
+ 5. New options to sqlite3\_vtab\_config():
+
+ - _SQLITE\_VTAB\_INNOCUOUS_ → tags the vtab as Innocuous
+
- _SQLITE\_VTAB\_DIRECTONLY_ → tags the vtab as Direct-Only
+
+
+ 6. Change many of the functions and virtual tables in the SQLite source
+ tree to use one of the tags above.
+
+ 7. Enhanced PRAGMA function\_list and virtual-table "pragma\_function\_list"
+ with additional columns. The columns now are:
+
+ - _name_ → Name of the function
+
- _builtin_ → 1 for built-in functions. 0 otherwise.
+
- _type_ → 's'=Scalar, 'a'=Aggregate, 'w'=Window
+
- _enc_ → 'utf8', 'utf16le', or 'utf16be'
+
- _narg_ → number of argument
+
- _flags_ → Bitmask of SQLITE\_INNOCUOUS, SQLITE\_DIRECTONLY,
+ SQLITE\_DETERMINISTIC, SQLITE\_SUBTYPE, and
+ SQLITE\_FUNC\_INTERNAL flags.
+
+ The last four columns are new.
+
+ 8. The function\_list PRAGMA now also shows all entries for each function.
+ So, for example, if a function can take either 2 or 3 arguments,
+ there are separate rows for the 2-argument and 3-argument versions of
+ the function.
+
+## Additional Notes
+
+The function_list enhancements allow the application to query the set
+of SQL functions that meet various criteria. For example, to see all
+SQL functions that are never allowed to be used in the schema or in
+trigger or views:
+
+~~~
+ SELECT DISTINCT name FROM pragma_function_list
+ WHERE (flags & 0x80000)!=0
+ ORDER BY name;
+~~~
+
+Doing the same is not possible for virtual tables, as a virtual table
+might be Innocuous, Normal, or Direct-Only depending on the arguments
+passed into the xConnect method.
diff --git a/ext/expert/sqlite3expert.h b/ext/expert/sqlite3expert.h
index 39135dc274..6048137237 100644
--- a/ext/expert/sqlite3expert.h
+++ b/ext/expert/sqlite3expert.h
@@ -10,8 +10,8 @@
**
*************************************************************************
*/
-
-
+#if !defined(SQLITEEXPERT_H)
+#define SQLITEEXPERT_H 1
#include "sqlite3.h"
typedef struct sqlite3expert sqlite3expert;
@@ -165,4 +165,4 @@ const char *sqlite3_expert_report(sqlite3expert*, int iStmt, int eReport);
*/
void sqlite3_expert_destroy(sqlite3expert*);
-
+#endif /* !defined(SQLITEEXPERT_H) */
diff --git a/ext/fts3/fts3.c b/ext/fts3/fts3.c
index 2e19d6889f..77738eb543 100644
--- a/ext/fts3/fts3.c
+++ b/ext/fts3/fts3.c
@@ -308,18 +308,6 @@
SQLITE_EXTENSION_INIT1
#endif
-/*
-** The following are copied from sqliteInt.h.
-**
-** Constants for the largest and smallest possible 64-bit signed integers.
-** These macros are designed to work correctly on both 32-bit and 64-bit
-** compilers.
-*/
-#ifndef SQLITE_AMALGAMATION
-# define LARGEST_INT64 (0xffffffff|(((sqlite3_int64)0x7fffffff)<<32))
-# define SMALLEST_INT64 (((sqlite3_int64)-1) - LARGEST_INT64)
-#endif
-
static int fts3EvalNext(Fts3Cursor *pCsr);
static int fts3EvalStart(Fts3Cursor *pCsr);
static int fts3TermSegReaderCursor(
@@ -364,12 +352,7 @@ int sqlite3Fts3PutVarint(char *p, sqlite_int64 v){
v = (*ptr++); \
if( (v & mask2)==0 ){ var = v; return ret; }
-/*
-** Read a 64-bit variable-length integer from memory starting at p[0].
-** Return the number of bytes read, or 0 on error.
-** The value is stored in *v.
-*/
-int sqlite3Fts3GetVarint(const char *pBuf, sqlite_int64 *v){
+int sqlite3Fts3GetVarintU(const char *pBuf, sqlite_uint64 *v){
const unsigned char *p = (const unsigned char*)pBuf;
const unsigned char *pStart = p;
u32 a;
@@ -391,6 +374,41 @@ int sqlite3Fts3GetVarint(const char *pBuf, sqlite_int64 *v){
return (int)(p - pStart);
}
+/*
+** Read a 64-bit variable-length integer from memory starting at p[0].
+** Return the number of bytes read, or 0 on error.
+** The value is stored in *v.
+*/
+int sqlite3Fts3GetVarint(const char *pBuf, sqlite_int64 *v){
+ return sqlite3Fts3GetVarintU(pBuf, (sqlite3_uint64*)v);
+}
+
+/*
+** Read a 64-bit variable-length integer from memory starting at p[0] and
+** not extending past pEnd[-1].
+** Return the number of bytes read, or 0 on error.
+** The value is stored in *v.
+*/
+int sqlite3Fts3GetVarintBounded(
+ const char *pBuf,
+ const char *pEnd,
+ sqlite_int64 *v
+){
+ const unsigned char *p = (const unsigned char*)pBuf;
+ const unsigned char *pStart = p;
+ const unsigned char *pX = (const unsigned char*)pEnd;
+ u64 b = 0;
+ int shift;
+ for(shift=0; shift<=63; shift+=7){
+ u64 c = pnNodeSize = p->nPgsz-35;
+#if defined(SQLITE_DEBUG)||defined(SQLITE_TEST)
+ p->nMergeCount = FTS3_MERGE_COUNT;
+#endif
+
/* Declare the table schema to SQLite. */
fts3DeclareVtab(&rc, p);
@@ -1581,6 +1603,10 @@ static int fts3BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
int iDocidLe = -1; /* Index of docid<=x constraint, if present */
int iIdx;
+ if( p->bLock ){
+ return SQLITE_ERROR;
+ }
+
/* By default use a full table scan. This is an expensive option,
** so search through the constraints to see if a more efficient
** strategy is possible.
@@ -1779,7 +1805,11 @@ static int fts3CursorSeekStmt(Fts3Cursor *pCsr){
}else{
zSql = sqlite3_mprintf("SELECT %s WHERE rowid = ?", p->zReadExprlist);
if( !zSql ) return SQLITE_NOMEM;
- rc = sqlite3_prepare_v3(p->db, zSql,-1,SQLITE_PREPARE_PERSISTENT,&pCsr->pStmt,0);
+ p->bLock++;
+ rc = sqlite3_prepare_v3(
+ p->db, zSql,-1,SQLITE_PREPARE_PERSISTENT,&pCsr->pStmt,0
+ );
+ p->bLock--;
sqlite3_free(zSql);
}
if( rc==SQLITE_OK ) pCsr->bSeekStmt = 1;
@@ -1797,11 +1827,15 @@ static int fts3CursorSeek(sqlite3_context *pContext, Fts3Cursor *pCsr){
if( pCsr->isRequireSeek ){
rc = fts3CursorSeekStmt(pCsr);
if( rc==SQLITE_OK ){
+ Fts3Table *pTab = (Fts3Table*)pCsr->base.pVtab;
+ pTab->bLock++;
sqlite3_bind_int64(pCsr->pStmt, 1, pCsr->iPrevId);
pCsr->isRequireSeek = 0;
if( SQLITE_ROW==sqlite3_step(pCsr->pStmt) ){
+ pTab->bLock--;
return SQLITE_OK;
}else{
+ pTab->bLock--;
rc = sqlite3_reset(pCsr->pStmt);
if( rc==SQLITE_OK && ((Fts3Table *)pCsr->base.pVtab)->zContentTbl==0 ){
/* If no row was found and no error has occurred, then the %_content
@@ -1973,7 +2007,7 @@ static int fts3SelectLeaf(
fts3GetVarint32(zNode, &iHeight);
rc = fts3ScanInteriorNode(zTerm, nTerm, zNode, nNode, piLeaf, piLeaf2);
- assert( !piLeaf2 || !piLeaf || rc!=SQLITE_OK || (*piLeaf<=*piLeaf2) );
+ assert_fts3_nc( !piLeaf2 || !piLeaf || rc!=SQLITE_OK || (*piLeaf<=*piLeaf2) );
if( rc==SQLITE_OK && iHeight>1 ){
char *zBlob = 0; /* Blob read from %_segments table */
@@ -1993,7 +2027,13 @@ static int fts3SelectLeaf(
rc = sqlite3Fts3ReadBlock(p, piLeaf?*piLeaf:*piLeaf2, &zBlob, &nBlob, 0);
}
if( rc==SQLITE_OK ){
- rc = fts3SelectLeaf(p, zTerm, nTerm, zBlob, nBlob, piLeaf, piLeaf2);
+ int iNewHeight = 0;
+ fts3GetVarint32(zBlob, &iNewHeight);
+ if( iNewHeight>=iHeight ){
+ rc = FTS_CORRUPT_VTAB;
+ }else{
+ rc = fts3SelectLeaf(p, zTerm, nTerm, zBlob, nBlob, piLeaf, piLeaf2);
+ }
}
sqlite3_free(zBlob);
}
@@ -2448,12 +2488,12 @@ static void fts3GetDeltaVarint3(
if( *pp>=pEnd ){
*pp = 0;
}else{
- sqlite3_int64 iVal;
- *pp += sqlite3Fts3GetVarint(*pp, &iVal);
+ u64 iVal;
+ *pp += sqlite3Fts3GetVarintU(*pp, &iVal);
if( bDescIdx ){
- *pVal -= iVal;
+ *pVal = (i64)((u64)*pVal - iVal);
}else{
- *pVal += iVal;
+ *pVal = (i64)((u64)*pVal + iVal);
}
}
}
@@ -2480,15 +2520,16 @@ static void fts3PutDeltaVarint3(
int *pbFirst, /* IN/OUT: True after first int written */
sqlite3_int64 iVal /* Write this value to the list */
){
- sqlite3_int64 iWrite;
+ sqlite3_uint64 iWrite;
if( bDescIdx==0 || *pbFirst==0 ){
- iWrite = iVal - *piPrev;
+ assert_fts3_nc( *pbFirst==0 || iVal>=*piPrev );
+ iWrite = (u64)iVal - (u64)*piPrev;
}else{
- iWrite = *piPrev - iVal;
+ assert_fts3_nc( *piPrev>=iVal );
+ iWrite = (u64)*piPrev - (u64)iVal;
}
assert( *pbFirst || *piPrev==0 );
assert_fts3_nc( *pbFirst==0 || iWrite>0 );
- assert( *pbFirst==0 || iWrite>=0 );
*pp += sqlite3Fts3PutVarint(*pp, iWrite);
*piPrev = iVal;
*pbFirst = 1;
@@ -2504,7 +2545,8 @@ static void fts3PutDeltaVarint3(
** Using this makes it easier to write code that can merge doclists that are
** sorted in either ascending or descending order.
*/
-#define DOCID_CMP(i1, i2) ((bDescDoclist?-1:1) * (i1-i2))
+/* #define DOCID_CMP(i1, i2) ((bDescDoclist?-1:1) * (i64)((u64)i1-i2)) */
+#define DOCID_CMP(i1, i2) ((bDescDoclist?-1:1) * (i1>i2?1:((i1==i2)?0:-1)))
/*
** This function does an "OR" merge of two doclists (output contains all
@@ -2918,7 +2960,7 @@ static int fts3SegReaderCursor(
** Fts3SegReaderPending might segfault, as the data structures used by
** fts4aux are not completely populated. So it's easiest to filter these
** calls out here. */
- if( iLevel<0 && p->aIndex ){
+ if( iLevel<0 && p->aIndex && p->iPrevLangid==iLangid ){
Fts3SegReader *pSeg = 0;
rc = sqlite3Fts3SegReaderPending(p, iIndex, zTerm, nTerm, isPrefix||isScan, &pSeg);
if( rc==SQLITE_OK && pSeg ){
@@ -3181,6 +3223,8 @@ static int fts3NextMethod(sqlite3_vtab_cursor *pCursor){
int rc;
Fts3Cursor *pCsr = (Fts3Cursor *)pCursor;
if( pCsr->eSearch==FTS3_DOCID_SEARCH || pCsr->eSearch==FTS3_FULLSCAN_SEARCH ){
+ Fts3Table *pTab = (Fts3Table*)pCursor->pVtab;
+ pTab->bLock++;
if( SQLITE_ROW!=sqlite3_step(pCsr->pStmt) ){
pCsr->isEof = 1;
rc = sqlite3_reset(pCsr->pStmt);
@@ -3188,6 +3232,7 @@ static int fts3NextMethod(sqlite3_vtab_cursor *pCursor){
pCsr->iPrevId = sqlite3_column_int64(pCsr->pStmt, 0);
rc = SQLITE_OK;
}
+ pTab->bLock--;
}else{
rc = fts3EvalNext((Fts3Cursor *)pCursor);
}
@@ -3248,6 +3293,10 @@ static int fts3FilterMethod(
UNUSED_PARAMETER(idxStr);
UNUSED_PARAMETER(nVal);
+ if( p->bLock ){
+ return SQLITE_ERROR;
+ }
+
eSearch = (idxNum & 0x0000FFFF);
assert( eSearch>=0 && eSearch<=(FTS3_FULLTEXT_SEARCH+p->nColumn) );
assert( p->pSegments==0 );
@@ -3319,7 +3368,11 @@ static int fts3FilterMethod(
);
}
if( zSql ){
- rc = sqlite3_prepare_v3(p->db,zSql,-1,SQLITE_PREPARE_PERSISTENT,&pCsr->pStmt,0);
+ p->bLock++;
+ rc = sqlite3_prepare_v3(
+ p->db,zSql,-1,SQLITE_PREPARE_PERSISTENT,&pCsr->pStmt,0
+ );
+ p->bLock--;
sqlite3_free(zSql);
}else{
rc = SQLITE_NOMEM;
@@ -4336,7 +4389,7 @@ static int fts3EvalPhraseStart(Fts3Cursor *pCsr, int bOptOk, Fts3Phrase *p){
int bIncrOk = (bOptOk
&& pCsr->bDesc==pTab->bDescIdx
&& p->nToken<=MAX_INCR_PHRASE_TOKENS && p->nToken>0
-#ifdef SQLITE_TEST
+#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
&& pTab->bNoIncrDoclist==0
#endif
);
@@ -4478,15 +4531,16 @@ static void fts3EvalDlPhraseNext(
u8 *pbEof
){
char *pIter; /* Used to iterate through aAll */
- char *pEnd = &pDL->aAll[pDL->nAll]; /* 1 byte past end of aAll */
+ char *pEnd; /* 1 byte past end of aAll */
if( pDL->pNextDocid ){
pIter = pDL->pNextDocid;
+ assert( pDL->aAll!=0 || pIter==0 );
}else{
pIter = pDL->aAll;
}
- if( pIter>=pEnd ){
+ if( pIter==0 || pIter>=(pEnd = pDL->aAll + pDL->nAll) ){
/* We have already reached the end of this doclist. EOF. */
*pbEof = 1;
}else{
@@ -4858,12 +4912,13 @@ static int fts3EvalAverageDocsize(Fts3Cursor *pCsr, int *pnPage){
rc = sqlite3Fts3SelectDoctotal(p, &pStmt);
if( rc!=SQLITE_OK ) return rc;
a = sqlite3_column_blob(pStmt, 0);
- assert( a );
-
- pEnd = &a[sqlite3_column_bytes(pStmt, 0)];
- a += sqlite3Fts3GetVarint(a, &nDoc);
- while( anMergeCount)
+#else
+# define MergeCount(P) FTS3_MERGE_COUNT
+#endif
+
/*
** When the core wants to read from the virtual table, it creates a
** virtual table cursor (an instance of the following structure) using
@@ -567,6 +581,8 @@ int sqlite3Fts3Incrmerge(Fts3Table*,int,int);
void sqlite3Fts3ErrMsg(char**,const char*,...);
int sqlite3Fts3PutVarint(char *, sqlite3_int64);
int sqlite3Fts3GetVarint(const char *, sqlite_int64 *);
+int sqlite3Fts3GetVarintU(const char *, sqlite_uint64 *);
+int sqlite3Fts3GetVarintBounded(const char*,const char*,sqlite3_int64*);
int sqlite3Fts3GetVarint32(const char *, int *);
int sqlite3Fts3VarintLen(sqlite3_uint64);
void sqlite3Fts3Dequote(char *);
diff --git a/ext/fts3/fts3_snippet.c b/ext/fts3/fts3_snippet.c
index 6db3fd7d96..2b20ba10a7 100644
--- a/ext/fts3/fts3_snippet.c
+++ b/ext/fts3/fts3_snippet.c
@@ -560,7 +560,7 @@ static int fts3BestSnippet(
/* Set the *pmSeen output variable. */
for(i=0; ipEnd ){
+ return FTS_CORRUPT_VTAB;
+ }
+ *pnDoc = nDoc;
if( paLen ) *paLen = a;
+ if( ppEnd ) *ppEnd = pEnd;
return SQLITE_OK;
}
@@ -1237,7 +1249,7 @@ static int fts3MatchinfoValues(
case FTS3_MATCHINFO_NDOC:
if( bGlobal ){
sqlite3_int64 nDoc = 0;
- rc = fts3MatchinfoSelectDoctotal(pTab, &pSelect, &nDoc, 0);
+ rc = fts3MatchinfoSelectDoctotal(pTab, &pSelect, &nDoc, 0, 0);
pInfo->aMatchinfo[0] = (u32)nDoc;
}
break;
@@ -1246,14 +1258,19 @@ static int fts3MatchinfoValues(
if( bGlobal ){
sqlite3_int64 nDoc; /* Number of rows in table */
const char *a; /* Aggregate column length array */
+ const char *pEnd; /* First byte past end of length array */
- rc = fts3MatchinfoSelectDoctotal(pTab, &pSelect, &nDoc, &a);
+ rc = fts3MatchinfoSelectDoctotal(pTab, &pSelect, &nDoc, &a, &pEnd);
if( rc==SQLITE_OK ){
int iCol;
for(iCol=0; iColnCol; iCol++){
u32 iVal;
sqlite3_int64 nToken;
a += sqlite3Fts3GetVarint(a, &nToken);
+ if( a>pEnd ){
+ rc = SQLITE_CORRUPT_VTAB;
+ break;
+ }
iVal = (u32)(((u32)(nToken&0xffffffff)+nDoc/2)/nDoc);
pInfo->aMatchinfo[iCol] = iVal;
}
@@ -1267,9 +1284,14 @@ static int fts3MatchinfoValues(
if( rc==SQLITE_OK ){
int iCol;
const char *a = sqlite3_column_blob(pSelectDocsize, 0);
+ const char *pEnd = a + sqlite3_column_bytes(pSelectDocsize, 0);
for(iCol=0; iColnCol; iCol++){
sqlite3_int64 nToken;
- a += sqlite3Fts3GetVarint(a, &nToken);
+ a += sqlite3Fts3GetVarintBounded(a, pEnd, &nToken);
+ if( a>pEnd ){
+ rc = SQLITE_CORRUPT_VTAB;
+ break;
+ }
pInfo->aMatchinfo[iCol] = (u32)nToken;
}
}
@@ -1300,7 +1322,7 @@ static int fts3MatchinfoValues(
if( rc!=SQLITE_OK ) break;
if( bGlobal ){
if( pCsr->pDeferred ){
- rc = fts3MatchinfoSelectDoctotal(pTab, &pSelect, &pInfo->nDoc, 0);
+ rc = fts3MatchinfoSelectDoctotal(pTab, &pSelect, &pInfo->nDoc,0,0);
if( rc!=SQLITE_OK ) break;
}
rc = fts3ExprIterate(pExpr, fts3ExprGlobalHitsCb,(void*)pInfo);
diff --git a/ext/fts3/fts3_tokenizer.c b/ext/fts3/fts3_tokenizer.c
index 0196f0f2d5..eab3f513e5 100644
--- a/ext/fts3/fts3_tokenizer.c
+++ b/ext/fts3/fts3_tokenizer.c
@@ -390,7 +390,9 @@ int queryTokenizer(
sqlite3_bind_text(pStmt, 1, zName, -1, SQLITE_STATIC);
if( SQLITE_ROW==sqlite3_step(pStmt) ){
- if( sqlite3_column_type(pStmt, 0)==SQLITE_BLOB ){
+ if( sqlite3_column_type(pStmt, 0)==SQLITE_BLOB
+ && sqlite3_column_bytes(pStmt, 0)==sizeof(*pp)
+ ){
memcpy((void *)pp, sqlite3_column_blob(pStmt, 0), sizeof(*pp));
}
}
@@ -479,7 +481,7 @@ int sqlite3Fts3InitHashTable(
){
int rc = SQLITE_OK;
void *p = (void *)pHash;
- const int any = SQLITE_ANY;
+ const int any = SQLITE_UTF8|SQLITE_DIRECTONLY;
#ifdef SQLITE_TEST
char *zTest = 0;
diff --git a/ext/fts3/fts3_write.c b/ext/fts3/fts3_write.c
index 6960c31bd1..197aebdd49 100644
--- a/ext/fts3/fts3_write.c
+++ b/ext/fts3/fts3_write.c
@@ -23,7 +23,7 @@
#include
#include
#include
-
+#include
#define FTS_MAX_APPENDABLE_HEIGHT 16
@@ -67,7 +67,7 @@ int test_fts3_node_chunk_threshold = (4*1024)*4;
#endif
/*
-** The two values that may be meaningfully bound to the :1 parameter in
+** The values that may be meaningfully bound to the :1 parameter in
** statements SQL_REPLACE_STAT and SQL_SELECT_STAT.
*/
#define FTS_STAT_DOCTOTAL 0
@@ -335,7 +335,7 @@ static int fts3SqlStmt(
** returns zero rows. */
/* 28 */ "SELECT level, count(*) AS cnt FROM %Q.'%q_segdir' "
" GROUP BY level HAVING cnt>=?"
- " ORDER BY (level %% 1024) ASC LIMIT 1",
+ " ORDER BY (level %% 1024) ASC, 2 DESC LIMIT 1",
/* Estimate the upper limit on the number of leaf nodes in a new segment
** created by merging the oldest :2 segments from absolute level :1. See
@@ -696,7 +696,7 @@ static int fts3PendingListAppend(
assert( !p || p->iLastDocid<=iDocid );
if( !p || p->iLastDocid!=iDocid ){
- sqlite3_int64 iDelta = iDocid - (p ? p->iLastDocid : 0);
+ u64 iDelta = (u64)iDocid - (u64)(p ? p->iLastDocid : 0);
if( p ){
assert( p->nDatanSpace );
assert( p->aData[p->nData]==0 );
@@ -1153,7 +1153,7 @@ static int fts3AllocateSegdirIdx(
** segment and allocate (newly freed) index 0 at level iLevel. Otherwise,
** if iNext is less than FTS3_MERGE_COUNT, allocate index iNext.
*/
- if( iNext>=FTS3_MERGE_COUNT ){
+ if( iNext>=MergeCount(p) ){
fts3LogMerge(16, getAbsoluteLevel(p, iLangid, iIndex, iLevel));
rc = fts3SegmentMerge(p, iLangid, iIndex, iLevel);
*piIdx = 0;
@@ -1237,6 +1237,8 @@ int sqlite3Fts3ReadBlock(
}
*paBlob = aByte;
}
+ }else if( rc==SQLITE_ERROR ){
+ rc = FTS_CORRUPT_VTAB;
}
return rc;
@@ -1379,7 +1381,7 @@ static int fts3SegReaderNext(
pNext += fts3GetVarint32(pNext, &nSuffix);
if( nSuffix<=0
|| (&pReader->aNode[pReader->nNode] - pNext)pReader->nTermAlloc
+ || nPrefix>pReader->nTerm
){
return FTS_CORRUPT_VTAB;
}
@@ -1529,18 +1531,18 @@ static int fts3SegReaderNextDocid(
}else{
rc = fts3SegReaderRequire(pReader, p, FTS3_VARINT_MAX);
if( rc==SQLITE_OK ){
- sqlite3_int64 iDelta;
- pReader->pOffsetList = p + sqlite3Fts3GetVarint(p, &iDelta);
+ u64 iDelta;
+ pReader->pOffsetList = p + sqlite3Fts3GetVarintU(p, &iDelta);
if( pTab->bDescIdx ){
- pReader->iDocid -= iDelta;
+ pReader->iDocid = (i64)((u64)pReader->iDocid - iDelta);
}else{
- pReader->iDocid += iDelta;
+ pReader->iDocid = (i64)((u64)pReader->iDocid + iDelta);
}
}
}
}
- return SQLITE_OK;
+ return rc;
}
@@ -2030,6 +2032,11 @@ static int fts3NodeAddTerm(
nPrefix = fts3PrefixCompress(pTree->zTerm, pTree->nTerm, zTerm, nTerm);
nSuffix = nTerm-nPrefix;
+ /* If nSuffix is zero or less, then zTerm/nTerm must be a prefix of
+ ** pWriter->zTerm/pWriter->nTerm. i.e. must be equal to or less than when
+ ** compared with BINARY collation. This indicates corruption. */
+ if( nSuffix<=0 ) return FTS_CORRUPT_VTAB;
+
nReq += sqlite3Fts3VarintLen(nPrefix)+sqlite3Fts3VarintLen(nSuffix)+nSuffix;
if( nReq<=p->nNodeSize || !pTree->zTerm ){
@@ -2274,6 +2281,7 @@ static int fts3SegWriterAdd(
int rc;
/* The current leaf node is full. Write it out to the database. */
+ if( pWriter->iFree==LARGEST_INT64 ) return FTS_CORRUPT_VTAB;
rc = fts3WriteSegment(p, pWriter->iFree++, pWriter->aData, nData);
if( rc!=SQLITE_OK ) return rc;
p->nLeafAdd++;
@@ -2323,9 +2331,11 @@ static int fts3SegWriterAdd(
/* Append the prefix-compressed term and doclist to the buffer. */
nData += sqlite3Fts3PutVarint(&pWriter->aData[nData], nPrefix);
nData += sqlite3Fts3PutVarint(&pWriter->aData[nData], nSuffix);
+ assert( nSuffix>0 );
memcpy(&pWriter->aData[nData], &zTerm[nPrefix], nSuffix);
nData += nSuffix;
nData += sqlite3Fts3PutVarint(&pWriter->aData[nData], nDoclist);
+ assert( nDoclist>0 );
memcpy(&pWriter->aData[nData], aDoclist, nDoclist);
pWriter->nData = nData + nDoclist;
@@ -2345,6 +2355,7 @@ static int fts3SegWriterAdd(
pWriter->zTerm = zNew;
}
assert( pWriter->zTerm==pWriter->zMalloc );
+ assert( nTerm>0 );
memcpy(pWriter->zTerm, zTerm, nTerm);
}else{
pWriter->zTerm = (char *)zTerm;
@@ -2653,6 +2664,7 @@ static int fts3MsrBufferData(
pMsr->aBuffer = pNew;
}
+ assert( nList>0 );
memcpy(pMsr->aBuffer, pList, nList);
return SQLITE_OK;
}
@@ -2966,14 +2978,12 @@ int sqlite3Fts3SegReaderStep(
** doclist. */
sqlite3_int64 iDelta;
if( p->bDescIdx && nDoclist>0 ){
- iDelta = iPrev - iDocid;
+ if( iPrev<=iDocid ) return FTS_CORRUPT_VTAB;
+ iDelta = (i64)((u64)iPrev - (u64)iDocid);
}else{
- iDelta = iDocid - iPrev;
+ if( nDoclist>0 && iPrev>=iDocid ) return FTS_CORRUPT_VTAB;
+ iDelta = (i64)((u64)iDocid - (u64)iPrev);
}
- if( iDelta<=0 && (nDoclist>0 || iDelta!=iDocid) ){
- return FTS_CORRUPT_VTAB;
- }
- assert( nDoclist>0 || iDelta==iDocid );
nByte = sqlite3Fts3VarintLen(iDelta) + (isRequirePos?nList+1:0);
if( nDoclist+nByte>pCsr->nBuffer ){
@@ -3255,7 +3265,7 @@ static int fts3SegmentMerge(
csr.zTerm, csr.nTerm, csr.aDoclist, csr.nDoclist);
}
if( rc!=SQLITE_OK ) goto finished;
- assert( pWriter || bIgnoreEmpty );
+ assert_fts3_nc( pWriter || bIgnoreEmpty );
if( iLevel!=FTS3_SEGCURSOR_PENDING ){
rc = fts3DeleteSegdir(
@@ -3482,7 +3492,10 @@ static int fts3DoOptimize(Fts3Table *p, int bReturnDone){
int rc;
sqlite3_stmt *pAllLangid = 0;
- rc = fts3SqlStmt(p, SQL_SELECT_ALL_LANGID, &pAllLangid, 0);
+ rc = sqlite3Fts3PendingTermsFlush(p);
+ if( rc==SQLITE_OK ){
+ rc = fts3SqlStmt(p, SQL_SELECT_ALL_LANGID, &pAllLangid, 0);
+ }
if( rc==SQLITE_OK ){
int rc2;
sqlite3_bind_int(pAllLangid, 1, p->iPrevLangid);
@@ -3503,7 +3516,6 @@ static int fts3DoOptimize(Fts3Table *p, int bReturnDone){
}
sqlite3Fts3SegmentsClose(p);
- sqlite3Fts3PendingTermsClear(p);
return (rc==SQLITE_OK && bReturnDone && bSeenDone) ? SQLITE_DONE : rc;
}
@@ -3841,6 +3853,7 @@ static int fts3IncrmergePush(
** be added to. */
nPrefix = fts3PrefixCompress(pNode->key.a, pNode->key.n, zTerm, nTerm);
nSuffix = nTerm - nPrefix;
+ if(nSuffix<=0 ) return FTS_CORRUPT_VTAB;
nSpace = sqlite3Fts3VarintLen(nPrefix);
nSpace += sqlite3Fts3VarintLen(nSuffix) + nSuffix;
@@ -4235,6 +4248,10 @@ static int fts3IncrmergeLoad(
pWriter->bNoLeafData = (pWriter->nLeafData==0);
nRoot = sqlite3_column_bytes(pSelect, 4);
aRoot = sqlite3_column_blob(pSelect, 4);
+ if( aRoot==0 ){
+ sqlite3_reset(pSelect);
+ return nRoot ? SQLITE_NOMEM : FTS_CORRUPT_VTAB;
+ }
}else{
return sqlite3_reset(pSelect);
}
@@ -4270,6 +4287,10 @@ static int fts3IncrmergeLoad(
int i;
int nHeight = (int)aRoot[0];
NodeWriter *pNode;
+ if( nHeight<1 || nHeight>FTS_MAX_APPENDABLE_HEIGHT ){
+ sqlite3_reset(pSelect);
+ return FTS_CORRUPT_VTAB;
+ }
pWriter->nLeafEst = (int)((iEnd - iStart) + 1)/FTS_MAX_APPENDABLE_HEIGHT;
pWriter->iStart = iStart;
@@ -4830,13 +4851,17 @@ static int fts3IncrmergeHintPop(Blob *pHint, i64 *piAbsLevel, int *pnInput){
const int nHint = pHint->n;
int i;
- i = pHint->n-2;
+ i = pHint->n-1;
+ if( (pHint->a[i] & 0x80) ) return FTS_CORRUPT_VTAB;
while( i>0 && (pHint->a[i-1] & 0x80) ) i--;
+ if( i==0 ) return FTS_CORRUPT_VTAB;
+ i--;
while( i>0 && (pHint->a[i-1] & 0x80) ) i--;
pHint->n = i;
i += sqlite3Fts3GetVarint(&pHint->a[i], piAbsLevel);
i += fts3GetVarint32(&pHint->a[i], pnInput);
+ assert( i<=nHint );
if( i!=nHint ) return FTS_CORRUPT_VTAB;
return SQLITE_OK;
@@ -4906,8 +4931,14 @@ int sqlite3Fts3Incrmerge(Fts3Table *p, int nMerge, int nMin){
rc = fts3IncrmergeHintPop(&hint, &iHintAbsLevel, &nHintSeg);
if( nSeg<0 || (iAbsLevel % nMod) >= (iHintAbsLevel % nMod) ){
+ /* Based on the scan in the block above, it is known that there
+ ** are no levels with a relative level smaller than that of
+ ** iAbsLevel with more than nSeg segments, or if nSeg is -1,
+ ** no levels with more than nMin segments. Use this to limit the
+ ** value of nHintSeg to avoid a large memory allocation in case the
+ ** merge-hint is corrupt*/
iAbsLevel = iHintAbsLevel;
- nSeg = nHintSeg;
+ nSeg = MIN(MAX(nMin,nSeg), nHintSeg);
bUseHint = 1;
bDirtyHint = 1;
}else{
@@ -4920,7 +4951,7 @@ int sqlite3Fts3Incrmerge(Fts3Table *p, int nMerge, int nMin){
/* If nSeg is less that zero, then there is no level with at least
** nMin segments and no hint in the %_stat table. No work to do.
** Exit early in this case. */
- if( nSeg<0 ) break;
+ if( nSeg<=0 ) break;
/* Open a cursor to iterate through the contents of the oldest nSeg
** indexes of absolute level iAbsLevel. If this cursor is opened using
@@ -4948,8 +4979,15 @@ int sqlite3Fts3Incrmerge(Fts3Table *p, int nMerge, int nMin){
}
if( SQLITE_OK==rc && pCsr->nSegment==nSeg
&& SQLITE_OK==(rc = sqlite3Fts3SegReaderStart(p, pCsr, pFilter))
- && SQLITE_ROW==(rc = sqlite3Fts3SegReaderStep(p, pCsr))
){
+ int bEmpty = 0;
+ rc = sqlite3Fts3SegReaderStep(p, pCsr);
+ if( rc==SQLITE_OK ){
+ bEmpty = 1;
+ }else if( rc!=SQLITE_ROW ){
+ sqlite3Fts3SegReaderFinish(pCsr);
+ break;
+ }
if( bUseHint && iIdx>0 ){
const char *zKey = pCsr->zTerm;
int nKey = pCsr->nTerm;
@@ -4960,11 +4998,13 @@ int sqlite3Fts3Incrmerge(Fts3Table *p, int nMerge, int nMin){
if( rc==SQLITE_OK && pWriter->nLeafEst ){
fts3LogMerge(nSeg, iAbsLevel);
- do {
- rc = fts3IncrmergeAppend(p, pWriter, pCsr);
- if( rc==SQLITE_OK ) rc = sqlite3Fts3SegReaderStep(p, pCsr);
- if( pWriter->nWork>=nRem && rc==SQLITE_ROW ) rc = SQLITE_OK;
- }while( rc==SQLITE_ROW );
+ if( bEmpty==0 ){
+ do {
+ rc = fts3IncrmergeAppend(p, pWriter, pCsr);
+ if( rc==SQLITE_OK ) rc = sqlite3Fts3SegReaderStep(p, pCsr);
+ if( pWriter->nWork>=nRem && rc==SQLITE_ROW ) rc = SQLITE_OK;
+ }while( rc==SQLITE_ROW );
+ }
/* Update or delete the input segments */
if( rc==SQLITE_OK ){
@@ -5029,7 +5069,7 @@ static int fts3DoIncrmerge(
const char *zParam /* Nul-terminated string containing "A,B" */
){
int rc;
- int nMin = (FTS3_MERGE_COUNT / 2);
+ int nMin = (MergeCount(p) / 2);
int nMerge = 0;
const char *z = zParam;
@@ -5074,7 +5114,7 @@ static int fts3DoAutoincrmerge(
int rc = SQLITE_OK;
sqlite3_stmt *pStmt = 0;
p->nAutoincrmerge = fts3Getint(&zParam);
- if( p->nAutoincrmerge==1 || p->nAutoincrmerge>FTS3_MERGE_COUNT ){
+ if( p->nAutoincrmerge==1 || p->nAutoincrmerge>MergeCount(p) ){
p->nAutoincrmerge = 8;
}
if( !p->bHasStat ){
@@ -5157,12 +5197,12 @@ static u64 fts3ChecksumIndex(
i64 iDocid = 0;
i64 iCol = 0;
- i64 iPos = 0;
+ u64 iPos = 0;
pCsr += sqlite3Fts3GetVarint(pCsr, &iDocid);
while( pCsrbDescIdx ){
+ iDocid = (i64)((u64)iDocid - iVal);
+ }else{
+ iDocid = (i64)((u64)iDocid + iVal);
+ }
}
}else{
iPos += (iVal - 2);
@@ -5244,10 +5288,9 @@ static int fts3IntegrityCheck(Fts3Table *p, int *pbOk){
for(iCol=0; rc==SQLITE_OK && iColnColumn; iCol++){
if( p->abNotindexed[iCol]==0 ){
const char *zText = (const char *)sqlite3_column_text(pStmt, iCol+1);
- int nText = sqlite3_column_bytes(pStmt, iCol+1);
sqlite3_tokenizer_cursor *pT = 0;
- rc = sqlite3Fts3OpenTokenizer(p->pTokenizer, iLang, zText, nText,&pT);
+ rc = sqlite3Fts3OpenTokenizer(p->pTokenizer, iLang, zText, -1, &pT);
while( rc==SQLITE_OK ){
char const *zToken; /* Buffer containing token */
int nToken = 0; /* Number of bytes in token */
@@ -5332,7 +5375,7 @@ static int fts3DoIntegrityCheck(
** meaningful value to insert is the text 'optimize'.
*/
static int fts3SpecialInsert(Fts3Table *p, sqlite3_value *pVal){
- int rc; /* Return Code */
+ int rc = SQLITE_ERROR; /* Return Code */
const char *zVal = (const char *)sqlite3_value_text(pVal);
int nVal = sqlite3_value_bytes(pVal);
@@ -5348,21 +5391,27 @@ static int fts3SpecialInsert(Fts3Table *p, sqlite3_value *pVal){
rc = fts3DoIncrmerge(p, &zVal[6]);
}else if( nVal>10 && 0==sqlite3_strnicmp(zVal, "automerge=", 10) ){
rc = fts3DoAutoincrmerge(p, &zVal[10]);
-#ifdef SQLITE_TEST
- }else if( nVal>9 && 0==sqlite3_strnicmp(zVal, "nodesize=", 9) ){
- p->nNodeSize = atoi(&zVal[9]);
- rc = SQLITE_OK;
- }else if( nVal>11 && 0==sqlite3_strnicmp(zVal, "maxpending=", 9) ){
- p->nMaxPendingData = atoi(&zVal[11]);
- rc = SQLITE_OK;
- }else if( nVal>21 && 0==sqlite3_strnicmp(zVal, "test-no-incr-doclist=", 21) ){
- p->bNoIncrDoclist = atoi(&zVal[21]);
- rc = SQLITE_OK;
-#endif
+#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
}else{
- rc = SQLITE_ERROR;
+ int v;
+ if( nVal>9 && 0==sqlite3_strnicmp(zVal, "nodesize=", 9) ){
+ v = atoi(&zVal[9]);
+ if( v>=24 && v<=p->nPgsz-35 ) p->nNodeSize = v;
+ rc = SQLITE_OK;
+ }else if( nVal>11 && 0==sqlite3_strnicmp(zVal, "maxpending=", 9) ){
+ v = atoi(&zVal[11]);
+ if( v>=64 && v<=FTS3_MAX_PENDING_DATA ) p->nMaxPendingData = v;
+ rc = SQLITE_OK;
+ }else if( nVal>21 && 0==sqlite3_strnicmp(zVal,"test-no-incr-doclist=",21) ){
+ p->bNoIncrDoclist = atoi(&zVal[21]);
+ rc = SQLITE_OK;
+ }else if( nVal>11 && 0==sqlite3_strnicmp(zVal,"mergecount=",11) ){
+ v = atoi(&zVal[11]);
+ if( v>=4 && v<=FTS3_MERGE_COUNT && (v&1)==0 ) p->nMergeCount = v;
+ rc = SQLITE_OK;
+ }
+#endif
}
-
return rc;
}
diff --git a/ext/fts5/fts5.h b/ext/fts5/fts5.h
index 9d71d3fb89..081e534f3f 100644
--- a/ext/fts5/fts5.h
+++ b/ext/fts5/fts5.h
@@ -159,7 +159,7 @@ struct Fts5PhraseIter {
**
** xSetAuxdata(pFts5, pAux, xDelete)
**
-** Save the pointer passed as the second argument as the extension functions
+** Save the pointer passed as the second argument as the extension function's
** "auxiliary data". The pointer may then be retrieved by the current or any
** future invocation of the same fts5 extension function made as part of
** the same MATCH query using the xGetAuxdata() API.
@@ -401,8 +401,8 @@ struct Fts5ExtensionApi {
**
** There are several ways to approach this in FTS5:
**
-** - By mapping all synonyms to a single token. In this case, the
-** In the above example, this means that the tokenizer returns the
+**
- By mapping all synonyms to a single token. In this case, using
+** the above example, this means that the tokenizer returns the
** same token for inputs "first" and "1st". Say that token is in
** fact "first", so that when the user inserts the document "I won
** 1st place" entries are added to the index for tokens "i", "won",
diff --git a/ext/fts5/fts5Int.h b/ext/fts5/fts5Int.h
index c29b42b7ad..e0287d1616 100644
--- a/ext/fts5/fts5Int.h
+++ b/ext/fts5/fts5Int.h
@@ -61,6 +61,11 @@ typedef sqlite3_uint64 u64;
*/
#define FTS5_MAX_PREFIX_INDEXES 31
+/*
+** Maximum segments permitted in a single index
+*/
+#define FTS5_MAX_SEGMENT 2000
+
#define FTS5_DEFAULT_NEARDIST 10
#define FTS5_DEFAULT_RANK "bm25"
@@ -417,6 +422,11 @@ int sqlite3Fts5IterNextFrom(Fts5IndexIter*, i64 iMatch);
*/
void sqlite3Fts5IterClose(Fts5IndexIter*);
+/*
+** Close the reader blob handle, if it is open.
+*/
+void sqlite3Fts5IndexCloseReader(Fts5Index*);
+
/*
** This interface is used by the fts5vocab module.
*/
diff --git a/ext/fts5/fts5_config.c b/ext/fts5/fts5_config.c
index 4e1707b3f4..ddd2317974 100644
--- a/ext/fts5/fts5_config.c
+++ b/ext/fts5/fts5_config.c
@@ -23,7 +23,7 @@
#define FTS5_DEFAULT_HASHSIZE (1024*1024)
/* Maximum allowed page size */
-#define FTS5_MAX_PAGE_SIZE (128*1024)
+#define FTS5_MAX_PAGE_SIZE (64*1024)
static int fts5_iswhitespace(char x){
return (x==' ');
@@ -150,7 +150,7 @@ static int fts5Dequote(char *z){
assert( q=='[' || q=='\'' || q=='"' || q=='`' );
if( q=='[' ) q = ']';
- while( ALWAYS(z[iIn]) ){
+ while( z[iIn] ){
if( z[iIn]==q ){
if( z[iIn+1]!=q ){
/* Character iIn was the close quote. */
@@ -828,7 +828,7 @@ int sqlite3Fts5ConfigSetValue(
if( SQLITE_INTEGER==sqlite3_value_numeric_type(pVal) ){
pgsz = sqlite3_value_int(pVal);
}
- if( pgsz<=0 || pgsz>FTS5_MAX_PAGE_SIZE ){
+ if( pgsz<32 || pgsz>FTS5_MAX_PAGE_SIZE ){
*pbBadkey = 1;
}else{
pConfig->pgsz = pgsz;
@@ -881,6 +881,7 @@ int sqlite3Fts5ConfigSetValue(
*pbBadkey = 1;
}else{
if( nCrisisMerge<=1 ) nCrisisMerge = FTS5_DEFAULT_CRISISMERGE;
+ if( nCrisisMerge>=FTS5_MAX_SEGMENT ) nCrisisMerge = FTS5_MAX_SEGMENT-1;
pConfig->nCrisisMerge = nCrisisMerge;
}
}
diff --git a/ext/fts5/fts5_expr.c b/ext/fts5/fts5_expr.c
index ce462af0f0..d9de1c8178 100644
--- a/ext/fts5/fts5_expr.c
+++ b/ext/fts5/fts5_expr.c
@@ -2516,10 +2516,12 @@ static void fts5ExprFunction(
azConfig[1] = "main";
azConfig[2] = "tbl";
for(i=3; iArgpReader ){
sqlite3_blob *pReader = p->pReader;
p->pReader = 0;
@@ -648,7 +643,7 @@ static Fts5Data *fts5DataRead(Fts5Index *p, i64 iRowid){
assert( p->pReader==0 );
p->pReader = pBlob;
if( rc!=SQLITE_OK ){
- fts5CloseReader(p);
+ sqlite3Fts5IndexCloseReader(p);
}
if( rc==SQLITE_ABORT ) rc = SQLITE_OK;
}
@@ -5209,7 +5204,7 @@ int sqlite3Fts5IndexBeginWrite(Fts5Index *p, int bDelete, i64 iRowid){
int sqlite3Fts5IndexSync(Fts5Index *p){
assert( p->rc==SQLITE_OK );
fts5IndexFlush(p);
- fts5CloseReader(p);
+ sqlite3Fts5IndexCloseReader(p);
return fts5IndexReturn(p);
}
@@ -5220,7 +5215,7 @@ int sqlite3Fts5IndexSync(Fts5Index *p){
** records must be invalidated.
*/
int sqlite3Fts5IndexRollback(Fts5Index *p){
- fts5CloseReader(p);
+ sqlite3Fts5IndexCloseReader(p);
fts5IndexDiscardData(p);
fts5StructureInvalidate(p);
/* assert( p->rc==SQLITE_OK ); */
@@ -5235,6 +5230,7 @@ int sqlite3Fts5IndexRollback(Fts5Index *p){
int sqlite3Fts5IndexReinit(Fts5Index *p){
Fts5Structure s;
fts5StructureInvalidate(p);
+ fts5IndexDiscardData(p);
memset(&s, 0, sizeof(Fts5Structure));
fts5DataWrite(p, FTS5_AVERAGES_ROWID, (const u8*)"", 0);
fts5StructureWrite(p, &s);
@@ -5322,9 +5318,13 @@ int sqlite3Fts5IndexCharlenToBytelen(
for(i=0; i=nByte ) return 0; /* Input contains fewer than nChar chars */
if( (unsigned char)p[n++]>=0xc0 ){
+ if( n>=nByte ) return 0;
while( (p[n] & 0xc0)==0x80 ){
n++;
- if( n>=nByte ) break;
+ if( n>=nByte ){
+ if( i+1==nChar ) break;
+ return 0;
+ }
}
}
}
@@ -5460,7 +5460,7 @@ int sqlite3Fts5IndexQuery(
if( p->rc ){
sqlite3Fts5IterClose((Fts5IndexIter*)pRet);
pRet = 0;
- fts5CloseReader(p);
+ sqlite3Fts5IndexCloseReader(p);
}
*ppIter = (Fts5IndexIter*)pRet;
@@ -5533,7 +5533,7 @@ void sqlite3Fts5IterClose(Fts5IndexIter *pIndexIter){
Fts5Iter *pIter = (Fts5Iter*)pIndexIter;
Fts5Index *pIndex = pIter->pIndex;
fts5MultiIterFree(pIter);
- fts5CloseReader(pIndex);
+ sqlite3Fts5IndexCloseReader(pIndex);
}
}
@@ -5726,6 +5726,37 @@ static int fts5QueryCksum(
return rc;
}
+/*
+** Check if buffer z[], size n bytes, contains as series of valid utf-8
+** encoded codepoints. If so, return 0. Otherwise, if the buffer does not
+** contain valid utf-8, return non-zero.
+*/
+static int fts5TestUtf8(const char *z, int n){
+ assert_nc( n>0 );
+ int i = 0;
+ while( i=n || (z[i+1] & 0xC0)!=0x80 ) return 1;
+ i += 2;
+ }else
+ if( (z[i] & 0xF0)==0xE0 ){
+ if( i+2>=n || (z[i+1] & 0xC0)!=0x80 || (z[i+2] & 0xC0)!=0x80 ) return 1;
+ i += 3;
+ }else
+ if( (z[i] & 0xF8)==0xF0 ){
+ if( i+3>=n || (z[i+1] & 0xC0)!=0x80 || (z[i+2] & 0xC0)!=0x80 ) return 1;
+ if( (z[i+2] & 0xC0)!=0x80 ) return 1;
+ i += 3;
+ }else{
+ return 1;
+ }
+ }
+
+ return 0;
+}
/*
** This function is also purely an internal test. It does not contribute to
@@ -5766,8 +5797,14 @@ static void fts5TestTerm(
** This check may only be performed if the hash table is empty. This
** is because the hash table only supports a single scan query at
** a time, and the multi-iter loop from which this function is called
- ** is already performing such a scan. */
- if( p->nPendingData==0 ){
+ ** is already performing such a scan.
+ **
+ ** Also only do this if buffer zTerm contains nTerm bytes of valid
+ ** utf-8. Otherwise, the last part of the buffer contents might contain
+ ** a non-utf-8 sequence that happens to be a prefix of a valid utf-8
+ ** character stored in the main fts index, which will cause the
+ ** test to fail. */
+ if( p->nPendingData==0 && 0==fts5TestUtf8(zTerm, nTerm) ){
if( iIdx>0 && rc==SQLITE_OK ){
int f = flags|FTS5INDEX_QUERY_TEST_NOIDX;
ck2 = 0;
@@ -5890,7 +5927,8 @@ static void fts5IndexIntegrityCheckSegment(
if( pSeg->pgnoFirst==0 ) return;
fts5IndexPrepareStmt(p, &pStmt, sqlite3_mprintf(
- "SELECT segid, term, (pgno>>1), (pgno&1) FROM %Q.'%q_idx' WHERE segid=%d",
+ "SELECT segid, term, (pgno>>1), (pgno&1) FROM %Q.'%q_idx' WHERE segid=%d "
+ "ORDER BY 1, 2",
pConfig->zDb, pConfig->zName, pSeg->iSegid
));
@@ -5899,8 +5937,8 @@ static void fts5IndexIntegrityCheckSegment(
i64 iRow; /* Rowid for this leaf */
Fts5Data *pLeaf; /* Data for this leaf */
+ const char *zIdxTerm = (const char*)sqlite3_column_blob(pStmt, 1);
int nIdxTerm = sqlite3_column_bytes(pStmt, 1);
- const char *zIdxTerm = (const char*)sqlite3_column_text(pStmt, 1);
int iIdxLeaf = sqlite3_column_int(pStmt, 2);
int bIdxDlidx = sqlite3_column_int(pStmt, 3);
diff --git a/ext/fts5/fts5_main.c b/ext/fts5/fts5_main.c
index fc4ec0c482..347bf7f23e 100644
--- a/ext/fts5/fts5_main.c
+++ b/ext/fts5/fts5_main.c
@@ -289,7 +289,10 @@ static void fts5CheckTransactionState(Fts5FullTable *p, int op, int iSavepoint){
case FTS5_ROLLBACKTO:
assert( p->ts.eState==1 );
assert( iSavepoint>=-1 );
- assert( iSavepoint<=p->ts.iSavepoint );
+ /* The following assert() can fail if another vtab strikes an error
+ ** within an xSavepoint() call then SQLite calls xRollbackTo() - without
+ ** having called xSavepoint() on this vtab. */
+ /* assert( iSavepoint<=p->ts.iSavepoint ); */
p->ts.iSavepoint = iSavepoint;
break;
}
@@ -744,6 +747,7 @@ static void fts5FreeCursorComponents(Fts5Cursor *pCsr){
sqlite3_free(pCsr->zRankArgs);
}
+ sqlite3Fts5IndexCloseReader(pTab->p.pIndex);
memset(&pCsr->ePlan, 0, sizeof(Fts5Cursor) - ((u8*)&pCsr->ePlan - (u8*)pCsr));
}
@@ -894,15 +898,24 @@ static int fts5NextMethod(sqlite3_vtab_cursor *pCursor){
break;
}
- default:
+ default: {
+ Fts5Config *pConfig = ((Fts5Table*)pCursor->pVtab)->pConfig;
+ pConfig->bLock++;
rc = sqlite3_step(pCsr->pStmt);
+ pConfig->bLock--;
if( rc!=SQLITE_ROW ){
CsrFlagSet(pCsr, FTS5CSR_EOF);
rc = sqlite3_reset(pCsr->pStmt);
+ if( rc!=SQLITE_OK ){
+ pCursor->pVtab->zErrMsg = sqlite3_mprintf(
+ "%s", sqlite3_errmsg(pConfig->db)
+ );
+ }
}else{
rc = SQLITE_OK;
}
break;
+ }
}
}
@@ -1187,6 +1200,13 @@ static int fts5FilterMethod(
int iIdxStr = 0;
Fts5Expr *pExpr = 0;
+ if( pConfig->bLock ){
+ pTab->p.base.zErrMsg = sqlite3_mprintf(
+ "recursively defined fts5 content table"
+ );
+ return SQLITE_ERROR;
+ }
+
if( pCsr->ePlan ){
fts5FreeCursorComponents(pCsr);
memset(&pCsr->ePlan, 0, sizeof(Fts5Cursor) - ((u8*)&pCsr->ePlan-(u8*)pCsr));
@@ -1407,10 +1427,13 @@ static int fts5SeekCursor(Fts5Cursor *pCsr, int bErrormsg){
}
if( rc==SQLITE_OK && CsrFlagTest(pCsr, FTS5CSR_REQUIRE_CONTENT) ){
+ Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
assert( pCsr->pExpr );
sqlite3_reset(pCsr->pStmt);
sqlite3_bind_int64(pCsr->pStmt, 1, fts5CursorRowid(pCsr));
+ pTab->pConfig->bLock++;
rc = sqlite3_step(pCsr->pStmt);
+ pTab->pConfig->bLock--;
if( rc==SQLITE_ROW ){
rc = SQLITE_OK;
CsrFlagClear(pCsr, FTS5CSR_REQUIRE_CONTENT);
@@ -1418,6 +1441,10 @@ static int fts5SeekCursor(Fts5Cursor *pCsr, int bErrormsg){
rc = sqlite3_reset(pCsr->pStmt);
if( rc==SQLITE_OK ){
rc = FTS5_CORRUPT;
+ }else if( pTab->pConfig->pzErrmsg ){
+ *pTab->pConfig->pzErrmsg = sqlite3_mprintf(
+ "%s", sqlite3_errmsg(pTab->pConfig->db)
+ );
}
}
}
@@ -2433,10 +2460,12 @@ static int fts5ColumnMethod(
}
}
}else if( !fts5IsContentless(pTab) ){
+ pConfig->pzErrmsg = &pTab->p.base.zErrMsg;
rc = fts5SeekCursor(pCsr, 1);
if( rc==SQLITE_OK ){
sqlite3_result_value(pCtx, sqlite3_column_value(pCsr->pStmt, iCol+1));
}
+ pConfig->pzErrmsg = 0;
}
return rc;
}
diff --git a/ext/fts5/fts5_storage.c b/ext/fts5/fts5_storage.c
index 960c1805c3..22f90c0ef8 100644
--- a/ext/fts5/fts5_storage.c
+++ b/ext/fts5/fts5_storage.c
@@ -560,6 +560,8 @@ int sqlite3Fts5StorageDeleteAll(Fts5Storage *p){
Fts5Config *pConfig = p->pConfig;
int rc;
+ p->bTotalsValid = 0;
+
/* Delete the contents of the %_data and %_docsize tables. */
rc = fts5ExecPrintf(pConfig->db, 0,
"DELETE FROM %Q.'%q_data';"
@@ -611,10 +613,11 @@ int sqlite3Fts5StorageRebuild(Fts5Storage *p){
for(ctx.iCol=0; rc==SQLITE_OK && ctx.iColnCol; ctx.iCol++){
ctx.szCol = 0;
if( pConfig->abUnindexed[ctx.iCol]==0 ){
+ const char *zText = (const char*)sqlite3_column_text(pScan, ctx.iCol+1);
+ int nText = sqlite3_column_bytes(pScan, ctx.iCol+1);
rc = sqlite3Fts5Tokenize(pConfig,
FTS5_TOKENIZE_DOCUMENT,
- (const char*)sqlite3_column_text(pScan, ctx.iCol+1),
- sqlite3_column_bytes(pScan, ctx.iCol+1),
+ zText, nText,
(void*)&ctx,
fts5StorageInsertCallback
);
@@ -736,10 +739,11 @@ int sqlite3Fts5StorageIndexInsert(
for(ctx.iCol=0; rc==SQLITE_OK && ctx.iColnCol; ctx.iCol++){
ctx.szCol = 0;
if( pConfig->abUnindexed[ctx.iCol]==0 ){
+ const char *zText = (const char*)sqlite3_value_text(apVal[ctx.iCol+2]);
+ int nText = sqlite3_value_bytes(apVal[ctx.iCol+2]);
rc = sqlite3Fts5Tokenize(pConfig,
FTS5_TOKENIZE_DOCUMENT,
- (const char*)sqlite3_value_text(apVal[ctx.iCol+2]),
- sqlite3_value_bytes(apVal[ctx.iCol+2]),
+ zText, nText,
(void*)&ctx,
fts5StorageInsertCallback
);
@@ -908,10 +912,11 @@ int sqlite3Fts5StorageIntegrity(Fts5Storage *p){
rc = sqlite3Fts5TermsetNew(&ctx.pTermset);
}
if( rc==SQLITE_OK ){
+ const char *zText = (const char*)sqlite3_column_text(pScan, i+1);
+ int nText = sqlite3_column_bytes(pScan, i+1);
rc = sqlite3Fts5Tokenize(pConfig,
FTS5_TOKENIZE_DOCUMENT,
- (const char*)sqlite3_column_text(pScan, i+1),
- sqlite3_column_bytes(pScan, i+1),
+ zText, nText,
(void*)&ctx,
fts5StorageIntegrityCallback
);
diff --git a/ext/fts5/test/fts5content.test b/ext/fts5/test/fts5content.test
index bd510a552d..74a74e2ad0 100644
--- a/ext/fts5/test/fts5content.test
+++ b/ext/fts5/test/fts5content.test
@@ -257,16 +257,41 @@ do_execsql_test 6.2 {
# Check that an fts5 table cannot be its own content table.
#
reset_db
-do_execsql_test 7.1 {
+do_execsql_test 7.1.1 {
CREATE VIRTUAL TABLE t1 USING fts5(a, c=t1 );
INSERT INTO t1( a ) VALUES('abc');
}
-do_catchsql_test 7.2 {
+do_catchsql_test 7.1.2 {
SELECT * FROM t1;
} {1 {recursively defined fts5 content table}}
-do_catchsql_test 7.3 {
+do_catchsql_test 7.1.3 {
SELECT * FROM t1('abc');
} {1 {recursively defined fts5 content table}}
+do_catchsql_test 7.1.4 {
+ SELECT count(*) FROM t1;
+} {1 {recursively defined fts5 content table}}
+do_catchsql_test 7.1.5 {
+ SELECT * FROM t1('abc') ORDER BY rank;
+} {1 {recursively defined fts5 content table}}
+
+reset_db
+do_execsql_test 7.2.1 {
+ CREATE VIRTUAL TABLE t1 USING fts5(a, c=t2 );
+ CREATE VIRTUAL TABLE t2 USING fts5(a, c=t1 );
+ INSERT INTO t1( a ) VALUES('abc');
+}
+do_catchsql_test 7.2.2 {
+ SELECT * FROM t1;
+} {1 {recursively defined fts5 content table}}
+do_catchsql_test 7.2.3 {
+ SELECT * FROM t1('abc');
+} {1 {recursively defined fts5 content table}}
+do_catchsql_test 7.2.4 {
+ SELECT count(*) FROM t1;
+} {1 {recursively defined fts5 content table}}
+do_catchsql_test 7.2.5 {
+ SELECT * FROM t1('abc') ORDER BY rank;
+} {1 {recursively defined fts5 content table}}
finish_test
diff --git a/ext/fts5/test/fts5corrupt3.test b/ext/fts5/test/fts5corrupt3.test
index bab61e80c8..4e0ae64a9a 100644
--- a/ext/fts5/test/fts5corrupt3.test
+++ b/ext/fts5/test/fts5corrupt3.test
@@ -4484,7 +4484,7 @@ do_test 36.0 {
do_catchsql_test 36.1 {
INSERT INTO t1(b) VALUES(
x'78de3fa24af3733ca8769291a0fee3669f9fddefc5cba913e4225d4b6ce2b04f26b87fad3ee6f9b7d90a1ea62a169bf41e5d32707a6ca5c3d05e4bde05c9d89eaaa8c50e74333d2e9fcd7dfe95528a3a016aac1102d825c5cd70cf99d8a88e0ea7f798d4334386518b7ad359beb168b93aba059a2a3bd93112d65b44c12b9904ea786b204d80531cdf0504bf9b203dbe927061974caf7b9f30cbc3397b61f802e732012a6663d41c3607d6f1c0dbcfd489adac05ca500c0b04439d894cd93a840159225ef73b627e178b9f84b3ffe66cf22a963a8368813ff7961fc47f573211ccec95e0220dcbb3bf429f4a50ba54d7a53784ac51bfef346e6a');
-} {1 {database disk image is malformed}}
+} {0 {}}
#-------------------------------------------------------------------------
reset_db
@@ -9774,6 +9774,339 @@ do_catchsql_test 66.1 {
INSERT INTO t1(t1) VALUES('integrity-check');
} {1 {database disk image is malformed}}
+#-------------------------------------------------------------------------
+#
+reset_db
+do_test 67.0 {
+ sqlite3 db {}
+ db deserialize [decode_hexdb {
+.open --hexdb
+| size 24576 pagesize 4096 filename crash-43ed0ad79c0194.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 00 00 00 06 0d e2 00 0f c4 0f 6a ...............j
+| 112: 0e fc 0e 9d 0e 3d 0d e2 01 00 00 00 00 00 00 00 .....=..........
+| 3552: 00 00 59 06 06 17 21 21 01 7f 74 61 62 6c 65 74 ..Y...!!..tablet
+| 3568: 74 74 5f 63 6f 6e 66 69 67 74 74 74 5f 63 6f 6e tt_configttt_con
+| 3584: 66 69 67 06 43 52 45 41 54 45 20 54 41 42 4c 45 fig.CREATE TABLE
+| 3600: 20 27 74 74 74 5f 63 6f 6e 66 69 67 27 28 6b 20 'ttt_config'(k
+| 3616: 50 52 49 4d 41 52 59 20 4b 45 59 2c 20 76 29 20 PRIMARY KEY, v)
+| 3632: 57 49 54 48 4f 55 54 20 52 4f 57 49 44 5e 05 07 WITHOUT ROWID^..
+| 3648: 17 23 23 01 81 03 74 61 62 6c 65 74 74 74 5f 64 .##...tablettt_d
+| 3664: 6f 63 73 69 7a 65 74 74 74 5f 64 6f 63 73 69 7a ocsizettt_docsiz
+| 3680: 65 05 43 52 45 41 54 45 20 54 41 42 4c 45 20 27 e.CREATE TABLE '
+| 3696: 74 74 74 5f 64 6f 63 73 69 7a 65 27 28 69 64 20 ttt_docsize'(id
+| 3712: 49 4e 54 45 47 45 52 20 51 52 49 4d 41 52 59 20 INTEGER QRIMARY
+| 3728: 4b 45 59 2c 20 73 7a 20 42 4c 4f 42 29 5d 04 07 KEY, sz BLOB)]..
+| 3744: 17 23 23 01 81 01 74 61 62 6c 65 74 74 74 5f 63 .##...tablettt_c
+| 3760: 6f 6e 74 65 6e 74 74 74 74 5f 63 6f 6e 74 65 6e ontentttt_conten
+| 3776: 74 04 43 52 45 41 54 45 20 54 41 42 4c 45 20 27 t.CREATE TABLE '
+| 3792: 74 74 74 5f 63 6f 6e 74 65 6e 74 27 28 69 64 20 ttt_content'(id
+| 3808: 49 4e 54 45 47 45 52 20 50 52 49 4d 41 f1 59 20 INTEGER PRIMA.Y
+| 3824: 4b 45 59 2c 20 63 30 2c 20 63 31 29 6c 03 07 17 KEY, c0, c1)l...
+| 3840: 1b 1b 01 81 2f 74 61 62 6c 65 74 74 74 5f 69 64 ..../tablettt_id
+| 3856: 78 74 74 74 5f 69 64 78 03 43 52 45 41 54 45 20 xttt_idx.CREATE
+| 3872: 54 41 42 4c 45 20 27 74 74 74 5f 69 64 78 27 28 TABLE 'ttt_idx'(
+| 3888: 73 65 67 69 64 2c 20 74 65 72 6d 2c 20 70 67 6e segid, term, pgn
+| 3904: 6f 2c 20 50 52 49 4d 41 52 59 20 4b 45 59 28 73 o, PRIMARY KEY(s
+| 3920: 65 67 69 64 2c 20 74 65 72 6d 29 29 20 57 49 54 egid, term)) WIT
+| 3936: 48 4f 55 54 20 52 4f 57 49 44 58 02 07 17 1d 1d HOUT ROWIDX.....
+| 3952: 01 81 03 74 61 62 6c 65 74 74 74 5f 64 61 74 61 ...tablettt_data
+| 3968: 74 74 74 5f 64 61 74 61 02 43 52 45 41 54 45 20 ttt_data.CREATE
+| 3984: 54 41 42 4c 45 20 27 74 74 74 5f 64 61 74 61 27 TABLE 'ttt_data'
+| 4000: 28 69 64 20 49 4e 54 45 47 55 52 20 50 52 49 4d (id INTEGUR PRIM
+| 4016: 41 52 59 20 4b 45 59 2c 20 62 6c 6f 63 6b 20 42 ARY KEY, block B
+| 4032: 4c 50 42 29 3a 02 06 17 13 13 08 5f 74 61 62 6c LPB):......_tabl
+| 4048: 65 74 74 74 74 74 74 43 52 45 41 54 45 20 56 49 ettttttCREATE VI
+| 4064: 52 54 55 41 4c 20 54 41 42 4c 45 20 74 74 74 20 RTUAL TABLE ttt
+| 4080: 55 53 49 4e 47 20 66 74 73 35 28 61 2c 20 62 29 USING fts5(a, b)
+| page 2 offset 4096
+| 0: 0d 0f 44 00 05 0e 71 00 0f e7 0e 81 0f af 0f 58 ..D...q........X
+| 16: 0e 98 01 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+| 3712: 00 15 0a 03 00 30 00 00 00 00 01 03 03 00 03 01 .....0..........
+| 3728: 01 01 02 01 01 03 01 01 81 24 8c 80 80 80 80 01 .........$......
+| 3744: 04 00 82 4c 00 00 00 9b 02 30 65 03 1a 12 05 05 ...L.....0e.....
+| 3760: 07 05 01 01 04 03 03 08 04 03 01 2e 02 05 f7 07 ................
+| 3776: 01 e6 f5 07 05 01 01 04 03 03 01 22 03 18 03 03 ................
+| 3792: 08 03 03 02 01 65 03 1e 03 05 05 04 05 05 01 01 .....e..........
+| 3808: 03 06 03 f4 06 04 03 00 36 03 ff 05 04 05 05 04 ........6.......
+| 3824: 05 05 04 05 04 f1 01 03 06 04 04 06 04 04 06 04 ................
+| 3840: 04 07 04 03 03 01 65 03 14 04 05 07 05 05 01 01 ......e.........
+| 3856: 02 08 a5 01 20 04 05 01 94 f7 05 07 05 05 01 01 .... ...........
+| 3872: 02 08 0a 0a 0a 04 01 65 03 02 0a 00 06 0a 0a 0a .......e........
+| 3888: 05 01 65 03 06 a7 01 0a 01 0a 01 01 0a 0a 0a 04 ..e.............
+| 3904: 2b 31 21 0b 0f ef 00 14 2a 00 00 00 00 01 02 02 +1!.....*.......
+| 3920: 00 02 01 01 01 02 11 01 50 88 80 80 80 80 01 04 ........P.......
+| 3936: 00 81 24 00 00 00 47 02 30 65 02 1a 02 05 05 07 ..$...G.0e......
+| 3952: 05 e6 01 07 aa e3 08 03 03 02 01 65 02 1e 03 05 ...........e....
+| 3968: 05 05 04 f5 01 01 03 06 04 04 06 04 13 03 01 65 ...............e
+| 3984: 02 14 04 05 07 05 05 01 f7 f2 08 0a 04 01 65 02 ..............e.
+| 4000: 02 0a 05 01 65 02 06 00 f1 0a 04 12 14 0f 06 31 ....e..........1
+| 4016: 84 80 80 80 80 01 03 00 68 00 00 00 2b 02 30 65 ........h...+.0e
+| 4032: 01 10 02 05 05 00 01 04 03 03 02 01 65 01 12 03 ............e...
+| 4048: 05 05 01 01 03 06 04 03 03 01 65 01 0e 04 05 04 ..........e.....
+| 4064: 01 01 02 08 04 0d 0e 06 01 03 00 12 04 4c 4c 00 .............LL.
+| 4080: 00 00 11 24 00 00 00 00 01 01 01 00 01 01 01 02 ...$............
+| page 3 offset 8192
+| 0: 0a 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+| page 4 offset 12288
+| 3600: 00 00 00 00 00 00 00 00 00 00 81 52 04 06 00 81 ...........R....
+| 3616: 5d 81 55 65 20 65 65 20 65 65 65 20 65 20 65 65 ].Ue ee eee e ee
+| 3632: 20 65 65 65 28 15 20 65 65 20 65 65 65 65 20 65 eee(. ee eeee e
+| 3648: 65 20 65 65 65 20 65 20 65 65 20 65 65 65 20 65 e eee e ee eee e
+| 3664: 20 65 65 20 65 65 65 65 20 65 66 20 65 65 55 20 ee eeee ef eeU
+| 3680: 65 20 65 55 20 65 65 65 20 65 20 65 65 20 65 65 e eU eee e ee ee
+| 3696: 65 64 20 65 61 c0 65 65 65 20 65 20 65 65 20 65 ed ea.eee e ee e
+| 3712: 65 65 20 79 20 65 65 20 65 65 65 65 65 65 20 65 ee y ee eeeeee e
+| 3728: 65 1f 65 20 65 20 65 20 65 65 20 65 65 65 20 65 e.e e e ee eee e
+| 3744: 65 20 65 65 65 65 65 20 65 65 20 65 20 65 20 65 e eeeee ee e e e
+| 3760: 20 65 65 20 65 65 65 20 6b 85 20 65 65 65 66 65 ee eee k. eeefe
+| 3776: 20 65 65 10 65 20 65 20 65 20 65 65 20 65 65 65 ee.e e e ee eee
+| 3792: 20 65 65 20 65 65 65 65 65 20 65 65 20 65 20 65 ee eeeee ee e e
+| 3808: 20 65 20 65 65 20 65 65 65 20 65 65 20 65 65 6a e ee eee ee eej
+| 3824: 03 04 00 75 71 65 20 65 65 20 65 65 65 20 65 30 ...uqe ee eee e0
+| 3840: 65 65 20 65 65 65 20 65 20 65 65 20 65 65 65 65 ee eee e ee eeee
+| 3856: 20 65 65 20 65 65 65 20 65 1f 65 65 20 65 65 65 ee eee e.ee eee
+| 3872: 20 65 20 65 65 20 65 65 65 65 65 66 20 65 65 20 e ee eeeeef ee
+| 3888: 65 21 27 20 65 20 55 65 20 66 65 64 20 65 65 00 e!' e Ue fed ee.
+| page 5 offset 16384
+| 4064: 00 00 00 00 05 04 03 00 10 11 20 05 03 03 00 10 .......... .....
+| 4080: 11 11 05 02 03 00 00 11 11 05 01 03 00 10 09 09 ................
+| page 6 offset 20480
+| 0: 0a 00 00 00 01 0f f4 00 0f f4 00 01 00 00 00 00 ................
+| 4080: 00 00 00 00 0b 03 1b 01 76 65 72 73 69 6f 6e 04 ........version.
+| end crash-43ed0ad79c0194.db
+}]} {}
+
+do_catchsql_test 67.1 {
+ SELECT snippet(ttt, null,null,
+ EXISTS(SELECT 1 FROM ttt('e NuOT ee*e*ÏNuOY ee*') ) , '',
+ (SELECT 1 FROM ttt('eu NuOT ee*e* NuOY ee*'))
+ ), * FROM ttt('e')
+} {1 {database disk image is malformed}}
+
+#-------------------------------------------------------------------------
+#
+reset_db
+do_test 68.0 {
+ sqlite3 db {}
+ db deserialize [decode_hexdb {
+.open --hexdb
+| size 32768 pagesize 4096 filename crash-41234e232809e7.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 01 00 00 00 09 00 00 00 04 ................
+| 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 0d 92 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 30 2c 20 63 31 2c 20 63 32 29 69 04 07 17 19 c0, 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 ................
+| 16: 00 00 00 00 01 00 00 00 00 00 00 00 00 00 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 00 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 03 f1 06 62 69 6e 62 72 79 03 06 ........binbry..
+| 3328: 01 02 02 03 06 01 02 02 03 06 01 02 01 03 16 01 ................
+| 3344: 02 02 03 06 01 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 04 71 02 02 03 06 11 02 02 01 08 63 6f 6d 70 ..q.........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 03 02 ................
+| 3472: 00 02 02 01 02 02 01 02 02 01 02 02 01 02 02 01 ................
+| 3488: 02 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 0a 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 66 63 63 01 02 03 01 02 03 01 02 03 ....fcc.........
+| 3568: 02 06 65 6f 70 6f 6c 79 10 02 03 01 02 03 01 02 ..eopoly........
+| 3584: 03 01 05 6a 73 6f 5e 31 13 02 03 01 02 03 01 02 ...jso^1........
+| 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 13 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 02 ...omit.........
+| 3744: 01 05 72 74 72 65 65 19 02 03 01 02 03 01 02 03 ..rtree.........
+| 3760: 04 02 69 6d 01 06 01 02 02 03 06 01 12 02 03 06 ..im............
+| 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 01 02 01 06 01 01 02 01 06 01 01 02 ................
+| 3888: 01 06 01 01 02 01 06 01 01 02 01 05 f1 01 02 01 ................
+| 3904: 06 01 01 02 01 06 01 5b 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: 01 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 0c 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 0b 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 35 0d 1b 0c fb .......h.O.5....
+| 64: 0c da 0c b9 0c 99 0c 78 0c 57 0c 3e 0c 24 0c 0a .......x.W.>.$..
+| 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: 4f 41 52 59 18 23 05 00 25 0f 19 54 48 52 45 41 OARY.#..%..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 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 44 20 45 58 54 45 4e 53 OMIT LOAD EXTENS
+| 3248: 49 4f 4e 58 52 54 52 49 4d 1f 1e 05 00 33 0f 19 IONXRTRIM....3..
+| 3264: 4d 41 58 20 4d 45 4d 4f 52 59 3d 35 30 30 30 30 MAX 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 4f 52 59 3d 35 30 30 ..MAX MEMORY=500
+| 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 46 45 58 4e 4f 43 41 53 45 17 LE RTRFEXNOCASE.
+| 3408: 19 05 00 25 0f 17 45 4e 41 42 4c 45 20 52 54 52 ...%..ENABLE RTR
+| 3424: 45 45 58 52 54 52 49 4d 1a 18 05 00 29 0f 19 45 EEXRTRIM....)..E
+| 3440: 49 41 42 4c 45 20 4d 45 4d 53 59 53 35 58 42 49 IABLE MEMSYS5XBI
+| 3456: 4e 41 52 59 1a 17 05 00 29 0f 19 45 4e 41 42 4c NARY....)..ENABL
+| 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 1a 12 05 00 29 0f 19 45 N1XRTRIM....)..E
+| 3600: 4e 41 42 4c 45 20 47 45 4f 50 4f 4c 59 57 42 49 NABLE GEOPOLYWBI
+| 3616: 4e 41 52 59 1a 11 05 00 29 0f 19 45 4e 41 42 4c NARY....)..ENABL
+| 3632: 45 20 47 45 4f 50 4f 4c 59 58 4e 4f 42 41 53 45 E GEOPOLYXNOBASE
+| 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 4c NARY....#..ENABL
+| 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: 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 17 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 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 b7 4e 41 42 4c 45 20 44 42 53 ...1...NABLE DBS
+| 3904: 54 41 54 20 66 54 41 42 58 52 54 52 49 4d 11 06 TAT fTABXRTRIM..
+| 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 04 05 00 17 0f 17 44 45 42 55 47 CASE.......DEBUG
+| 3968: 58 62 54 52 49 4d 27 03 05 00 43 0f 19 43 4f 4d XbTRIM'...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 52 02 4a 4e 41 52 59 27 20160609R.JNARY'
+| 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 0f 17 43 9XNOCASE&...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 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 0f 30 0f 28 0f 20 .X.P.H.@.8.0.(.
+| 64: 0f 18 0f 10 0f 08 0f 00 0e f8 0e f0 0e e8 0e e0 ................
+| 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 0f 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 03 0f d6 00 0f f4 0f e9 0f d6 00 00 ................
+| 4048: 00 00 00 00 00 00 11 04 02 2b 69 6e 74 65 67 72 .........+integr
+| 4064: 69 74 79 2d 63 68 65 63 6b 09 02 02 1b 72 65 62 ity-check....reb
+| 4080: 75 69 6c 64 0a 01 02 1d 6f 70 74 69 5d 69 71 a5 uild....opti]iq.
+| end crash-41234e232809e7.db
+.testctrl prng_seed 1 db
+}]} {}
+
+do_catchsql_test 68.1 {
+ PRAGMA reverse_unordered_selects=ON;
+ INSERT INTO t1(t1) SELECT x FROM t2;
+} {1 {database disk image is malformed}}
sqlite3_fts5_may_be_corrupt 0
diff --git a/ext/fts5/test/fts5eb.test b/ext/fts5/test/fts5eb.test
index dd66decb9b..9d6f251ed1 100644
--- a/ext/fts5/test/fts5eb.test
+++ b/ext/fts5/test/fts5eb.test
@@ -59,10 +59,27 @@ do_catchsql_test 2.1 {
SELECT fts5_expr()
} {1 {wrong number of arguments to function fts5_expr}}
-do_catchsql_test 2.1 {
+do_catchsql_test 2.2 {
SELECT fts5_expr_tcl()
} {1 {wrong number of arguments to function fts5_expr_tcl}}
+do_catchsql_test 2.3 {
+ SELECT fts5_expr('')
+} {1 {fts5: syntax error near ""}}
+
+do_catchsql_test 2.4 {
+ SELECT fts5_expr(NULL)
+} {1 {fts5: syntax error near ""}}
+
+do_catchsql_test 2.5 {
+ SELECT fts5_expr(NULL, NULL)
+} {1 {parse error in ""}}
+
+for {set i 0} {$i < 255} {incr i} {
+ do_test 2.6.$i {
+ lindex [catchsql {sELECT fts5_expr(NULL, char($i));}] 0
+ } 1
+}
do_execsql_test 3.0 {
CREATE VIRTUAL TABLE e1 USING fts5(text, tokenize = 'porter unicode61');
diff --git a/ext/fts5/test/fts5full.test b/ext/fts5/test/fts5full.test
index 91ded37d8f..751e874c3b 100644
--- a/ext/fts5/test/fts5full.test
+++ b/ext/fts5/test/fts5full.test
@@ -36,7 +36,7 @@ do_test 1.1 {
execsql { INSERT INTO x8 VALUES( rnddoc(5) ); }
}
} msg] $msg
-} {1 {database or disk is full}}
+} {0 {}}
finish_test
diff --git a/ext/fts5/test/fts5integrity.test b/ext/fts5/test/fts5integrity.test
index 25c7277305..38dff21f79 100644
--- a/ext/fts5/test/fts5integrity.test
+++ b/ext/fts5/test/fts5integrity.test
@@ -210,4 +210,76 @@ foreach {tn pgsz} {
} {1000}
}
+#-------------------------------------------------------------------------
+#
+reset_db
+do_execsql_test 7.0 {
+ PRAGMA encoding = 'UTF-16';
+ CREATE VIRTUAL TABLE vt0 USING fts5(c0);
+ INSERT INTO vt0 VALUES (x'46f0');
+ SELECT quote(c0) FROM vt0;
+} {X'46F0'}
+do_execsql_test 7.1 {
+ INSERT INTO vt0(vt0) VALUES('integrity-check');
+}
+do_execsql_test 7.2 {
+ INSERT INTO vt0(vt0) VALUES('rebuild');
+}
+do_execsql_test 7.3 {
+ INSERT INTO vt0(vt0) VALUES('integrity-check');
+}
+do_execsql_test 7.4 {
+ UPDATE vt0 SET c0='';
+}
+do_execsql_test 7.5 {
+ INSERT INTO vt0(vt0) VALUES('integrity-check');
+}
+
+#-------------------------------------------------------------------------
+# Ticket 7a458c2a5f4
+#
+reset_db
+do_execsql_test 8.0 {
+ PRAGMA locking_mode = EXCLUSIVE;
+ PRAGMA journal_mode = PERSIST;
+ CREATE VIRTUAL TABLE vt0 USING fts5(c0);
+} {exclusive persist}
+do_execsql_test 8.1 {
+ PRAGMA data_version
+} {1}
+do_execsql_test 8.2 {
+ INSERT INTO vt0(vt0) VALUES('integrity-check');
+ PRAGMA data_version;
+} {1}
+do_execsql_test 8.1 {
+ INSERT INTO vt0(vt0, rank) VALUES('usermerge', 2);
+}
+
+#-------------------------------------------------------------------------
+# Ticket [771fe617]
+#
+reset_db
+do_execsql_test 9.0 {
+ PRAGMA encoding = 'UTF16';
+ CREATE VIRTUAL TABLE vt0 USING fts5(c0);
+}
+
+#explain_i { SELECT quote(SUBSTR(x'37', 0)); }
+#execsql { PRAGMA vdbe_trace = 1 }
+do_execsql_test 9.1.1 {
+ SELECT quote(SUBSTR(x'37', 0));
+} {X'37'}
+do_execsql_test 9.1.2 {
+ SELECT quote(x'37');
+} {X'37'}
+
+breakpoint
+do_execsql_test 9.2 {
+ INSERT INTO vt0 VALUES (SUBSTR(x'37', 0));
+-- INSERT INTO vt0 VALUES (x'37');
+}
+do_execsql_test 9.3 {
+ INSERT INTO vt0(vt0) VALUES('integrity-check');
+}
+
finish_test
diff --git a/ext/fts5/test/fts5matchinfo.test b/ext/fts5/test/fts5matchinfo.test
index 4dc04b7897..d8d8d84e79 100644
--- a/ext/fts5/test/fts5matchinfo.test
+++ b/ext/fts5/test/fts5matchinfo.test
@@ -491,4 +491,30 @@ do_catchsql_test 14.2 {
SELECT matchinfo(x1, 'd') FROM x1('a b c');
} {1 {unrecognized matchinfo flag: d}}
+#-------------------------------------------------------------------------
+# Test using matchinfo() and similar on a non-full-text query
+#
+do_execsql_test 15.0 {
+ CREATE VIRTUAL TABLE t1 USING fts5(x, y);
+ INSERT INTO t1 VALUES('a', 'b');
+ INSERT INTO t1 VALUES('c', 'd');
+}
+
+do_execsql_test 15.1 {
+ SELECT quote(matchinfo(t1, 'n')) FROM t1 LIMIT 1;
+} {X'02000000'}
+
+do_execsql_test 15.2 {
+ DELETE FROM t1_content WHERE rowid=1;
+ SELECT quote(matchinfo(t1, 'n')) FROM t1 LIMIT 1;
+} {X'02000000'}
+
+fts5_aux_test_functions db
+do_execsql_test 15.3 {
+ SELECT fts5_test_all(t1) FROM t1 LIMIT 1;
+} {
+ {columnsize {0 0} columntext {c d} columntotalsize {2 2} poslist {} tokenize {c d} rowcount 2}
+}
+
finish_test
+
diff --git a/ext/fts5/test/fts5misc.test b/ext/fts5/test/fts5misc.test
index 009f578dce..9abc92b23f 100644
--- a/ext/fts5/test/fts5misc.test
+++ b/ext/fts5/test/fts5misc.test
@@ -59,5 +59,269 @@ do_catchsql_test 1.3.3 {
WHERE rank = (SELECT highlight(t1, 4, '', '') FROM t1('*reads'));
} {1 {no such cursor: 1}}
+#-------------------------------------------------------------------------
+reset_db
+do_execsql_test 2.0 {
+ CREATE TABLE t0(c0);
+ CREATE VIRTUAL TABLE vt0 USING fts5(c0);
+}
+do_execsql_test 2.1.1 {
+ BEGIN TRANSACTION;
+ INSERT INTO vt0(c0) VALUES ('xyz');
+}
+do_execsql_test 2.1.2 {
+ ALTER TABLE t0 ADD COLUMN c5;
+}
+do_execsql_test 2.1.3 {
+ INSERT INTO vt0(vt0) VALUES('integrity-check');
+}
+do_execsql_test 2.1.4 {
+ INSERT INTO vt0(c0) VALUES ('abc');
+ COMMIT
+}
+do_execsql_test 2.1.5 {
+ INSERT INTO vt0(vt0) VALUES('integrity-check');
+}
+
+reset_db
+do_execsql_test 2.2.1 {
+ CREATE TABLE t0(c0);
+ CREATE VIRTUAL TABLE vt0 USING fts5(c0);
+ BEGIN TRANSACTION;
+ INSERT INTO vt0(c0) VALUES ('xyz');
+}
+
+breakpoint
+do_execsql_test 2.2.2 {
+ ALTER TABLE t0 RENAME TO t1;
+}
+do_execsql_test 2.2.3 {
+ INSERT INTO vt0(vt0) VALUES('integrity-check');
+}
+do_execsql_test 2.2.4 {
+ INSERT INTO vt0(c0) VALUES ('abc');
+ COMMIT;
+}
+do_execsql_test 2.2.5 {
+ INSERT INTO vt0(vt0) VALUES('integrity-check');
+}
+
+#-------------------------------------------------------------------------
+reset_db
+do_execsql_test 3.0 {
+ CREATE VIRTUAL TABLE vt0 USING fts5(a);
+ PRAGMA reverse_unordered_selects = true;
+ INSERT INTO vt0 VALUES('365062398'), (0), (0);
+ INSERT INTO vt0(vt0, rank) VALUES('pgsz', '38');
+}
+do_execsql_test 3.1 {
+ UPDATE vt0 SET a = 399905135; -- unexpected: database disk image is malformed
+}
+do_execsql_test 3.2 {
+ INSERT INTO vt0(vt0) VALUES('integrity-check');
+}
+
+#-------------------------------------------------------------------------
+reset_db
+do_execsql_test 4.0 {
+ CREATE VIRTUAL TABLE vt0 USING fts5(c0);
+ INSERT INTO vt0(c0) VALUES ('xyz');
+}
+
+do_execsql_test 4.1 {
+ BEGIN;
+ INSERT INTO vt0(c0) VALUES ('abc');
+ INSERT INTO vt0(vt0) VALUES('rebuild');
+ COMMIT;
+}
+
+do_execsql_test 4.2 {
+ INSERT INTO vt0(vt0) VALUES('integrity-check');
+}
+
+do_execsql_test 4.3 {
+ BEGIN;
+ INSERT INTO vt0(vt0) VALUES('rebuild');
+ INSERT INTO vt0(vt0) VALUES('rebuild');
+ COMMIT;
+}
+
+do_execsql_test 4.4 {
+ INSERT INTO vt0(vt0) VALUES('integrity-check');
+}
+
+#-------------------------------------------------------------------------
+# Ticket [81a7f7b9].
+#
+reset_db
+do_execsql_test 5.0 {
+ CREATE VIRTUAL TABLE vt0 USING fts5(c0, c1);
+ INSERT INTO vt0(vt0, rank) VALUES('pgsz', '65536');
+ WITH s(i) AS (
+ SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<1236
+ )
+ INSERT INTO vt0(c0) SELECT '0' FROM s;
+} {}
+
+do_execsql_test 5.1 {
+ UPDATE vt0 SET c1 = 'T,D&p^y/7#3*v='0' && h<='9') || (h>='a' && h<='f') || (h>='A' && h<='F') );
+#ifdef SQLITE_EBCDIC
+ h += 9*(1&~(h>>4));
+#else
+ h += 9*(1&(h>>6));
+#endif
+ return (u8)(h & 0xf);
+}
+
+/*
+** Convert a 4-byte hex string into an integer
+*/
+static u32 jsonHexToInt4(const char *z){
+ u32 v;
+ assert( safe_isxdigit(z[0]) );
+ assert( safe_isxdigit(z[1]) );
+ assert( safe_isxdigit(z[2]) );
+ assert( safe_isxdigit(z[3]) );
+ v = (jsonHexToInt(z[0])<<12)
+ + (jsonHexToInt(z[1])<<8)
+ + (jsonHexToInt(z[2])<<4)
+ + jsonHexToInt(z[3]);
+ return v;
+}
+
/*
** Make the JsonNode the return value of the function.
*/
@@ -615,15 +646,8 @@ static void jsonReturn(
}else{
c = z[++i];
if( c=='u' ){
- u32 v = 0, k;
- for(k=0; k<4; i++, k++){
- assert( i>6));
zOut[j++] = 0x80 | (v&0x3f);
}else{
- zOut[j++] = (char)(0xe0 | (v>>12));
- zOut[j++] = 0x80 | ((v>>6)&0x3f);
- zOut[j++] = 0x80 | (v&0x3f);
+ u32 vlo;
+ if( (v&0xfc00)==0xd800
+ && i>18);
+ zOut[j++] = 0x80 | ((v>>12)&0x3f);
+ zOut[j++] = 0x80 | ((v>>6)&0x3f);
+ zOut[j++] = 0x80 | (v&0x3f);
+ }else{
+ zOut[j++] = 0xe0 | (v>>12);
+ zOut[j++] = 0x80 | ((v>>6)&0x3f);
+ zOut[j++] = 0x80 | (v&0x3f);
+ }
}
}else{
if( c=='b' ){
@@ -1136,18 +1176,49 @@ static JsonNode *jsonLookupStep(
}
return pNode;
}
- }else if( zPath[0]=='[' && safe_isdigit(zPath[1]) ){
- if( pRoot->eType!=JSON_ARRAY ) return 0;
+ }else if( zPath[0]=='[' ){
i = 0;
j = 1;
while( safe_isdigit(zPath[j]) ){
i = i*10 + zPath[j] - '0';
j++;
}
- if( zPath[j]!=']' ){
- *pzErr = zPath;
- return 0;
+ if( j<2 || zPath[j]!=']' ){
+ if( zPath[1]=='#' ){
+ JsonNode *pBase = pRoot;
+ int iBase = iRoot;
+ if( pRoot->eType!=JSON_ARRAY ) return 0;
+ for(;;){
+ while( j<=pBase->n ){
+ if( (pBase[j].jnFlags & JNODE_REMOVE)==0 ) i++;
+ j += jsonNodeSize(&pBase[j]);
+ }
+ if( (pBase->jnFlags & JNODE_APPEND)==0 ) break;
+ iBase += pBase->u.iAppend;
+ pBase = &pParse->aNode[iBase];
+ j = 1;
+ }
+ j = 2;
+ if( zPath[2]=='-' && safe_isdigit(zPath[3]) ){
+ unsigned int x = 0;
+ j = 3;
+ do{
+ x = x*10 + zPath[j] - '0';
+ j++;
+ }while( safe_isdigit(zPath[j]) );
+ if( x>i ) return 0;
+ i -= x;
+ }
+ if( zPath[j]!=']' ){
+ *pzErr = zPath;
+ return 0;
+ }
+ }else{
+ *pzErr = zPath;
+ return 0;
+ }
}
+ if( pRoot->eType!=JSON_ARRAY ) return 0;
zPath += j + 1;
j = 1;
for(;;){
@@ -2020,6 +2091,7 @@ static int jsonEachConnect(
pNew = *ppVtab = sqlite3_malloc( sizeof(*pNew) );
if( pNew==0 ) return SQLITE_NOMEM;
memset(pNew, 0, sizeof(*pNew));
+ sqlite3_vtab_config(db, SQLITE_VTAB_INNOCUOUS);
}
return rc;
}
@@ -2510,16 +2582,19 @@ int sqlite3Json1Init(sqlite3 *db){
{ "json_tree", &jsonTreeModule },
};
#endif
+ static const int enc =
+ SQLITE_UTF8 |
+ SQLITE_DETERMINISTIC |
+ SQLITE_INNOCUOUS;
for(i=0; i
+#include
+
+/*
+** Implementation of the noop() function.
+**
+** The function returns its argument, unchanged.
+*/
+static void noopfunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ assert( argc==1 );
+ sqlite3_result_value(context, argv[0]);
+}
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+int sqlite3_noop_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ int rc = SQLITE_OK;
+ SQLITE_EXTENSION_INIT2(pApi);
+ (void)pzErrMsg; /* Unused parameter */
+ rc = sqlite3_create_function(db, "noop", 1,
+ SQLITE_UTF8 | SQLITE_DETERMINISTIC,
+ 0, noopfunc, 0, 0);
+ if( rc ) return rc;
+ rc = sqlite3_create_function(db, "noop_i", 1,
+ SQLITE_UTF8 | SQLITE_DETERMINISTIC | SQLITE_INNOCUOUS,
+ 0, noopfunc, 0, 0);
+ if( rc ) return rc;
+ rc = sqlite3_create_function(db, "noop_do", 1,
+ SQLITE_UTF8 | SQLITE_DETERMINISTIC | SQLITE_DIRECTONLY,
+ 0, noopfunc, 0, 0);
+ if( rc ) return rc;
+ rc = sqlite3_create_function(db, "noop_nd", 1,
+ SQLITE_UTF8,
+ 0, noopfunc, 0, 0);
+ return rc;
+}
diff --git a/ext/misc/percentile.c b/ext/misc/percentile.c
index 88fc5a96ff..d83bc5b838 100644
--- a/ext/misc/percentile.c
+++ b/ext/misc/percentile.c
@@ -213,7 +213,8 @@ int sqlite3_percentile_init(
int rc = SQLITE_OK;
SQLITE_EXTENSION_INIT2(pApi);
(void)pzErrMsg; /* Unused parameter */
- rc = sqlite3_create_function(db, "percentile", 2, SQLITE_UTF8, 0,
+ rc = sqlite3_create_function(db, "percentile", 2,
+ SQLITE_UTF8|SQLITE_INNOCUOUS, 0,
0, percentStep, percentFinal);
return rc;
}
diff --git a/ext/misc/prefixes.c b/ext/misc/prefixes.c
index 3aa579b8d3..3f053b7f1c 100644
--- a/ext/misc/prefixes.c
+++ b/ext/misc/prefixes.c
@@ -79,6 +79,7 @@ static int prefixesConnect(
*ppVtab = (sqlite3_vtab*)pNew;
if( pNew==0 ) return SQLITE_NOMEM;
memset(pNew, 0, sizeof(*pNew));
+ sqlite3_vtab_config(db, SQLITE_VTAB_INNOCUOUS);
}
return rc;
}
diff --git a/ext/misc/regexp.c b/ext/misc/regexp.c
index 3359109ab3..03bbeb97d3 100644
--- a/ext/misc/regexp.c
+++ b/ext/misc/regexp.c
@@ -156,7 +156,7 @@ static unsigned re_next_char(ReInput *p){
&& (p->z[p->i+1]&0xc0)==0x80 ){
c = (c&0x0f)<<12 | ((p->z[p->i]&0x3f)<<6) | (p->z[p->i+1]&0x3f);
p->i += 2;
- if( c<=0x3ff || (c>=0xd800 && c<=0xdfff) ) c = 0xfffd;
+ if( c<=0x7ff || (c>=0xd800 && c<=0xdfff) ) c = 0xfffd;
}else if( (c&0xf8)==0xf0 && p->i+3mx && (p->z[p->i]&0xc0)==0x80
&& (p->z[p->i+1]&0xc0)==0x80 && (p->z[p->i+2]&0xc0)==0x80 ){
c = (c&0x07)<<18 | ((p->z[p->i]&0x3f)<<12) | ((p->z[p->i+1]&0x3f)<<6)
@@ -754,7 +754,7 @@ int sqlite3_regexp_init(
){
int rc = SQLITE_OK;
SQLITE_EXTENSION_INIT2(pApi);
- rc = sqlite3_create_function(db, "regexp", 2, SQLITE_UTF8, 0,
- re_sql_func, 0, 0);
+ rc = sqlite3_create_function(db, "regexp", 2, SQLITE_UTF8|SQLITE_INNOCUOUS,
+ 0, re_sql_func, 0, 0);
return rc;
}
diff --git a/ext/misc/rot13.c b/ext/misc/rot13.c
index 2e9dd21c60..05b4a18801 100644
--- a/ext/misc/rot13.c
+++ b/ext/misc/rot13.c
@@ -105,8 +105,9 @@ int sqlite3_rot_init(
int rc = SQLITE_OK;
SQLITE_EXTENSION_INIT2(pApi);
(void)pzErrMsg; /* Unused parameter */
- rc = sqlite3_create_function(db, "rot13", 1, SQLITE_UTF8, 0,
- rot13func, 0, 0);
+ rc = sqlite3_create_function(db, "rot13", 1,
+ SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_DETERMINISTIC,
+ 0, rot13func, 0, 0);
if( rc==SQLITE_OK ){
rc = sqlite3_create_collation(db, "rot13", SQLITE_UTF8, 0, rot13CollFunc);
}
diff --git a/ext/misc/series.c b/ext/misc/series.c
index 86309dd7be..d24959001f 100644
--- a/ext/misc/series.c
+++ b/ext/misc/series.c
@@ -126,6 +126,7 @@ static int seriesConnect(
pNew = *ppVtab = sqlite3_malloc( sizeof(*pNew) );
if( pNew==0 ) return SQLITE_NOMEM;
memset(pNew, 0, sizeof(*pNew));
+ sqlite3_vtab_config(db, SQLITE_INNOCUOUS);
}
return rc;
}
diff --git a/ext/misc/sha1.c b/ext/misc/sha1.c
index 886b1db7bd..0050fdfbdc 100644
--- a/ext/misc/sha1.c
+++ b/ext/misc/sha1.c
@@ -39,25 +39,9 @@ struct SHA1Context {
unsigned char buffer[64];
};
-
-#if __GNUC__ && (defined(__i386__) || defined(__x86_64__))
-/*
- * GCC by itself only generates left rotates. Use right rotates if
- * possible to be kinder to dinky implementations with iterative rotate
- * instructions.
- */
-#define SHA_ROT(op, x, k) \
- ({ unsigned int y; asm(op " %1,%0" : "=r" (y) : "I" (k), "0" (x)); y; })
-#define rol(x,k) SHA_ROT("roll", x, k)
-#define ror(x,k) SHA_ROT("rorl", x, k)
-
-#else
-/* Generic C equivalent */
#define SHA_ROT(x,l,r) ((x) << (l) | (x) >> (r))
#define rol(x,k) SHA_ROT(x,k,32-(k))
#define ror(x,k) SHA_ROT(x,32-(k),k)
-#endif
-
#define blk0le(i) (block[i] = (ror(block[i],8)&0xFF00FF00) \
|(rol(block[i],8)&0x00FF00FF))
@@ -397,10 +381,11 @@ int sqlite3_sha_init(
int rc = SQLITE_OK;
SQLITE_EXTENSION_INIT2(pApi);
(void)pzErrMsg; /* Unused parameter */
- rc = sqlite3_create_function(db, "sha1", 1, SQLITE_UTF8, 0,
+ rc = sqlite3_create_function(db, "sha1", 1, SQLITE_UTF8|SQLITE_INNOCUOUS, 0,
sha1Func, 0, 0);
if( rc==SQLITE_OK ){
- rc = sqlite3_create_function(db, "sha1_query", 1, SQLITE_UTF8, 0,
+ rc = sqlite3_create_function(db, "sha1_query", 1,
+ SQLITE_UTF8|SQLITE_DIRECTONLY, 0,
sha1QueryFunc, 0, 0);
}
return rc;
diff --git a/ext/misc/shathree.c b/ext/misc/shathree.c
index e35fa49477..56eba564ce 100644
--- a/ext/misc/shathree.c
+++ b/ext/misc/shathree.c
@@ -696,19 +696,23 @@ int sqlite3_shathree_init(
int rc = SQLITE_OK;
SQLITE_EXTENSION_INIT2(pApi);
(void)pzErrMsg; /* Unused parameter */
- rc = sqlite3_create_function(db, "sha3", 1, SQLITE_UTF8, 0,
- sha3Func, 0, 0);
+ rc = sqlite3_create_function(db, "sha3", 1,
+ SQLITE_UTF8 | SQLITE_INNOCUOUS | SQLITE_DETERMINISTIC,
+ 0, sha3Func, 0, 0);
if( rc==SQLITE_OK ){
- rc = sqlite3_create_function(db, "sha3", 2, SQLITE_UTF8, 0,
- sha3Func, 0, 0);
+ rc = sqlite3_create_function(db, "sha3", 2,
+ SQLITE_UTF8 | SQLITE_INNOCUOUS | SQLITE_DETERMINISTIC,
+ 0, sha3Func, 0, 0);
}
if( rc==SQLITE_OK ){
- rc = sqlite3_create_function(db, "sha3_query", 1, SQLITE_UTF8, 0,
- sha3QueryFunc, 0, 0);
+ rc = sqlite3_create_function(db, "sha3_query", 1,
+ SQLITE_UTF8 | SQLITE_DIRECTONLY,
+ 0, sha3QueryFunc, 0, 0);
}
if( rc==SQLITE_OK ){
- rc = sqlite3_create_function(db, "sha3_query", 2, SQLITE_UTF8, 0,
- sha3QueryFunc, 0, 0);
+ rc = sqlite3_create_function(db, "sha3_query", 2,
+ SQLITE_UTF8 | SQLITE_DIRECTONLY,
+ 0, sha3QueryFunc, 0, 0);
}
return rc;
}
diff --git a/ext/misc/spellfix.c b/ext/misc/spellfix.c
index 81bef139a3..b7d4468d9e 100644
--- a/ext/misc/spellfix.c
+++ b/ext/misc/spellfix.c
@@ -2069,6 +2069,7 @@ static int spellfix1Init(
if( pNew->zTableName==0 ){
rc = SQLITE_NOMEM;
}else{
+ sqlite3_vtab_config(db, SQLITE_INNOCUOUS);
rc = sqlite3_declare_vtab(db,
"CREATE TABLE x(word,rank,distance,langid, "
"score, matchlen, phonehash HIDDEN, "
diff --git a/ext/misc/sqlar.c b/ext/misc/sqlar.c
index e812d70c99..8b90f9d1d8 100644
--- a/ext/misc/sqlar.c
+++ b/ext/misc/sqlar.c
@@ -111,10 +111,12 @@ int sqlite3_sqlar_init(
int rc = SQLITE_OK;
SQLITE_EXTENSION_INIT2(pApi);
(void)pzErrMsg; /* Unused parameter */
- rc = sqlite3_create_function(db, "sqlar_compress", 1, SQLITE_UTF8, 0,
+ rc = sqlite3_create_function(db, "sqlar_compress", 1,
+ SQLITE_UTF8|SQLITE_INNOCUOUS, 0,
sqlarCompressFunc, 0, 0);
if( rc==SQLITE_OK ){
- rc = sqlite3_create_function(db, "sqlar_uncompress", 2, SQLITE_UTF8, 0,
+ rc = sqlite3_create_function(db, "sqlar_uncompress", 2,
+ SQLITE_UTF8|SQLITE_INNOCUOUS, 0,
sqlarUncompressFunc, 0, 0);
}
return rc;
diff --git a/ext/misc/totype.c b/ext/misc/totype.c
index 5dc99f3d7d..50d7f05d90 100644
--- a/ext/misc/totype.c
+++ b/ext/misc/totype.c
@@ -502,11 +502,13 @@ int sqlite3_totype_init(
int rc = SQLITE_OK;
SQLITE_EXTENSION_INIT2(pApi);
(void)pzErrMsg; /* Unused parameter */
- rc = sqlite3_create_function(db, "tointeger", 1, SQLITE_UTF8, 0,
- tointegerFunc, 0, 0);
+ rc = sqlite3_create_function(db, "tointeger", 1,
+ SQLITE_UTF8 | SQLITE_DETERMINISTIC | SQLITE_INNOCUOUS, 0,
+ tointegerFunc, 0, 0);
if( rc==SQLITE_OK ){
- rc = sqlite3_create_function(db, "toreal", 1, SQLITE_UTF8, 0,
- torealFunc, 0, 0);
+ rc = sqlite3_create_function(db, "toreal", 1,
+ SQLITE_UTF8 | SQLITE_DETERMINISTIC | SQLITE_INNOCUOUS, 0,
+ torealFunc, 0, 0);
}
return rc;
}
diff --git a/ext/misc/urifuncs.c b/ext/misc/urifuncs.c
new file mode 100644
index 0000000000..9697b724cb
--- /dev/null
+++ b/ext/misc/urifuncs.c
@@ -0,0 +1,209 @@
+/*
+** 2020-01-11
+**
+** 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 SQLite extension implements various SQL functions used to access
+** the following SQLite C-language APIs:
+**
+** sqlite3_uri_parameter()
+** sqlite3_uri_boolean()
+** sqlite3_uri_int64()
+** sqlite3_uri_key()
+** sqlite3_filename_database()
+** sqlite3_filename_journal()
+** sqlite3_filename_wal()
+** sqlite3_db_filename()
+**
+** These SQL functions are for testing and demonstration purposes only.
+**
+**
+*/
+#include "sqlite3ext.h"
+SQLITE_EXTENSION_INIT1
+#include
+#include
+
+/*
+** SQL function: sqlite3_db_filename(SCHEMA)
+**
+** Return the filename corresponding to SCHEMA.
+*/
+static void func_db_filename(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ const char *zSchema = (const char*)sqlite3_value_text(argv[0]);
+ sqlite3 *db = sqlite3_context_db_handle(context);
+ const char *zFile = sqlite3_db_filename(db, zSchema);
+ sqlite3_result_text(context, zFile, -1, SQLITE_TRANSIENT);
+}
+
+/*
+** SQL function: sqlite3_uri_parameter(SCHEMA,NAME)
+**
+** Return the value of the NAME query parameter to the database for SCHEMA
+*/
+static void func_uri_parameter(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ const char *zSchema = (const char*)sqlite3_value_text(argv[0]);
+ sqlite3 *db = sqlite3_context_db_handle(context);
+ const char *zName = (const char*)sqlite3_value_text(argv[1]);
+ const char *zFile = sqlite3_db_filename(db, zSchema);
+ const char *zRes = sqlite3_uri_parameter(zFile, zName);
+ sqlite3_result_text(context, zRes, -1, SQLITE_TRANSIENT);
+}
+
+/*
+** SQL function: sqlite3_uri_boolean(SCHEMA,NAME,DEFAULT)
+**
+** Return the boolean value of the NAME query parameter to
+** the database for SCHEMA
+*/
+static void func_uri_boolean(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ const char *zSchema = (const char*)sqlite3_value_text(argv[0]);
+ sqlite3 *db = sqlite3_context_db_handle(context);
+ const char *zName = (const char*)sqlite3_value_text(argv[1]);
+ const char *zFile = sqlite3_db_filename(db, zSchema);
+ int iDflt = sqlite3_value_int(argv[2]);
+ int iRes = sqlite3_uri_boolean(zFile, zName, iDflt);
+ sqlite3_result_int(context, iRes);
+}
+
+/*
+** SQL function: sqlite3_uri_key(SCHEMA,N)
+**
+** Return the name of the Nth query parameter
+*/
+static void func_uri_key(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ const char *zSchema = (const char*)sqlite3_value_text(argv[0]);
+ sqlite3 *db = sqlite3_context_db_handle(context);
+ int N = sqlite3_value_int(argv[1]);
+ const char *zFile = sqlite3_db_filename(db, zSchema);
+ const char *zRes = sqlite3_uri_key(zFile, N);
+ sqlite3_result_text(context, zRes, -1, SQLITE_TRANSIENT);
+}
+
+/*
+** SQL function: sqlite3_uri_int64(SCHEMA,NAME,DEFAULT)
+**
+** Return the int64 value of the NAME query parameter to
+** the database for SCHEMA
+*/
+static void func_uri_int64(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ const char *zSchema = (const char*)sqlite3_value_text(argv[0]);
+ sqlite3 *db = sqlite3_context_db_handle(context);
+ const char *zName = (const char*)sqlite3_value_text(argv[1]);
+ const char *zFile = sqlite3_db_filename(db, zSchema);
+ sqlite3_int64 iDflt = sqlite3_value_int64(argv[2]);
+ sqlite3_int64 iRes = sqlite3_uri_int64(zFile, zName, iDflt);
+ sqlite3_result_int64(context, iRes);
+}
+
+/*
+** SQL function: sqlite3_filename_database(SCHEMA)
+**
+** Return the database filename for SCHEMA
+*/
+static void func_filename_database(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ const char *zSchema = (const char*)sqlite3_value_text(argv[0]);
+ sqlite3 *db = sqlite3_context_db_handle(context);
+ const char *zFile = sqlite3_db_filename(db, zSchema);
+ const char *zRes = zFile ? sqlite3_filename_database(zFile) : 0;
+ sqlite3_result_text(context, zRes, -1, SQLITE_TRANSIENT);
+}
+
+/*
+** SQL function: sqlite3_filename_journal(SCHEMA)
+**
+** Return the rollback journal filename for SCHEMA
+*/
+static void func_filename_journal(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ const char *zSchema = (const char*)sqlite3_value_text(argv[0]);
+ sqlite3 *db = sqlite3_context_db_handle(context);
+ const char *zFile = sqlite3_db_filename(db, zSchema);
+ const char *zRes = zFile ? sqlite3_filename_journal(zFile) : 0;
+ sqlite3_result_text(context, zRes, -1, SQLITE_TRANSIENT);
+}
+
+/*
+** SQL function: sqlite3_filename_wal(SCHEMA)
+**
+** Return the WAL filename for SCHEMA
+*/
+static void func_filename_wal(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ const char *zSchema = (const char*)sqlite3_value_text(argv[0]);
+ sqlite3 *db = sqlite3_context_db_handle(context);
+ const char *zFile = sqlite3_db_filename(db, zSchema);
+ const char *zRes = zFile ? sqlite3_filename_wal(zFile) : 0;
+ sqlite3_result_text(context, zRes, -1, SQLITE_TRANSIENT);
+}
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+int sqlite3_urifuncs_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ static const struct {
+ const char *zFuncName;
+ int nArg;
+ void (*xFunc)(sqlite3_context*,int,sqlite3_value**);
+ } aFunc[] = {
+ { "sqlite3_db_filename", 1, func_db_filename },
+ { "sqlite3_uri_parameter", 2, func_uri_parameter },
+ { "sqlite3_uri_boolean", 3, func_uri_boolean },
+ { "sqlite3_uri_int64", 3, func_uri_int64 },
+ { "sqlite3_uri_key", 2, func_uri_key },
+ { "sqlite3_filename_database", 1, func_filename_database },
+ { "sqlite3_filename_journal", 1, func_filename_journal },
+ { "sqlite3_filename_wal", 1, func_filename_wal },
+ };
+ int rc = SQLITE_OK;
+ int i;
+ SQLITE_EXTENSION_INIT2(pApi);
+ (void)pzErrMsg; /* Unused parameter */
+ for(i=0; rc==SQLITE_OK && i
+#include
+#include
+
+#if !defined(SQLITE_ASCII) && !defined(SQLITE_EBCDIC)
+# define SQLITE_ASCII 1
+#endif
+
+/*
+** Translate a single byte of Hex into an integer.
+** This routine only works if h really is a valid hexadecimal
+** character: 0..9a..fA..F
+*/
+static unsigned char sqlite3UuidHexToInt(int h){
+ assert( (h>='0' && h<='9') || (h>='a' && h<='f') || (h>='A' && h<='F') );
+#ifdef SQLITE_ASCII
+ h += 9*(1&(h>>6));
+#endif
+#ifdef SQLITE_EBCDIC
+ h += 9*(1&~(h>>4));
+#endif
+ return (unsigned char)(h & 0xf);
+}
+
+/*
+** Convert a 16-byte BLOB into a well-formed RFC-4122 UUID. The output
+** buffer zStr should be at least 37 bytes in length. The output will
+** be zero-terminated.
+*/
+static void sqlite3UuidBlobToStr(
+ const unsigned char *aBlob, /* Input blob */
+ unsigned char *zStr /* Write the answer here */
+){
+ static const char zDigits[] = "0123456789abcdef";
+ int i, k;
+ unsigned char x;
+ k = 0;
+ for(i=0, k=0x550; i<16; i++, k=k>>1){
+ if( k&1 ){
+ zStr[0] = '-';
+ zStr++;
+ }
+ x = aBlob[i];
+ zStr[0] = zDigits[x>>4];
+ zStr[1] = zDigits[x&0xf];
+ zStr += 2;
+ }
+ *zStr = 0;
+}
+
+/*
+** Attempt to parse a zero-terminated input string zStr into a binary
+** UUID. Return 0 on success, or non-zero if the input string is not
+** parsable.
+*/
+static int sqlite3UuidStrToBlob(
+ const unsigned char *zStr, /* Input string */
+ unsigned char *aBlob /* Write results here */
+){
+ int i;
+ if( zStr[0]=='{' ) zStr++;
+ for(i=0; i<16; i++){
+ if( zStr[0]=='-' ) zStr++;
+ if( isxdigit(zStr[0]) && isxdigit(zStr[1]) ){
+ aBlob[i] = (sqlite3UuidHexToInt(zStr[0])<<4)
+ + sqlite3UuidHexToInt(zStr[1]);
+ zStr += 2;
+ }else{
+ return 1;
+ }
+ }
+ if( zStr[0]=='}' ) zStr++;
+ return zStr[0]!=0;
+}
+
+/*
+** Render sqlite3_value pIn as a 16-byte UUID blob. Return a pointer
+** to the blob, or NULL if the input is not well-formed.
+*/
+static const unsigned char *sqlite3UuidInputToBlob(
+ sqlite3_value *pIn, /* Input text */
+ unsigned char *pBuf /* output buffer */
+){
+ switch( sqlite3_value_type(pIn) ){
+ case SQLITE_TEXT: {
+ const unsigned char *z = sqlite3_value_text(pIn);
+ if( sqlite3UuidStrToBlob(z, pBuf) ) return 0;
+ return pBuf;
+ }
+ case SQLITE_BLOB: {
+ int n = sqlite3_value_bytes(pIn);
+ return n==16 ? sqlite3_value_blob(pIn) : 0;
+ }
+ default: {
+ return 0;
+ }
+ }
+}
+
+/* Implementation of uuid() */
+static void sqlite3UuidFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ unsigned char aBlob[16];
+ unsigned char zStr[37];
+ (void)argc;
+ (void)argv;
+ sqlite3_randomness(16, aBlob);
+ aBlob[6] = (aBlob[6]&0x0f) + 0x40;
+ aBlob[8] = (aBlob[8]&0x3f) + 0x80;
+ sqlite3UuidBlobToStr(aBlob, zStr);
+ sqlite3_result_text(context, (char*)zStr, 36, SQLITE_TRANSIENT);
+}
+
+/* Implementation of uuid_str() */
+static void sqlite3UuidStrFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ unsigned char aBlob[16];
+ unsigned char zStr[37];
+ const unsigned char *pBlob;
+ (void)argc;
+ pBlob = sqlite3UuidInputToBlob(argv[0], aBlob);
+ if( pBlob==0 ) return;
+ sqlite3UuidBlobToStr(pBlob, zStr);
+ sqlite3_result_text(context, (char*)zStr, 36, SQLITE_TRANSIENT);
+}
+
+/* Implementation of uuid_blob() */
+static void sqlite3UuidBlobFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ unsigned char aBlob[16];
+ const unsigned char *pBlob;
+ (void)argc;
+ pBlob = sqlite3UuidInputToBlob(argv[0], aBlob);
+ if( pBlob==0 ) return;
+ sqlite3_result_blob(context, pBlob, 16, SQLITE_TRANSIENT);
+}
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+int sqlite3_uuid_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ int rc = SQLITE_OK;
+ SQLITE_EXTENSION_INIT2(pApi);
+ (void)pzErrMsg; /* Unused parameter */
+ rc = sqlite3_create_function(db, "uuid", 0, SQLITE_UTF8|SQLITE_INNOCUOUS, 0,
+ sqlite3UuidFunc, 0, 0);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_create_function(db, "uuid_str", 1,
+ SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_DETERMINISTIC,
+ 0, sqlite3UuidStrFunc, 0, 0);
+ }
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_create_function(db, "uuid_blob", 1,
+ SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_DETERMINISTIC,
+ 0, sqlite3UuidBlobFunc, 0, 0);
+ }
+ return rc;
+}
diff --git a/ext/misc/wholenumber.c b/ext/misc/wholenumber.c
index 63369c6ac4..5643f9cf7e 100644
--- a/ext/misc/wholenumber.c
+++ b/ext/misc/wholenumber.c
@@ -50,6 +50,7 @@ static int wholenumberConnect(
pNew = *ppVtab = sqlite3_malloc( sizeof(*pNew) );
if( pNew==0 ) return SQLITE_NOMEM;
sqlite3_declare_vtab(db, "CREATE TABLE x(value)");
+ sqlite3_vtab_config(db, SQLITE_VTAB_INNOCUOUS);
memset(pNew, 0, sizeof(*pNew));
return SQLITE_OK;
}
diff --git a/ext/misc/zipfile.c b/ext/misc/zipfile.c
index 0b14917cb2..a35a26f4d8 100644
--- a/ext/misc/zipfile.c
+++ b/ext/misc/zipfile.c
@@ -369,6 +369,7 @@ static int zipfileConnect(
zipfileDequote(pNew->zFile);
}
}
+ sqlite3_vtab_config(db, SQLITE_VTAB_DIRECTONLY);
*ppVtab = (sqlite3_vtab*)pNew;
return rc;
}
@@ -981,25 +982,25 @@ static int zipfileDeflate(
u8 **ppOut, int *pnOut, /* Output */
char **pzErr /* OUT: Error message */
){
- sqlite3_int64 nAlloc = compressBound(nIn);
- u8 *aOut;
int rc = SQLITE_OK;
+ sqlite3_int64 nAlloc;
+ z_stream str;
+ u8 *aOut;
+ memset(&str, 0, sizeof(str));
+ str.next_in = (Bytef*)aIn;
+ str.avail_in = nIn;
+ deflateInit2(&str, 9, Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY);
+
+ nAlloc = deflateBound(&str, nIn);
aOut = (u8*)sqlite3_malloc64(nAlloc);
if( aOut==0 ){
rc = SQLITE_NOMEM;
}else{
int res;
- z_stream str;
- memset(&str, 0, sizeof(str));
- str.next_in = (Bytef*)aIn;
- str.avail_in = nIn;
str.next_out = aOut;
str.avail_out = nAlloc;
-
- deflateInit2(&str, 9, Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY);
res = deflate(&str, Z_FINISH);
-
if( res==Z_STREAM_END ){
*ppOut = aOut;
*pnOut = (int)str.total_out;
@@ -1308,10 +1309,10 @@ static int zipfileBestIndex(
idx = i;
}
}
+ pIdxInfo->estimatedCost = 1000.0;
if( idx>=0 ){
pIdxInfo->aConstraintUsage[idx].argvIndex = 1;
pIdxInfo->aConstraintUsage[idx].omit = 1;
- pIdxInfo->estimatedCost = 1000.0;
pIdxInfo->idxNum = 1;
}else if( unusable ){
return SQLITE_CONSTRAINT;
@@ -1433,8 +1434,8 @@ static int zipfileGetMode(
** identical, ignoring any trailing '/' character in either path. */
static int zipfileComparePath(const char *zA, const char *zB, int nB){
int nA = (int)strlen(zA);
- if( zA[nA-1]=='/' ) nA--;
- if( zB[nB-1]=='/' ) nB--;
+ if( nA>0 && zA[nA-1]=='/' ) nA--;
+ if( nB>0 && zB[nB-1]=='/' ) nB--;
if( nA==nB && memcmp(zA, zB, nA)==0 ) return 0;
return 1;
}
@@ -1444,6 +1445,10 @@ static int zipfileBegin(sqlite3_vtab *pVtab){
int rc = SQLITE_OK;
assert( pTab->pWriteFd==0 );
+ if( pTab->zFile==0 || pTab->zFile[0]==0 ){
+ pTab->base.zErrMsg = sqlite3_mprintf("zipfile: missing filename");
+ return SQLITE_ERROR;
+ }
/* Open a write fd on the file. Also load the entire central directory
** structure into memory. During the transaction any new file data is
@@ -1618,6 +1623,7 @@ static int zipfileUpdate(
if( rc==SQLITE_OK ){
zPath = (const char*)sqlite3_value_text(apVal[2]);
+ if( zPath==0 ) zPath = "";
nPath = (int)strlen(zPath);
mTime = zipfileGetTime(apVal[4]);
}
@@ -1627,11 +1633,15 @@ static int zipfileUpdate(
** '/'. This appears to be required for compatibility with info-zip
** (the unzip command on unix). It does not create directories
** otherwise. */
- if( zPath[nPath-1]!='/' ){
+ if( nPath<=0 || zPath[nPath-1]!='/' ){
zFree = sqlite3_mprintf("%s/", zPath);
- if( zFree==0 ){ rc = SQLITE_NOMEM; }
zPath = (const char*)zFree;
- nPath++;
+ if( zFree==0 ){
+ rc = SQLITE_NOMEM;
+ nPath = 0;
+ }else{
+ nPath = (int)strlen(zPath);
+ }
}
}
@@ -2024,19 +2034,19 @@ void zipfileStep(sqlite3_context *pCtx, int nVal, sqlite3_value **apVal){
** at the end of the path. Or, if this is not a directory and the path
** ends in '/' it is an error. */
if( bIsDir==0 ){
- if( zName[nName-1]=='/' ){
+ if( nName>0 && zName[nName-1]=='/' ){
zErr = sqlite3_mprintf("non-directory name must not end with /");
rc = SQLITE_ERROR;
goto zipfile_step_out;
}
}else{
- if( zName[nName-1]!='/' ){
+ if( nName==0 || zName[nName-1]!='/' ){
zName = zFree = sqlite3_mprintf("%s/", zName);
- nName++;
if( zName==0 ){
rc = SQLITE_NOMEM;
goto zipfile_step_out;
}
+ nName = (int)strlen(zName);
}else{
while( nName>1 && zName[nName-2]=='/' ) nName--;
}
diff --git a/ext/rbu/sqlite3rbu.c b/ext/rbu/sqlite3rbu.c
index 5c2ae95453..8e82cd8b92 100644
--- a/ext/rbu/sqlite3rbu.c
+++ b/ext/rbu/sqlite3rbu.c
@@ -4936,33 +4936,6 @@ static int rbuVfsShmUnmap(sqlite3_file *pFile, int delFlag){
return rc;
}
-/*
-** A main database named zName has just been opened. The following
-** function returns a pointer to a buffer owned by SQLite that contains
-** the name of the *-wal file this db connection will use. SQLite
-** happens to pass a pointer to this buffer when using xAccess()
-** or xOpen() to operate on the *-wal file.
-*/
-static const char *rbuMainToWal(const char *zName, int flags){
- int n = (int)strlen(zName);
- const char *z = &zName[n];
- if( flags & SQLITE_OPEN_URI ){
- int odd = 0;
- while( 1 ){
- if( z[0]==0 ){
- odd = 1 - odd;
- if( odd && z[1]==0 ) break;
- }
- z++;
- }
- z += 2;
- }else{
- while( *z==0 ) z++;
- }
- z += (n + 8 + 1);
- return z;
-}
-
/*
** Open an rbu file handle.
*/
@@ -5011,7 +4984,7 @@ static int rbuVfsOpen(
** the name of the *-wal file this db connection will use. SQLite
** happens to pass a pointer to this buffer when using xAccess()
** or xOpen() to operate on the *-wal file. */
- pFd->zWal = rbuMainToWal(zName, flags);
+ pFd->zWal = sqlite3_filename_wal(zName);
}
else if( flags & SQLITE_OPEN_WAL ){
rbu_file *pDb = rbuFindMaindb(pRbuVfs, zName, 0);
@@ -5026,7 +4999,7 @@ static int rbuVfsOpen(
char *zCopy;
if( rbuIsVacuum(pDb->pRbu) ){
zBase = sqlite3_db_filename(pDb->pRbu->dbRbu, "main");
- zBase = rbuMainToWal(zBase, SQLITE_OPEN_URI);
+ zBase = sqlite3_filename_wal(zBase);
}
nCopy = strlen(zBase);
zCopy = sqlite3_malloc64(nCopy+2);
diff --git a/ext/rtree/geopoly.c b/ext/rtree/geopoly.c
index fa58838a31..14facad534 100644
--- a/ext/rtree/geopoly.c
+++ b/ext/rtree/geopoly.c
@@ -1345,17 +1345,11 @@ static int geopolyFilter(
RtreeNode *pRoot = 0;
int rc = SQLITE_OK;
int iCell = 0;
- sqlite3_stmt *pStmt;
rtreeReference(pRtree);
/* Reset the cursor to the same state as rtreeOpen() leaves it in. */
- freeCursorConstraints(pCsr);
- sqlite3_free(pCsr->aPoint);
- pStmt = pCsr->pReadAux;
- memset(pCsr, 0, sizeof(RtreeCursor));
- pCsr->base.pVtab = (sqlite3_vtab*)pRtree;
- pCsr->pReadAux = pStmt;
+ resetCursor(pCsr);
pCsr->iStrategy = idxNum;
if( idxNum==1 ){
@@ -1792,14 +1786,20 @@ static int sqlite3_geopoly_init(sqlite3 *db){
};
int i;
for(i=0; ibase.pVtab);
+ int ii;
+ sqlite3_stmt *pStmt;
if( pCsr->aConstraint ){
int i; /* Used to iterate through constraint array */
for(i=0; inConstraint; i++){
@@ -1073,6 +1083,13 @@ static void freeCursorConstraints(RtreeCursor *pCsr){
sqlite3_free(pCsr->aConstraint);
pCsr->aConstraint = 0;
}
+ for(ii=0; iiaNode[ii]);
+ sqlite3_free(pCsr->aPoint);
+ pStmt = pCsr->pReadAux;
+ memset(pCsr, 0, sizeof(RtreeCursor));
+ pCsr->base.pVtab = (sqlite3_vtab*)pRtree;
+ pCsr->pReadAux = pStmt;
+
}
/*
@@ -1080,13 +1097,10 @@ static void freeCursorConstraints(RtreeCursor *pCsr){
*/
static int rtreeClose(sqlite3_vtab_cursor *cur){
Rtree *pRtree = (Rtree *)(cur->pVtab);
- int ii;
RtreeCursor *pCsr = (RtreeCursor *)cur;
assert( pRtree->nCursor>0 );
- freeCursorConstraints(pCsr);
+ resetCursor(pCsr);
sqlite3_finalize(pCsr->pReadAux);
- sqlite3_free(pCsr->aPoint);
- for(ii=0; iiaNode[ii]);
sqlite3_free(pCsr);
pRtree->nCursor--;
nodeBlobReset(pRtree);
@@ -1244,9 +1258,12 @@ static void rtreeNonleafConstraint(
pCellData += 8 + 4*(p->iCoord&0xfe);
assert(p->op==RTREE_LE || p->op==RTREE_LT || p->op==RTREE_GE
- || p->op==RTREE_GT || p->op==RTREE_EQ );
+ || p->op==RTREE_GT || p->op==RTREE_EQ || p->op==RTREE_TRUE
+ || p->op==RTREE_FALSE );
assert( ((((char*)pCellData) - (char*)0)&3)==0 ); /* 4-byte aligned */
switch( p->op ){
+ case RTREE_TRUE: return; /* Always satisfied */
+ case RTREE_FALSE: break; /* Never satisfied */
case RTREE_LE:
case RTREE_LT:
case RTREE_EQ:
@@ -1284,16 +1301,19 @@ static void rtreeLeafConstraint(
RtreeDValue xN; /* Coordinate value converted to a double */
assert(p->op==RTREE_LE || p->op==RTREE_LT || p->op==RTREE_GE
- || p->op==RTREE_GT || p->op==RTREE_EQ );
+ || p->op==RTREE_GT || p->op==RTREE_EQ || p->op==RTREE_TRUE
+ || p->op==RTREE_FALSE );
pCellData += 8 + p->iCoord*4;
assert( ((((char*)pCellData) - (char*)0)&3)==0 ); /* 4-byte aligned */
RTREE_DECODE_COORD(eInt, pCellData, xN);
switch( p->op ){
- case RTREE_LE: if( xN <= p->u.rValue ) return; break;
- case RTREE_LT: if( xN < p->u.rValue ) return; break;
- case RTREE_GE: if( xN >= p->u.rValue ) return; break;
- case RTREE_GT: if( xN > p->u.rValue ) return; break;
- default: if( xN == p->u.rValue ) return; break;
+ case RTREE_TRUE: return; /* Always satisfied */
+ case RTREE_FALSE: break; /* Never satisfied */
+ case RTREE_LE: if( xN <= p->u.rValue ) return; break;
+ case RTREE_LT: if( xN < p->u.rValue ) return; break;
+ case RTREE_GE: if( xN >= p->u.rValue ) return; break;
+ case RTREE_GT: if( xN > p->u.rValue ) return; break;
+ default: if( xN == p->u.rValue ) return; break;
}
*peWithin = NOT_WITHIN;
}
@@ -1786,17 +1806,11 @@ static int rtreeFilter(
int ii;
int rc = SQLITE_OK;
int iCell = 0;
- sqlite3_stmt *pStmt;
rtreeReference(pRtree);
/* Reset the cursor to the same state as rtreeOpen() leaves it in. */
- freeCursorConstraints(pCsr);
- sqlite3_free(pCsr->aPoint);
- pStmt = pCsr->pReadAux;
- memset(pCsr, 0, sizeof(RtreeCursor));
- pCsr->base.pVtab = (sqlite3_vtab*)pRtree;
- pCsr->pReadAux = pStmt;
+ resetCursor(pCsr);
pCsr->iStrategy = idxNum;
if( idxNum==1 ){
@@ -1805,7 +1819,15 @@ static int rtreeFilter(
RtreeSearchPoint *p; /* Search point for the leaf */
i64 iRowid = sqlite3_value_int64(argv[0]);
i64 iNode = 0;
- rc = findLeafNode(pRtree, iRowid, &pLeaf, &iNode);
+ int eType = sqlite3_value_numeric_type(argv[0]);
+ if( eType==SQLITE_INTEGER
+ || (eType==SQLITE_FLOAT && sqlite3_value_double(argv[0])==iRowid)
+ ){
+ rc = findLeafNode(pRtree, iRowid, &pLeaf, &iNode);
+ }else{
+ rc = SQLITE_OK;
+ pLeaf = 0;
+ }
if( rc==SQLITE_OK && pLeaf!=0 ){
p = rtreeSearchPointNew(pCsr, RTREE_ZERO, 0);
assert( p!=0 ); /* Always returns pCsr->sPoint */
@@ -1835,6 +1857,7 @@ static int rtreeFilter(
|| (idxStr && (int)strlen(idxStr)==argc*2) );
for(ii=0; iiaConstraint[ii];
+ int eType = sqlite3_value_numeric_type(argv[ii]);
p->op = idxStr[ii*2];
p->iCoord = idxStr[ii*2+1]-'0';
if( p->op>=RTREE_MATCH ){
@@ -1849,12 +1872,21 @@ static int rtreeFilter(
p->pInfo->nCoord = pRtree->nDim2;
p->pInfo->anQueue = pCsr->anQueue;
p->pInfo->mxLevel = pRtree->iDepth + 1;
- }else{
+ }else if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
#ifdef SQLITE_RTREE_INT_ONLY
p->u.rValue = sqlite3_value_int64(argv[ii]);
#else
p->u.rValue = sqlite3_value_double(argv[ii]);
#endif
+ }else{
+ p->u.rValue = RTREE_ZERO;
+ if( eType==SQLITE_NULL ){
+ p->op = RTREE_FALSE;
+ }else if( p->op==RTREE_LT || p->op==RTREE_LE ){
+ p->op = RTREE_TRUE;
+ }else{
+ p->op = RTREE_FALSE;
+ }
}
}
}
@@ -3631,6 +3663,14 @@ static int getNodeSize(
return rc;
}
+/*
+** Return the length of a token
+*/
+static int rtreeTokenLength(const char *z){
+ int dummy = 0;
+ return sqlite3GetToken((const unsigned char*)z,&dummy);
+}
+
/*
** This function is the implementation of both the xConnect and xCreate
** methods of the r-tree virtual table.
@@ -3667,8 +3707,8 @@ static int rtreeInit(
};
assert( RTREE_MAX_AUX_COLUMN<256 ); /* Aux columns counted by a u8 */
- if( argc>RTREE_MAX_AUX_COLUMN+3 ){
- *pzErr = sqlite3_mprintf("%s", aErrMsg[3]);
+ if( argc<6 || argc>RTREE_MAX_AUX_COLUMN+3 ){
+ *pzErr = sqlite3_mprintf("%s", aErrMsg[2 + (argc>=6)]);
return SQLITE_ERROR;
}
@@ -3696,16 +3736,18 @@ static int rtreeInit(
** the r-tree table schema.
*/
pSql = sqlite3_str_new(db);
- sqlite3_str_appendf(pSql, "CREATE TABLE x(%s", argv[3]);
+ sqlite3_str_appendf(pSql, "CREATE TABLE x(%.*s INT",
+ rtreeTokenLength(argv[3]), argv[3]);
for(ii=4; iinAux++;
- sqlite3_str_appendf(pSql, ",%s", argv[ii]+1);
+ sqlite3_str_appendf(pSql, ",%.*s", rtreeTokenLength(zArg+1), zArg+1);
}else if( pRtree->nAux>0 ){
break;
}else{
pRtree->nDim2++;
- sqlite3_str_appendf(pSql, ",%s", argv[ii]);
+ sqlite3_str_appendf(pSql, ",%.*s NUM", rtreeTokenLength(zArg), zArg);
}
}
sqlite3_str_appendf(pSql, ");");
diff --git a/ext/rtree/rtree1.test b/ext/rtree/rtree1.test
index 77494573b6..447ef5dadd 100644
--- a/ext/rtree/rtree1.test
+++ b/ext/rtree/rtree1.test
@@ -112,6 +112,9 @@ for {set nCol 1} {$nCol<[llength $cols]} {incr nCol} {
catchsql { DROP TABLE t1 }
}
+do_catchsql_test rtree-1.3.1000 {
+ CREATE VIRTUAL TABLE t1000 USING rtree;
+} {1 {Too few columns for an rtree table}}
# Like execsql except display output as integer where that can be
# done without loss of information.
@@ -374,13 +377,43 @@ do_test rtree-8.1.1 {
INSERT INTO t6 VALUES(2, 4, 6);
}
} {}
-do_test rtree-8.1.2 { execsql { SELECT ii FROM t6 WHERE x1>2 } } {1 2}
-do_test rtree-8.1.3 { execsql { SELECT ii FROM t6 WHERE x1>3 } } {2}
-do_test rtree-8.1.4 { execsql { SELECT ii FROM t6 WHERE x1>4 } } {}
-do_test rtree-8.1.5 { execsql { SELECT ii FROM t6 WHERE x1>5 } } {}
-do_test rtree-8.1.6 { execsql { SELECT ii FROM t6 WHERE x1<3 } } {}
-do_test rtree-8.1.7 { execsql { SELECT ii FROM t6 WHERE x1<4 } } {1}
-do_test rtree-8.1.8 { execsql { SELECT ii FROM t6 WHERE x1<5 } } {1 2}
+do_test rtree-8.1.2 { execsql { SELECT ii FROM t6 WHERE x1>2 } } {1 2}
+do_test rtree-8.1.3 { execsql { SELECT ii FROM t6 WHERE x1>3 } } {2}
+do_test rtree-8.1.4 { execsql { SELECT ii FROM t6 WHERE x1>4 } } {}
+do_test rtree-8.1.5 { execsql { SELECT ii FROM t6 WHERE x1>5 } } {}
+do_test rtree-8.1.6 { execsql { SELECT ii FROM t6 WHERE x1>''} } {}
+do_test rtree-8.1.7 { execsql { SELECT ii FROM t6 WHERE x1>null}} {}
+do_test rtree-8.1.8 { execsql { SELECT ii FROM t6 WHERE x1>'2'} } {1 2}
+do_test rtree-8.1.9 { execsql { SELECT ii FROM t6 WHERE x1>'3'} } {2}
+do_test rtree-8.2.2 { execsql { SELECT ii FROM t6 WHERE x1>=2 } } {1 2}
+do_test rtree-8.2.3 { execsql { SELECT ii FROM t6 WHERE x1>=3 } } {1 2}
+do_test rtree-8.2.4 { execsql { SELECT ii FROM t6 WHERE x1>=4 } } {2}
+do_test rtree-8.2.5 { execsql { SELECT ii FROM t6 WHERE x1>=5 } } {}
+do_test rtree-8.2.6 { execsql { SELECT ii FROM t6 WHERE x1>=''} } {}
+do_test rtree-8.2.7 { execsql { SELECT ii FROM t6 WHERE x1>=null}} {}
+do_test rtree-8.2.8 { execsql { SELECT ii FROM t6 WHERE x1>='4'} } {2}
+do_test rtree-8.2.9 { execsql { SELECT ii FROM t6 WHERE x1>='5'} } {}
+do_test rtree-8.3.2 { execsql { SELECT ii FROM t6 WHERE x1<2 } } {}
+do_test rtree-8.3.3 { execsql { SELECT ii FROM t6 WHERE x1<3 } } {}
+do_test rtree-8.3.4 { execsql { SELECT ii FROM t6 WHERE x1<4 } } {1}
+do_test rtree-8.3.5 { execsql { SELECT ii FROM t6 WHERE x1<5 } } {1 2}
+do_test rtree-8.3.6 { execsql { SELECT ii FROM t6 WHERE x1<''} } {1 2}
+do_test rtree-8.3.7 { execsql { SELECT ii FROM t6 WHERE x1 '-1';
+ SELECT rt0.c1 > '-1' FROM rt0;
+} {9 1}
+
+
expand_all_sql db
finish_test
diff --git a/ext/rtree/rtree2.test b/ext/rtree/rtree2.test
index 853737b9c7..31c191481e 100644
--- a/ext/rtree/rtree2.test
+++ b/ext/rtree/rtree2.test
@@ -33,12 +33,13 @@ if {[info exists G(isquick)] && $G(isquick)} {
}
foreach module {rtree_i32 rtree} {
+ if {$module=="rtree_i32"} {set etype INT} {set etype REAL}
for {set nDim 1} {$nDim <= 5} {incr nDim} {
do_test rtree2-$module.$nDim.1 {
set cols [list]
foreach c [list c0 c1 c2 c3 c4 c5 c6 c7 c8 c9] {
- lappend cols "$c REAL"
+ lappend cols "$c $etype"
}
set cols [join [lrange $cols 0 [expr {$nDim*2-1}]] ", "]
execsql "
diff --git a/ext/rtree/rtreeC.test b/ext/rtree/rtreeC.test
index 19a1f7fe6c..47ca3ad7b9 100644
--- a/ext/rtree/rtreeC.test
+++ b/ext/rtree/rtreeC.test
@@ -177,7 +177,7 @@ do_execsql_test 4.3 {
#
reset_db
do_execsql_test 5.1 {
- CREATE TABLE t1(x PRIMARY KEY, y);
+ CREATE TABLE t1(x INT PRIMARY KEY, y);
CREATE VIRTUAL TABLE rt USING rtree(id, x1, x2, +d1);
INSERT INTO t1(x) VALUES(1);
diff --git a/ext/rtree/rtreeH.test b/ext/rtree/rtreeH.test
index bff765d530..e26107f075 100644
--- a/ext/rtree/rtreeH.test
+++ b/ext/rtree/rtreeH.test
@@ -43,10 +43,33 @@ do_execsql_test rtreeH-101 {
do_execsql_test rtreeH-102 {
SELECT * FROM t1 WHERE rowid=5;
} {5 40.0 60.0 40.0 60.0 center {}}
+do_execsql_test rtreeH-102b {
+ SELECT * FROM t1 WHERE rowid=5.0;
+} {5 40.0 60.0 40.0 60.0 center {}}
+do_execsql_test rtreeH-102c {
+ SELECT * FROM t1 WHERE rowid='5';
+} {5 40.0 60.0 40.0 60.0 center {}}
+do_execsql_test rtreeH-102d {
+ SELECT * FROM t1 WHERE rowid='0005';
+} {5 40.0 60.0 40.0 60.0 center {}}
+do_execsql_test rtreeH-102e {
+ SELECT * FROM t1 WHERE rowid='+5.0e+0';
+} {5 40.0 60.0 40.0 60.0 center {}}
do_execsql_test rtreeH-103 {
SELECT * FROM t1 WHERE label='center';
} {5 40.0 60.0 40.0 60.0 center {}}
+do_execsql_test rtreeH-104 {
+ SELECT * FROM t1 WHERE rowid='+5.0e+0x';
+} {}
+do_execsql_test rtreeH-105 {
+ SELECT * FROM t1 WHERE rowid=x'35';
+} {}
+do_execsql_test rtreeH-106 {
+ SELECT * FROM t1 WHERE rowid=null;
+} {}
+
+
do_rtree_integrity_test rtreeH-110 t1
do_execsql_test rtreeH-120 {
diff --git a/ext/rtree/rtreeI.test b/ext/rtree/rtreeI.test
new file mode 100644
index 0000000000..0bc910e0f4
--- /dev/null
+++ b/ext/rtree/rtreeI.test
@@ -0,0 +1,74 @@
+# 2019-12-05
+#
+# 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.
+#
+#***********************************************************************
+# Additional test cases
+
+if {![info exists testdir]} {
+ set testdir [file join [file dirname [info script]] .. .. test]
+}
+source [file join [file dirname [info script]] rtree_util.tcl]
+source $testdir/tester.tcl
+ifcapable !rtree { finish_test ; return }
+
+# The following is a test of rowvalue handling on virtual tables that
+# deal with inequalities and that set the OMIT flag on terms of the
+# WHERE clause. This is not specific to rtree. We just use rtree because
+# it is a convenient test platform since it has all the right
+# characteristics.
+#
+do_execsql_test rtreeI-1.10 {
+ CREATE TABLE t1(a);
+ INSERT INTO t1 VALUES(2);
+ CREATE VIRTUAL TABLE t2 USING rtree(id,x0,x1);
+ INSERT INTO t2(id,x0,x1) VALUES(1,2,3);
+} {}
+do_execsql_test rtreeI-1.20 {
+ SELECT 123 FROM t1, t2 WHERE (a,0)>(x0,0);
+} {}
+do_execsql_test rtreeI-1.21 {
+ SELECT 123 FROM t1, t2 WHERE (a,0.1)>(x0,0);
+} {123}
+do_execsql_test rtreeI-1.22 {
+ SELECT 123 FROM t1, t2 WHERE (a,0)>=(x0,0);
+} {123}
+do_execsql_test rtreeI-1.23 {
+ SELECT 123 FROM t1, t2 WHERE (a,0)<=(x0,0);
+} {123}
+do_execsql_test rtreeI-1.24 {
+ SELECT 123 FROM t1, t2 WHERE (a,0)<(x0,0);
+} {}
+do_execsql_test rtreeI-1.30 {
+ SELECT 123 FROM t1, t2 WHERE (x0,0)<(a,0);
+} {}
+do_execsql_test rtreeI-1.31 {
+ SELECT 123 FROM t1, t2 WHERE (x0,0)<(a,0.1);
+} {123}
+do_execsql_test rtreeI-1.40 {
+ SELECT 123 FROM t1, t2 WHERE x1<5 AND id<99 AND (a,0)>(x0,0);
+} {}
+do_execsql_test rtreeI-1.41 {
+ SELECT 123 FROM t1, t2 WHERE x1<5 AND id<99 AND (a,0.5)>(x0,0);
+} {123}
+do_execsql_test rtreeI-1.42 {
+ SELECT 123 FROM t1, t2 WHERE x1<5 AND id<99 AND (a,0)>=(x0,0);
+} {123}
+do_execsql_test rtreeI-1.43 {
+ SELECT 123 FROM t1, t2 WHERE x1<5 AND id<99 AND (a,0)<(x0,0);
+} {}
+do_execsql_test rtreeI-1.50 {
+ SELECT 123 FROM t1, t2 WHERE 5>x1 AND 99>id AND (x0,0)<(a,0);
+} {}
+do_execsql_test rtreeI-1.51 {
+ SELECT 123 FROM t1, t2 WHERE 5>x1 AND 99>id AND (x0,0)<(a,0.5);
+} {123}
+
+
+
+finish_test
diff --git a/ext/session/sqlite3session.h b/ext/session/sqlite3session.h
index 2f9ee9cd3c..1ed3b550f4 100644
--- a/ext/session/sqlite3session.h
+++ b/ext/session/sqlite3session.h
@@ -200,7 +200,7 @@ int sqlite3session_attach(
** The second argument (xFilter) is the "filter callback". For changes to rows
** in tables that are not attached to the Session object, the filter is called
** to determine whether changes to the table's rows should be tracked or not.
-** If xFilter returns 0, changes is not tracked. Note that once a table is
+** If xFilter returns 0, changes are not tracked. Note that once a table is
** attached, xFilter will not be called again.
*/
void sqlite3session_table_filter(
@@ -374,7 +374,7 @@ int sqlite3session_changeset(
** It an error if database zFrom does not exist or does not contain the
** required compatible table.
**
-** If the operation successful, SQLITE_OK is returned. Otherwise, an SQLite
+** If the operation is successful, SQLITE_OK is returned. Otherwise, an SQLite
** error code. In this case, if argument pzErrMsg is not NULL, *pzErrMsg
** may be set to point to a buffer containing an English language error
** message. It is the responsibility of the caller to free this buffer using
@@ -511,7 +511,7 @@ int sqlite3changeset_start_v2(
** CAPI3REF: Advance A Changeset Iterator
** METHOD: sqlite3_changeset_iter
**
-** This function may only be used with iterators created by function
+** This function may only be used with iterators created by the function
** [sqlite3changeset_start()]. If it is called on an iterator passed to
** a conflict-handler callback by [sqlite3changeset_apply()], SQLITE_MISUSE
** is returned and the call has no effect.
@@ -927,8 +927,8 @@ int sqlite3changegroup_new(sqlite3_changegroup **pp);
** case, this function fails with SQLITE_SCHEMA. If the input changeset
** appears to be corrupt and the corruption is detected, SQLITE_CORRUPT is
** returned. Or, if an out-of-memory condition occurs during processing, this
-** function returns SQLITE_NOMEM. In all cases, if an error occurs the
-** final contents of the changegroup is undefined.
+** function returns SQLITE_NOMEM. In all cases, if an error occurs the state
+** of the final contents of the changegroup is undefined.
**
** If no error occurs, SQLITE_OK is returned.
*/
@@ -1103,7 +1103,7 @@ void sqlite3changegroup_delete(sqlite3_changegroup*);
**
** It is safe to execute SQL statements, including those that write to the
** table that the callback related to, from within the xConflict callback.
-** This can be used to further customize the applications conflict
+** This can be used to further customize the application's conflict
** resolution strategy.
**
** All changes made by these functions are enclosed in a savepoint transaction.
@@ -1413,7 +1413,7 @@ int sqlite3rebaser_configure(
**
** Argument pIn must point to a buffer containing a changeset nIn bytes
** in size. This function allocates and populates a buffer with a copy
-** of the changeset rebased rebased according to the configuration of the
+** of the changeset rebased according to the configuration of the
** rebaser object passed as the first argument. If successful, (*ppOut)
** is set to point to the new buffer containing the rebased changeset and
** (*pnOut) to its size in bytes and SQLITE_OK returned. It is the
diff --git a/main.mk b/main.mk
index 5a3ba030b8..82a500e2fa 100644
--- a/main.mk
+++ b/main.mk
@@ -935,10 +935,6 @@ fuzztest: fuzzcheck$(EXE) $(FUZZDATA) sessionfuzz$(EXE) $(TOP)/test/sessionfuzz-
./fuzzcheck$(EXE) $(FUZZDATA)
./sessionfuzz run $(TOP)/test/sessionfuzz-data1.db
-fastfuzztest: fuzzcheck$(EXE) $(FUZZDATA) sessionfuzz$(EXE) $(TOP)/test/sessionfuzz-data1.db
- ./fuzzcheck$(EXE) --limit-mem 100M $(FUZZDATA)
- ./sessionfuzz run $(TOP)/test/sessionfuzz-data1.db
-
valgrindfuzz: fuzzcheck$(EXE) $(FUZZDATA) sessionfuzz$(EXE) $(TOP)/test/sessionfuzz-data1.db
valgrind ./fuzzcheck$(EXE) --cell-size-check --limit-mem 10M --timeout 600 $(FUZZDATA)
valgrind ./sessionfuzz run $(TOP)/test/sessionfuzz-data1.db
@@ -956,7 +952,7 @@ quicktest: ./testfixture$(EXE)
# The default test case. Runs most of the faster standard TCL tests,
# and fuzz tests, and sqlite3_analyzer and sqldiff tests.
-test: fastfuzztest sourcetest $(TESTPROGS) tcltest
+test: fuzztest sourcetest $(TESTPROGS) tcltest
# Run a test using valgrind. This can take a really long time
# because valgrind is so much slower than a native machine.
diff --git a/manifest b/manifest
index 33372b32cb..9c667d3dd8 100644
--- a/manifest
+++ b/manifest
@@ -1,13 +1,13 @@
-C Bring\sthe\swal2\sbranch\sup\sto\sdate\swith\sversion\s3.30.0
-D 2019-10-04T16:15:45.861
+C Merge\srecent\senhancements\sand\sfixes\sfrom\strunk.
+D 2020-01-15T14:11:34.103
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
-F Makefile.in 284fe4779f95772f821de8642bb27c158ee103be0f1968748582751e4a44271e
+F Makefile.in a830a84749ce3312f5e0217698415516ca7f26897821970f662cafc817d3359d
F Makefile.linux-gcc f609543700659711fbd230eced1f01353117621dccae7b9fb70daa64236c5241
-F Makefile.msc ebf071dd120414de88af7fdc277dec4ced4a3af5080897c4a16eee0aab1145c1
+F Makefile.msc 3a8bf24fcbfe4be4b053201a3e1976aacde9356282e7c535c1931d8b1a3bf790
F README.md 1514a365ffca3c138e00c5cc839906108a01011a6b082bad19b09781e3aa498a
-F VERSION 4c516d84c2a5f26c477ed34c09ac4136630f71c68139631f2eb591b22eea7cf1
+F VERSION 081500f0aeaadc989d85aafbc717af45512018aebc73d89e5c2368fe62a600ff
F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50
F art/sqlite370.eps aa97a671332b432a54e1d74ff5e8775be34200c2
F art/sqlite370.ico af56c1d00fee7cd4753e8631ed60703ed0fc6e90
@@ -15,10 +15,10 @@ F art/sqlite370.jpg d512473dae7e378a67e28ff96a34da7cb331def2
F autoconf/INSTALL 83e4a25da9fd053c7b3665eaaaf7919707915903
F autoconf/Makefile.am e14b629addaa1ce372b72043f28f40de2e32b7e211b6e0fc18dbb87989197e40
F autoconf/Makefile.fallback 22fe523eb36dfce31e0f6349f782eb084e86a5620b2b0b4f84a2d6133f53f5ac
-F autoconf/Makefile.msc 3804b004efb6abd2d2e0f5f887dfc6ade3d1661f39335c0531df96e1ab61a062
+F autoconf/Makefile.msc 1d1e4af61289c62b94aa65a93afcd3dfa4b53e4195908980e0b138203e71e1c9
F autoconf/README.first 6c4f34fe115ff55d4e8dbfa3cecf04a0188292f7
F autoconf/README.txt 4f04b0819303aabaa35fff5f7b257fb0c1ef95f1
-F autoconf/configure.ac 308de24343e76ecfbe9a67f8fcd4c5216b790d230c5d9ce10210b7d5965d6192
+F autoconf/configure.ac 3cd933b959fe514eebd1ca1717dfddbf2c9b825b6bc2c5f744deaf5d63af9288
F autoconf/tea/Makefile.in b438a7020446c8a8156e8d97c8914a04833da6fd
F autoconf/tea/README 3e9a3c060f29a44344ab50aec506f4db903fb873
F autoconf/tea/aclocal.m4 52c47aac44ce0ddb1f918b6993e8beb8eee88f43
@@ -34,12 +34,13 @@ F autoconf/tea/win/rules.vc c511f222b80064096b705dbeb97060ee1d6b6d63
F config.guess 883205ddf25b46f10c181818bf42c09da9888884af96f79e1719264345053bd6
F config.h.in 6376abec766e9a0785178b1823b5a587e9f1ccbc
F config.sub c2d0260f17f3e4bc0b6808fccf1b291cb5e9126c14fc5890efc77b9fd0175559
-F configure 6f5136d2574d7aa08370021ab63be3ef8a8bf32af60594de08393b01feeb4bab x
-F configure.ac 3552d3aecade98a9d4b64bceb48ffb7726cbc85902efde956812942f060fbd0a
+F configure aae28230005acf833d466c8a160bd4c70cf42984f5a6756fa327e15e7f473477 x
+F configure.ac 798a24cee2879325ca5b688a618199eb32cc77ed8136edbaa43d9137b470d54e
F contrib/sqlitecon.tcl 210a913ad63f9f991070821e599d600bd913e0ad
F doc/F2FS.txt c1d4a0ae9711cfe0e1d8b019d154f1c29e0d3abfe820787ba1e9ed7691160fcd
F doc/lemon.html 24956ab2995e55fe171e55bdd04f22b553957dc8bb43501dbb9311e30187e0d3
F doc/pager-invariants.txt 27fed9a70ddad2088750c4a2b493b63853da2710
+F doc/trusted-schema.md 33625008620e879c7bcfbbfa079587612c434fa094d338b08242288d358c3e8a
F doc/vfs-shm.txt e101f27ea02a8387ce46a05be2b1a902a021d37a
F doc/wal2.md a807405a05e19a4945c5905a9ffa0fe45b8560dd7572461192501f565c19cdb5
F ext/README.md fd5f78013b0a2bc6f0067afb19e6ad040e89a10179b4f6f03eee58fac5f169bd
@@ -50,7 +51,7 @@ F ext/expert/README.md b321c2762bb93c18ea102d5a5f7753a4b8bac646cb392b3b437f633ca
F ext/expert/expert.c d548d603a4cc9e61f446cc179c120c6713511c413f82a4a32b1e1e69d3f086a4
F ext/expert/expert1.test e2afc53a27610e8251e44c7f961806607a5490ff204b3db342740d558e052662
F ext/expert/sqlite3expert.c 3da865f2286433588260f41e796422c611bceaca3a0bbf9139a619cf7d062c19
-F ext/expert/sqlite3expert.h af6354f8ee5c9e025024e63fec3bd640a802afcc3099a44d804752cf0791d811
+F ext/expert/sqlite3expert.h ca81efc2679a92373a13a3e76a6138d0310e32be53d6c3bfaedabd158ea8969b
F ext/expert/test_expert.c d56c194b769bdc90cf829a14c9ecbc1edca9c850b837a4d0b13be14095c32a72
F ext/fts1/README.txt 20ac73b006a70bcfd80069bdaf59214b6cf1db5e
F ext/fts1/ft_hash.c 3927bd880e65329bdc6f506555b228b28924921b
@@ -82,25 +83,25 @@ F ext/fts3/README.content fdc666a70d5257a64fee209f97cf89e0e6e32b51
F ext/fts3/README.syntax a19711dc5458c20734b8e485e75fb1981ec2427a
F ext/fts3/README.tokenizers b92bdeb8b46503f0dd301d364efc5ef59ef9fa8e2758b8e742f39fa93a2e422d
F ext/fts3/README.txt 8c18f41574404623b76917b9da66fcb0ab38328d
-F ext/fts3/fts3.c a01da95e840a6ddb14d0a14b35c9017a8b034b08511ca97af716f00df102fb3f
+F ext/fts3/fts3.c 52c09f459364732b5df73eff0373f991fd6af8f0f60fcdbb4b649205e88a7568
F ext/fts3/fts3.h 3a10a0af180d502cecc50df77b1b22df142817fe
-F ext/fts3/fts3Int.h 74384e28b778a057f1467529715668b98f3f12f52eeb564fd6ae1e894125c00c
+F ext/fts3/fts3Int.h f091030b976045e7df91af2337935952b477cdbd9f48058c44c965684484cb50
F ext/fts3/fts3_aux.c 96708c8b3a7d9b8ca1b68ea2b7e503e283f20e95f145becadedfad096dbd0f34
F ext/fts3/fts3_expr.c b132af223e90e35b9f9efa9fe63d6ae737d34153a3b6066736086df8abc78a1f
F ext/fts3/fts3_hash.c 8b6e31bfb0844c27dc6092c2620bdb1fca17ed613072db057d96952c6bdb48b7
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 7963dd25ec81013c31f3c61697d0a1f3d06be21af3565774645c08d3dedf1fa7
+F ext/fts3/fts3_snippet.c 052b35ad746349ffb53820379bacdb23ff3ac60d3cc13d986e56d42822ef5a9a
F ext/fts3/fts3_term.c f45a1e7c6ef464abb1231245d123dae12266b69e05cc56e14045b76591ae92d1
F ext/fts3/fts3_test.c 73b16e229e517c1b1f0fb8e1046182a4e5dbc8dbe6eea8a5d4353fcce7dbbf39
F ext/fts3/fts3_tokenize_vtab.c 1de9a61acfa2a0445ed989310c31839c57f6b6086dd9d5c97177ae734a17fd8b
-F ext/fts3/fts3_tokenizer.c 8034a5604c31559493fef0fed432cb251a566c46043c0b2c11b92c740e6f036f
+F ext/fts3/fts3_tokenizer.c 6d8fc150c48238955d5182bf661498db0dd473c8a2a80e00c16994a646fa96e7
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 13582783abedf905e6946ce95edff7103c07810fb03a9c3b40212d21a3efa09c
+F ext/fts3/fts3_write.c 6f9dd5d774003ea81b8b32daa7d0819f9aaf01bf2b5f33498a69aab096094ed3
F ext/fts3/fts3speed.tcl b54caf6a18d38174f1a6e84219950d85e98bb1e9
F ext/fts3/mkfts3amal.tcl 252ecb7fe6467854f2aa237bf2c390b74e71f100
F ext/fts3/tool/fts3cov.sh c331d006359456cf6f8f953e37f2b9c7d568f3863f00bb5f7eb87fea4ac01b73
@@ -110,16 +111,16 @@ F ext/fts3/unicode/UnicodeData.txt cd07314edb62d49fde34debdaf92fa2aa69011e7
F ext/fts3/unicode/mkunicode.tcl bf7fcaa6d68e6d38223467983785d054f1cff4d9e3905dd51f6ed8801bb590d5
F ext/fts3/unicode/parseunicode.tcl a981bd6466d12dd17967515801c3ff23f74a281be1a03cf1e6f52a6959fc77eb
F ext/fts5/extract_api_docs.tcl a36e54ec777172ddd3f9a88daf593b00848368e0
-F ext/fts5/fts5.h 7c9da96f2b9dcfa4dd94081fb2d87ec418d8cdb35b25df56756c334b6b558fd7
-F ext/fts5/fts5Int.h 0ec19a906a54c0e53f8a380c0ff70f11a866aa259490bc13aa39f8d2491800fd
+F ext/fts5/fts5.h c132a9323f22a972c4c93a8d5a3d901113a6e612faf30ca8e695788438c5ca2a
+F ext/fts5/fts5Int.h d7cbc214ee167496f70905667e18f73ea0402f7ef09236ce305e117e0efc866a
F ext/fts5/fts5_aux.c dcc627d8b6e3fc773db528ff67b39955dab7b51628f9dba8e15849e5bedfd7fa
F ext/fts5/fts5_buffer.c 5a5fe0159752c0fb0a5a93c722e9db2662822709490769d482b76a6dc8aaca70
-F ext/fts5/fts5_config.c 606a29f2962a8f4508923e6ad833974b32a3ab4093f63fd6de0fb33a87eed54c
-F ext/fts5/fts5_expr.c 5661fe64f4f5a499710df9561075de84b743f01e808af46df4130a9ec343a0fd
+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 6601d085d8e8cf4750ee49e2e1d18907582cc0aab78233d3b21bc240ba76a199
-F ext/fts5/fts5_main.c bf637030722badf06667d28f7159e4c209dbafd7aa76c33f387104b78ad147e1
-F ext/fts5/fts5_storage.c 801b4e3cd33786a60a07b6b01f86d0fbdf7e68325054e08d17176293a8081e99
+F ext/fts5/fts5_index.c e3573c88ce8238f7a5892c777a9ddf646c1355012780337d783fb2dfc3dca650
+F ext/fts5/fts5_main.c e881a2ea0bf01b3a3ff0bc1b31373c58fd54b6c9f3c43ea3d431bea4e5d4025e
+F ext/fts5/fts5_storage.c 3ecda8edadc1f62a355d6789776be0da609f8658c50d72e422674093ab7e1528
F ext/fts5/fts5_tcl.c 39bcbae507f594aad778172fa914cad0f585bf92fd3b078c686e249282db0d95
F ext/fts5/fts5_test_mi.c 08c11ec968148d4cb4119d96d819f8c1f329812c568bac3684f5464be177d3ee
F ext/fts5/fts5_test_tok.c f96c6e193c466711d6d7828d5f190407fe7ab897062d371426dd3036f01258e7
@@ -155,10 +156,10 @@ F ext/fts5/test/fts5columnsize.test 45459ce4dd9fd853b6044cdc9674921bff89e3d840f3
F ext/fts5/test/fts5config.test 60094712debc59286c59aef0e6cf511c37d866802776a825ce437d26afe0817f
F ext/fts5/test/fts5conflict.test 655925678e630d3cdf145d18725a558971806416f453ac8410ca8c04d934238d
F ext/fts5/test/fts5connect.test 08030168fc96fc278fa81f28654fb7e90566f33aff269c073e19b3ae9126b2f4
-F ext/fts5/test/fts5content.test 9517cc527a8e8a33949652d5c7b5e251f8c3d5ae3f23f01d4320e30f29a0336b
+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 e188a43cecb3ff53b6236f862f82b2ec36962b9e39f20cb620dfa07aed70afa4
+F ext/fts5/test/fts5corrupt3.test fab4ea761b2df254fb3909423989320772a3a757de4d151ddcfa2a40a3b93328
F ext/fts5/test/fts5corrupt4.test ea805c4d7c68b5f185b9db5d2060a7ae5875339738dd48203c92162f41e7ca91
F ext/fts5/test/fts5delete.test cbf87e3b8867c4d5cfcaed975c7475fd3f99d072bce2075fcedf43d1f82af775
F ext/fts5/test/fts5detail.test 31b240dbf6d44ac3507e2f8b65f29fdc12465ffd531212378c7ce1066766f54e
@@ -166,7 +167,7 @@ F ext/fts5/test/fts5determin.test 1b77879b2ae818b5b71c859e534ee334dac088b7cf3ff3
F ext/fts5/test/fts5dlidx.test b90852c55881b29dbac6380b274de27beae623ac4b6d567c6c8fb9cdc315a86e
F ext/fts5/test/fts5doclist.test e39a6001495f1dc68e20323586ac965787986c2bf6f515b9b0285627b089d9e6
F ext/fts5/test/fts5ea.test b01e3a18cdfabbff8104a96a5242a06a68a998a0
-F ext/fts5/test/fts5eb.test e5fe57b4141db456f06094afca45541fb0c13b30032eccae05100b4dbec11955
+F ext/fts5/test/fts5eb.test 239bb2f02571f8cccfc7018d08f502df1cd8cc6a69b65ed1dde5f6a070e3f669
F ext/fts5/test/fts5fault1.test d28a65caee75db6897c3cf1358c5230d3bb2a3bf7fb31062c19c7e5382b3d2bd
F ext/fts5/test/fts5fault2.test 69c8fdbef830cd0d450908d4504d5bb86609e255af99c421c20a0756251fe344
F ext/fts5/test/fts5fault3.test da2f9e3e56ff5740d68ebdd6877c97089e7ed28ddff28a0da87a6afea27e5522
@@ -180,17 +181,17 @@ F ext/fts5/test/fts5faultA.test be4487576bff8c22cee6597d1893b312f306504a8c6ccd3c
F ext/fts5/test/fts5faultB.test d606bdb8e81aaeb6f41de3fc9fc7ae315733f0903fbff05cf54f5b045b729ab5
F ext/fts5/test/fts5faultD.test cc5d1225556e356615e719c612e845d41bff7d5a
F ext/fts5/test/fts5first.test 3fcf2365c00a15fc9704233674789a3b95131d12de18a9b996159f6909dc8079
-F ext/fts5/test/fts5full.test 49b565da02918c06e58f51f0b953b0302b96f155aa68baba24782b81570685e2
+F ext/fts5/test/fts5full.test e1701a112354e0ff9a1fdffb0c940c576530c33732ee20ac5e8361777070d717
F ext/fts5/test/fts5fuzz1.test 238d8c45f3b81342aa384de3e581ff2fa330bf922a7b69e484bbc06051a1080e
F ext/fts5/test/fts5hash.test a4cf51acad99bfc43c16fb74f9d22495dc221ae0701fc5e908ca963a9b26a02b
-F ext/fts5/test/fts5integrity.test 4317561cd25eca7df16aa1f7d1a700ee958059fa639785f94aba0a84df9ab17b
+F ext/fts5/test/fts5integrity.test 8ffabcd91b058d812aba3e3e0a06f76ce165ba402a18cca20e34204a7feec92e
F ext/fts5/test/fts5interrupt.test 09613247b273a99889808ef852898177e671406fe71fdde7ea00e78ea283d227
F ext/fts5/test/fts5lastrowid.test be98fe3e03235296585b72daad7aed5717ba0062bae5e5c18dd6e04e194c6b28
F ext/fts5/test/fts5leftjoin.test c0b4cafb9661379e576dc4405c0891d8fcc2782680740513c4d1fc114b43d4ad
-F ext/fts5/test/fts5matchinfo.test 79129ff6c9a2d86943b287a5a8caa7ee639f6dcf004d8975d15c279374e82e35
+F ext/fts5/test/fts5matchinfo.test 50d86da66ec5b27603dcd90ba0227f5d9deb10351cbc52974a88e24f6fc9b076
F ext/fts5/test/fts5merge.test e92a8db28b45931e7a9c7b1bbd36101692759d00274df74d83fd29d25d53b3a6
F ext/fts5/test/fts5merge2.test 3ebad1a59d6ad3fb66eff6523a09e95dc6367cbefb3cd73196801dea0425c8e2
-F ext/fts5/test/fts5misc.test 5becd134b66f7370042968a2b127b92ea7748e249f16cb6a996f450812e89eec
+F ext/fts5/test/fts5misc.test 088ac5f0f5de1ad45b0f83197ab5263bcae8130156cdc901bff2375ff2b8af86
F ext/fts5/test/fts5multi.test a15bc91cdb717492e6e1b66fec1c356cb57386b980c7ba5af1915f97fe878581
F ext/fts5/test/fts5multiclient.test 5ff811c028d6108045ffef737f1e9f05028af2458e456c0937c1d1b8dea56d45
F ext/fts5/test/fts5near.test 211477940142d733ac04fad97cb24095513ab2507073a99c2765c3ddd2ef58bd
@@ -206,6 +207,7 @@ F ext/fts5/test/fts5rank.test c9fd4a1e36b4fa92d572ec13d846469b97da249d1c2f7fd3ee
F ext/fts5/test/fts5rebuild.test 55d6f17715cddbf825680dd6551efbc72ed916d8cf1cde40a46fc5d785b451e7
F ext/fts5/test/fts5restart.test 835ecc8f449e3919f72509ab58056d0cedca40d1fe04108ccf8ac4c2ba41f415
F ext/fts5/test/fts5rowid.test b8790ec170a8dc1942a15aef3db926a5f3061b1ff171013003d8297203a20ad6
+F ext/fts5/test/fts5savepoint.test fc02929f238d02a22df4172625704e029f7c1e0e92e332d654375690f8e6e43f
F ext/fts5/test/fts5simple.test a298670508c1458b88ce6030440f26a30673931884eb5f4094ac1773b3ba217b
F ext/fts5/test/fts5simple2.test 258a1b0c590409bfa5271e872c79572b319d2a56554d0585f68f146a0da603f0
F ext/fts5/test/fts5simple3.test d5c74a9d3ca71bd5dd5cacb7c55b86ea12cdddfc8b1910e3de2995206898380f
@@ -230,7 +232,7 @@ 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/icu.c c2c7592574c08cd1270d909b8fb8797f6ea1f49e931e71dbcc25506b9b224580
+F ext/icu/icu.c 7adfe8a72dd4f54b47684dc9b88523399c6ef119d733b73e17371445f7428dd1
F ext/icu/sqliteicu.h 728867a802baa5a96de7495e9689a8e01715ef37
F ext/lsm1/Makefile a553b728bba6c11201b795188c5708915cc4290f02b7df6ba7e8c4c943fd5cd9
F ext/lsm1/Makefile.msc f8c878b467232226de288da320e1ac71c131f5ec91e08b21f502303347260013
@@ -278,7 +280,7 @@ F ext/lsm1/test/lsm1_common.tcl 5ed4bab07c93be2e4f300ebe46007ecf4b3e20bc5fbe1ded
F ext/lsm1/test/lsm1_simple.test a04d08e8661ae6fc53786c67f0bd102c6692f003e859dde03ed9ac3f12e066e5
F ext/lsm1/tool/mklsm1c.tcl f31561bbee5349f0a554d1ad7236ac1991fc09176626f529f6078e07335398b0
F ext/misc/README.md d6dd0fe1d8af77040216798a6a2b0c46c73054d2f0ea544fbbcdccf6f238c240
-F ext/misc/amatch.c 50a9ef2d38dabfa371f8c1904097d493271e63d58ccb0e9b79a4fa4a94e66660
+F ext/misc/amatch.c e3ad5532799cee9a97647f483f67f43b38796b84b5a8c60594fe782a4338f358
F ext/misc/anycollseq.c 5ffdfde9829eeac52219136ad6aa7cd9a4edb3b15f4f2532de52f4a22525eddb
F ext/misc/appendvfs.c 3777f22ec1057dc4e5fd89f2fbddcc7a29fbeef1ad038c736c54411bb1967af7
F ext/misc/bgckpt.c 49ae19aa03e6da393db5d17da256374d4c4d36889fdd89d6e4bc93aca2b752e6
@@ -286,46 +288,49 @@ F ext/misc/blobio.c a867c4c4617f6ec223a307ebfe0eabb45e0992f74dd47722b96f3e631c0e
F ext/misc/btreeinfo.c 4f0ebf278f46e68e6306c667917766cebc5550fd35d5de17847988e22892d4d2
F ext/misc/carray.c 91e9a7f512fda934894bed30464552fffa7d3073b5be04189ae0bd0c59f26bfd
F ext/misc/closure.c dbfd8543b2a017ae6b1a5843986b22ddf99ff126ec9634a2f4047cd14c85c243
-F ext/misc/completion.c cec672d40604075bb341a7f11ac48393efdcd90a979269b8fe7977ea62d0547f
-F ext/misc/compress.c dd4f8a6d0baccff3c694757db5b430f3bbd821d8686d1fc24df55cf9f035b189
-F ext/misc/csv.c 7f047aeb68f5802e7ce6639292095d622a488bb43526ed04810e0649faa71ceb
+F ext/misc/completion.c a0efe03edfdc4f717c61e6c9b0bfe2708ff7878010dae3174980a68fdf76aabc
+F ext/misc/compress.c 3ed77691a3ce9e50921ae2b133dc176bb4d5587fdb57bde5872c4e5c348ce0bc
+F ext/misc/csv.c 3ed979c1eb35e35a98b30ef545a2facf62994594217681d9138b4b75faf6b0d7
F ext/misc/dbdata.c e316fba936571584e55abd5b974a32a191727a6b746053a0c9d439bd2cf93940
F ext/misc/dbdump.c baf6e37447c9d6968417b1cd34cbedb0b0ab3f91b5329501d8a8d5be3287c336
-F ext/misc/eval.c 4b4757592d00fd32e44c7a067e6a0e4839c81a4d57abc4131ee7806d1be3104e
+F ext/misc/eval.c 04bc9aada78c888394204b4ed996ab834b99726fb59603b0ee3ed6e049755dc1
F ext/misc/explain.c d5c12962d79913ef774b297006872af1fccda388f61a11d37758f9179a09551f
-F ext/misc/fileio.c 288e7230e0fe464d71b0694e2d8bdd3a353118ac2e31da3964b95f460f09915f
-F ext/misc/fossildelta.c 7708651072eb5620ab21bbfb518d184f27b2c29c0131b09b9a2d8852a8016430
-F ext/misc/fuzzer.c c4e27daf41433a64cad5265cd27dbcb891147e9994d0422200ce81ce9a54b625
-F ext/misc/ieee754.c f190d0cc5182529acb15babd177781be1ac1718c
-F ext/misc/json1.c 66ccdfa63283adb2c015019b431eeee1f5af40a78d9aad10afd22c2c6db0e3b0
+F ext/misc/fileio.c bfa11a207da4eed8e5f84a1e3954608492f25f8850f9f00d0d2076f4648d7608
+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/memstat.c 3017a0832c645c0f8c773435620d663855f04690172316bd127270d1a7523d4d
F ext/misc/memtrace.c 7c0d115d2ef716ad0ba632c91e05bd119cb16c1aedf3bec9f06196ead2d5537b
F ext/misc/memvfs.c ab36f49e02ebcdf85a1e08dc4d8599ea8f343e073ac9e0bca18a98b7e1ec9567
F ext/misc/mmapwarm.c 8c5fe90d807a23e44a8b93e96e8b812b19b300d5fd8c1d40a4fd1d8224e33f46
-F ext/misc/nextchar.c 279f80fe8ef5ba413242e2704e246503ac601f005eefb180d19e6c920338a0ba
+F ext/misc/nextchar.c 7877914c2a80c2f181dd04c3dbef550dfb54c93495dc03da2403b5dd58f34edd
+F ext/misc/noop.c 81efe4cad9ec740e64388b14281cb983e6e2c223fed43eb77ab3e34946e0c1ab
F ext/misc/normalize.c b4290464f542bae7a97b43f15bd197949b833ffd668b7c313631bd5d4610212c
-F ext/misc/percentile.c 148dd07286b16e50f232bb638a47850085ad37d51f270429905bd865e595d1ca
-F ext/misc/prefixes.c 7be86d17525cfae6ed462fc3c519efc44488ac329890f77491c8f82871f57e17
-F ext/misc/regexp.c 653b6ab5e89bcb5d45f9ebe0747d7f8f3f5706cac963fcbc9a3ddbe5fdc1efa2
+F ext/misc/percentile.c b9086e223d583bdaf8cb73c98a6539d501a2fc4282654adbfea576453d82e691
+F ext/misc/prefixes.c 0f4f8cff5aebc00a7e3ac4021fd59cfe1a8e17c800ceaf592859ecb9cbc38196
+F ext/misc/regexp.c 246244c714267f303df76acf73dcf110cf2eaf076896aaaba8db6d6d21a129db
F ext/misc/remember.c add730f0f7e7436cd15ea3fd6a90fd83c3f706ab44169f7f048438b7d6baa69c
-F ext/misc/rot13.c 540a169cb0d74f15522a8930b0cccdcb37a4fd071d219a5a083a319fc6e8db77
+F ext/misc/rot13.c 51ac5f51e9d5fd811db58a9c23c628ad5f333c173f1fc53c8491a3603d38556c
F ext/misc/scrub.c db9fff56fed322ca587d73727c6021b11ae79ce3f31b389e1d82891d144f22ad
-F ext/misc/series.c 0c97f63378fddc9f425e82ba139b9aaf902211f24ced115c2b6ae12b425f7334
-F ext/misc/sha1.c df0a667211baa2c0612d8486acbf6331b9f8633fd4d605c17c7cccd26d59c6bd
-F ext/misc/shathree.c 22ba7ca84a433d6466a7d05dcc876910b435a715da8cc462517db9351412b8c8
+F ext/misc/series.c a733a77d152983cc5d337c9df7b358ad17cfb44965476843cd03e2f571054914
+F ext/misc/sha1.c 1190aec0d9d886d9f5ffdf891142a626812327d11472c0cade3489db3b7b140a
+F ext/misc/shathree.c 135b7c145db4a09b1650c3e7aff9cb538763a9a361e834c015dd1aaf8d5c9a00
F ext/misc/showauth.c 732578f0fe4ce42d577e1c86dc89dd14a006ab52
-F ext/misc/spellfix.c f88ecb2c0294453ce8b7704b211f5350c41b085b38c8e056852e3a08b0f5e484
-F ext/misc/sqlar.c 57d5bc45cd5492208e451f697404be88f8612527d64c9d42f96b325b64983d74
+F ext/misc/spellfix.c 5cb7e1876925508aeef0e5ecd5ec8dab6089e09fa44cbf4322d5cb7a821a53f9
+F ext/misc/sqlar.c c9e5d58544e1506135806a1e0f525f92d4bb6bb125348dce469d778fb334fbce
F ext/misc/stmt.c 8a8dc4675042e4551e4afe99b8d0cc7a4a2fc1a8dacc0a9ce1b1bbff145da93d
F ext/misc/templatevtab.c 8a16a91a5ceaccfcbd6aaaa56d46828806e460dd194965b3f77bf38f14b942c4
-F ext/misc/totype.c 4a167594e791abeed95e0a8db028822b5e8fe512
+F ext/misc/totype.c fa4aedeb07f66169005dffa8de3b0a2b621779fd44f85c103228a42afa71853b
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/vtablog.c 5538acd0c8ddaae372331bee11608d76973436b77d6a91e8635cfc9432fba5ae
F ext/misc/vtshim.c 1976e6dd68dd0d64508c91a6dfab8e75f8aaf6cd
-F ext/misc/wholenumber.c 784b12543d60702ebdd47da936e278aa03076212
-F ext/misc/zipfile.c c1ca8f52330b4564207036b978edac8141c737bf612659bf6f7bee3ddd563a03
+F ext/misc/wholenumber.c 520f34c3099e5b7d546f13708607dc2fa173c46b68952eecf0d19cd675fec85e
+F ext/misc/zipfile.c d1be54ea83ac9ad71b8b6ffc4b60db8946ce2ceacdf6bff063fcd9489f41bb49
F ext/misc/zorder.c b0ff58fa643afa1d846786d51ea8d5c4b6b35aa0254ab5a82617db92f3adda64
F ext/rbu/rbu.c 8681f6157db6adc82c34af24b14ea8a3be0146ad2a3b6c1d5da6cb8a5796c8ce
F ext/rbu/rbu1.test 221d9c18a5e600ac9ac6b1810d99d9f99163a7909ba61597876ab6e4d4beb3d6
@@ -367,7 +372,7 @@ 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 f3a3e09f575157052813be667d6ab3b54f47fb02e6e1c9f767ad7bb8f1fb90b3
+F ext/rbu/sqlite3rbu.c 77a47f3231f5f363b2c584dba3e310a7efdaf073ad8c18728ab846b38de2879c
F ext/rbu/sqlite3rbu.h 1dc88ab7bd32d0f15890ea08d23476c4198d3da3056985403991f8c9cd389812
F ext/rbu/test_rbu.c 03f6f177096a5f822d68d8e4069ad8907fe572c62ff2d19b141f59742821828a
F ext/repair/README.md 92f5e8aae749a4dae14f02eea8e1bb42d4db2b6ce5e83dbcdd6b1446997e0c15
@@ -380,11 +385,11 @@ 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 c591164125808f8bba9659e92665b78412cd263e654b6f05294f3a8da7cdd9fb
-F ext/rtree/rtree.c f8d9ea7d988c1002bff5acfac77d188f2f5d9eb025f24d5038a3d70a9c3f3d9d
+F ext/rtree/geopoly.c cac70b5502742bd0ba8877a1329a74e86a379c78567546a2a18cf5f9c3787f73
+F ext/rtree/rtree.c 84b939a9a558edd0461bb976b98f60012e3e574b3b17a0f44533d6f2a9aa2f2e
F ext/rtree/rtree.h 4a690463901cb5e6127cf05eb8e642f127012fd5003830dbc974eca5802d9412
-F ext/rtree/rtree1.test 7573134f1b4f59df36c1b0a6de51268fd3b9c714d91f3811482263e734e416ea
-F ext/rtree/rtree2.test 5f25b01acd03470067a2d52783b2eb0a50bf836803d4342d20ca39e541220fe2
+F ext/rtree/rtree1.test 4092a8bd2b5eafc4fafe4fe9024249c12b13e4bab23c2c3eaff57412fdf805fa
+F ext/rtree/rtree2.test 9d9deddbb16fd0c30c36e6b4fdc3ee3132d765567f0f9432ee71e1303d32603d
F ext/rtree/rtree3.test 4ee5d7df86040efe3d8d84f141f2962a7745452200a7cba1db06f86d97050499
F ext/rtree/rtree4.test 304de65d484540111b896827e4261815e5dca4ce28eeecd58be648cd73452c4b
F ext/rtree/rtree5.test 49c9041d713d54560b315c2c7ef7207ee287eba1b20f8266968a06f2e55d3142
@@ -394,12 +399,13 @@ F ext/rtree/rtree8.test 2d99006a1386663978c9e1df167554671e4f711c419175b39f332719
F ext/rtree/rtree9.test c646f12c8c1c68ef015c6c043d86a0c42488e2e68ed1bb1b0771a7ca246cbabf
F ext/rtree/rtreeA.test ed2f1be9c06dde0b1ab93a95dd9e87eeaa02db2d30bcb4b9179b69ee3dc3319b
F ext/rtree/rtreeB.test 4cec297f8e5c588654bbf3c6ed0903f10612be8a2878055dd25faf8c71758bc9
-F ext/rtree/rtreeC.test 128928549d22b65c381ab1366760d08703cd75e34f6a7a506ece38f9330b7282
+F ext/rtree/rtreeC.test 6aa87eba4d9a3003b941a1ba77db259c5cabc3fd92fc5a6360f5369520eb9a4d
F ext/rtree/rtreeD.test fe46aa7f012e137bd58294409b16c0d43976c3bb92c8f710481e577c4a1100dc
F ext/rtree/rtreeE.test e65d3fc625da1800b412fc8785817327d43ccfec5f5973912d8c9e471928caa9
F ext/rtree/rtreeF.test 81ffa7ef51c4e4618d497a57328c265bf576990c7070633b623b23cd450ed331
F ext/rtree/rtreeG.test 1b9ca6e3effb48f4161edaa463ddeaa8fca4b2526d084f9cbf5dbe4e0184939c
-F ext/rtree/rtreeH.test aa08cc4fa8005b4c67446c7110205055b4d6da90e760e6f44b82dfa4cdf8d87a
+F ext/rtree/rtreeH.test 0885151ee8429242625600ae47142cca935332c70a06737f35af53a7bd7aaf90
+F ext/rtree/rtreeI.test 608e77f7fde9be5a12eae316baef640fffaafcfa90a3d67443e78123e19c4ca4
F ext/rtree/rtree_perf.tcl 6c18c1f23cd48e0f948930c98dfdd37dfccb5195
F ext/rtree/rtree_util.tcl db734b4c5e75fed6acc56d9701f2235345acfdec750b5fc7b587936f5f6bceed
F ext/rtree/rtreecheck.test d67d5b3e9e45bfa8cd90734e8e9302144ac415b8e9176c6f02d4f92892ee8a35
@@ -441,7 +447,7 @@ F ext/session/sessionrebase.test ccfa716b23bd1d3b03217ee58cfd90c78d4b99f53e6a9a2
F ext/session/sessionstat1.test 218d351cf9fcd6648f125a26b607b140310160184723c2666091b54450a68fb5
F ext/session/sessionwor.test 67b5ab91d4f93ce65ff1f58240ac5ddf73f8670facc1ffa49cef56293d52818d
F ext/session/sqlite3session.c a4dfb372f270df93422b0dc7666fd46849e6979b62a152f11287c21eed4ac21b
-F ext/session/sqlite3session.h 919be6649d39d6413ce7a63fc3e3bca3270e18bc2d57ad4040a70007b9e54397
+F ext/session/sqlite3session.h a2db5b72b938d12c727b4b4ec632254ca493670a9c0de597af3271a7f774fc57
F ext/session/test_session.c 98797aba475a799376c9a42214f2d1debf2d0c3cb657d9c8bbf4f70bf3fb4aec
F ext/userauth/sqlite3userauth.h 7f3ea8c4686db8e40b0a0e7a8e0b00fac13aa7a3
F ext/userauth/user-auth.txt e6641021a9210364665fe625d067617d03f27b04
@@ -449,7 +455,7 @@ F ext/userauth/userauth.c f81aa5a3ecacf406f170c62a144405858f6f6de51dbdc0920134e6
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60
-F main.mk 75e8e97df691c3b55988e00a14c662f8678a58f30ceb643f36154c0d822f64e1
+F main.mk c538a7e0f5106a7d72c7ce2c8153123458319f87ce28973a8e8955c14cb29c9a
F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83
F mptest/config01.test 3c6adcbc50b991866855f1977ff172eb6d901271
F mptest/config02.test 4415dfe36c48785f751e16e32c20b077c28ae504
@@ -461,38 +467,38 @@ F spec.template 86a4a43b99ebb3e75e6b9a735d5fd293a24e90ca
F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
F sqlite3.1 fc7ad8990fc8409983309bb80de8c811a7506786
F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a
-F src/alter.c 5c3031e45e80f79d7d54c2d32dd3c44926544d4f6a478858bfe4ee3191570190
-F src/analyze.c a3f4ea45cdb4e9df78d4ea7beb87ec8a7a46f494173b641cd28512a40a97bff2
-F src/attach.c 3ca19504849c2d9be10fc5899d6811f9d6e848665d1a41ffb53df0cd6e7c13ed
+F src/alter.c f48a4423c8f198d7f1ae4940f74b606707d05384ac79fb219be8e3323af2a2de
+F src/analyze.c b3ceec3fc052df8a96ca8a8c858d455dc5029ba681b4be98bb5c5a9162cfa58c
+F src/attach.c df0ead9091042c68964856ecc08dba55d5403ad5f3ca865d9d396d71528c511a
F src/auth.c a3d5bfdba83d25abed1013a8c7a5f204e2e29b0c25242a56bc02bb0c07bf1e06
F src/backup.c f70077d40c08b7787bfe934e4d1da8030cb0cc57d46b345fba2294b7d1be23ab
F src/bitvec.c 17ea48eff8ba979f1f5b04cc484c7bb2be632f33
F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6
-F src/btree.c 48b4ced9555171d4a5800ae65ef491dac12d1aa9706f09e3f76f3c6e0bff7a41
-F src/btree.h c11446f07ec0e9dc85af8041cb0855c52f5359c8b2a43e47e02a685282504d89
-F src/btreeInt.h 6111c15868b90669f79081039d19e7ea8674013f907710baa3c814dc3f8bfd3f
-F src/build.c 4814d55abb5553ac82763f6df9e185503d913f912cc0abea00965bb02912cc2d
-F src/callback.c 25dda5e1c2334a367b94a64077b1d06b2553369f616261ca6783c48bcb6bda73
+F src/btree.c dff80958a9a0e63a0f3d53a2f00765dd14015434a6a19e9b3471fab7a4ecf553
+F src/btree.h 6111552f19ed7a40f029cf4b33badc6fef9880314fffd80a945f0b7f43ab7471
+F src/btreeInt.h 6794084fad08c9750b45145743c0e3e5c27c94dee89f26dd8df7073314934fd2
+F src/build.c bd2f382562b08f14748d54402220be1082c2f8ff8973fad47e45a381c438f9bf
+F src/callback.c c547d00963ae28100117b4fb1f0f32242109b5804374ee3bfe01138a54da7f76
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
F src/ctime.c 1b0724e66f95f33b160b1af85caaf9cceb325d22abf39bd24df4f54a73982251
F src/date.c e1d8ac7102f3f283e63e13867acb0efa33861cf34f0faf4cdbaf9fa7a1eb7041
-F src/dbpage.c 135eb3b5e74f9ef74bde5cec2571192c90c86984fa534c88bf4a055076fa19b7
-F src/dbstat.c c12833de69cb655751487d2c5a59607e36be1c58ba1f4bd536609909ad47b319
-F src/delete.c d08c9e01a2664afd12edcfa3a9c6578517e8ff8735f35509582693adbe0edeaf
-F src/expr.c 1e9a6da29e3e13c14783891e867e19a54e2731c6a9b58d011cc4f3b4742a59e4
+F src/dbpage.c 8a01e865bf8bc6d7b1844b4314443a6436c07c3efe1d488ed89e81719047833a
+F src/dbstat.c 0f55297469d4244ab7df395849e1af98eb5e95816af7c661e7d2d8402dea23da
+F src/delete.c a5c59b9c0251cf7682bc52af0d64f09b1aefc6781a63592c8f1136f7b73c66e4
+F src/expr.c 003c59158b33d7f3b198122cb0d1e13c06517cc3932e56b42283eb0e96696d66
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
-F src/fkey.c 6b79f4c2447691aa9ac86e2a6a774b65f3b3dd053d4220a4893051a0de20f82e
-F src/func.c ed33e38cd642058182a31a3f518f2e34f4bbe53aa483335705c153c4d3e50b12
-F src/global.c a1a8d698762ddd9a1543aac26c1e0029b20fcc3fcb56bfa41ec8cea2368f2798
+F src/fkey.c 92a248ec0fa4ed8ab60c98d9b188ce173aaf218f32e7737ba77deb2a684f9847
+F src/func.c 259496e4856bd0a3215d16804992f3339f3e8db29f129a5a7285c341488bbe9c
+F src/global.c 59601d885a0dbbfbd22ed2d030424a5e7f1b9809a17ca46686058bbc4a55e980
F src/hash.c 8d7dda241d0ebdafb6ffdeda3149a412d7df75102cecfc1021c98d6219823b19
F src/hash.h 9d56a9079d523b648774c1784b74b89bd93fac7b365210157482e4319a468f38
-F src/hwtime.h 747c1bbe9df21a92e9c50f3bbec1de841dc5e5da
+F src/hwtime.h cb1d7e3e1ed94b7aa6fde95ae2c2daccc3df826be26fc9ed7fd90d1750ae6144
F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
-F src/insert.c 40557ebd69f4115e7a273f9304a8ab637a47ce44f3c6923396928f023967b5e8
+F src/insert.c 5ba8fd376f539240939ae76b5bc9fa7ad9a0d86e9914ecd11eb7002204138c11
F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa
-F src/loadext.c 4ddc65ae13c0d93db0ceedc8b14a28c8c260513448b0eb8c5a2ac375e3b6a85d
-F src/main.c 3851950717170ade4f6d718c18c6c7400ef5994c2a654679af2cff2ffd0fb2b9
-F src/malloc.c 0f9da2a66b230a5785af94b9672126845099b57b70a32c987d04ac28c69da990
+F src/loadext.c 8cd803f1747c03a50b32fe87ebfb5851998d0cdafefe02737daa95e0616b42bb
+F src/main.c da8b42cee9b83cc923bf23d1945c9fb48cf57cb0422d5fe43a1ff88dc453b97b
+F src/malloc.c eaa4dc9602ce28b077f7de2eb275db2be270c5cc56d7fec5466301bd9b80e2f5
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
F src/mem1.c c12a42539b1ba105e3707d0e628ad70e611040d8f5e38cf942cee30c867083de
F src/mem2.c f1940d9e91948dd6a908fbb9ce3835c36b5d83c3
@@ -507,37 +513,37 @@ 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 20f7b32c1e8839999fa7e79756a6cdc3041b44d7fc635c25a1b9399180d1fbd9
+F src/os.c 669cc3839cc35d20f81faf0be1ab6d4581cea35e9d8f3a9d48a98d6571f7c285
F src/os.h 48388821692e87da174ea198bf96b1b2d9d83be5dfc908f673ee21fafbe0d432
F src/os_common.h b2f4707a603e36811d9b1a13278bffd757857b85
F src/os_setup.h 0dbaea40a7d36bf311613d31342e0b99e2536586
-F src/os_unix.c a76a75f179cb233d54e505c3e0c84832224cfe5dfb3ee470bdcaf1ed29da57ab
+F src/os_unix.c ad7640c04eed946052a3b12856362a773d0a717696707313037186df0e2b59f2
F src/os_win.c 035a813cbd17f355bdcad7ab894af214a9c13a1db8aeac902365350b98cd45a7
F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
-F src/pager.c 3469df53e0d6acd4f40d77f1f414079e1c0b17e5ca2a782e7ccd91262a8ce67e
-F src/pager.h 3abf6d65199fd0680b26a047c6167a96a4d6ead7535e02522b79f0fb27a3edec
-F src/parse.y 50bfcb34be7320dd0cb875021a93ae6451c8f0b083f21b71934a1a3a9108015a
+F src/pager.c fda3600e72367db8410f28b64f5d3a64731840c76ebe3f88d795a1e8772c6cfb
+F src/pager.h d49d4cb7be2e29ce2c376fe87443b2cbf1d95168ed85a65c39530c817303e246
+F src/parse.y c8d2de64db469fd56e0fa24da46cd8ec8523eb98626567d2708df371b47fdc3f
F src/pcache.c 385ff064bca69789d199a98e2169445dc16e4291fa807babd61d4890c3b34177
F src/pcache.h 4f87acd914cef5016fae3030343540d75f5b85a1877eed1a2a19b9f284248586
-F src/pcache1.c 62714cbd1b7299a6e6a27a587b66b4fd3a836a84e1181e7f96f5c34a50917848
-F src/pragma.c 3ab9816bab2b2b1662aaf29c5ac0d204daaee23c66daea180dc10303c7d68761
-F src/pragma.h 40962d65b645bb3f08c1f4c456effd01c6e7f073f68ea25177e0c95e181cff75
-F src/prepare.c 132484635a30f873ee7eccd47f93ed1932503863b93b28423b42332d81adffaf
+F src/pcache1.c 6596e10baf3d8f84cc1585d226cf1ab26564a5f5caf85a15757a281ff977d51a
+F src/pragma.c 8b6013dbf6932f373998c54f24ff7a6ef05f1d8b775577ffc79630c8516daca5
+F src/pragma.h 9f86a3a3a0099e651189521c8ad03768df598974e7bbdc21c7f9bb6125592fbd
+F src/prepare.c 6049beb71385f017af6fc320d2c75a4e50b75e280c54232442b785fbb83df057
F src/printf.c 9be6945837c839ba57837b4bc3af349eba630920fa5532aa518816defe42a7d4
F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384
-F src/resolve.c e021be0c1c4a2125fa38aabcd8dbb764bf5b2c889a948c30d3708430ec6ccd00
+F src/resolve.c 1139e3157c710c6e6f04fe726f4e0d8bdb1ae89a276d3b0ca4975af163141c9c
F src/rowset.c d977b011993aaea002cab3e0bb2ce50cf346000dff94e944d547b989f4b1fe93
-F src/select.c f509982c96bb24ccf57a0155fbe1e6184e0b8fb8866a04397dc41baa400e5240
-F src/shell.c.in d70bcf630c4073eaa994fa74be98886c781918e794cb8b562be8df10f018e274
-F src/sqlite.h.in 5725a6b20190a1e8d662077a1c1c8ea889ad7be90dd803f914c2de226f5fe6ab
+F src/select.c 924b61cef57033a8ca1ed3dcffd02445a7dd0c837cc849b2e4117251cac831f5
+F src/shell.c.in 1b2a636ba5b676f844a2af2a5f719b5c4ace7c6825d56270e2ae912b2a5fc840
+F src/sqlite.h.in cedb3737511a45ae35fba6e4d6c250ae36f6b82da0de38113efa1a3bc83ee105
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
-F src/sqlite3ext.h cef696ce3293242c67b2339763608427bf72ee66f1f3a05389ac2a7b46001c31
-F src/sqliteInt.h 246740eab76d3ac87f856f8d979567089e8749104c12932143a6ba570e38e415
+F src/sqlite3ext.h b0f776a0d042b23b6bcbb6b0943e8a3768c7f0b438a275e7168f0204e223a4db
+F src/sqliteInt.h 7a29ba700a51eeb925731749a570cf3859f6a58ed94797ecf47508875b0ba279
F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b
-F src/status.c 46e7aec11f79dad50965a5ca5fa9de009f7d6bde08be2156f1538a0a296d4d0e
+F src/status.c 9ff2210207c6c3b4d9631a8241a7d45ab1b26a0e9c84cb07a9b5ce2de9a3b278
F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34
-F src/tclsqlite.c 50c93be3e1c03b4e6cf6756e5197afcfe7f5cd0497d83a7ac317cde09e19b290
-F src/test1.c 17e1395cbddeb9226b756d723a7566b45b43b99a5f9f55afb4ff70888de6ad6f
+F src/tclsqlite.c f2dae14bfe7a35c94b6d515df88071014678ec39dafebdcf8e6bde91d62516c1
+F src/test1.c 4d0ab2f67053a4fff87d1d3586ecc0e5322a1fc45dd4119ab11dc96de44f17a1
F src/test2.c 3efb99ab7f1fc8d154933e02ae1378bac9637da5
F src/test3.c 61798bb0d38b915067a8c8e03f5a534b431181f802659a6616f9b4ff7d872644
F src/test4.c 405834f6a93ec395cc4c9bb8ecebf7c3d8079e7ca16ae65e82d01afd229694bb
@@ -584,40 +590,40 @@ F src/test_tclsh.c 9bd1251cb78a0e52e1998386d061d7dda79911e63eb082b87e0fee3b81d48
F src/test_tclvar.c 33ff42149494a39c5fbb0df3d25d6fafb2f668888e41c0688d07273dcb268dfc
F src/test_thread.c 911d15fb14e19c0c542bdc8aabf981c2f10a4858
F src/test_vdbecov.c f60c6f135ec42c0de013a1d5136777aa328a776d33277f92abac648930453d43
-F src/test_vfs.c 32618cbd953963278804bb47e97be7085d9e0d8755b1e734c3e54e9b9e115277
+F src/test_vfs.c 36822d696789535bdd0260f07d2c9a46546082fea8bb1d0a7354c7f9366e37ea
F src/test_vfstrace.c bab9594adc976cbe696ff3970728830b4c5ed698
F src/test_windirent.c a895e2c068a06644eef91a7f0a32182445a893b9a0f33d0cdb4283dca2486ac1
F src/test_windirent.h 90dfbe95442c9762357fe128dc7ae3dc199d006de93eb33ba3972e0a90484215
F src/test_window.c cdae419fdcea5bad6dcd9368c685abdad6deb59e9fc8b84b153de513d394ba3f
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c
-F src/tokenize.c d3615f0cbe4db5949503bf5916f3cd4fa5de855d5b4ef560f3b6dd5629423a1e
-F src/treeview.c fddeb413159c3eeeaea3f496172f121cf3695606c461dc4e6dcee51417952df5
-F src/trigger.c 845ccc08f60716c58aa28fe6470385c18ef8c4e1d88c93dcf449bc13d464eb2e
-F src/update.c 7f05fad5e145248a00048aeb0bac78b8fdb4ed17216e14a6eb24c55596e87ee7
-F src/upsert.c 710c91bb13e3c3fed5b6fe17cb13e09560bdd003ad8b8c51e6b16c80cfc48b10
-F src/utf.c 2f0fac345c7660d5c5bd3df9e9d8d33d4c27f366bcfb09e07443064d751a0507
-F src/util.c fffdfa627be74d69ef425f92db124e7148af449bb8a3286e79577c42bca84061
+F src/tokenize.c 7b17f6e2f20f6cbcb0b215025a86b7457c38451fc7622f705e553d7a488c572d
+F src/treeview.c 438c1000587b33faba35e87596bebcf7f40638d98f33781cdd9e04711b18b09c
+F src/trigger.c a40d50e88bd3355f1d2a73f0a3b2d6b42eae26ca4219001b82ef0d064439badc
+F src/update.c 9ad19af96aff95dc02a923a99f97c1bc0b909009a29a2914b796f786b9ac0c60
+F src/upsert.c 2920de71b20f04fe25eb00b655d086f0ba60ea133c59d7fa3325c49838818e78
+F src/utf.c 736ff76753236ffbc8b5b939f5e0607f28aeaa7c780b3a56b419228f0a81c87b
+F src/util.c e5f3971160154e5c9b660fd119b02ec4890e87cd18a5bc4d45ee60cddbb9e6a2
F src/vacuum.c 82dcec9e7b1afa980288718ad11bc499651c722d7b9f32933c4d694d91cb6ebf
-F src/vdbe.c e72bbea7812aa9483fb9e09cfbcaaf77ee5b118ca5a2e98a9e2e46a77bf21de5
-F src/vdbe.h 3f2b571e702e77e6bf031f0236e554aedfae643e991f69000320f481408455cf
-F src/vdbeInt.h e95de5129124d77f01439e6635012adfaf23c0017bff47296126143cf18bd0c6
-F src/vdbeapi.c 95001d0f84ee3cda344fed98ca0d7961deb4fc836b83495630d0af1f7cc4789e
-F src/vdbeaux.c 7ccf418141df1c7f87b0d69510523ae522abbe47c769d1b2c15120e88fac3eb9
+F src/vdbe.c 0fe7bdf9a47a0988a855604cd814de3cb7e4a0df59d042238105faa9068fc15c
+F src/vdbe.h defd693289c7bb8d325f109be9490c77138061211a116827da7244b6015a4934
+F src/vdbeInt.h 30d3e8b991547cdf39025e416a0a737b0416d46747af70ae058f60e2e0466fe7
+F src/vdbeapi.c 1252d80c548711e47a6d84dae88ed4e95d3fbb4e7bd0eaa1347299af7efddf02
+F src/vdbeaux.c ff690e6c9314ef281de7c06f8c8c33393f0afca80aabb1fe69836dcf2d60b0bf
F src/vdbeblob.c 253ed82894924c362a7fa3079551d3554cd1cdace39aa833da77d3bc67e7c1b1
-F src/vdbemem.c d8e10d1773806105e62094c4ede0a4684f46caaf07667a45e6d461e94306b530
-F src/vdbesort.c da75f505aba230060ce6472605a4aa6494f73eeb1071e1cc2643c3d4035e671b
+F src/vdbemem.c ad9e6217635f2b04df98bc57b12c98cefc9c0a1745cca47f4e8109119213253d
+F src/vdbesort.c a3be032cc3fee0e3af31773af4a7a6f931b7230a34f53282ccf1d9a2a72343be
F src/vdbetrace.c fa3bf238002f0bbbdfb66cc8afb0cea284ff9f148d6439bc1f6f2b4c3b7143f0
-F src/vtab.c 5a0b7193d586991b3db30e343d6b59959906bfe8658a6a0a85709b20ca50bb49
+F src/vtab.c 7b704a90515a239c6cdba6a66b1bb3a385e62326cceb5ecb05ec7a091d6b8515
F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
-F src/wal.c 727863144d842b2cb08f0346e529cd841baa71c79769b641d1c38c4862bd0962
+F src/wal.c 4485157dfc1379cf6bfd545a011a193ab7e7c5d9737049d62984dbc5d4e6b3f0
F src/wal.h d2a69695c84137f76e19a247a342cb02ab0131001b6f58153d94b71195bbd84d
-F src/walker.c d5a94907dcac990e31976be9dc769d17f6a806782593d6aec9d760ee01ec22cd
-F src/where.c 9f3f23efc45934e7b7ea6c0c1042420b73053e7c3264feef6faf9ce6fbd5df61
-F src/whereInt.h 2c6bae136a7c0be6ff75dc36950d1968c67d005c8e51d7a9d77cb996bb4843d9
-F src/wherecode.c 535c8e228478fd971b9a5b6cb6773995b0fbf7020d5989508a5094ce5b8cd95b
-F src/whereexpr.c 05c283d26aa9c3f5d1bf13a5f6a573b43295b9db280eff18e26f97d7d7f119b4
-F src/window.c 064f251451c8e2a1c76b6269229d911a651e119c6a5f522b6eaebf8dc8714041
+F src/walker.c a137468bf36c92e64d2275caa80c83902e3a0fc59273591b96c6416d3253d05d
+F src/where.c df2bea0e0122e853d9f1a8ec68920744166d2a524e338eba92e5470538ecd1f9
+F src/whereInt.h e1d1db6bbec0ba4f345acc338f956c8237a6f06413afa68c6414e82fb5b06745
+F src/wherecode.c ec8870d6fe79668dd12d7edc65ae9771828d6cdfe478348c8abd872a89fdbadd
+F src/whereexpr.c 4b34be1434183e7bb8a05d4bf42bd53ea53021b0b060936fbd12062b4ff6b396
+F src/window.c f8ba2ee12a19b51d3ba42c16277c74185ee9215306bc0d5a03974ade8b5bc98f
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
F test/affinity2.test ce1aafc86e110685b324e9a763eab4f2a73f737842ec3b687bd965867de90627
F test/affinity3.test 6a101af2fc945ce2912f6fe54dd646018551710d
@@ -625,19 +631,19 @@ F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
F test/aggnested.test 12106f0748e8e9bfc1a8e6840e203e051eae06a26ed13fc9fd5db108a8d6db54
F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87
F test/all.test 2ecb8bbd52416642e41c9081182a8df05d42c75637afd4488aace78cc4b69e13
-F test/alter.test 16ed8d2470193f34bc711e51506ff1211ebfab8025ca3b9510ff2aef139874cb
+F test/alter.test 77f0092d137dd9470fc683b64ed92868e188462e713e52f48deae8902ea60b96
F test/alter2.test a966ccfcddf9ce0a4e0e6ff1aca9e6e7948e0e242cd7e43fc091948521807687
-F test/alter3.test 4d79934d812eaeacc6f22781a080f8cfe012fdc3
-F test/alter4.test 7e93a21fe131e1dfeb317e90056856f96b10381fc7fe3a05e765569a23400433
+F test/alter3.test 9351a9f0c59ff9dddecccaaa2f777ffee5369870c63d30d3a74add815254ec0f
+F test/alter4.test 74b22251c5e9c48093cfc4921ed9c11b59df84634aeeb00e501773320beb8424
F test/alterauth.test 63442ba61ceb0c1eeb63aac1f4f5cebfa509d352276059d27106ae256bafc959
F test/alterauth2.test c0a1ddf5b93d93cb0d15ba7acaf0c5c6fb515bbe861ede75b2d3fabad33b6499
-F test/altercol.test 54374d2ba18af25bb24e23acf18a60270d4ec120b7ec0558078b59d5aa1a31ad
+F test/altercol.test 1d6a6fe698b81e626baea4881f5717f9bc53d7d07f1cd23ee7ad1b931f117ddf
F test/alterlegacy.test 82022721ce0de29cedc9a7af63bc9fcc078b0ee000f8283b4b6ea9c3eab2f44b
F test/altermalloc.test 167a47de41b5c638f5f5c6efb59784002b196fff70f98d9b4ed3cd74a3fb80c9
F test/altermalloc2.test fa7b1c1139ea39b8dec407cf1feb032ca8e0076bd429574969b619175ad0174b
-F test/altertab.test b2004ac589207fed7e19877bc3f1ad65142be482f269c176ee407e3b4a65f1a0
-F test/altertab2.test 8883693952f6d7fb5f754dbf1d694ed780aa883027bef04cb1fb99a3b88c9272
-F test/altertab3.test c755ef31f8a61911331b46d71e43f6f3ef94af05c56314b168e47520355fa18e
+F test/altertab.test bd61e5b73d495ec4707133db91b07f09d57e339d988de5ec5a76d34a2198e8f2
+F test/altertab2.test b0d62f323ca5dab42b0bc028c52e310ebdd13e655e8fac070fe622bad7852c2b
+F test/altertab3.test 155b8dc225ce484454a7fb4c8ba745680b6fa0fc3e08919cbbc19f9309d128ff
F test/amatch1.test b5ae7065f042b7f4c1c922933f4700add50cdb9f
F test/analyze.test 547bb700f903107b38611b014ca645d6b5bb819f5210d7bf39c40802aafeb7d7
F test/analyze3.test 01f0b122e3e54ad2544f14f7cc7dcb4c2cb8753cad5e88c6b8d49615b3fd6a2b
@@ -657,14 +663,14 @@ F test/async2.test c0a9bd20816d7d6a2ceca7b8c03d3d69c28ffb8b
F test/async3.test d73a062002376d7edc1fe3edff493edbec1fc2f7
F test/async4.test 1787e3952128aa10238bf39945126de7ca23685a
F test/async5.test 383ab533fdb9f7ad228cc99ee66e1acb34cc0dc0
-F test/atof1.test ff0b0156fd705b67c506e1f2bfe9e26102bea9bd
+F test/atof1.test 1ccfc96a6888566597b83d882c81b3c04258dc39317e8c1cec89ba481eaa2fba
F test/atomic.test 065a453dde33c77ff586d91ccaa6ed419829d492dbb1a5694b8a09f3f9d7d061
F test/atomic2.test b6863b4aa552543874f80b42fb3063f1c8c2e3d8e56b6562f00a3cc347b5c1da
F test/atrc.c ec92d56d8fbed9eb3e11aaf1ab98cf7dd59e69dae31f128013f1d97e54e7dfed
F test/attach.test 21bce8681f780a8d631a5ec7ecd0d849bfe84611257b038ae4ffeccc609d8a4e
F test/attach2.test 256bd240da1835fb8408dd59fb7ef71f8358c7a756c46662434d11d07ba3a0ce
F test/attach3.test c59d92791070c59272e00183b7353eeb94915976
-F test/attach4.test 53bf502f17647c6d6c5add46dda6bac8b6f4665c
+F test/attach4.test aa05b1d8218b24eba5a7cccf4f224f514ba57ba705c9267f09d2bb63fed0eea1
F test/attachmalloc.test 12c4f028e570acf9e0a4b0b7fe6f536e21f3d5ebddcece423603d0569beaf438
F test/auth.test 2154625c05bc79f0e0ea72cb2358395a8041243caa0fd7ce7617d50da4331794
F test/auth2.test 9eb7fce9f34bf1f50d3f366fb3e606be5a2000a1
@@ -726,15 +732,15 @@ F test/capi3b.test efb2b9cfd127efa84433cd7a2d72ce0454ae0dc4
F test/capi3c.test 54e2dc0c8fd7c34ad1590d1be6864397da2438c95a9f5aee2f8fbc60c112e44b
F test/capi3d.test aba917805573a03deed961a21f07a5a84505ad0a616f7e3fc1508844a15bccc4
F test/capi3e.test 3d49c01ef2a1a55f41d73cba2b23b5059ec460fe
-F test/cast.test 3619f0c58c2e4b2a94aa86e75607e497d34ef40ab74418e71aef7b4ca5155895
+F test/cast.test 2906ccab6a3ebd147ffa63304b635be903ce58264110d0a0eb4fd9939422bb53
F test/cffault.test 9d6b20606afe712374952eec4f8fd74b1a8097ef
-F test/check.test 4b57ecbbb300336382ca21ef983dfa70b291a70ae430690494d13f1629f45a38
+F test/check.test b21a76546c2115af2674280566a8eba577e72adfec330c3d9a8a466d41f8eb0d
F test/checkfault.test da6cb3d50247169efcb20bdf57863a3ccfa1d27d9e55cd324f0680096970f014
F test/chunksize.test 427d87791743486cbf0c3b8c625002f3255cb3a89c6eba655a98923b1387b760
F test/close.test eccbad8ecd611d974cbf47278c3d4e5874faf02d811338d5d348af42d56d647c
F test/closure01.test 9905883f1b171a4638f98fc764879f154e214a306d3d8daf412a15e7f3a9b1e0
F test/coalesce.test cee0dccb9fbd2d494b77234bccf9dc6c6786eb91
-F test/collate1.test f9b653f515ef3324a0c4e3c6adbf136bb1903622af678d482a60c11c9c054e6c
+F test/collate1.test 532b4992f78e91dd80c2e3c7bd944fada8cbe3d6c0ded0b20f7182b4dfca0006
F test/collate2.test 9aaa410a00734e48bcb27f3872617d6f69b2a621
F test/collate3.test 89defc49983ddfbf0a0555aca8c0521a676f56a5
F test/collate4.test c953715fb498b87163e3e73dd94356bff1f317bd
@@ -747,9 +753,9 @@ F test/collateA.test b8218ab90d1fa5c59dcf156efabb1b2599c580d6
F test/collateB.test 1e68906951b846570f29f20102ed91d29e634854ee47454d725f2151ecac0b95
F test/colmeta.test 2c765ea61ee37bc43bbe6d6047f89004e6508eb1
F test/colname.test 87ad5458bb8709312dac0d6755fd30e8e4ca83298d0a9ef6e5c24277a3c3390e
-F test/conflict.test c7cc007e2af151516ddf38f7412fe10d473a694f55e3df437e2c7b31c2590e8d
+F test/conflict.test 58857e2533fb9f2e0358ea7cb191215657846be1dd9da3b3d6df3e750c02ae03
F test/conflict2.test bb0b94cf7196c64a3cbd815c66d3ee98c2fecd9c
-F test/conflict3.test 56d18aedfa521a7ebffadb8254cfff10caf4e49cd8659cb54da39513aed478ba
+F test/conflict3.test 81865d9599609aca394fb3b9cd5f561d4729ea5b176bece3644f6ecb540f88ac
F test/contrib01.test 2a1cbc0f2f48955d7d073f725765da6fbceda6b4
F test/corrupt.test d7cb0300e4a297147b6a05e92a1684bc8973635c3bcaa3d66e983c9cbdbf47a3
F test/corrupt2.test bb50042cf9a1f1023d73af325d47eb02a6bb11e3c52f8812644b220c5d4bca35
@@ -762,16 +768,16 @@ F test/corrupt8.test 2399dfe40d2c0c63af86706e30f3e6302a8d0516
F test/corrupt9.test 730a3db08d4ab9aa43392ea30d9c2b4879cbff85
F test/corruptA.test 56e8f321adaf3411960e9d2c7136669d8e1a91cbde6cf401ea84e6d6c7ccbe10
F test/corruptB.test 73a8d6c0b9833697ecf16b63e3c5c05c945b5dec
-F test/corruptC.test 776f43eb7df750f6d00b8b59c36c3b690822b2880ddbd80d22bf44e9f66acf5c
+F test/corruptC.test 74d4498fd25759618b393f1e9cde111de828b88c1848ab320f6c179fd52b5a60
F test/corruptD.test 33a37ce3ed56a20093ceee778cd2d7109c7085a59f3213d2baede11d952e8e50
-F test/corruptE.test 82ccf4f8f543fdbedd4aa42c709cb077f7374c62
+F test/corruptE.test 4143791f2dfb443aec5b7fabfa5821e6063eccc3b49b06f212c2f014715fd476
F test/corruptF.test be9fde98e4c93648f1ba52b74e5318edc8f59fe4
F test/corruptG.test adf79b669cbfd19e28c8191a610d083ae53a6d51
F test/corruptH.test 79801d97ec5c2f9f3c87739aa1ec2eb786f96454
F test/corruptI.test a17bbf54fdde78d43cf3cc34b0057719fd4a173a3d824285b67dc5257c064c7b
F test/corruptJ.test 4d5ccc4bf959464229a836d60142831ef76a5aa4
F test/corruptK.test 5b4212fe346699831c5ad559a62c54e11c0611bdde1ea8423a091f9c01aa32af
-F test/corruptL.test dfad96373bf9264d73039315ea6013994b90bf6776847adc7ec06b6fad3c04b2
+F test/corruptL.test 4f28fbef85a6f27489542bb915ab7938dcd68f896e8f62a7d23de02b32489e5d
F test/corruptM.test 7d574320e08c1b36caa3e47262061f186367d593a7e305d35f15289cc2c3e067
F test/cost.test 51f4fcaae6e78ad5a57096831259ed6c760e2ac6876836e91c00030fad385b34
F test/count.test cb2e0f934c6eb33670044520748d2ecccd46259c
@@ -795,7 +801,7 @@ F test/cursorhint.test 7bc346788390475e77a345da2b92270d04d35856
F test/cursorhint2.test 6f3aa9cb19e7418967a10ec6905209bcbb5968054da855fc36c8beee9ae9c42f
F test/dataversion1.test 6e5e86ac681f0782e766ebcb56c019ae001522d114e0e111e5ebf68ccf2a7bb8
F test/date.test 9b73bbeb1b82d9c1f44dec5cf563bf7da58d2373
-F test/date2.test 74c234bece1b016e94dd4ef9c8cc7a199a8806c0e2291cab7ba64bace6350b10
+F test/date2.test 5ef8265c71460cda6b1698bf18f4bb0ffb40ac08c5092f6afe84d398c2feb5be
F test/dbdata.test 042f49acff3438f940eeba5868d3af080ae64ddf26ae78f80c92bec3ca7d8603
F test/dbfuzz.c 73047c920d6210e5912c87cdffd9a1c281d4252e
F test/dbfuzz001.test 42aad1dcef6219fbee86a9b7d08832c9bbb2e41508f6f128ae91745927276292
@@ -810,12 +816,12 @@ F test/delete2.test 3a03f2cca1f9a67ec469915cb8babd6485db43fa
F test/delete3.test 555e84a00a99230b7d049d477a324a631126a6ab
F test/delete4.test 6aa279f459f4aa792cc251435c3809415c1ecaf9f27dce91675e26f05b503db3
F test/delete_db.test 096d828493c7907f9ea11a7098ea6a0f73edba89406487d5d6cc2228dc4ab8b0
-F test/descidx1.test 6d03b44c8538fe0eb4924e19fba10cdd8f3c9240
-F test/descidx2.test 9f1a0c83fd57f8667c82310ca21b30a350888b5d
-F test/descidx3.test 09ddbe3f5295f482d2f8b687cf6db8bad7acd9a2
+F test/descidx1.test edc8adee58d491b06c7157c50364eaf1c3605c9c19f8093cb1ea2b6184f3ac13
+F test/descidx2.test a0ba347037ff3b811f4c6ceca5fd0f9d5d72e74e59f2d9de346a9d2f6ad78298
+F test/descidx3.test 953c831df7ea219c73826dfbf2f6ee02d95040725aa88ccb4fa43d1a1999b926
F test/diskfull.test 106391384780753ea6896b7b4f005d10e9866b6e
-F test/distinct.test a1783b960ad8c15a77cd9f207be072898db1026c
-F test/distinct2.test b854b442111bf362328981f55d39d0df13140383b112057f6e046e311f14e5c3
+F test/distinct.test 8b6c652f0b2d477f0830884736f2a1cd2e8f7fc10a04aa6d571a401fa13ed88b
+F test/distinct2.test 11b0594c932098e969d084ba45ab81d5040f4d4e766db65d49146705a305ed98
F test/distinctagg.test 1a6ef9c87a58669438fc771450d7a72577417376
F test/e_blobbytes.test 439a945953b35cb6948a552edaec4dc31fd70a05
F test/e_blobclose.test 4b3c8c60c2171164d472059c73e9f3c1844bb66d
@@ -826,7 +832,7 @@ F test/e_createtable.test 1c602347e73ab80b11b9fa083f47155861aaafcff8054aac9e0b76
F test/e_delete.test ab39084f26ae1f033c940b70ebdbbd523dc4962e
F test/e_droptrigger.test 3cd080807622c13e5bbb61fc9a57bd7754da2412
F test/e_dropview.test 21ce09c361227ddbc9819a5608ee2700c276bdd5
-F test/e_expr.test e6048fe3901241799c4315bdd625f39dae790ff089c454979ca85f03b644dc6f
+F test/e_expr.test 328d2d7c84f8e53e942a13eac771b337bcdfcf4c3569324001868b5639f3c857
F test/e_fkey.test 2febb2084aef9b0186782421c07bc9d377abf067c9cb4efd49d9647ae31f5afe
F test/e_fts3.test 17ba7c373aba4d4f5696ba147ee23fd1a1ef70782af050e03e262ca187c5ee07
F test/e_insert.test f02f7f17852b2163732c6611d193f84fc67bc641fb4882c77a464076e5eba80e
@@ -850,23 +856,23 @@ F test/enc4.test c8f1ce3618508fd0909945beb8b8831feef2c020
F test/eqp.test 84879b63e3110552bf8ce648a3507dc3ceb72109ecec83c2aef0db37a27f6382
F test/errmsg.test eae9f091eb39ce7e20305de45d8e5d115b68fa856fba4ea6757b6ca3705ff7f9
F test/eval.test a64c9105d6ff163df7cf09d6ac29cdad5922078c
-F test/exclusive.test 1206b87e192497d78c7f35552e86a9d05421498da300fb1cce5ca5351ccde3c3
+F test/exclusive.test d6ccc6acc5d660544f8e0cacaec2c620f8ebb42a764d783ab53430e26057a185
F test/exclusive2.test 984090e8e9d1b331d2e8111daf6e5d61dda0bef7
F test/exec.test e949714dc127eaa5ecc7d723efec1ec27118fdd7
F test/exists.test 79a75323c78f02bbe9c251ea502a092f9ef63dac
-F test/expr.test 7cb55e80aeb41d65fec968c08212505123063fea60bdc355d764d747670e9eea
+F test/expr.test 26cd01e8485bc48c8aa6a1add598e9ce1e706b4eb4f3f554e0b0223022e8c2cf
F test/expr2.test c27327ae9c017a7ff6280123f67aff496f912da74d78c888926d68b46ec75fd8
F test/extension01.test 00d13cec817f331a687a243e0e5a2d87b0e358c9
F test/extraquick.test cb254400bd42bfb777ff675356aabf3287978f79
F test/fallocate.test 37a62e396a68eeede8f8d2ecf23573a80faceb630788d314d0a073d862616717
F test/filectrl.test 6e871c2d35dead1d9a88e176e8d2ca094fec6bb3
F test/filefmt.test f393e80c4b8d493b7a7f8f3809a8425bbf4292af1f5140f01cb1427798a2bbd4
-F test/filter1.test c2f34e58ee82a60c3ee9b5b4c4f2004ec2f529dff2f473706eeffa684cbb6719
+F test/filter1.test 8a6f047a000ef391db2ca17b6beecc0006f4e0f9ca8bbe272b2443c7316e66b1
F test/filter2.tcl 44e525497ce07382915f01bd29ffd0fa49dab3adb87253b5e5103ba8f93393e8
F test/filter2.test 485cf95d1f6d6ceee5632201ca52a71868599836f430cdee42e5f7f14666e30a
F test/filterfault.test c08fb491d698e8df6c122c98f7db1c65ffcfcad2c1ab0e07fa8a5be1b34eaa8b
F test/fkey1.test d11dbb8a93ead9b5c46ae5d02da016d61245d47662fb2d844c99214f6163f768
-F test/fkey2.test d35d1c81e7569bdd2b872e91750f7098117d2e8291369f70b7e3d50a0e523dc2
+F test/fkey2.test 65c86b11127c11f80c0f450b3480321e0f087edea3031b9daa1978e3c020c91b
F test/fkey3.test 76d475c80b84ee7a5d062e56ccb6ea68882e2b49
F test/fkey4.test 86446017011273aad8f9a99c1a65019e7bd9ca9d
F test/fkey5.test 24dd28eb3d9f1b5a174f47e9899ace5facb08373a4223593c8c631e6cf9f7d5a
@@ -875,7 +881,7 @@ F test/fkey7.test 64fb28da03da5dfe3cdef5967aa7e832c2507bf7fb8f0780cacbca1f2338d0
F test/fkey8.test 48ef829d63f5f7b37aabd4df9363ac05f65539d1da8c4a44251631769d920579
F test/fkey_malloc.test 594a7ea1fbab553c036c70813cd8bd9407d63749
F test/fordelete.test eb93a2f34137bb87bdab88fcab06c0bd92719aff
-F test/format4.test 1f0cac8ff3895e9359ed87e41aaabee982a812eb
+F test/format4.test eeae341953db8b6bda7f549044797c3278a6cc345d11ada81471671b654f8ef4
F test/fts-9fd058691.test 78b887e30ae6816df0e1fed6259de4b5a64ad33c
F test/fts1a.test 46090311f85da51bb33bd5ce84f7948359c6d8d7
F test/fts1b.test 5d8a01aefbecc8b7442b36c94c05eb7a845462d5
@@ -928,20 +934,20 @@ F test/fts3al.test 07d64326e79bbdbab20ee87fc3328fbf01641c9f
F test/fts3am.test 218aa6ba0dfc50c7c16b2022aac5c6be593d08d8
F test/fts3an.test a49ccadc07a2f7d646ec1b81bc09da2d85a85b18
F test/fts3ao.test 266989148fec6d9f1bb6c5382f7aa3dcea0e9cd444576e28dd2b9287ac7dd220
-F test/fts3atoken.test bef8a163490098a6b8a6ec5f5407269a3a15b9902c0fcf5e962825a81675b3a0
-F test/fts3auto.test 19097050a3ca7ab7a43b2be967cb3dfd8ddf841dfdc4eac88deb172ad2f209f2
+F test/fts3atoken.test dc2078ce464914efe3a8dfc545dd034a0fc14f2ab425c240471d5a5f1c721400
+F test/fts3auto.test bfe0857bd0b69d68dd685a931b58486411a69f5794a7f6d6fe808bfa31a99614
F test/fts3aux1.test 7a170e172afdbceb67f5baa05941fd4fbf56af42f61daa3d140f4b4bf4cb68f6
F test/fts3aux2.test 2459e7fa3e22734aed237d1e2ae192f5541c4d8b218956ad2d90754977bf907f
F test/fts3b.test c15c4a9d04e210d0be67e54ce6a87b927168fbf9c1e3faec8c1a732c366fd491
F test/fts3c.test fc723a9cf10b397fdfc2b32e73c53c8b1ec02958
F test/fts3comp1.test a0f5b16a2df44dd0b15751787130af2183167c0c
F test/fts3conf.test c84bbaec81281c1788aa545ac6e78a6bd6cde2bdbbce2da261690e3659f5a76b
-F test/fts3corrupt.test 46b9ddda7f6588fd5a5b1f4bb4fc0618dc45010e7dddb8a3a188baf3197177ae
+F test/fts3corrupt.test ce7f7b5eaeee5f1804584d061b978d85e64abf2af9adaa7577589fac6f7eae01
F test/fts3corrupt2.test bf55c3fa0b0dc8ea1c0fe5543623bd27714585da6a129038fd6999fe3b0d25f3
F test/fts3corrupt3.test 0d5b69a0998b4adf868cc301fc78f3d0707745f1d984ce044c205cdb764b491f
-F test/fts3corrupt4.test 545c50e70d1fe922b6efef12019a92829832f52993c5421086489ce72bde2251
+F test/fts3corrupt4.test e407c7b4f4cd3335080833aff3a8855d520e531b79f84dcc77be4623af2342d4
F test/fts3corrupt5.test 0549f85ec4bd22e992f645f13c59b99d652f2f5e643dac75568bfd23a6db7ed5
-F test/fts3cov.test cb932743da52a1c79a1ab8983e26c8121cf02263d6ff16e1f642e6f9b8348338
+F test/fts3cov.test 7eacdbefd756cfa4dc2241974e3db2834e9b372ca215880e00032222f32194cf
F test/fts3d.test 2bd8c97bcb9975f2334147173b4872505b6a41359a4f9068960a36afe07a679f
F test/fts3defer.test f4c20e4c7153d20a98ee49ee5f3faef624fefc9a067f8d8d629db380c4d9f1de
F test/fts3defer2.test 3da52ca2114e300e9971eee2f0cc1a2e5f27e6a9ee67957d49e63e41fdfcc0e7
@@ -960,7 +966,7 @@ F test/fts3fuzz001.test e3c7b0ce9b04cc02281dcc96812a277f02df03cd7dc082055d87e11e
F test/fts3join.test 949b4f5ae3ae9cc2423cb865d711e32476bdb205ab2be923fdf48246e4a44166
F test/fts3malloc.test b0e4c133b8d61d4f6d112d8110f8320e9e453ef6
F test/fts3matchinfo.test aa66cc50615578b30f6df9984819ae5b702511cf8a94251ec7c594096a703a4a
-F test/fts3misc.test 0b20083efab36a42804bf8017a003f72f963c46163403dae7256493367d2f9d3
+F test/fts3misc.test c47d2c1ea1351c51c32c688545b02c8180a3f22156d1aedc206a8c09b9d95905
F test/fts3near.test 7e3354d46f155a822b59c0e957fd2a70c1d7e905
F test/fts3offsets.test b85fd382abdc78ebce721d8117bd552dfb75094c
F test/fts3prefix.test fa794eaab0bdae466494947b0b153d7844478ab2
@@ -969,21 +975,21 @@ F test/fts3query.test ca033ff2ebcc22c69d89032fb0bc1850997d31e7e60ecd26440796ba16
F test/fts3rank.test cd99bc83a3c923c8d52afd90d86979cf05fc41849f892faeac3988055ef37b99
F test/fts3rnd.test 1320d8826a845e38a96e769562bf83d7a92a15d0
F test/fts3shared.test 57e26a801f21027b7530da77db54286a6fe4997e
-F test/fts3snippet.test 430bb5ace2b31ccd99de4d71775d956da832c114c4b3e39589748f114458647c
+F test/fts3snippet.test d9b9f4b717584040fb56df1dacab53acd474958e9c1d00b073d10726695cea0c
F test/fts3sort.test ed34c716a11cc2009a35210e84ad5f9c102362ca
F test/fts3tok1.test a663f4cac22a9505400bc22aacb818d7055240409c28729669ea7d4cc2120d15
F test/fts3tok_err.test 52273cd193b9036282f7bacb43da78c6be87418d
F test/fts3varint.test 0b84a3fd4eba8a39f3687523804d18f3b322e6d4539a55bf342079c3614f2ada
-F test/fts4aa.test 10aac8e9d62c7357590acfabe3fad01e9a9ce1cb
+F test/fts4aa.test 4338ea7a67f7e19269bf6e6fb4a291352aa32296e7daed87f9823d57016a1ef7
F test/fts4check.test 6259f856604445d7b684c9b306b2efb6346834c3f50e8fc4a59a2ca6d5319ad0
-F test/fts4content.test 1518195a9f92b711d94419f76409a31cc78755854fb0abb1da2b74b9e0cf843e
+F test/fts4content.test 73bbb123420d2c46ef2fb3b24761e9acdb78b0877179d3a5d7d57aada08066f6
F test/fts4docid.test e33c383cfbdff0284685604d256f347a18fdbf01
F test/fts4growth.test 289833c34ad45a5e6e6133b53b6a71647231fb89d36ddcb8d9c87211b6721d7f
F test/fts4growth2.test 13ad4e76451af6e6906c95cdc725d01b00044269
F test/fts4incr.test 4e353a0bd886ea984e56fce9e77724fc923b8d0d
-F test/fts4langid.test 2168ba330af34f8a1c8832de0aab4c4b6fa195a16419c9c0c8aad59ceb6ff714
+F test/fts4langid.test 89e623218935507bca69d076ca254a7a8969dfc681c282b6374feaea8c7de784
F test/fts4lastrowid.test 185835895948d5325c7710649824042373b2203149abe8024a9319d25234dfd7
-F test/fts4merge.test 1096e30b58ad616bd502141bfe5bfe4c3a518df89e958d41a5ed1ce322369b9c
+F test/fts4merge.test e2b2ec21e287d54ec09824ccfb41e66896eeca568fc818ba0e0eb2efd94c35d2
F test/fts4merge2.test 5faa558d1b672f82b847d2a337465fa745e46891
F test/fts4merge3.test 8d9ccb4a3d41c4c617a149d6c4b13ad02de797d0
F test/fts4merge4.test d895b1057a7798b67e03455d0fa50e9ea836c47b
@@ -996,7 +1002,7 @@ F test/fts4rename.test 15fd9985c2bce6dea20da2245b22029ec89bd4710ed317c4c53abbe3c
F test/fts4umlaut.test fcaca4471de7e78c9d1f7e8976e3e8704d7d8ad979d57a739d00f3f757380429
F test/fts4unicode.test ceca76422abc251818cb25dabe33d3c3970da5f7c90e1540f190824e6b3a7c95
F test/full.test 6b3c8fb43c6beab6b95438c1675374b95fab245d
-F test/func.test 0889128141b99b38aa9ce78445acfc4c1f9fbe9aa4f51d4c6aff88ae43cf125b
+F test/func.test b7f1a706d1bb8de103a24bd0c30c9e3dc3eedf0df24aabc54b0a4f6e08742622
F test/func2.test 772d66227e4e6684b86053302e2d74a2500e1e0f
F test/func3.test 2bb0f31ab7baaed690b962a88544d7be6b34fa389364bc36a44e441ed3e3f1e6
F test/func4.test 6beacdfcb0e18c358e6c2dcacf1b65d1fa80955f
@@ -1009,19 +1015,20 @@ F test/fuzz3.test 9c813e6613b837cb7a277b0383cd66bfa07042b4cf0317157c35852f30043c
F test/fuzz4.test c229bcdb45518a89e1d208a21343e061503460ac69fae1539320a89f572eb634
F test/fuzz_common.tcl a87dfbb88c2a6b08a38e9a070dabd129e617b45b
F test/fuzz_malloc.test f348276e732e814802e39f042b1f6da6362a610af73a528d8f76898fde6b22f2
-F test/fuzzcheck.c 3ad76298a80cda31d270dc5e4f31194fa38d507d3e9b3f355cf1c283895cd5a5
-F test/fuzzdata1.db 7ee3227bad0e7ccdeb08a9e6822916777073c664
+F test/fuzzcheck.c 0df68e0df3b93a8c8fc24c9873127c7d78024b51444193545f985dbc90ac024e
+F test/fuzzdata1.db d36e88741b4f23bcbaaf55b006290669d03c6c891cf13c7b3a53bc1b097b693f
F test/fuzzdata2.db 128b3feeb78918d075c9b14b48610145a0dd4c8d6f1ca7c2870c7e425f5bf31f
F test/fuzzdata3.db c6586d3e3cef0fbc18108f9bb649aa77bfc38aba
F test/fuzzdata4.db b502c7d5498261715812dd8b3c2005bad08b3a26e6489414bd13926cd3e42ed2
F test/fuzzdata5.db e35f64af17ec48926481cfaf3b3855e436bd40d1cfe2d59a9474cb4b748a52a5
F test/fuzzdata6.db 92a80e4afc172c24f662a10a612d188fb272de4a9bd19e017927c95f737de6d7
F test/fuzzdata7.db e7a86fd83dda151d160445d542e32e5c6019c541b3a74c2a525b6ac640639711
-F test/fuzzdata8.db c75b0fd1d28c262f9c3a9428393ff9c420ea5bdbe0b33c557a971915a94bab71
+F test/fuzzdata8.db 8bd41f8e1b9c61af011bf5cf16a85fb7f718fdd3348e476b78ba36adab872653
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/genesis.tcl 1e2e2e8e5cc4058549a154ff1892fe5c9de19f98
F test/having.test e4098a4b8962f9596035c3b87a8928a10648acc509f1bb8d6f96413bbf79a1b3
F test/hexlit.test 4a6a5f46e3c65c4bf1fa06f5dd5a9507a5627751
@@ -1034,7 +1041,7 @@ F test/imposter1.test c3f1db2d3db2c24611a6596a3fc0ffc14f1466c8
F test/in.test 3e9bd58597a444123a40a9ac94cae0fec8897e17e9f519b02fc370bcf5ba5175
F test/in2.test 5d4c61d17493c832f7d2d32bef785119e87bde75
F test/in3.test 3cbf58c87f4052cee3a58b37b6389777505aa0c0
-F test/in4.test 0f77b0ff371549e6a119d0356be10bdba72258162e9701e83527a560482f5e98
+F test/in4.test 65460600d48933adba4283c6ebd089aae173d16136ab9d01f74c89089090c5a5
F test/in5.test b32ce7f4a93f44c5dee94af16886d922cc16ebe33c8e1765c73d4049d0f4b40f
F test/in6.test 62d943a02f722948f4410ee0b53c3cb39acd7c41afb083df8d7004238fe90a20
F test/incrblob.test c9b96afc292aeff43d6687bcb09b0280aa599822
@@ -1053,19 +1060,19 @@ F test/index2.test f835d5e13ca163bd78c4459ca15fd2e4ed487407
F test/index3.test 51685f39345462b84fcf77eb8537af847fdf438cc96b05c45d6aaca4e473ade0
F test/index4.test ab92e736d5946840236cd61ac3191f91a7856bf6
F test/index5.test 8621491915800ec274609e42e02a97d67e9b13e7
-F test/index6.test 4d1dd3cab97fba2ddf30bb70afc82eab35bd6e61788b3ac941e55263f81ef7e9
+F test/index6.test f172653b35b20233e59200e8b92a76db61bf7285437bf777b93b306ba26a47e7
F test/index7.test 1d764c0cca45f5a76150b08e127ccc8d52492cfa788b5fafed4be784a351b020
F test/index8.test bc2e3db70e8e62459aaa1bd7e4a9b39664f8f9d7
F test/index9.test 0aa3e509dddf81f93380396e40e9bb386904c1054924ba8fa9bcdfe85a8e7721
F test/indexedby.test a52c8c6abfae4fbfb51d99440de4ca1840dbacc606b05e29328a2a8ba7cd914e
-F test/indexexpr1.test c26c8b352311c1deb30642cd0379e5cb94e416c7e9e0885e92d9e01554df2db9
-F test/indexexpr2.test b580f378423bca443ffab47ada677203cfcf8a60f48a8aa20065f27c8f7739b5
+F test/indexexpr1.test 284e119999d132cc8bf37735a928c9859b28e8e295d02b7a6a4f93977c7f9ba5
+F test/indexexpr2.test dba11dbb0a58fcba4cd694f46b4004976123b81b0501f525d43c9be59f0207b1
F test/indexfault.test 98d78a8ff1f5335628b62f886a1cb7c7dac1ef6d48fa39c51ec871c87dce9811
F test/init.test 15c823093fdabbf7b531fe22cf037134d09587a7
-F test/insert.test 72004f6a900a25bd3f1ce9a72e73d02749644666a8ce6d6d2dba061137e5aa63
+F test/insert.test 4e3f0de67aac3c5be1f4aaedbcea11638f1b5cdc9a3115be14d19aa9db7623c6
F test/insert2.test 4d14b8f1b810a41995f6286b64a6943215d52208
F test/insert3.test 1b7db95a03ad9c5013fdf7d6722b6cd66ee55e30
-F test/insert4.test 7802ada6ba8738661b9f6c0e26858d3375b40cc7180289fd350644cd7a08fec9
+F test/insert4.test fb9e0f752c75f453555990250b449f6d123ae6a3ebf054d14e4470de4498dce3
F test/insert5.test 394f96728d1258f406fe5f5aeb0aaf29487c39a6
F test/insertfault.test ac63d14ea3b49c573673a572f4014b9117383a03e497c58f308b5c776e4a7f74
F test/instr.test 107df2b9b74a4b59315916b575590a08f2a714de0754abe541f10a0971d0a2a4
@@ -1083,22 +1090,23 @@ F test/ioerr4.test f130fe9e71008577b342b8874d52984bd04ede2c
F test/ioerr5.test 2edfa4fb0f896f733071303b42224df8bedd9da4
F test/ioerr6.test a395a6ab144b26a9e3e21059a1ab6a7149cca65b
F test/istrue.test 75327829744e65cc8700e69340b8e6c192e10e39dfae7ccb0e970d3c4f49090a
-F test/join.test 6ce8296a08e78632c322cde0add78a7ce05466c3d9ec7d5130b38b5b489e7c27
-F test/join2.test 10f7047e723ebd68b2f47189be8eed20451a6f665d8bf46f1774c640d1062417
+F test/join.test 0e8d3f4092897c717abcaf64e2e7b298e1cb143e2436010c57cfed5596bf6d30
+F test/join2.test 659bc6193f5c3fe20fa444dd2c91713db8c33e376b098b860644e175e87b8dbc
F test/join3.test 6f0c774ff1ba0489e6c88a3e77b9d3528fb4fda0
F test/join4.test 1a352e4e267114444c29266ce79e941af5885916
F test/join5.test 3a96dc62f0b45402d7207e22d1993fe0c2fce1c57644a11439891dd62b990eb7
F test/join6.test cfe6503791ceb0cbb509966740286ec423cbf10b
F test/journal1.test c7b768041b7f494471531e17abc2f4f5ebf9e5096984f43ed17c4eb80ba34497
F test/journal2.test 9dac6b4ba0ca79c3b21446bbae993a462c2397c4
-F test/journal3.test 939a3578396dffa0cdaa9b2685088c5a1a644db90d61aca08bd7e19d33932c00
+F test/journal3.test 7c3cf23ffc77db06601c1fcfc9743de8441cb77db9d1aa931863d94f5ffa140e
F test/jrnlmode.test 9b5bc01dac22223cb60ec2d5f97acf568d73820794386de5634dcadbea9e1946
F test/jrnlmode2.test 8759a1d4657c064637f8b079592651530db738419e1d649c6df7048cd724363d
F test/jrnlmode3.test 556b447a05be0e0963f4311e95ab1632b11c9eaa
-F test/json101.test 8f8977b00ba02f9a26c1d1f52f29f540f6d5eb162cbd5eb78bb805366d4ab26d
+F test/json101.test bb71538005f2d9e18620bdd3b76839a93ca0be61903eb8d751a64e78cf99b8fb
F test/json102.test eeb54efa221e50b74a2d6fb9259963b48d7414dca3ce2fdfdeed45cb28487bc1
F test/json103.test aff6b7a4c17d5a20b487a7bc1a274bfdc63b829413bdfb83bedac42ec7f67e3b
F test/json104.test 317f4ec4b2d87afbba4d2460cf5be297aea76f2285eb618d276dbcd40a50950f
+F test/json105.test 45f7d6a9a54c85f8a9589b68d3e7a1f42d02f2359911a8cdbad1f9988f571173
F test/keyword1.test 37ef6bba5d2ed5b07ecdd6810571de2956599dff
F test/kvtest.c 94da54bb66aae7a54e47cf7e4ea4acecc0f217560f79ad3abfcc0361d6d557ba
F test/lastinsert.test 42e948fd6442f07d60acbd15d33fb86473e0ef63
@@ -1154,7 +1162,7 @@ F test/memleak.test 10b9c6c57e19fc68c32941495e9ba1c50123f6e2
F test/memsubsys1.test 9e7555a22173b8f1c96c281ce289b338fcba2abe8b157f8798ca195bbf1d347e
F test/memsubsys2.test 3e4a8d0c05fd3e5fa92017c64666730a520c7e08
F test/minmax.test 6751e87b409fe11b02e70a306d846fa544e25a41
-F test/minmax2.test dae92964ac87c1d2ef978c582e81a95e11c00f1cbef68980bfb2abaf10315063
+F test/minmax2.test 1edf66901ddfab26ae1e04165e8da834c8d3284e2b20aefb26b80ef217962eab
F test/minmax3.test cc1e8b010136db0d01a6f2a29ba5a9f321034354
F test/minmax4.test 272ca395257f05937dc96441c9dde4bc9fbf116a8d4fa02baeb0d13d50e36c87
F test/misc1.test 7ce84b25df9872e7d7878613a96815d2ba5bc974ac4e15a50118dde8f3917599
@@ -1182,13 +1190,13 @@ F test/mutex2.test bfeaeac2e73095b2ac32285d2756e3a65e681660
F test/nan.test 437d40e6d0778b050d7750726c0cbd2c9936b81962926e8f8c48ca698f00f4d1
F test/nockpt.test 8c43b25af63b0bd620cf1b003529e37b6f1dc53bd22690e96a1bd73f78dde53a
F test/nolock.test f196cf8b8fbea4e2ca345140a2b3f3b0da45c76e
-F test/normalize.test 422027884ffb67ebba32bb78487c67cf67643496d19c077b07044bdba071a3f6
+F test/normalize.test f23b6c5926c59548635fcf39678ac613e726121e073dd902a3062fbb83903b72
F test/notify1.test 669b2b743618efdc18ca4b02f45423d5d2304abf
F test/notify2.test 2ecabaa1305083856b7c39cf32816b612740c161
F test/notify3.test 10ff25cde502e72a92053a2f215d64bece4ef934
F test/notnull.test a37b663d5bb728d66fc182016613fb8e4a0a4bbf3d75b8876a7527f7d4ed3f18
F test/null.test 0dcce4f04284ec66108c503327ad6d224c0752b3
-F test/nulls1.test 725fb4d99db2ddcce59ca6bf847cd92db8f1af861785918892f84ac3bcd4223d
+F test/nulls1.test fe4153fd59a3786b4b9f3663a3e65a3aa43a318c7b4d7dcb3f6c3ed5652c9095
F test/numcast.test 5d126f7f581432e86a90d1e35cac625164aec4a1
F test/numindex1.test 20a5450d4b056e48cd5db30e659f13347a099823
F test/offset1.test f06b83657bcf26f9ce805e67450e189e282143b2
@@ -1196,7 +1204,7 @@ F test/openv2.test 0d3040974bf402e19b7df4b783e447289d7ab394
F test/optfuzz-db01.c a0c256905c8ac79f9a5de2f374a3d9f757bef0dca2a238dc7c10cc8a38031834
F test/optfuzz-db01.txt 21f6bdeadc701cf11528276e2a55c70bfcb846ba42df327f979bd9e7b6ce7041
F test/optfuzz.c 50e330304eb1992e15ddd11f3daaad9bcc0d9aaad09cb2bcc77f9515df2e88b1
-F test/orderby1.test e4501f54721f804ca56922e253403ac6775f88e9f07569994ce99212b3ca5b10
+F test/orderby1.test 6bf0ce45cbfb1cf4779dd418ac5e8cf66abfa04de2c1d2edf1e0e85f1520d8f3
F test/orderby2.test bc11009f7cd99d96b1b11e57b199b00633eb5b04
F test/orderby3.test 8619d06a3debdcd80a27c0fdea5c40b468854b99
F test/orderby4.test 4d39bfbaaa3ae64d026ca2ff166353d2edca4ba4
@@ -1207,7 +1215,7 @@ F test/orderby8.test 23ef1a5d72bd3adcc2f65561c654295d1b8047bd
F test/orderby9.test 87fb9548debcc2cd141c5299002dd94672fa76a3
F test/orderbyA.test df608e59efc2ef50c1eddf1a773b272de3252e9401bfec86d04b52fd973866d5
F test/oserror.test 1fc9746b83d778e70d115049747ba19c7fba154afce7cc165b09feb6ca6abbc5
-F test/ossfuzz.c 18af635fa73d12a109b305faca727a734c1fa28a421b161d9d15c5a84a4998a2
+F test/ossfuzz.c 9636dad2092a05a32110df0ca06713038dd0c43dd89a77dabe4b8b0d71096715
F test/ossshell.c f125c5bd16e537a2549aa579b328dd1c59905e7ab1338dfc210e755bb7b69f17
F test/ovfl.test 199c482696defceacee8c8e0e0ef36da62726b2f
F test/pager1.test 1e9ee778bdeaf4f7f09997d029cdaca6a42dfc2092edafe4f5e590acbf1eab13
@@ -1227,9 +1235,9 @@ F test/permutations.test e92fe7c8eee860225761c275037740c306df12c70d1ff739096c60a
F test/pg_common.tcl 222a1bad1c41c308fa366313cd7b51b3be7e9b21c8736a421b974ac941693b54
F test/pragma.test 59becdfd720b80d463ab750f69f7118fde10dfd556aa5d554f3bf6b7e5ea7533
F test/pragma2.test e5d5c176360c321344249354c0c16aec46214c9f
-F test/pragma3.test 8300aa9c63cff1027006ca34bf413a148abbd6dcd471fa9a1ded322fe18c0df9
-F test/pragma4.test 1cb4b32f1a304ed9e291d7c4d49c91c2c8dc1b9450e6d2c1198b2cc895d40d77
-F test/pragma5.test 2be6a44c91e8585ccb4c71c5f221ccebe0692a49557215a912916ed391188959
+F test/pragma3.test 92a46bbea12322dd94a404f49edcfbfc913a2c98115f0d030a7459bb4712ef31
+F test/pragma4.test 10c624e45a83c0096a82a7579a5ff658542391d3b77355192da6572c8c17c00b
+F test/pragma5.test 7b33fc43e2e41abf17f35fb73f71b49671a380ea92a6c94b6ce530a25f8d9102
F test/pragmafault.test 275edaf3161771d37de60e5c2b412627ac94cef11739236bec12ed1258b240f8
F test/prefixes.test b524a1c44bffec225b9aec98bd728480352aa8532ac4c15771fb85e8beef65d9
F test/printf.test 0300699733e53101b2ce48800518427249edd4053bb50fa0621c6607482f0fdb
@@ -1262,7 +1270,7 @@ F test/round1.test 768018b04522ca420b1aba8a24bd76091d269f3bce3902af3ec6ebcee41ab
F test/rowallock.test 3f88ec6819489d0b2341c7a7528ae17c053ab7cc
F test/rowhash.test 0bc1d31415e4575d10cacf31e1a66b5cc0f8be81
F test/rowid.test bfbd7b97d9267660be3c8f28507c4ed7f205196b8877c0db42df347c2e8845e3
-F test/rowvalue.test a3e729d5c1f32da03bba15af1e3128218d2ba3c40d4f4ed5fa0497a713df68ea
+F test/rowvalue.test 8964f95b253d3b5cc8dc1cfd0cdb7529bce3ecc6b6259e23c5f829f80f4d51cd
F test/rowvalue2.test 060d238b7e5639a7c5630cb5e63e311b44efef2b
F test/rowvalue3.test 3068f508753af69884b12125995f023da0dbb256
F test/rowvalue4.test 02e35f7762371c2f57ebd856aa056eac56cb27ef7715a0bb31eac1895a745356
@@ -1272,6 +1280,7 @@ F test/rowvalue7.test c1cbdbf407029db01f87764097c6ac02a1c5a37efd2776eff32a9cdfdf
F test/rowvalue8.test 5900eddad9e2c3c2e26f1a95f74aafc1232ee5e0
F test/rowvalue9.test d8dd2c6ecac432dadaa79e41dc2434f007be1b6b
F test/rowvaluefault.test 7cd9ccc6c2fbdd881672984087aad0491bb75504
+F test/rowvaluevtab.test d166df5b666662de1ebf40d6f3849f8a76b34e17183a6cc7f81b420c462ce447
F test/rtree.test 0c8d9dd458d6824e59683c19ab2ffa9ef946f798
F test/run-wordcount.sh 891e89c4c2d16e629cd45951d4ed899ad12afc09
F test/savepoint.test ea1a6c08454e1a4edd973589bcf1fca83928ed09c48858fde1e8653b6daab278
@@ -1291,7 +1300,7 @@ F test/schema6.test e4bd1f23d368695eb9e7b51ef6e02ca0642ea2ab4a52579959826b5e7dce
F test/schemafault.test 1936bceca55ac82c5efbcc9fc91a1933e45c8d1e1d106b9a7e56c972a5a2a51e
F test/securedel.test 2f70b2449186a1921bd01ec9da407fbfa98c3a7a5521854c300c194b2ff09384
F test/securedel2.test 2d54c28e46eb1fd6902089958b20b1b056c6f1c5
-F test/select1.test 703154cbf66d0a9fbbd5b771dc3d2c4d3700121d133d695958d4a9c5a33251e8
+F test/select1.test 009a6d8eacd9684d046302b8d13b50846a87e39d6f08e92178aa13e95ea29a2d
F test/select2.test 352480e0e9c66eda9c3044e412abdf5be0215b56
F test/select3.test 3905450067c28766bc83ee397f6d87342de868baa60f2bcfd00f286dfbd62cb9
F test/select4.test 5389d9895968d1196c457d59b3ee6515d771d328
@@ -1336,7 +1345,7 @@ F test/shortread1.test bb591ef20f0fd9ed26d0d12e80eee6d7ac8897a3
F test/show_speedtest1_rtree.tcl 32e6c5f073d7426148a6936a0408f4b5b169aba5
F test/shrink.test 1b4330b1fd9e818c04726d45cb28db73087535ce
F test/sidedelete.test f0ad71abe6233e3b153100f3b8d679b19a488329
-F test/skipscan1.test 2a64ca7b3e6246bb86b47c9051bfd324603b1b60675fe606513535267713e080
+F test/skipscan1.test ed524bc86f27646b3a297f45d6557b55db338977b6838f8064b196b35848b31b
F test/skipscan2.test 3eb703ce794f139e7b83567911046298bcde29606116727f9b700ce34f559d2d
F test/skipscan3.test ec5bab3f81c7038b43450e7b3062e04a198bdbb5
F test/skipscan5.test 67817a4b6857c47e0e33ba3e506da6f23ef68de2
@@ -1372,7 +1381,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 f8f1279ffffabe6df825723af18cc6e0ae70a893
+F test/stat.test 423257dc36e5865fb9dd1d9051ac985763b6fba1daec134932f37772d5ed1e64
F test/statfault.test f525a7bf633e50afd027700e9a486090684b1ac1
F test/stmt.test 54ed2cc0764bf3e48a058331813c3dbd19fc1d0827c3d8369914a5d8f564ec75
F test/stmtvtab1.test 6873dfb24f8e79cbb5b799b95c2e4349060eb7a3b811982749a84b359468e2d5
@@ -1387,16 +1396,17 @@ F test/swarmvtab.test 9a3fd5ab3e9b3c976ad1b3d7646aab725114f2ac26b59395d0778b33ba
F test/swarmvtab2.test c948cb2fdfc5b01d85e8f6d6504854202dc1a0782ab2a0ed61538f27cbd0aa5c
F test/swarmvtab3.test 247aa38b6ebd2b99db2075847ae47e789ac34f1c2ab5c720dfcffd990004c544
F test/swarmvtabfault.test 8a67a9f27c61073a47990829e92bc0c64420a807cb642b15a25f6c788210ed95
-F test/symlink.test 0d816670325536b8973ec08d32b45136baddb80bd45fd178e0ce7a9e8153f3e7
+F test/symlink.test 72b22238d4405ba34df8e60b335d290a3b1129fd5c260835c944c1e4e77288a9
+F test/symlink2.test 9531f475a53d8781c4f81373f87faf2e2aff4f5fb2102ec6386e0c827916a670
F test/sync.test 89539f4973c010eda5638407e71ca7fddbcd8e0594f4c9980229f804d4333092
F test/sync2.test 8f9f7d4f6d5be8ca8941a8dadcc4299e558cb6a1ff653a9469146c7a76ef2039
F test/syscall.test a39d9a36f852ae6e4800f861bc2f2e83f68bbc2112d9399931ecfadeabd2d69d
F test/sysfault.test c9f2b0d8d677558f74de750c75e12a5454719d04
-F test/tabfunc01.test 20e98ffe55f35d8d33fd834ca8bf9d4b637e560af8fcd00464b4154d90a4db45
+F test/tabfunc01.test 5ca6d004157a3e886a55a9387b960cc0db41acd88753eb597ff409ec6cfb1be0
F test/table.test eb3463b7add9f16a5bb836badf118cf391b809d09fdccd1f79684600d07ec132
F test/tableapi.test ecbcc29c4ab62c1912c3717c48ea5c5e59f7d64e4a91034e6148bd2b82f177f4
F test/tableopts.test dba698ba97251017b7c80d738c198d39ab747930
-F test/tclsqlite.test f9acb83122be0a7c4997ab7f17742507874dced95144c20217c2428553f110bb
+F test/tclsqlite.test 6f8705d09377e2f2ff482ab181a1388773953a280623fff2ccab0e87d2bc10a2
F test/tempdb.test 4cdaa23ddd8acb4d79cbb1b68ccdfd09b0537aaba909ca69a876157c2a2cbd08
F test/tempdb2.test 353864e96fd3ae2f70773d0ffbf8b1fe48589b02c2ec05013b540879410c3440
F test/tempfault.test 0c0d349c9a99bf5f374655742577f8712c647900
@@ -1404,7 +1414,7 @@ F test/temptable.test d2c9b87a54147161bcd1822e30c1d1cd891e5b30
F test/temptable2.test d2940417496e2b9548e01d09990763fbe88c316504033256d51493e1f1a5ce6a
F test/temptable3.test d11a0974e52b347e45ee54ef1923c91ed91e4637
F test/temptrigger.test 38f0ca479b1822d3117069e014daabcaacefffcc
-F test/tester.tcl 58b257126aaac00e31df68d0c997255ff8c370b8324f35d5619011ba2cee534f
+F test/tester.tcl 3fb2de5b008f169819050539352fdc75e742010829aa479c384c5650e4d8d409
F test/thread001.test b61a29dd87cf669f5f6ac96124a7c97d71b0c80d9012746072055877055cf9ef
F test/thread002.test e630504f8a06c00bf8bbe68528774dd96aeb2e58
F test/thread003.test ee4c9efc3b86a6a2767516a37bd64251272560a7
@@ -1419,7 +1429,7 @@ F test/threadtest3.c 38a612ea62854349ed66372f330a40d73c5cf956
F test/threadtest4.c c1e67136ceb6c7ec8184e56ac61db28f96bd2925
F test/time-wordcount.sh 8e0b0f8109367827ad5d58f5cc849705731e4b90
F test/tkt-02a8e81d44.test 6c80d9c7514e2a42d4918bf87bf6bc54f379110c
-F test/tkt-18458b1a.test c543c4b8e8c7c2200579a635e72c15bc374a92d44eddb1d588d4fdeca9cca532
+F test/tkt-18458b1a.test 6a62cb1ee50fa3c620da59e3a6f531eb38fceaf7e2166203816b724524e6f1d6
F test/tkt-26ff0c2d1e.test c15bec890c4d226c0da2f35ff30f9e84c169cfef90e73a8cb5cec11d723dfa96
F test/tkt-2a5629202f.test 0521bd25658428baa26665aa53ffed9367d33af2
F test/tkt-2d1a5c67d.test be1326f3061caec85085f4c9ee4490561ca037c0
@@ -1455,7 +1465,7 @@ F test/tkt-9a8b09f8e6.test b2ef151d0984b2ebf237760dbeaa50724e5a0667
F test/tkt-9d68c883.test 16f7cb96781ba579bc2e19bb14b4ad609d9774b6
F test/tkt-9f2eb3abac.test cb6123ac695a08b4454c3792fbe85108f67fabf8
F test/tkt-a7b7803e.test 159ef554234fa1f9fb318c751b284bd1cf858da4
-F test/tkt-a7debbe0.test 65a647034e3416d068f81e7d86fffc07edfae371c70b8761714edb56ec1c7521
+F test/tkt-a7debbe0.test e295fa83cd4416a8ca37b354eb5fadefc5e81fb55253db538d35261fe9c95067
F test/tkt-a8a0d2996a.test 002e1cde8fc30c39611b52cf981c88200b858765748556822da72e0d32fac73e
F test/tkt-b1d3a2e531.test 8f7576e41ca179289ee1a8fee28386fd8e4b0550
F test/tkt-b351d95f9.test d14a503c414c5c58fdde3e80f9a3cfef986498c0
@@ -1519,7 +1529,7 @@ F test/tkt3080.test 1bca7579260920a66b4dd7e196e807c0f25ff804
F test/tkt3093.test fbdbc5b4969244ad11f540759003e361fcaf391f
F test/tkt3121.test 536df66a02838c26a12fe98639354ca1290ca68b
F test/tkt3201.test f1500ccecc0d578dc4cde7d3242008297c4d59b3
-F test/tkt3292.test 962465a0984a3b8c757efe59c2c59144871ee1dd
+F test/tkt3292.test 7bad4423cf5eb075dbb58511d66d46fe816744754c9f0050ae60157f71a4fca7
F test/tkt3298.test 20fd8773b825cb602e033aa04f8602e1ebdcd93c
F test/tkt3334.test 9756631e3c4aa3c416362c279e3c0953a83b7ca8274cb81a13264bb56296d8b0
F test/tkt3346.test 6f67c3ed7db94dfc5df4f5f0b63809a1f611e01a
@@ -1570,8 +1580,8 @@ F test/trans.test 6e1b4c6a42dba31bd65f8fa5e61a2708e08ddde6
F test/trans2.test 62bd045bfc7a1c14c5ba83ba64d21ade31583f76
F test/trans3.test 91a100e5412b488e22a655fe423a14c26403ab94
F test/transitive1.test 293300f46916569f08875cdb2fe2134be2c27677
-F test/trigger1.test 6be279c9d48b25320eab68c30fd5268ab787955679f4c584128f71800247fb50
-F test/trigger2.test 5cd7d69a7ba1143ee045e4ae2963ff32ae4c87a6
+F test/trigger1.test d30cd09ae8ac365a088f09daba583cc5c0b8fc7d4e1d70809d0b4be3bf6ae2ab
+F test/trigger2.test d15da46f7012832faf3e0c536b47024409d5fb1722d2bb77e29c06d96d704bb1
F test/trigger3.test aa640bb2bbb03edd5ff69c055117ea088f121945
F test/trigger4.test 74700b76ebf3947b2f7a92405141eb2cf2a5d359
F test/trigger5.test 619391a3e9fc194081d22cefd830d811e7badf83
@@ -1586,6 +1596,7 @@ F test/triggerD.test 8e7f3921a92a5797d472732108109e44575fa650
F test/triggerE.test ede2e4bce4ba802337bd69d39447fa04a938e06d84a8bfc53c76850fc36ed86d
F test/triggerF.test 5d76f0a8c428ff87a4d5ed52da06f6096a2c787a1e21b846111dfac4123de3ad
F test/triggerG.test d5caeef6144ede2426dd13211fd72248241ff2ebc68e12a4c0bf30f5faa21499
+F test/trustschema1.test 4e970aef0bfe0cee139703cc7209d0e0f07725d999b180ba50770f49edef1494
F test/tt3_checkpoint.c 9e75cf7c1c364f52e1c47fd0f14c4340a9db0fe1
F test/tt3_index.c 39eec10a35f57672225be4d182862152896dee4a
F test/tt3_lookaside1.c 0377e202c3c2a50d688cb65ba203afeda6fafeb9
@@ -1600,9 +1611,9 @@ F test/unique.test 93f8b2ef5ea51b9495f8d6493429b1fd0f465264
F test/unique2.test 3674e9f2a3f1fbbfd4772ac74b7a97090d0f77d2
F test/unixexcl.test d936ba2b06794018e136418addd59a2354eeae97
F test/unordered.test ffeea7747d5ba962a8009a20b7e53d68cbae05b063604c68702c5998eb50c981
-F test/update.test 1148de8d913e9817717990603aadeca07aab9ddbb10a30f167cbfd8d3a3ccb60
+F test/update.test e906ca7cb1dc6f52af1ea243e08f727edfa79f924c2691f2f9e72481f847310d
F test/update2.test 67455bc61fcbcf96923c45b3bc4f87bc72be7d67575ad35f134906148c7b06d3
-F test/upsert1.test 9b115320149e6d72db64511a373c522746c2a2156efdbdb52add33504f66c989
+F test/upsert1.test 88f9e258c6a0eeeb85937b08831e8daad440ba41f125af48439e9d33f266fb18
F test/upsert2.test 9c3cdbb1a890227f6504ce4b0e3de68f4cdfa16bb21d8641208a9239896c5a09
F test/upsert3.test 88d7d590a1948a9cb6eac1b54b0642f67a9f35a1fc0f19b200e97d5d39e3179c
F test/upsert4.test 25d2a1da92f149331ae0c51ca6e3eee78189577585eab92de149900d62994fa5
@@ -1687,7 +1698,7 @@ F test/walrofault.test c70cb6e308c443867701856cce92ad8288cd99488fa52afab77cca6cf
F test/walshared.test 0befc811dcf0b287efae21612304d15576e35417
F test/walslow.test c05c68d4dc2700a982f89133ce103a1a84cc285f
F test/walthread.test 14b20fcfa6ae152f5d8e12f5dc8a8a724b7ef189f5d8ef1e2ceab79f2af51747
-F test/walvfs.test f1accd66c876e3a0f6b4bef5b18d13411062d0ff0a0016e32bb41570474e99fc
+F test/walvfs.test ca81c9f427e0e5434076dfa948fd1d8e6d5ddd192b2fb6991635d81da5f3f5d4
F test/wapp.tcl b440cd8cf57953d3a49e7ee81e6a18f18efdaf113b69f7d8482b0710a64566ec
F test/wapptest.tcl 3cca775aede0591756a1fc0da55bbb3715d8c363873fd2cfdd4d555b0a4af57d x
F test/where.test 19c709c9f0f6ed12c23f909f6592aa55fba34269d5a2898537aa27a22b9ce650
@@ -1705,12 +1716,12 @@ F test/whereC.test cae295158703cb3fc23bf1a108a9ab730efff0f6
F test/whereD.test 711d4df58d6d4fb9b3f5ce040b818564198be002
F test/whereE.test b3a055eef928c992b0a33198a7b8dc10eea5ad2f
F test/whereF.test 3d9412b1199d3e2bed34fcb76b4c48d0bf4df95d27e3f8dd27b6f8b4716d0d89
-F test/whereG.test 4cda56de49f0c7d9a4f2590a3ddc5f79a7f2a03d2229d0f5bb5d3981ce57f293
+F test/whereG.test c9378b285828754377ef47fbece7264018c0a3743e7eb686e89917bb9df10885
F test/whereH.test e4b07f7a3c2f5d31195cd33710054c78667573b2
F test/whereI.test a2874062140ed4aba9ffae76e6190a3df6fc73d1373fdfa8fd632945082a5364
F test/whereJ.test 88287550f6ee604422403b053455b1ad894eeaa5c35d348532dfa1439286cb9a
F test/whereK.test f8e3cf26a8513ecc7f514f54df9f0572c046c42b
-F test/whereL.test 0a19fc44cd1122040f56c934f1b14d0ca85bde28f270268a428dd9796ea0634c
+F test/whereL.test 976f100f412ce2f39bf923eb57794cdc39fc0a3fec8fab025d51706a7cc4845b
F test/wherefault.test 1374c3aa198388925246475f84ad4cd5f9528864
F test/wherelfault.test 9012e4ef5259058b771606616bd007af5d154e64cc25fa9fd4170f6411db44e3
F test/wherelimit.test 592081800806d297dd7449b1030c863d2883d6d42901837ccd2e5a9bd962edb0
@@ -1719,9 +1730,9 @@ F test/win32heap.test 10fd891266bd00af68671e702317726375e5407561d859be1aa04696f2
F test/win32lock.test fbf107c91d8f5512be5a5b87c4c42ab9fdd54972
F test/win32longpath.test 169c75a3b2e43481f4a62122510210c67b08f26d
F test/win32nolock.test ac4f08811a562e45a5755e661f45ca85892bdbbc
-F test/window1.test 376a7c9c5b9df9868d92a6d9d455262e1b769f4410b19006f5f8c5507c2a7ed7
-F test/window2.tcl 66db96fd9fd202bc31ee7f8ce7904cb469564864cff3f74e009bfef8102333f4
-F test/window2.test af2a001ded703bb8f2474fb0edfef170d5aba00f5c1f2aa9f65935b5da13df90
+F test/window1.test cec56b9a0a2e7ca4bd63b30590c7b049dce9acfd87478e2597e13b67152bd821
+F test/window2.tcl 492c125fa550cda1dd3555768a2303b3effbeceee215293adf8871efc25f1476
+F test/window2.test e466a88bd626d66edc3d352d7d7e1d5531e0079b549ba44efb029d1fbff9fd3c
F test/window3.tcl acea6e86a4324a210fd608d06741010ca83ded9fde438341cb978c49928faf03
F test/window3.test e9959a993c8a71e96433be8daaa1827d78b8921e4f12debd7bdbeb3c856ef3cb
F test/window4.tcl d732df0e81beedc0ba8a563ade68611d322d27303ad0c0c8e4444107c39e84ec
@@ -1732,20 +1743,20 @@ F test/window7.tcl 6a1210f05d40ec89c22960213a22cd3f98d4e2f2eb20646c83c8c30d4d761
F test/window7.test 1d31276961ae7801edc72173edaf7593e3cbc79c06d1f1f09e20d8418af403cd
F test/window8.tcl f2711aa3571e4e6b0dad98db8d95fd6cb8d9db0c92bbdf535f153b07606a1ce2
F test/window8.test c4331b27a6f66d69fa8f8bab10cc731db1a81d293ae108a68f7c3487fa94e65b
-F test/window9.test ae8be07be05a5a4c8ead1818ac5d45f278b8dd456e589d67f24270b0070c35a0
+F test/window9.test b63f6f74d730547e63e78946f951f5d1a7d4e99f91f6d5906305469043d92a15
F test/windowA.test 6d63dc1260daa17141a55007600581778523a8b420629f1282d2acfc36af23be
F test/windowB.test 7a983ea1cc1cf72be7f378e4b32f6cb2d73014c5cd8b25aaee825164cd4269e5
F test/windowerr.tcl f5acd6fbc210d7b5546c0e879d157888455cd4a17a1d3f28f07c1c8a387019e0
F test/windowerr.test a8b752402109c15aa1c5efe1b93ccb0ce1ef84fa964ae1cd6684dd0b3cc1819b
-F test/windowfault.test a90b397837209f15e54afa62e8be39b2759a0101fae04e05a08bcc50e243a452
-F test/with1.test d32792084dcb5f6c047d77bb8a032822ef9fe050ade07d0aeffa37753a05e3c9
+F test/windowfault.test 8e3b69abe0eea9595ba3940afd9c63644e11966ed8815734b67f1479a8e9891a
+F test/with1.test 386d1c1763a9d369fd08ea03145869b6313ba263e1a102df5a275007000d1b47
F test/with2.test e0030e2f0267a910d6c0e4f46f2dfe941c1cc0d4f659ba69b3597728e7e8f1ab
-F test/with3.test b5f1372097690c6ef84db2f13fc7e64a88c7263c3f88493605f90597e8a68d45
+F test/with3.test 7de8dff2891aca0f9453463e4a2d6eb995baf137827d5596116fee53e22a4e29
F test/with4.test 257be66c0c67fee1defbbac0f685c3465e2cad037f21ce65f23f86084f198205
F test/withM.test 693b61765f2b387b5e3e24a4536e2e82de15ff64
-F test/without_rowid1.test 0abe18762b74714580c1d4d00a8e540e58966d3e46aae41ddb1a1d2c88c9277d
+F test/without_rowid1.test 9cfb83705c506e3849fa7efc88a3c9a15f9a50bf9b1516b41757a7cef9bba8c3
F test/without_rowid2.test af260339f79d13cb220288b67cd287fbcf81ad99
-F test/without_rowid3.test ea4b59dd1b0d7f5f5e4b7cca978cdb905752a9d7c57dc4344a591dba765a3691
+F test/without_rowid3.test 392e6e12f275d11d931a8bc4580e573342f391639c87ffb631010a7b3cedfdc0
F test/without_rowid4.test 4e08bcbaee0399f35d58b5581881e7a6243d458a
F test/without_rowid5.test 89b1c587bd92a0590e440da33e7666bf4891572a
F test/without_rowid6.test 8463b20098e9f75a501a9f17dfb42fffc79068eac0b2775fe56ef2281d2df45e
@@ -1754,17 +1765,17 @@ F test/wordcount.c d721a4b6fae93e6e33449700bce1686bc23257c27425bc3ef1599dc912ade
F test/writecrash.test f1da7f7adfe8d7f09ea79b42e5ca6dcc41102f27f8e334ad71539501ddd910cc
F test/zeroblob.test 07a5b11ab591d1f26c626945fb7f228f68b993533b2ada77273edf6ee29db174
F test/zerodamage.test 9c41628db7e8d9e8a0181e59ea5f189df311a9f6ce99cc376dc461f66db6f8dc
-F test/zipfile.test b3b558639f7a103e095713ad0f57fec1fce1b7d60c8054df5789b98f7547a395
+F test/zipfile.test 429cb81c518487fa1b644b6b04b6e9af704a4fa767bd1a110204c5f03b2e8616
F test/zipfile2.test 9903388a602a3834189857a985106ff95c3bba6a3969e0134127df991889db5d
F test/zipfilefault.test 44d4d7a7f7cca7521d569d7f71026b241d65a6b1757aa409c1a168827edbbc2c
-F tool/GetFile.cs a15e08acb5dd7539b75ba23501581d7c2b462cb5
+F tool/GetFile.cs 47852aa0d806fe47ed1ac5138bdce7f000fe87aaa7f28107d0cb1e26682aeb44
F tool/GetTclKit.bat 8995df40c4209808b31f24de0b58f90930239a234f7591e3675d45bfbb990c5d
F tool/Replace.cs 02c67258801c2fb5f63231e0ac0f220b4b36ba91
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 a06228aa21ebc4e6ea8daa486601d938499238a5
+F tool/dbhash.c 19560c9a2aa2b269b6a5108259b93d26d12f8f0877c31fe9f8f61dfbd219ba63
F tool/dbtotxt.c b2221864a20fb391c46bd31bc1fbdc4a96f5c8a89bef58f421eb9b9c36b1702c
F tool/dbtotxt.md c9a57af8739957ef36d2cfad5c4b1443ff3688ed33e4901ee200c8b651f43f3c
F tool/extract-sqlite3h.tcl 069ceab0cee26cba99952bfa08c0b23e35941c837acabe143f0c355d96c9e2eb x
@@ -1777,8 +1788,8 @@ F tool/genfkey.test b6afd7b825d797a1e1274f519ab5695373552ecad5cd373530c63533638a
F tool/getlock.c f4c39b651370156cae979501a7b156bdba50e7ce
F tool/index_usage.c 9ec344d29cbeb03fdc0fce668eedfb7495792170de933adf95cf8d6904a166ad
F tool/kvtest-speed.sh 4761a9c4b3530907562314d7757995787f7aef8f
-F tool/lemon.c 61d5f0af1eff8f754b75ddca668c9897fd30759e389bfffb42ce9e4d38fd4746
-F tool/lempar.c eb2841e2a7fd484cf44b1f526b06e7ab0f216d2f41818bf9485e8f38e3d1db19
+F tool/lemon.c a361b85fa230560b783006ac002a6a8bad214c3b9d7fa48980aecc2b691ddcad
+F tool/lempar.c e8899b28488f060d0ff931539ea6311b16b22dce068c086c788a06d5e8d01ab7
F tool/libvers.c caafc3b689638a1d88d44bc5f526c2278760d9b9
F tool/loadfts.c c3c64e4d5e90e8ba41159232c2189dba4be7b862
F tool/logest.c 11346aa019e2e77a00902aa7d0cabd27bd2e8cca
@@ -1786,14 +1797,14 @@ F tool/max-limits.c cbb635fbb37ae4d05f240bfb5b5270bb63c54439
F tool/mkautoconfamal.sh 422fc365358a2e92876ffc62971a0ff28ed472fc8bcf9de0df921c736fdeca5e
F tool/mkccode.tcl 86463e68ce9c15d3041610fedd285ce32a5cf7a58fc88b3202b8b76837650dbe x
F tool/mkctimec.tcl dd183b73ae1c28249669741c250525f0407e579a70482371668fd5f130d9feb3
-F tool/mkkeywordhash.c bc5bcc92ebcaf15345346be7cf2204b83ed649b5208234adb5e543c061209bbf
-F tool/mkmsvcmin.tcl cad0c7b54d7dd92bc87d59f36d4cc4f070eb2e625f14159dc2f5c4204e6a13ea
+F tool/mkkeywordhash.c 27ffc6f6e7e3ecbfc5bca1f1f11a09fc5badf6d67557a5fb2d3b069dbed90617
+F tool/mkmsvcmin.tcl 6ecab9fe22c2c8de4d82d4c46797bda3d2deac8e763885f5a38d0c44a895ab33
F tool/mkopcodec.tcl d1b6362bd3aa80d5520d4d6f3765badf01f6c43c
F tool/mkopcodeh.tcl 352a4319c0ad869eb26442bf7c3b015aa15594c21f1cce5a6420dbe999367c21
F tool/mkopts.tcl 680f785fdb09729fd9ac50632413da4eadbdf9071535e3f26d03795828ab07fa
-F tool/mkpragmatab.tcl f115d63ada8171f9da28dc8e34e043a1a159692d46b89f66b6e681140bc4683d
+F tool/mkpragmatab.tcl ca12b1c718ececdab2d3aacb437bc3c81ebf68467f19d7974e17f18844a3a48f
F tool/mkshellc.tcl 70a9978e363b0f3280ca9ce1c46d72563ff479c1930a12a7375e3881b7325712
-F tool/mksourceid.c d458f9004c837bee87a6382228ac20d3eae3c49ea3b0a5aace936f8b60748d3b
+F tool/mksourceid.c 36aa8020014aed0836fd13c51d6dc9219b0df1761d6b5f58ff5b616211b079b9
F tool/mkspeedsql.tcl a1a334d288f7adfe6e996f2e712becf076745c97
F tool/mksqlite3c-noext.tcl 4f7cfef5152b0c91920355cbfc1d608a4ad242cb819f1aea07f6d0274f584a7f
F tool/mksqlite3c.tcl 5fed3d75069d8f66f202d3b5200b0cea4aa7108481acd06732a06fdd42eb83a2
@@ -1808,7 +1819,7 @@ 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 97d14a1ce32d5edda84081a5c939bd8975abd89568a773b288940e67e4c7e3ad
+F tool/showdb.c 9b2dbb4b7a00afaf8fc1719f0d775775effa5b135ac1a2c23f1c3f5d670c4e15
F tool/showjournal.c 5bad7ae8784a43d2b270d953060423b8bd480818
F tool/showlocks.c 9920bcc64f58378ff1118caead34147201f48c68
F tool/showshm.c a0ab6ec32dd1f11218ca2a4018f8fb875b59414801ab8ceed8b2e69b7b45a809
@@ -1858,7 +1869,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 918bd97d2946c0a403030fcf0eba596a742ada94b122bf0ac4b808097171056b c20a35336432025445f9f7e289d0cc3e4003fb17f45a4ce74c6269c407c6e09f
-R 91e58e4c42392d174fea53a7ebaa765a
+P 16e1dced8b56ef422e5b747dd26accba5bf9f2df69b24b10363ef288890e21ee 3d7434a9d85dae9135473d1c58c22ac01a282e654807aa10be9b39f127291594
+R f7f5342b1e9d98d7f957dbfbefcf0bb4
U drh
-Z 58d2e4880548cfcff6bf27ec6060bdee
+Z 4cfafb5668b639ed08b37e9d8bd3fdf2
diff --git a/manifest.uuid b/manifest.uuid
index 25b09297c3..f6132a9bc8 100644
--- a/manifest.uuid
+++ b/manifest.uuid
@@ -1 +1 @@
-16e1dced8b56ef422e5b747dd26accba5bf9f2df69b24b10363ef288890e21ee
\ No newline at end of file
+35eae71a4dd4bd4e2d4a8f12c5e4a0cdb93dadee353b92e67a70a79b29587984
\ No newline at end of file
diff --git a/src/alter.c b/src/alter.c
index 8c3fefd1bf..ee193d18bf 100644
--- a/src/alter.c
+++ b/src/alter.c
@@ -31,9 +31,8 @@
static int isAlterableTable(Parse *pParse, Table *pTab){
if( 0==sqlite3StrNICmp(pTab->zName, "sqlite_", 7)
#ifndef SQLITE_OMIT_VIRTUALTABLE
- || ( (pTab->tabFlags & TF_Shadow)
- && (pParse->db->flags & SQLITE_Defensive)
- && pParse->db->nVdbeExec==0
+ || ( (pTab->tabFlags & TF_Shadow)!=0
+ && sqlite3ReadOnlyShadowTables(pParse->db)
)
#endif
){
@@ -298,14 +297,6 @@ void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
}
#endif
- /* If the default value for the new column was specified with a
- ** literal NULL, then set pDflt to 0. This simplifies checking
- ** for an SQL NULL default below.
- */
- assert( pDflt==0 || pDflt->op==TK_SPAN );
- if( pDflt && pDflt->pLeft->op==TK_NULL ){
- pDflt = 0;
- }
/* Check that the new column is not specified as PRIMARY KEY or UNIQUE.
** If there is a NOT NULL constraint, then the default value for the
@@ -319,35 +310,49 @@ void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
sqlite3ErrorMsg(pParse, "Cannot add a UNIQUE column");
return;
}
- if( (db->flags&SQLITE_ForeignKeys) && pNew->pFKey && pDflt ){
- sqlite3ErrorMsg(pParse,
- "Cannot add a REFERENCES column with non-NULL default value");
- return;
- }
- if( pCol->notNull && !pDflt ){
- sqlite3ErrorMsg(pParse,
- "Cannot add a NOT NULL column with default value NULL");
+ if( (pCol->colFlags & COLFLAG_GENERATED)==0 ){
+ /* If the default value for the new column was specified with a
+ ** literal NULL, then set pDflt to 0. This simplifies checking
+ ** for an SQL NULL default below.
+ */
+ assert( pDflt==0 || pDflt->op==TK_SPAN );
+ if( pDflt && pDflt->pLeft->op==TK_NULL ){
+ pDflt = 0;
+ }
+ if( (db->flags&SQLITE_ForeignKeys) && pNew->pFKey && pDflt ){
+ sqlite3ErrorMsg(pParse,
+ "Cannot add a REFERENCES column with non-NULL default value");
+ return;
+ }
+ if( pCol->notNull && !pDflt ){
+ sqlite3ErrorMsg(pParse,
+ "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.)
+ */
+ if( pDflt ){
+ sqlite3_value *pVal = 0;
+ int rc;
+ rc = sqlite3ValueFromExpr(db, pDflt, SQLITE_UTF8, SQLITE_AFF_BLOB, &pVal);
+ assert( rc==SQLITE_OK || rc==SQLITE_NOMEM );
+ if( rc!=SQLITE_OK ){
+ assert( db->mallocFailed == 1 );
+ return;
+ }
+ if( !pVal ){
+ sqlite3ErrorMsg(pParse,"Cannot add a column with non-constant default");
+ return;
+ }
+ sqlite3ValueFree(pVal);
+ }
+ }else if( pCol->colFlags & COLFLAG_STORED ){
+ sqlite3ErrorMsg(pParse, "cannot add a STORED column");
return;
}
- /* Ensure the default expression is something that sqlite3ValueFromExpr()
- ** can handle (i.e. not CURRENT_TIME etc.)
- */
- if( pDflt ){
- sqlite3_value *pVal = 0;
- int rc;
- rc = sqlite3ValueFromExpr(db, pDflt, SQLITE_UTF8, SQLITE_AFF_BLOB, &pVal);
- assert( rc==SQLITE_OK || rc==SQLITE_NOMEM );
- if( rc!=SQLITE_OK ){
- assert( db->mallocFailed == 1 );
- return;
- }
- if( !pVal ){
- sqlite3ErrorMsg(pParse, "Cannot add a column with non-constant default");
- return;
- }
- sqlite3ValueFree(pVal);
- }
/* Modify the CREATE TABLE statement. */
zCol = sqlite3DbStrNDup(db, (char*)pColDef->z, pColDef->n);
@@ -435,6 +440,7 @@ void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){
goto exit_begin_add_column;
}
+ sqlite3MayAbort(pParse);
assert( pTab->addColOffset>0 );
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
@@ -691,12 +697,14 @@ void *sqlite3RenameTokenMap(Parse *pParse, void *pPtr, Token *pToken){
RenameToken *pNew;
assert( pPtr || pParse->db->mallocFailed );
renameTokenCheckAll(pParse, pPtr);
- pNew = sqlite3DbMallocZero(pParse->db, sizeof(RenameToken));
- if( pNew ){
- pNew->p = pPtr;
- pNew->t = *pToken;
- pNew->pNext = pParse->pRename;
- pParse->pRename = pNew;
+ if( pParse->eParseMode!=PARSE_MODE_UNMAP ){
+ pNew = sqlite3DbMallocZero(pParse->db, sizeof(RenameToken));
+ if( pNew ){
+ pNew->p = pPtr;
+ pNew->t = *pToken;
+ pNew->pNext = pParse->pRename;
+ pParse->pRename = pNew;
+ }
}
return pPtr;
@@ -727,17 +735,39 @@ static int renameUnmapExprCb(Walker *pWalker, Expr *pExpr){
return WRC_Continue;
}
+/*
+** Iterate through the Select objects that are part of WITH clauses attached
+** to select statement pSelect.
+*/
+static void renameWalkWith(Walker *pWalker, Select *pSelect){
+ With *pWith = pSelect->pWith;
+ if( pWith ){
+ int i;
+ for(i=0; inCte; i++){
+ Select *p = pWith->a[i].pSelect;
+ NameContext sNC;
+ memset(&sNC, 0, sizeof(sNC));
+ sNC.pParse = pWalker->pParse;
+ sqlite3SelectPrep(sNC.pParse, p, &sNC);
+ sqlite3WalkSelect(pWalker, p);
+ sqlite3RenameExprlistUnmap(pWalker->pParse, pWith->a[i].pCols);
+ }
+ }
+}
+
/*
** Walker callback used by sqlite3RenameExprUnmap().
*/
static int renameUnmapSelectCb(Walker *pWalker, Select *p){
Parse *pParse = pWalker->pParse;
int i;
+ if( pParse->nErr ) return WRC_Abort;
+ if( NEVER(p->selFlags & SF_View) ) return WRC_Prune;
if( ALWAYS(p->pEList) ){
ExprList *pList = p->pEList;
for(i=0; inExpr; i++){
- if( pList->a[i].zName ){
- sqlite3RenameTokenRemap(pParse, 0, (void*)pList->a[i].zName);
+ if( pList->a[i].zEName && pList->a[i].eEName==ENAME_NAME ){
+ sqlite3RenameTokenRemap(pParse, 0, (void*)pList->a[i].zEName);
}
}
}
@@ -745,8 +775,11 @@ static int renameUnmapSelectCb(Walker *pWalker, Select *p){
SrcList *pSrc = p->pSrc;
for(i=0; inSrc; i++){
sqlite3RenameTokenRemap(pParse, 0, (void*)pSrc->a[i].zName);
+ if( sqlite3WalkExpr(pWalker, pSrc->a[i].pOn) ) return WRC_Abort;
}
}
+
+ renameWalkWith(pWalker, p);
return WRC_Continue;
}
@@ -754,12 +787,15 @@ static int renameUnmapSelectCb(Walker *pWalker, Select *p){
** Remove all nodes that are part of expression pExpr from the rename list.
*/
void sqlite3RenameExprUnmap(Parse *pParse, Expr *pExpr){
+ u8 eMode = pParse->eParseMode;
Walker sWalker;
memset(&sWalker, 0, sizeof(Walker));
sWalker.pParse = pParse;
sWalker.xExprCallback = renameUnmapExprCb;
sWalker.xSelectCallback = renameUnmapSelectCb;
+ pParse->eParseMode = PARSE_MODE_UNMAP;
sqlite3WalkExpr(&sWalker, pExpr);
+ pParse->eParseMode = eMode;
}
/*
@@ -775,7 +811,9 @@ void sqlite3RenameExprlistUnmap(Parse *pParse, ExprList *pEList){
sWalker.xExprCallback = renameUnmapExprCb;
sqlite3WalkExprList(&sWalker, pEList);
for(i=0; inExpr; i++){
- sqlite3RenameTokenRemap(pParse, 0, (void*)pEList->a[i].zName);
+ if( ALWAYS(pEList->a[i].eEName==ENAME_NAME) ){
+ sqlite3RenameTokenRemap(pParse, 0, (void*)pEList->a[i].zEName);
+ }
}
}
}
@@ -813,30 +851,13 @@ static void renameTokenFind(Parse *pParse, struct RenameCtx *pCtx, void *pPtr){
}
}
-/*
-** Iterate through the Select objects that are part of WITH clauses attached
-** to select statement pSelect.
-*/
-static void renameWalkWith(Walker *pWalker, Select *pSelect){
- if( pSelect->pWith ){
- int i;
- for(i=0; ipWith->nCte; i++){
- Select *p = pSelect->pWith->a[i].pSelect;
- NameContext sNC;
- memset(&sNC, 0, sizeof(sNC));
- sNC.pParse = pWalker->pParse;
- sqlite3SelectPrep(sNC.pParse, p, &sNC);
- sqlite3WalkSelect(pWalker, p);
- }
- }
-}
-
/*
** This is a Walker select callback. It does nothing. It is only required
** because without a dummy callback, sqlite3WalkExpr() and similar do not
** descend into sub-select statements.
*/
static int renameColumnSelectCb(Walker *pWalker, Select *p){
+ if( p->selFlags & SF_View ) return WRC_Prune;
renameWalkWith(pWalker, p);
return WRC_Continue;
}
@@ -930,8 +951,11 @@ static void renameColumnElistNames(
if( pEList ){
int i;
for(i=0; inExpr; i++){
- char *zName = pEList->a[i].zName;
- if( 0==sqlite3_stricmp(zName, zOld) ){
+ char *zName = pEList->a[i].zEName;
+ if( ALWAYS(pEList->a[i].eEName==ENAME_NAME)
+ && ALWAYS(zName!=0)
+ && 0==sqlite3_stricmp(zName, zOld)
+ ){
renameTokenFind(pParse, pCtx, (void*)zName);
}
}
@@ -967,7 +991,6 @@ static void renameColumnIdlistNames(
static int renameParseSql(
Parse *p, /* Memory to use for Parse object */
const char *zDb, /* Name of schema SQL belongs to */
- int bTable, /* 1 -> RENAME TABLE, 0 -> RENAME COLUMN */
sqlite3 *db, /* Database handle */
const char *zSql, /* SQL to parse */
int bTemp /* True if SQL is from temp schema */
@@ -981,7 +1004,7 @@ static int renameParseSql(
** occurs and the parse does not result in a new table, index or
** trigger object, the database must be corrupt. */
memset(p, 0, sizeof(Parse));
- p->eParseMode = (bTable ? PARSE_MODE_RENAME_TABLE : PARSE_MODE_RENAME_COLUMN);
+ p->eParseMode = PARSE_MODE_RENAME;
p->db = db;
p->nQueryLoop = 1;
rc = sqlite3RunParser(p, zSql, &zErr);
@@ -1288,7 +1311,7 @@ static void renameColumnFunc(
#ifndef SQLITE_OMIT_AUTHORIZATION
db->xAuth = 0;
#endif
- rc = renameParseSql(&sParse, zDb, 0, db, zSql, bTemp);
+ rc = renameParseSql(&sParse, zDb, db, zSql, bTemp);
/* Find tokens that need to be replaced. */
memset(&sWalker, 0, sizeof(Walker));
@@ -1302,8 +1325,9 @@ static void renameColumnFunc(
if( sParse.pNewTable ){
Select *pSelect = sParse.pNewTable->pSelect;
if( pSelect ){
+ pSelect->selFlags &= ~SF_View;
sParse.rc = SQLITE_OK;
- sqlite3SelectPrep(&sParse, sParse.pNewTable->pSelect, 0);
+ sqlite3SelectPrep(&sParse, pSelect, 0);
rc = (db->mallocFailed ? SQLITE_NOMEM : sParse.rc);
if( rc==SQLITE_OK ){
sqlite3WalkSelect(&sWalker, pSelect);
@@ -1330,6 +1354,11 @@ static void renameColumnFunc(
sqlite3WalkExprList(&sWalker, pIdx->aColExpr);
}
}
+#ifndef SQLITE_OMIT_GENERATED_COLUMNS
+ for(i=0; inCol; i++){
+ sqlite3WalkExpr(&sWalker, sParse.pNewTable->aCol[i].pDflt);
+ }
+#endif
for(pFKey=sParse.pNewTable->pFKey; pFKey; pFKey=pFKey->pNextFrom){
for(i=0; inCol; i++){
@@ -1415,6 +1444,7 @@ static int renameTableSelectCb(Walker *pWalker, Select *pSelect){
int i;
RenameCtx *p = pWalker->u.pRename;
SrcList *pSrc = pSelect->pSrc;
+ if( pSelect->selFlags & SF_View ) return WRC_Prune;
if( pSrc==0 ){
assert( pWalker->pParse->db->mallocFailed );
return WRC_Abort;
@@ -1485,7 +1515,7 @@ static void renameTableFunc(
sWalker.xSelectCallback = renameTableSelectCb;
sWalker.u.pRename = &sCtx;
- rc = renameParseSql(&sParse, zDb, 1, db, zInput, bTemp);
+ rc = renameParseSql(&sParse, zDb, db, zInput, bTemp);
if( rc==SQLITE_OK ){
int isLegacy = (db->flags & SQLITE_LegacyAlter);
@@ -1494,13 +1524,19 @@ static void renameTableFunc(
if( pTab->pSelect ){
if( isLegacy==0 ){
+ Select *pSelect = pTab->pSelect;
NameContext sNC;
memset(&sNC, 0, sizeof(sNC));
sNC.pParse = &sParse;
+ assert( pSelect->selFlags & SF_View );
+ pSelect->selFlags &= ~SF_View;
sqlite3SelectPrep(&sParse, pTab->pSelect, &sNC);
- if( sParse.nErr ) rc = sParse.rc;
- sqlite3WalkSelect(&sWalker, pTab->pSelect);
+ if( sParse.nErr ){
+ rc = sParse.rc;
+ }else{
+ sqlite3WalkSelect(&sWalker, pTab->pSelect);
+ }
}
}else{
/* Modify any FK definitions to point to the new table. */
@@ -1621,7 +1657,7 @@ static void renameTableTest(
if( zDb && zInput ){
int rc;
Parse sParse;
- rc = renameParseSql(&sParse, zDb, 1, db, zInput, bTemp);
+ rc = renameParseSql(&sParse, zDb, db, zInput, bTemp);
if( rc==SQLITE_OK ){
if( isLegacy==0 && sParse.pNewTable && sParse.pNewTable->pSelect ){
NameContext sNC;
diff --git a/src/analyze.c b/src/analyze.c
index 1904b9be02..2a071ef126 100644
--- a/src/analyze.c
+++ b/src/analyze.c
@@ -916,18 +916,17 @@ static const FuncDef statGetFuncdef = {
{0}
};
-static void callStatGet(Vdbe *v, int regStat4, int iParam, int regOut){
- assert( regOut!=regStat4 && regOut!=regStat4+1 );
+static void callStatGet(Parse *pParse, int regStat4, int iParam, int regOut){
#ifdef SQLITE_ENABLE_STAT4
- sqlite3VdbeAddOp2(v, OP_Integer, iParam, regStat4+1);
+ sqlite3VdbeAddOp2(pParse->pVdbe, OP_Integer, iParam, regStat4+1);
#elif SQLITE_DEBUG
assert( iParam==STAT_GET_STAT1 );
#else
UNUSED_PARAMETER( iParam );
#endif
- sqlite3VdbeAddOp4(v, OP_Function0, 0, regStat4, regOut,
- (char*)&statGetFuncdef, P4_FUNCDEF);
- sqlite3VdbeChangeP5(v, 1 + IsStat4);
+ assert( regOut!=regStat4 && regOut!=regStat4+1 );
+ sqlite3VdbeAddFunctionCall(pParse, 0, regStat4, regOut, 1+IsStat4,
+ &statGetFuncdef, 0);
}
/*
@@ -1095,9 +1094,8 @@ static void analyzeOneTable(
#endif
sqlite3VdbeAddOp2(v, OP_Integer, nCol, regStat4+1);
sqlite3VdbeAddOp2(v, OP_Integer, pIdx->nKeyCol, regStat4+2);
- sqlite3VdbeAddOp4(v, OP_Function0, 0, regStat4+1, regStat4,
- (char*)&statInitFuncdef, P4_FUNCDEF);
- sqlite3VdbeChangeP5(v, 2+IsStat4);
+ sqlite3VdbeAddFunctionCall(pParse, 0, regStat4+1, regStat4, 2+IsStat4,
+ &statInitFuncdef, 0);
/* Implementation of the following:
**
@@ -1182,7 +1180,7 @@ static void analyzeOneTable(
int j, k, regKey;
regKey = sqlite3GetTempRange(pParse, pPk->nKeyCol);
for(j=0; jnKeyCol; j++){
- k = sqlite3ColumnOfIndex(pIdx, pPk->aiColumn[j]);
+ k = sqlite3TableColumnToIndex(pIdx, pPk->aiColumn[j]);
assert( k>=0 && knColumn );
sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, k, regKey+j);
VdbeComment((v, "%s", pTab->aCol[pPk->aiColumn[j]].zName));
@@ -1192,13 +1190,12 @@ static void analyzeOneTable(
}
#endif
assert( regChng==(regStat4+1) );
- sqlite3VdbeAddOp4(v, OP_Function0, 1, regStat4, regTemp,
- (char*)&statPushFuncdef, P4_FUNCDEF);
- sqlite3VdbeChangeP5(v, 2+IsStat4);
+ sqlite3VdbeAddFunctionCall(pParse, 1, regStat4, regTemp, 2+IsStat4,
+ &statPushFuncdef, 0);
sqlite3VdbeAddOp2(v, OP_Next, iIdxCur, addrNextRow); VdbeCoverage(v);
/* Add the entry to the stat1 table. */
- callStatGet(v, regStat4, STAT_GET_STAT1, regStat1);
+ callStatGet(pParse, regStat4, 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);
@@ -1224,12 +1221,12 @@ static void analyzeOneTable(
pParse->nMem = MAX(pParse->nMem, regCol+nCol);
addrNext = sqlite3VdbeCurrentAddr(v);
- callStatGet(v, regStat4, STAT_GET_ROWID, regSampleRowid);
+ callStatGet(pParse, regStat4, STAT_GET_ROWID, regSampleRowid);
addrIsNull = sqlite3VdbeAddOp1(v, OP_IsNull, regSampleRowid);
VdbeCoverage(v);
- callStatGet(v, regStat4, STAT_GET_NEQ, regEq);
- callStatGet(v, regStat4, STAT_GET_NLT, regLt);
- callStatGet(v, regStat4, STAT_GET_NDLT, regDLt);
+ callStatGet(pParse, regStat4, STAT_GET_NEQ, regEq);
+ callStatGet(pParse, regStat4, STAT_GET_NLT, regLt);
+ callStatGet(pParse, regStat4, STAT_GET_NDLT, regDLt);
sqlite3VdbeAddOp4Int(v, seekOp, iTabCur, addrNext, regSampleRowid, 0);
VdbeCoverage(v);
for(i=0; ilookaside.bDisable++;
+ DisableLookaside;
rc = loadStat4(db, sInfo.zDatabase);
- db->lookaside.bDisable--;
+ EnableLookaside;
}
for(i=sqliteHashFirst(&pSchema->idxHash); i; i=sqliteHashNext(i)){
Index *pIdx = sqliteHashData(i);
diff --git a/src/attach.c b/src/attach.c
index 1dcb407edd..fdd71854ed 100644
--- a/src/attach.c
+++ b/src/attach.c
@@ -401,11 +401,8 @@ static void codeAttach(
assert( v || db->mallocFailed );
if( v ){
- sqlite3VdbeAddOp4(v, OP_Function0, 0, regArgs+3-pFunc->nArg, regArgs+3,
- (char *)pFunc, P4_FUNCDEF);
- assert( pFunc->nArg==-1 || (pFunc->nArg&0xff)==pFunc->nArg );
- sqlite3VdbeChangeP5(v, (u8)(pFunc->nArg));
-
+ sqlite3VdbeAddFunctionCall(pParse, 0, regArgs+3-pFunc->nArg, regArgs+3,
+ pFunc->nArg, pFunc, 0);
/* Code an OP_Expire. For an ATTACH statement, set P1 to true (expire this
** statement only). For DETACH, set it to false (expire all existing
** statements).
@@ -480,7 +477,7 @@ void sqlite3FixInit(
pFix->pSchema = db->aDb[iDb].pSchema;
pFix->zType = zType;
pFix->pName = pName;
- pFix->bVarOnly = (iDb==1);
+ pFix->bTemp = (iDb==1);
}
/*
@@ -508,7 +505,7 @@ int sqlite3FixSrcList(
if( NEVER(pList==0) ) return 0;
zDb = pFix->zDb;
for(i=0, pItem=pList->a; inSrc; i++, pItem++){
- if( pFix->bVarOnly==0 ){
+ if( pFix->bTemp==0 ){
if( pItem->zDatabase && sqlite3StrICmp(pItem->zDatabase, zDb) ){
sqlite3ErrorMsg(pFix->pParse,
"%s %T cannot reference objects in database %s",
@@ -518,6 +515,7 @@ int sqlite3FixSrcList(
sqlite3DbFree(pFix->pParse->db, pItem->zDatabase);
pItem->zDatabase = 0;
pItem->pSchema = pFix->pSchema;
+ pItem->fg.fromDDL = 1;
}
#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER)
if( sqlite3FixSelect(pFix, pItem->pSelect) ) return 1;
@@ -573,7 +571,7 @@ int sqlite3FixExpr(
Expr *pExpr /* The expression to be fixed to one database */
){
while( pExpr ){
- ExprSetProperty(pExpr, EP_Indirect);
+ if( !pFix->bTemp ) ExprSetProperty(pExpr, EP_FromDDL);
if( pExpr->op==TK_VARIABLE ){
if( pFix->pParse->db->init.busy ){
pExpr->op = TK_NULL;
diff --git a/src/btree.c b/src/btree.c
index 0b0d85dd4e..d90da74ae5 100644
--- a/src/btree.c
+++ b/src/btree.c
@@ -699,6 +699,9 @@ static int saveCursorPosition(BtCursor *pCur){
assert( 0==pCur->pKey );
assert( cursorHoldsMutex(pCur) );
+ if( pCur->curFlags & BTCF_Pinned ){
+ return SQLITE_CONSTRAINT_PINNED;
+ }
if( pCur->eState==CURSOR_SKIPNEXT ){
pCur->eState = CURSOR_VALID;
}else{
@@ -1446,7 +1449,7 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){
int sz2 = 0;
int sz = get2byte(&data[iFree+2]);
int top = get2byte(&data[hdr+5]);
- if( top>=iFree ){
+ if( NEVER(top>=iFree) ){
return SQLITE_CORRUPT_PAGE(pPage);
}
if( iFree2 ){
@@ -1455,7 +1458,7 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){
if( iFree2+sz2 > usableSize ) return SQLITE_CORRUPT_PAGE(pPage);
memmove(&data[iFree+sz+sz2], &data[iFree+sz], iFree2-(iFree+sz));
sz += sz2;
- }else if( iFree+sz>usableSize ){
+ }else if( NEVER(iFree+sz>usableSize) ){
return SQLITE_CORRUPT_PAGE(pPage);
}
@@ -1647,8 +1650,10 @@ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){
if( (data[hdr+2] || data[hdr+1]) && gap+2<=top ){
u8 *pSpace = pageFindSlot(pPage, nByte, &rc);
if( pSpace ){
+ int g2;
assert( pSpace+nByte<=data+pPage->pBt->usableSize );
- if( (*pIdx = (int)(pSpace-data))<=gap ){
+ *pIdx = g2 = (int)(pSpace-data);
+ if( NEVER(g2<=gap) ){
return SQLITE_CORRUPT_PAGE(pPage);
}else{
return SQLITE_OK;
@@ -1726,12 +1731,12 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
}else{
while( (iFreeBlk = get2byte(&data[iPtr]))pPage->pBt->usableSize-4 ){
+ if( iFreeBlk>pPage->pBt->usableSize-4 ){ /* TH3: corrupt081.100 */
return SQLITE_CORRUPT_PAGE(pPage);
}
assert( iFreeBlk>iPtr || iFreeBlk==0 );
@@ -1746,7 +1751,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( iEnd > pPage->pBt->usableSize ){
+ if( NEVER(iEnd > pPage->pBt->usableSize) ){
return SQLITE_CORRUPT_PAGE(pPage);
}
iSize = iEnd - iStart;
@@ -1774,7 +1779,8 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
/* The new freeblock is at the beginning of the cell content area,
** so just extend the cell content area rather than create another
** freelist entry */
- if( iStart0 ){
u32 next, size;
- if( pcnPage & 0x80000000)==0 || CORRUPT_DB );
return pBt->nPage;
}
u32 sqlite3BtreeLastPage(Btree *p){
assert( sqlite3BtreeHoldsMutex(p) );
- assert( ((p->pBt->nPage)&0x80000000)==0 );
- return btreePagecount(p->pBt);
+ return btreePagecount(p->pBt) & 0x7fffffff;
}
/*
@@ -2403,9 +2409,13 @@ int sqlite3BtreeOpen(
rc = sqlite3OsFullPathname(pVfs, zFilename,
nFullPathname, zFullPathname);
if( rc ){
- sqlite3_free(zFullPathname);
- sqlite3_free(p);
- return rc;
+ if( rc==SQLITE_OK_SYMLINK ){
+ rc = SQLITE_OK;
+ }else{
+ sqlite3_free(zFullPathname);
+ sqlite3_free(p);
+ return rc;
+ }
}
}
#if SQLITE_THREADSAFE
@@ -4365,8 +4375,9 @@ static int btreeCursor(
/* The following assert statements verify that if this is a sharable
** b-tree database, the connection is holding the required table locks,
** and that no other connection has any open cursor that conflicts with
- ** this lock. */
- assert( hasSharedCacheTableLock(p, iTable, pKeyInfo!=0, (wrFlag?2:1)) );
+ ** this lock. The iTable<1 term disables the check for corrupt schemas. */
+ assert( hasSharedCacheTableLock(p, iTable, pKeyInfo!=0, (wrFlag?2:1))
+ || iTable<1 );
assert( wrFlag==0 || !hasReadConflicts(p, iTable) );
/* Assert that the caller has opened the required transaction. */
@@ -4379,9 +4390,13 @@ static int btreeCursor(
allocateTempSpace(pBt);
if( pBt->pTmpSpace==0 ) return SQLITE_NOMEM_BKPT;
}
- if( iTable==1 && btreePagecount(pBt)==0 ){
- assert( wrFlag==0 );
- iTable = 0;
+ if( iTable<=1 ){
+ if( iTable<1 ){
+ return SQLITE_CORRUPT_BKPT;
+ }else if( btreePagecount(pBt)==0 ){
+ assert( wrFlag==0 );
+ iTable = 0;
+ }
}
/* Now that no other errors can occur, finish filling in the BtCursor
@@ -4406,6 +4421,19 @@ static int btreeCursor(
pCur->eState = CURSOR_INVALID;
return SQLITE_OK;
}
+static int btreeCursorWithLock(
+ Btree *p, /* The btree */
+ int iTable, /* Root page of table to open */
+ int wrFlag, /* 1 to write. 0 read-only */
+ struct KeyInfo *pKeyInfo, /* First arg to comparison function */
+ BtCursor *pCur /* Space for new cursor */
+){
+ int rc;
+ sqlite3BtreeEnter(p);
+ rc = btreeCursor(p, iTable, wrFlag, pKeyInfo, pCur);
+ sqlite3BtreeLeave(p);
+ return rc;
+}
int sqlite3BtreeCursor(
Btree *p, /* The btree */
int iTable, /* Root page of table to open */
@@ -4413,15 +4441,11 @@ int sqlite3BtreeCursor(
struct KeyInfo *pKeyInfo, /* First arg to xCompare() */
BtCursor *pCur /* Write new cursor here */
){
- int rc;
- if( iTable<1 ){
- rc = SQLITE_CORRUPT_BKPT;
+ if( p->sharable ){
+ return btreeCursorWithLock(p, iTable, wrFlag, pKeyInfo, pCur);
}else{
- sqlite3BtreeEnter(p);
- rc = btreeCursor(p, iTable, wrFlag, pKeyInfo, pCur);
- sqlite3BtreeLeave(p);
+ return btreeCursor(p, iTable, wrFlag, pKeyInfo, pCur);
}
- return rc;
}
/*
@@ -4544,6 +4568,18 @@ i64 sqlite3BtreeIntegerKey(BtCursor *pCur){
return pCur->info.nKey;
}
+/*
+** Pin or unpin a cursor.
+*/
+void sqlite3BtreeCursorPin(BtCursor *pCur){
+ assert( (pCur->curFlags & BTCF_Pinned)==0 );
+ pCur->curFlags |= BTCF_Pinned;
+}
+void sqlite3BtreeCursorUnpin(BtCursor *pCur){
+ assert( (pCur->curFlags & BTCF_Pinned)!=0 );
+ pCur->curFlags &= ~BTCF_Pinned;
+}
+
#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
/*
** Return the offset into the database file for the start of the
@@ -5700,8 +5736,11 @@ static SQLITE_NOINLINE int btreeNext(BtCursor *pCur){
** to be invalid here. This can only occur if a second cursor modifies
** the page while cursor pCur is holding a reference to it. Which can
** only happen if the database is corrupt in such a way as to link the
- ** page into more than one b-tree structure. */
- testcase( idx>pPage->nCell );
+ ** page into more than one b-tree structure.
+ **
+ ** Update 2019-12-23: appears to long longer be possible after the
+ ** addition of anotherValidCursor() condition on balance_deeper(). */
+ harmless( idx>pPage->nCell );
if( idx>=pPage->nCell ){
if( !pPage->leaf ){
@@ -6900,7 +6939,7 @@ static int rebuildPage(
assert( i(u32)usableSize ){ j = 0; }
+ if( NEVER(j>(u32)usableSize) ){ j = 0; }
memcpy(&pTmp[j], &aData[j], usableSize - j);
for(k=0; pCArray->ixNx[k]<=i && ALWAYS(kxCellSize(pPg, pCell) || CORRUPT_DB );
- testcase( sz!=pPg->xCellSize(pPg,pCell) );
+ testcase( sz!=pPg->xCellSize(pPg,pCell) )
i++;
if( i>=iEnd ) break;
if( pCArray->ixNx[k]<=i ){
@@ -8290,6 +8329,30 @@ static int balance_deeper(MemPage *pRoot, MemPage **ppChild){
return SQLITE_OK;
}
+/*
+** Return SQLITE_CORRUPT if any cursor other than pCur is currently valid
+** on the same B-tree as pCur.
+**
+** This can if a database is corrupt with two or more SQL tables
+** pointing to the same b-tree. If an insert occurs on one SQL table
+** and causes a BEFORE TRIGGER to do a secondary insert on the other SQL
+** table linked to the same b-tree. If the secondary insert causes a
+** rebalance, that can change content out from under the cursor on the
+** first SQL table, violating invariants on the first insert.
+*/
+static int anotherValidCursor(BtCursor *pCur){
+ BtCursor *pOther;
+ for(pOther=pCur->pBt->pCursor; pOther; pOther=pOther->pNext){
+ if( pOther!=pCur
+ && pOther->eState==CURSOR_VALID
+ && pOther->pPage==pCur->pPage
+ ){
+ return SQLITE_CORRUPT_BKPT;
+ }
+ }
+ return SQLITE_OK;
+}
+
/*
** The page that pCur currently points to has just been modified in
** some way. This function figures out if this modification means the
@@ -8317,7 +8380,7 @@ static int balance(BtCursor *pCur){
if( pPage->nOverflow==0 && pPage->nFree<=nMin ){
break;
}else if( (iPage = pCur->iPage)==0 ){
- if( pPage->nOverflow ){
+ if( pPage->nOverflow && (rc = anotherValidCursor(pCur))==SQLITE_OK ){
/* The root page of the b-tree is overfull. In this case call the
** balance_deeper() function to create a new child for the root-page
** and copy the current contents of the root-page to it. The
@@ -8613,7 +8676,6 @@ int sqlite3BtreeInsert(
if( flags & BTREE_SAVEPOSITION ){
assert( pCur->curFlags & BTCF_ValidNKey );
assert( pX->nKey==pCur->info.nKey );
- assert( pCur->info.nSize!=0 );
assert( loc==0 );
}
#endif
@@ -8688,7 +8750,9 @@ int sqlite3BtreeInsert(
}
}
- assert( pCur->eState==CURSOR_VALID || (pCur->eState==CURSOR_INVALID && loc) );
+ assert( pCur->eState==CURSOR_VALID
+ || (pCur->eState==CURSOR_INVALID && loc)
+ || CORRUPT_DB );
pPage = pCur->pPage;
assert( pPage->intKey || pX->nKey>=0 );
@@ -9459,7 +9523,7 @@ int sqlite3BtreeUpdateMeta(Btree *p, int idx, u32 iMeta){
** Otherwise, if an error is encountered (i.e. an IO error or database
** corruption) an SQLite error code is returned.
*/
-int sqlite3BtreeCount(BtCursor *pCur, i64 *pnEntry){
+int sqlite3BtreeCount(sqlite3 *db, BtCursor *pCur, i64 *pnEntry){
i64 nEntry = 0; /* Value to return in *pnEntry */
int rc; /* Return code */
@@ -9472,7 +9536,7 @@ int sqlite3BtreeCount(BtCursor *pCur, i64 *pnEntry){
/* Unless an error occurs, the following loop runs one iteration for each
** page in the B-Tree structure (not including overflow pages).
*/
- while( rc==SQLITE_OK ){
+ while( rc==SQLITE_OK && !db->u1.isInterrupted ){
int iIdx; /* Index of child node in parent */
MemPage *pPage; /* Current page of the b-tree */
@@ -9598,6 +9662,7 @@ static int checkRef(IntegrityCk *pCheck, Pgno iPage){
checkAppendMsg(pCheck, "2nd reference to page %d", iPage);
return 1;
}
+ if( pCheck->db->u1.isInterrupted ) return 1;
setPageReferenced(pCheck, iPage);
return 0;
}
@@ -10041,6 +10106,7 @@ end_of_check:
** returned. If a memory allocation error occurs, NULL is returned.
*/
char *sqlite3BtreeIntegrityCheck(
+ sqlite3 *db, /* Database connection that is running the check */
Btree *p, /* The btree to be checked */
int *aRoot, /* An array of root pages numbers for individual trees */
int nRoot, /* Number of entries in aRoot[] */
@@ -10058,6 +10124,7 @@ char *sqlite3BtreeIntegrityCheck(
assert( p->inTrans>TRANS_NONE && pBt->inTransaction>TRANS_NONE );
VVA_ONLY( nRef = sqlite3PagerRefcount(pBt->pPager) );
assert( nRef>=0 );
+ sCheck.db = db;
sCheck.pBt = pBt;
sCheck.pPager = pBt->pPager;
sCheck.nPage = btreePagecount(sCheck.pBt);
diff --git a/src/btree.h b/src/btree.h
index ed228c22eb..4bd41f7f37 100644
--- a/src/btree.h
+++ b/src/btree.h
@@ -306,6 +306,8 @@ int sqlite3BtreeNext(BtCursor*, int flags);
int sqlite3BtreeEof(BtCursor*);
int sqlite3BtreePrevious(BtCursor*, int flags);
i64 sqlite3BtreeIntegerKey(BtCursor*);
+void sqlite3BtreeCursorPin(BtCursor*);
+void sqlite3BtreeCursorUnpin(BtCursor*);
#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
i64 sqlite3BtreeOffset(BtCursor*);
#endif
@@ -314,7 +316,7 @@ const void *sqlite3BtreePayloadFetch(BtCursor*, u32 *pAmt);
u32 sqlite3BtreePayloadSize(BtCursor*);
sqlite3_int64 sqlite3BtreeMaxRecordSize(BtCursor*);
-char *sqlite3BtreeIntegrityCheck(Btree*, int *aRoot, int nRoot, int, int*);
+char *sqlite3BtreeIntegrityCheck(sqlite3*,Btree*,int*aRoot,int nRoot,int,int*);
struct Pager *sqlite3BtreePager(Btree*);
i64 sqlite3BtreeRowCountEst(BtCursor*);
@@ -335,7 +337,7 @@ int sqlite3BtreeCursorIsValid(BtCursor*);
int sqlite3BtreeCursorIsValidNN(BtCursor*);
#ifndef SQLITE_OMIT_BTREECOUNT
-int sqlite3BtreeCount(BtCursor *, i64 *);
+int sqlite3BtreeCount(sqlite3*, BtCursor*, i64*);
#endif
#ifdef SQLITE_TEST
diff --git a/src/btreeInt.h b/src/btreeInt.h
index ddd374efc9..7687a0f1ec 100644
--- a/src/btreeInt.h
+++ b/src/btreeInt.h
@@ -542,6 +542,7 @@ struct BtCursor {
#define BTCF_AtLast 0x08 /* Cursor is pointing ot the last entry */
#define BTCF_Incrblob 0x10 /* True if an incremental I/O handle */
#define BTCF_Multiple 0x20 /* Maybe another cursor on the same btree */
+#define BTCF_Pinned 0x40 /* Cursor is busy and cannot be moved */
/*
** Potential values for BtCursor.eState.
@@ -685,6 +686,7 @@ struct IntegrityCk {
int v1, v2; /* Values for up to two %d fields in zPfx */
StrAccum errMsg; /* Accumulate the error message text here */
u32 *heap; /* Min-heap used for analyzing cell coverage */
+ sqlite3 *db; /* Database connection running the check */
};
/*
diff --git a/src/build.c b/src/build.c
index a3d1abf042..f0435aacec 100644
--- a/src/build.c
+++ b/src/build.c
@@ -856,13 +856,14 @@ int sqlite3CheckObjectName(
}
}
}else{
- if( pParse->nested==0
- && 0==sqlite3StrNICmp(zName, "sqlite_", 7)
+ if( (pParse->nested==0 && 0==sqlite3StrNICmp(zName, "sqlite_", 7))
+ || (sqlite3ReadOnlyShadowTables(db) && sqlite3ShadowTableName(db, zName))
){
sqlite3ErrorMsg(pParse, "object name reserved for internal use: %s",
zName);
return SQLITE_ERROR;
}
+
}
return SQLITE_OK;
}
@@ -877,10 +878,12 @@ Index *sqlite3PrimaryKeyIndex(Table *pTab){
}
/*
-** Return the column of index pIdx that corresponds to table
-** column iCol. Return -1 if not found.
+** Convert an table column number into a index column number. That is,
+** for the column iCol in the table (as defined by the CREATE TABLE statement)
+** find the (first) offset of that column in index pIdx. Or return -1
+** if column iCol is not used in index pIdx.
*/
-i16 sqlite3ColumnOfIndex(Index *pIdx, i16 iCol){
+i16 sqlite3TableColumnToIndex(Index *pIdx, i16 iCol){
int i;
for(i=0; inColumn; i++){
if( iCol==pIdx->aiColumn[i] ) return i;
@@ -888,6 +891,84 @@ i16 sqlite3ColumnOfIndex(Index *pIdx, i16 iCol){
return -1;
}
+#ifndef SQLITE_OMIT_GENERATED_COLUMNS
+/* Convert a storage column number into a table column number.
+**
+** The storage column number (0,1,2,....) is the index of the value
+** as it appears in the record on disk. The true column number
+** is the index (0,1,2,...) of the column in the CREATE TABLE statement.
+**
+** The storage column number is less than the table column number if
+** and only there are VIRTUAL columns to the left.
+**
+** If SQLITE_OMIT_GENERATED_COLUMNS, this routine is a no-op macro.
+*/
+i16 sqlite3StorageColumnToTable(Table *pTab, i16 iCol){
+ if( pTab->tabFlags & TF_HasVirtual ){
+ int i;
+ for(i=0; i<=iCol; i++){
+ if( pTab->aCol[i].colFlags & COLFLAG_VIRTUAL ) iCol++;
+ }
+ }
+ return iCol;
+}
+#endif
+
+#ifndef SQLITE_OMIT_GENERATED_COLUMNS
+/* Convert a table column number into a storage column number.
+**
+** The storage column number (0,1,2,....) is the index of the value
+** as it appears in the record on disk. Or, if the input column is
+** the N-th virtual column (zero-based) then the storage number is
+** the number of non-virtual columns in the table plus N.
+**
+** The true column number is the index (0,1,2,...) of the column in
+** the CREATE TABLE statement.
+**
+** If the input column is a VIRTUAL column, then it should not appear
+** in storage. But the value sometimes is cached in registers that
+** follow the range of registers used to construct storage. This
+** avoids computing the same VIRTUAL column multiple times, and provides
+** values for use by OP_Param opcodes in triggers. Hence, if the
+** input column is a VIRTUAL table, put it after all the other columns.
+**
+** In the following, N means "normal column", S means STORED, and
+** V means VIRTUAL. Suppose the CREATE TABLE has columns like this:
+**
+** CREATE TABLE ex(N,S,V,N,S,V,N,S,V);
+** -- 0 1 2 3 4 5 6 7 8
+**
+** Then the mapping from this function is as follows:
+**
+** INPUTS: 0 1 2 3 4 5 6 7 8
+** OUTPUTS: 0 1 6 2 3 7 4 5 8
+**
+** So, in other words, this routine shifts all the virtual columns to
+** the end.
+**
+** If SQLITE_OMIT_GENERATED_COLUMNS then there are no virtual columns and
+** this routine is a no-op macro. If the pTab does not have any virtual
+** columns, then this routine is no-op that always return iCol. If iCol
+** is negative (indicating the ROWID column) then this routine return iCol.
+*/
+i16 sqlite3TableColumnToStorage(Table *pTab, i16 iCol){
+ int i;
+ i16 n;
+ assert( iColnCol );
+ if( (pTab->tabFlags & TF_HasVirtual)==0 || iCol<0 ) return iCol;
+ for(i=0, n=0; iaCol[i].colFlags & COLFLAG_VIRTUAL)==0 ) n++;
+ }
+ if( pTab->aCol[i].colFlags & COLFLAG_VIRTUAL ){
+ /* iCol is a virtual column itself */
+ return pTab->nNVCol + i - n;
+ }else{
+ /* iCol is a normal or stored column */
+ return n;
+ }
+}
+#endif
+
/*
** Begin constructing a new table representation in memory. This is
** the first of several action routines that get called in response
@@ -1178,6 +1259,7 @@ void sqlite3AddColumn(Parse *pParse, Token *pName, Token *pType){
pCol->colFlags |= COLFLAG_HASTYPE;
}
p->nCol++;
+ p->nNVCol++;
pParse->constraintName.n = 0;
}
@@ -1322,10 +1404,17 @@ void sqlite3AddDefaultValue(
sqlite3 *db = pParse->db;
p = pParse->pNewTable;
if( p!=0 ){
+ int isInit = db->init.busy && db->init.iDb!=1;
pCol = &(p->aCol[p->nCol-1]);
- if( !sqlite3ExprIsConstantOrFunction(pExpr, db->init.busy) ){
+ if( !sqlite3ExprIsConstantOrFunction(pExpr, isInit) ){
sqlite3ErrorMsg(pParse, "default value of column [%s] is not constant",
pCol->zName);
+#ifndef SQLITE_OMIT_GENERATED_COLUMNS
+ }else if( pCol->colFlags & COLFLAG_GENERATED ){
+ testcase( pCol->colFlags & COLFLAG_VIRTUAL );
+ testcase( pCol->colFlags & COLFLAG_STORED );
+ sqlite3ErrorMsg(pParse, "cannot use DEFAULT on a generated column");
+#endif
}else{
/* A copy of pExpr is used instead of the original, as pExpr contains
** tokens that point to volatile memory.
@@ -1371,6 +1460,21 @@ static void sqlite3StringToId(Expr *p){
}
}
+/*
+** Tag the given column as being part of the PRIMARY KEY
+*/
+static void makeColumnPartOfPrimaryKey(Parse *pParse, Column *pCol){
+ pCol->colFlags |= COLFLAG_PRIMKEY;
+#ifndef SQLITE_OMIT_GENERATED_COLUMNS
+ if( pCol->colFlags & COLFLAG_GENERATED ){
+ testcase( pCol->colFlags & COLFLAG_VIRTUAL );
+ testcase( pCol->colFlags & COLFLAG_STORED );
+ sqlite3ErrorMsg(pParse,
+ "generated columns cannot be part of the PRIMARY KEY");
+ }
+#endif
+}
+
/*
** Designate the PRIMARY KEY for the table. pList is a list of names
** of columns that form the primary key. If pList is NULL, then the
@@ -1410,7 +1514,7 @@ void sqlite3AddPrimaryKey(
if( pList==0 ){
iCol = pTab->nCol - 1;
pCol = &pTab->aCol[iCol];
- pCol->colFlags |= COLFLAG_PRIMKEY;
+ makeColumnPartOfPrimaryKey(pParse, pCol);
nTerm = 1;
}else{
nTerm = pList->nExpr;
@@ -1423,7 +1527,7 @@ void sqlite3AddPrimaryKey(
for(iCol=0; iColnCol; iCol++){
if( sqlite3StrICmp(zCName, pTab->aCol[iCol].zName)==0 ){
pCol = &pTab->aCol[iCol];
- pCol->colFlags |= COLFLAG_PRIMKEY;
+ makeColumnPartOfPrimaryKey(pParse, pCol);
break;
}
}
@@ -1444,6 +1548,7 @@ void sqlite3AddPrimaryKey(
assert( autoInc==0 || autoInc==1 );
pTab->tabFlags |= autoInc*TF_Autoincrement;
if( pList ) pParse->iPkSortOrder = pList->a[0].sortFlags;
+ (void)sqlite3HasExplicitNulls(pParse, pList);
}else if( autoInc ){
#ifndef SQLITE_OMIT_AUTOINCREMENT
sqlite3ErrorMsg(pParse, "AUTOINCREMENT is only allowed on an "
@@ -1520,41 +1625,58 @@ void sqlite3AddCollateType(Parse *pParse, Token *pToken){
}
}
-/*
-** This function returns the collation sequence for database native text
-** encoding identified by the string zName, length nName.
-**
-** If the requested collation sequence is not available, or not available
-** in the database native encoding, the collation factory is invoked to
-** request it. If the collation factory does not supply such a sequence,
-** and the sequence is available in another text encoding, then that is
-** returned instead.
-**
-** If no versions of the requested collations sequence are available, or
-** another error occurs, NULL is returned and an error message written into
-** pParse.
-**
-** This routine is a wrapper around sqlite3FindCollSeq(). This routine
-** invokes the collation factory if the named collation cannot be found
-** and generates an error message.
-**
-** See also: sqlite3FindCollSeq(), sqlite3GetCollSeq()
+/* Change the most recently parsed column to be a GENERATED ALWAYS AS
+** column.
*/
-CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char *zName){
- sqlite3 *db = pParse->db;
- u8 enc = ENC(db);
- u8 initbusy = db->init.busy;
- CollSeq *pColl;
-
- pColl = sqlite3FindCollSeq(db, enc, zName, initbusy);
- if( !initbusy && (!pColl || !pColl->xCmp) ){
- pColl = sqlite3GetCollSeq(pParse, enc, pColl, zName);
+void sqlite3AddGenerated(Parse *pParse, Expr *pExpr, Token *pType){
+#ifndef SQLITE_OMIT_GENERATED_COLUMNS
+ u8 eType = COLFLAG_VIRTUAL;
+ Table *pTab = pParse->pNewTable;
+ Column *pCol;
+ if( pTab==0 ){
+ /* generated column in an CREATE TABLE IF NOT EXISTS that already exists */
+ goto generated_done;
}
+ pCol = &(pTab->aCol[pTab->nCol-1]);
+ if( IN_DECLARE_VTAB ){
+ sqlite3ErrorMsg(pParse, "virtual tables cannot use computed columns");
+ goto generated_done;
+ }
+ if( pCol->pDflt ) goto generated_error;
+ if( pType ){
+ if( pType->n==7 && sqlite3StrNICmp("virtual",pType->z,7)==0 ){
+ /* no-op */
+ }else if( pType->n==6 && sqlite3StrNICmp("stored",pType->z,6)==0 ){
+ eType = COLFLAG_STORED;
+ }else{
+ goto generated_error;
+ }
+ }
+ if( eType==COLFLAG_VIRTUAL ) pTab->nNVCol--;
+ pCol->colFlags |= eType;
+ assert( TF_HasVirtual==COLFLAG_VIRTUAL );
+ assert( TF_HasStored==COLFLAG_STORED );
+ pTab->tabFlags |= eType;
+ if( pCol->colFlags & COLFLAG_PRIMKEY ){
+ makeColumnPartOfPrimaryKey(pParse, pCol); /* For the error message */
+ }
+ pCol->pDflt = pExpr;
+ pExpr = 0;
+ goto generated_done;
- return pColl;
+generated_error:
+ sqlite3ErrorMsg(pParse, "error in generated column \"%s\"",
+ pCol->zName);
+generated_done:
+ sqlite3ExprDelete(pParse->db, pExpr);
+#else
+ /* Throw and error for the GENERATED ALWAYS AS clause if the
+ ** SQLITE_OMIT_GENERATED_COLUMNS compile-time option is used. */
+ sqlite3ErrorMsg(pParse, "generated columns not supported");
+ sqlite3ExprDelete(pParse->db, pExpr);
+#endif
}
-
/*
** Generate code that will increment the schema cookie.
**
@@ -1812,15 +1934,24 @@ static int isDupColumn(Index *pIdx, int nKey, Index *pPk, int iCol){
** high-order bit of colNotIdxed is always 1. All unindexed columns
** of the table have a 1.
**
+** 2019-10-24: For the purpose of this computation, virtual columns are
+** not considered to be covered by the index, even if they are in the
+** index, because we do not trust the logic in whereIndexExprTrans() to be
+** able to find all instances of a reference to the indexed table column
+** and convert them into references to the index. Hence we always want
+** the actual table at hand in order to recompute the virtual column, if
+** necessary.
+**
** The colNotIdxed mask is AND-ed with the SrcList.a[].colUsed mask
** to determine if the index is covering index.
*/
static void recomputeColumnsNotIndexed(Index *pIdx){
Bitmask m = 0;
int j;
+ Table *pTab = pIdx->pTable;
for(j=pIdx->nColumn-1; j>=0; j--){
int x = pIdx->aiColumn[j];
- if( x>=0 ){
+ if( x>=0 && (pTab->aCol[x].colFlags & COLFLAG_VIRTUAL)==0 ){
testcase( x==BMS-1 );
testcase( x==BMS-2 );
if( xaCol[i].notNull = OE_Abort;
}
}
+ pTab->tabFlags |= TF_HasNotNull;
}
/* Convert the P3 operand of the OP_CreateBtree opcode from BTREE_INTKEY
@@ -1978,11 +2110,14 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
*/
nExtra = 0;
for(i=0; inCol; i++){
- if( !hasColumn(pPk->aiColumn, nPk, i) ) nExtra++;
+ if( !hasColumn(pPk->aiColumn, nPk, i)
+ && (pTab->aCol[i].colFlags & COLFLAG_VIRTUAL)==0 ) nExtra++;
}
if( resizeIndexObject(db, pPk, nPk+nExtra) ) return;
for(i=0, j=nPk; inCol; i++){
- if( !hasColumn(pPk->aiColumn, j, i) ){
+ if( !hasColumn(pPk->aiColumn, j, i)
+ && (pTab->aCol[i].colFlags & COLFLAG_VIRTUAL)==0
+ ){
assert( jnColumn );
pPk->aiColumn[j] = i;
pPk->azColl[j] = sqlite3StrBINARY;
@@ -1990,7 +2125,7 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
}
}
assert( pPk->nColumn==j );
- assert( pTab->nCol<=j );
+ assert( pTab->nNVCol<=j );
recomputeColumnsNotIndexed(pPk);
}
@@ -2002,7 +2137,7 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
** zName is temporarily modified while this routine is running, but is
** restored to its original value prior to this routine returning.
*/
-static int isShadowTableName(sqlite3 *db, char *zName){
+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 */
@@ -2020,8 +2155,6 @@ static int isShadowTableName(sqlite3 *db, char *zName){
if( pMod->pModule->xShadowName==0 ) return 0;
return pMod->pModule->xShadowName(zTail+1);
}
-#else
-# define isShadowTableName(x,y) 0
#endif /* ifndef SQLITE_OMIT_VIRTUALTABLE */
/*
@@ -2063,7 +2196,7 @@ void sqlite3EndTable(
p = pParse->pNewTable;
if( p==0 ) return;
- if( pSelect==0 && isShadowTableName(db, p->zName) ){
+ if( pSelect==0 && sqlite3ShadowTableName(db, p->zName) ){
p->tabFlags |= TF_Shadow;
}
@@ -2099,12 +2232,11 @@ void sqlite3EndTable(
}
if( (p->tabFlags & TF_HasPrimaryKey)==0 ){
sqlite3ErrorMsg(pParse, "PRIMARY KEY missing on table %s", p->zName);
- }else{
- p->tabFlags |= TF_WithoutRowid | TF_NoVisibleRowid;
- convertToWithoutRowidTable(pParse, p);
+ return;
}
+ p->tabFlags |= TF_WithoutRowid | TF_NoVisibleRowid;
+ convertToWithoutRowidTable(pParse, p);
}
-
iDb = sqlite3SchemaToIndex(db, p->pSchema);
#ifndef SQLITE_OMIT_CHECK
@@ -2112,8 +2244,45 @@ void sqlite3EndTable(
*/
if( p->pCheck ){
sqlite3ResolveSelfReference(pParse, p, NC_IsCheck, 0, p->pCheck);
+ if( pParse->nErr ){
+ /* If errors are seen, delete the CHECK constraints now, else they might
+ ** actually be used if PRAGMA writable_schema=ON is set. */
+ sqlite3ExprListDelete(db, p->pCheck);
+ p->pCheck = 0;
+ }
}
#endif /* !defined(SQLITE_OMIT_CHECK) */
+#ifndef SQLITE_OMIT_GENERATED_COLUMNS
+ if( p->tabFlags & TF_HasGenerated ){
+ int ii, nNG = 0;
+ testcase( p->tabFlags & TF_HasVirtual );
+ testcase( p->tabFlags & TF_HasStored );
+ for(ii=0; iinCol; ii++){
+ u32 colFlags = p->aCol[ii].colFlags;
+ if( (colFlags & COLFLAG_GENERATED)!=0 ){
+ Expr *pX = p->aCol[ii].pDflt;
+ testcase( colFlags & COLFLAG_VIRTUAL );
+ testcase( colFlags & COLFLAG_STORED );
+ if( sqlite3ResolveSelfReference(pParse, p, NC_GenCol, pX, 0) ){
+ /* If there are errors in resolving the expression, change the
+ ** expression to a NULL. This prevents code generators that operate
+ ** on the expression from inserting extra parts into the expression
+ ** tree that have been allocated from lookaside memory, which is
+ ** illegal in a schema and will lead to errors heap corruption when
+ ** the database connection closes. */
+ sqlite3ExprDelete(db, pX);
+ p->aCol[ii].pDflt = sqlite3ExprAlloc(db, TK_NULL, 0, 0);
+ }
+ }else{
+ nNG++;
+ }
+ }
+ if( nNG==0 ){
+ sqlite3ErrorMsg(pParse, "must have at least one non-generated column");
+ return;
+ }
+ }
+#endif
/* Estimate the average row size for the table and for all implied indices */
estimateTableWidth(p);
@@ -2190,7 +2359,7 @@ void sqlite3EndTable(
pSelTab = sqlite3ResultSetOfSelect(pParse, pSelect, SQLITE_AFF_BLOB);
if( pSelTab==0 ) return;
assert( p->aCol==0 );
- p->nCol = pSelTab->nCol;
+ p->nCol = p->nNVCol = pSelTab->nCol;
p->aCol = pSelTab->aCol;
pSelTab->nCol = 0;
pSelTab->aCol = 0;
@@ -2263,7 +2432,6 @@ void sqlite3EndTable(
sqlite3MPrintf(db, "tbl_name='%q' AND type!='trigger'", p->zName));
}
-
/* Add the table to the in-memory representation of the database.
*/
if( db->init.busy ){
@@ -2334,6 +2502,7 @@ void sqlite3CreateView(
** allocated rather than point to the input string - which means that
** they will persist after the current sqlite3_exec() call returns.
*/
+ pSelect->selFlags |= SF_View;
if( IN_RENAME_OBJECT ){
p->pSelect = pSelect;
pSelect = 0;
@@ -2447,7 +2616,7 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
n = pParse->nTab;
sqlite3SrcListAssignCursors(pParse, pSel->pSrc);
pTable->nCol = -1;
- db->lookaside.bDisable++;
+ DisableLookaside;
#ifndef SQLITE_OMIT_AUTHORIZATION
xAuth = db->xAuth;
db->xAuth = 0;
@@ -2457,7 +2626,10 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
pSelTab = sqlite3ResultSetOfSelect(pParse, pSel, SQLITE_AFF_NONE);
#endif
pParse->nTab = n;
- if( pTable->pCheck ){
+ if( pSelTab==0 ){
+ pTable->nCol = 0;
+ nErr++;
+ }else if( pTable->pCheck ){
/* CREATE VIEW name(arglist) AS ...
** The names of the columns in the table are taken from
** arglist which is stored in pTable->pCheck. The pCheck field
@@ -2473,7 +2645,7 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
sqlite3SelectAddColumnTypeAndCollation(pParse, pTable, pSel,
SQLITE_AFF_NONE);
}
- }else if( pSelTab ){
+ }else{
/* CREATE VIEW name AS... without an argument list. Construct
** the column names from the SELECT statement that defines the view.
*/
@@ -2483,13 +2655,11 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
pSelTab->nCol = 0;
pSelTab->aCol = 0;
assert( sqlite3SchemaMutexHeld(db, 0, pTable->pSchema) );
- }else{
- pTable->nCol = 0;
- nErr++;
}
+ pTable->nNVCol = pTable->nCol;
sqlite3DeleteTable(db, pSelTab);
sqlite3SelectDelete(db, pSel);
- db->lookaside.bDisable--;
+ EnableLookaside;
#ifndef SQLITE_OMIT_ALTERTABLE
pParse->eParseMode = eParseMode;
#endif
@@ -2746,6 +2916,37 @@ void sqlite3CodeDropTable(Parse *pParse, Table *pTab, int iDb, int isView){
sqliteViewResetAll(db, iDb);
}
+/*
+** Return TRUE if shadow tables should be read-only in the current
+** context.
+*/
+int sqlite3ReadOnlyShadowTables(sqlite3 *db){
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ if( (db->flags & SQLITE_Defensive)!=0
+ && db->pVtabCtx==0
+ && db->nVdbeExec==0
+ ){
+ return 1;
+ }
+#endif
+ return 0;
+}
+
+/*
+** Return true if it is not allowed to drop the given table
+*/
+static int tableMayNotBeDropped(sqlite3 *db, Table *pTab){
+ if( sqlite3StrNICmp(pTab->zName, "sqlite_", 7)==0 ){
+ if( sqlite3StrNICmp(pTab->zName+7, "stat", 4)==0 ) return 0;
+ if( sqlite3StrNICmp(pTab->zName+7, "parameters", 10)==0 ) return 0;
+ return 1;
+ }
+ if( (pTab->tabFlags & TF_Shadow)!=0 && sqlite3ReadOnlyShadowTables(db) ){
+ return 1;
+ }
+ return 0;
+}
+
/*
** This routine is called to do the work of a DROP TABLE statement.
** pName is the name of the table to be dropped.
@@ -2815,9 +3016,7 @@ void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, int noErr){
}
}
#endif
- if( sqlite3StrNICmp(pTab->zName, "sqlite_", 7)==0
- && sqlite3StrNICmp(pTab->zName+7, "stat", 4)!=0
- && sqlite3StrNICmp(pTab->zName+7, "parameters", 10)!=0 ){
+ if( tableMayNotBeDropped(db, pTab) ){
sqlite3ErrorMsg(pParse, "table %s may not be dropped", pTab->zName);
goto exit_drop_table;
}
@@ -2909,7 +3108,7 @@ void sqlite3CreateForeignKey(
nByte = sizeof(*pFKey) + (nCol-1)*sizeof(pFKey->aCol[0]) + pTo->n + 1;
if( pToCol ){
for(i=0; inExpr; i++){
- nByte += sqlite3Strlen30(pToCol->a[i].zName) + 1;
+ nByte += sqlite3Strlen30(pToCol->a[i].zEName) + 1;
}
}
pFKey = sqlite3DbMallocZero(db, nByte );
@@ -2934,7 +3133,7 @@ void sqlite3CreateForeignKey(
for(i=0; inCol; j++){
- if( sqlite3StrICmp(p->aCol[j].zName, pFromCol->a[i].zName)==0 ){
+ if( sqlite3StrICmp(p->aCol[j].zName, pFromCol->a[i].zEName)==0 ){
pFKey->aCol[i].iFrom = j;
break;
}
@@ -2942,22 +3141,22 @@ void sqlite3CreateForeignKey(
if( j>=p->nCol ){
sqlite3ErrorMsg(pParse,
"unknown column \"%s\" in foreign key definition",
- pFromCol->a[i].zName);
+ pFromCol->a[i].zEName);
goto fk_end;
}
if( IN_RENAME_OBJECT ){
- sqlite3RenameTokenRemap(pParse, &pFKey->aCol[i], pFromCol->a[i].zName);
+ sqlite3RenameTokenRemap(pParse, &pFKey->aCol[i], pFromCol->a[i].zEName);
}
}
}
if( pToCol ){
for(i=0; ia[i].zName);
+ int n = sqlite3Strlen30(pToCol->a[i].zEName);
pFKey->aCol[i].zCol = z;
if( IN_RENAME_OBJECT ){
- sqlite3RenameTokenRemap(pParse, z, pToCol->a[i].zName);
+ sqlite3RenameTokenRemap(pParse, z, pToCol->a[i].zEName);
}
- memcpy(z, pToCol->a[i].zName, n);
+ memcpy(z, pToCol->a[i].zEName, n);
z[n] = 0;
z += n+1;
}
@@ -3488,8 +3687,13 @@ void sqlite3CreateIndex(
assert( j<=0x7fff );
if( j<0 ){
j = pTab->iPKey;
- }else if( pTab->aCol[j].notNull==0 ){
- pIndex->uniqNotNull = 0;
+ }else{
+ if( pTab->aCol[j].notNull==0 ){
+ pIndex->uniqNotNull = 0;
+ }
+ if( pTab->aCol[j].colFlags & COLFLAG_VIRTUAL ){
+ pIndex->bHasVCol = 1;
+ }
}
pIndex->aiColumn[i] = (i16)j;
}
@@ -3544,13 +3748,13 @@ void sqlite3CreateIndex(
/* If this index contains every column of its table, then mark
** it as a covering index */
assert( HasRowid(pTab)
- || pTab->iPKey<0 || sqlite3ColumnOfIndex(pIndex, pTab->iPKey)>=0 );
+ || pTab->iPKey<0 || sqlite3TableColumnToIndex(pIndex, pTab->iPKey)>=0 );
recomputeColumnsNotIndexed(pIndex);
if( pTblName!=0 && pIndex->nColumn>=pTab->nCol ){
pIndex->isCovering = 1;
for(j=0; jnCol; j++){
if( j==pTab->iPKey ) continue;
- if( sqlite3ColumnOfIndex(pIndex,j)>=0 ) continue;
+ if( sqlite3TableColumnToIndex(pIndex,j)>=0 ) continue;
pIndex->isCovering = 0;
break;
}
@@ -3725,26 +3929,9 @@ void sqlite3CreateIndex(
sqlite3VdbeJumpHere(v, pIndex->tnum);
}
}
-
- /* When adding an index to the list of indices for a table, make
- ** sure all indices labeled OE_Replace come after all those labeled
- ** OE_Ignore. This is necessary for the correct constraint check
- ** processing (in sqlite3GenerateConstraintChecks()) as part of
- ** UPDATE and INSERT statements.
- */
if( db->init.busy || pTblName==0 ){
- if( onError!=OE_Replace || pTab->pIndex==0
- || pTab->pIndex->onError==OE_Replace){
- pIndex->pNext = pTab->pIndex;
- pTab->pIndex = pIndex;
- }else{
- Index *pOther = pTab->pIndex;
- while( pOther->pNext && pOther->pNext->onError!=OE_Replace ){
- pOther = pOther->pNext;
- }
- pIndex->pNext = pOther->pNext;
- pOther->pNext = pIndex;
- }
+ pIndex->pNext = pTab->pIndex;
+ pTab->pIndex = pIndex;
pIndex = 0;
}
else if( IN_RENAME_OBJECT ){
@@ -3756,6 +3943,21 @@ void sqlite3CreateIndex(
/* Clean up before exiting */
exit_create_index:
if( pIndex ) sqlite3FreeIndex(db, pIndex);
+ if( pTab ){ /* Ensure all REPLACE indexes are at the end of the list */
+ Index **ppFrom = &pTab->pIndex;
+ Index *pThis;
+ for(ppFrom=&pTab->pIndex; (pThis = *ppFrom)!=0; ppFrom=&pThis->pNext){
+ Index *pNext;
+ if( pThis->onError!=OE_Replace ) continue;
+ while( (pNext = pThis->pNext)!=0 && pNext->onError!=OE_Replace ){
+ *ppFrom = pNext;
+ pThis->pNext = pNext->pNext;
+ pNext->pNext = pThis;
+ ppFrom = &pNext->pNext;
+ }
+ break;
+ }
+ }
sqlite3ExprDelete(db, pPIWhere);
sqlite3ExprListDelete(db, pList);
sqlite3SrcListDelete(db, pTblName);
diff --git a/src/callback.c b/src/callback.c
index ad53bd4d3c..3d991901d1 100644
--- a/src/callback.c
+++ b/src/callback.c
@@ -65,51 +65,6 @@ static int synthCollSeq(sqlite3 *db, CollSeq *pColl){
return SQLITE_ERROR;
}
-/*
-** This function is responsible for invoking the collation factory callback
-** or substituting a collation sequence of a different encoding when the
-** requested collation sequence is not available in the desired encoding.
-**
-** If it is not NULL, then pColl must point to the database native encoding
-** collation sequence with name zName, length nName.
-**
-** The return value is either the collation sequence to be used in database
-** db for collation type name zName, length nName, or NULL, if no collation
-** sequence can be found. If no collation is found, leave an error message.
-**
-** See also: sqlite3LocateCollSeq(), sqlite3FindCollSeq()
-*/
-CollSeq *sqlite3GetCollSeq(
- Parse *pParse, /* Parsing context */
- u8 enc, /* The desired encoding for the collating sequence */
- CollSeq *pColl, /* Collating sequence with native encoding, or NULL */
- const char *zName /* Collating sequence name */
-){
- CollSeq *p;
- sqlite3 *db = pParse->db;
-
- p = pColl;
- if( !p ){
- p = sqlite3FindCollSeq(db, enc, zName, 0);
- }
- if( !p || !p->xCmp ){
- /* No collation sequence of this type for this encoding is registered.
- ** Call the collation factory to see if it can supply us with one.
- */
- callCollNeeded(db, enc, zName);
- p = sqlite3FindCollSeq(db, enc, zName, 0);
- }
- if( p && !p->xCmp && synthCollSeq(db, p) ){
- p = 0;
- }
- assert( !p || p->xCmp );
- if( p==0 ){
- sqlite3ErrorMsg(pParse, "no such collation sequence: %s", zName);
- pParse->rc = SQLITE_ERROR_MISSING_COLLSEQ;
- }
- return p;
-}
-
/*
** This routine is called on a collation sequence before it is used to
** check that it is defined. An undefined collation sequence exists when
@@ -202,10 +157,10 @@ static CollSeq *findCollSeqEntry(
** See also: sqlite3LocateCollSeq(), sqlite3GetCollSeq()
*/
CollSeq *sqlite3FindCollSeq(
- sqlite3 *db,
- u8 enc,
- const char *zName,
- int create
+ sqlite3 *db, /* Database connection to search */
+ u8 enc, /* Desired text encoding */
+ const char *zName, /* Name of the collating sequence. Might be NULL */
+ int create /* True to create CollSeq if doesn't already exist */
){
CollSeq *pColl;
if( zName ){
@@ -219,6 +174,85 @@ CollSeq *sqlite3FindCollSeq(
return pColl;
}
+/*
+** This function is responsible for invoking the collation factory callback
+** or substituting a collation sequence of a different encoding when the
+** requested collation sequence is not available in the desired encoding.
+**
+** If it is not NULL, then pColl must point to the database native encoding
+** collation sequence with name zName, length nName.
+**
+** The return value is either the collation sequence to be used in database
+** db for collation type name zName, length nName, or NULL, if no collation
+** sequence can be found. If no collation is found, leave an error message.
+**
+** See also: sqlite3LocateCollSeq(), sqlite3FindCollSeq()
+*/
+CollSeq *sqlite3GetCollSeq(
+ Parse *pParse, /* Parsing context */
+ u8 enc, /* The desired encoding for the collating sequence */
+ CollSeq *pColl, /* Collating sequence with native encoding, or NULL */
+ const char *zName /* Collating sequence name */
+){
+ CollSeq *p;
+ sqlite3 *db = pParse->db;
+
+ p = pColl;
+ if( !p ){
+ p = sqlite3FindCollSeq(db, enc, zName, 0);
+ }
+ if( !p || !p->xCmp ){
+ /* No collation sequence of this type for this encoding is registered.
+ ** Call the collation factory to see if it can supply us with one.
+ */
+ callCollNeeded(db, enc, zName);
+ p = sqlite3FindCollSeq(db, enc, zName, 0);
+ }
+ if( p && !p->xCmp && synthCollSeq(db, p) ){
+ p = 0;
+ }
+ assert( !p || p->xCmp );
+ if( p==0 ){
+ sqlite3ErrorMsg(pParse, "no such collation sequence: %s", zName);
+ pParse->rc = SQLITE_ERROR_MISSING_COLLSEQ;
+ }
+ return p;
+}
+
+/*
+** This function returns the collation sequence for database native text
+** encoding identified by the string zName.
+**
+** If the requested collation sequence is not available, or not available
+** in the database native encoding, the collation factory is invoked to
+** request it. If the collation factory does not supply such a sequence,
+** and the sequence is available in another text encoding, then that is
+** returned instead.
+**
+** If no versions of the requested collations sequence are available, or
+** another error occurs, NULL is returned and an error message written into
+** pParse.
+**
+** This routine is a wrapper around sqlite3FindCollSeq(). This routine
+** invokes the collation factory if the named collation cannot be found
+** and generates an error message.
+**
+** See also: sqlite3FindCollSeq(), sqlite3GetCollSeq()
+*/
+CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char *zName){
+ sqlite3 *db = pParse->db;
+ u8 enc = ENC(db);
+ u8 initbusy = db->init.busy;
+ CollSeq *pColl;
+
+ pColl = sqlite3FindCollSeq(db, enc, zName, initbusy);
+ if( !initbusy && (!pColl || !pColl->xCmp) ){
+ pColl = sqlite3GetCollSeq(pParse, enc, pColl, zName);
+ }
+
+ return pColl;
+}
+
/* During the search for the best function definition, this procedure
** is called to test how well the function passed as the first argument
** matches the request for a function with nArg arguments in a system
@@ -254,12 +288,13 @@ static int matchQuality(
u8 enc /* Desired text encoding */
){
int match;
-
- /* nArg of -2 is a special case */
- if( nArg==(-2) ) return (p->xSFunc==0) ? 0 : FUNC_PERFECT_MATCH;
+ assert( p->nArg>=-1 );
/* Wrong number of arguments means "no match" */
- if( p->nArg!=nArg && p->nArg>=0 ) return 0;
+ if( p->nArg!=nArg ){
+ if( nArg==(-2) ) return (p->xSFunc==0) ? 0 : FUNC_PERFECT_MATCH;
+ if( p->nArg>=0 ) return 0;
+ }
/* Give a better score to a function with a specific number of arguments
** than to function that accepts any number of arguments. */
diff --git a/src/dbpage.c b/src/dbpage.c
index 27c962d144..c4f0b539ef 100644
--- a/src/dbpage.c
+++ b/src/dbpage.c
@@ -73,6 +73,7 @@ static int dbpageConnect(
DbpageTable *pTab = 0;
int rc = SQLITE_OK;
+ sqlite3_vtab_config(db, SQLITE_VTAB_DIRECTONLY);
rc = sqlite3_declare_vtab(db,
"CREATE TABLE x(pgno INTEGER PRIMARY KEY, data BLOB, schema HIDDEN)");
if( rc==SQLITE_OK ){
diff --git a/src/dbstat.c b/src/dbstat.c
index 9b72fb147c..2fea48ce8c 100644
--- a/src/dbstat.c
+++ b/src/dbstat.c
@@ -12,7 +12,7 @@
**
** This file contains an implementation of the "dbstat" virtual table.
**
-** The dbstat virtual table is used to extract low-level formatting
+** The dbstat virtual table is used to extract low-level storage
** information from an SQLite database in order to implement the
** "sqlite3_analyzer" utility. See the ../tool/spaceanal.tcl script
** for an example implementation.
@@ -56,27 +56,30 @@
**
** '/1c2/000/' // Left-most child of 451st child of root
*/
-#define VTAB_SCHEMA \
- "CREATE TABLE xx( " \
- " name TEXT, /* Name of table or index */" \
- " path TEXT, /* Path to page from root */" \
- " pageno INTEGER, /* Page number */" \
- " pagetype TEXT, /* 'internal', 'leaf' or 'overflow' */" \
- " ncell INTEGER, /* Cells on page (0 for overflow) */" \
- " payload INTEGER, /* Bytes of payload on this page */" \
- " unused INTEGER, /* Bytes of unused space on this page */" \
- " mx_payload INTEGER, /* Largest payload size of all cells */" \
- " pgoffset INTEGER, /* Offset of page in file */" \
- " pgsize INTEGER, /* Size of the page */" \
- " schema TEXT HIDDEN /* Database schema being analyzed */" \
- ");"
-
+static const char zDbstatSchema[] =
+ "CREATE TABLE x("
+ " name TEXT," /* 0 Name of table or index */
+ " path TEXT," /* 1 Path to page from root (NULL for agg) */
+ " pageno INTEGER," /* 2 Page number (page count for aggregates) */
+ " pagetype TEXT," /* 3 'internal', 'leaf', 'overflow', or NULL */
+ " ncell INTEGER," /* 4 Cells on page (0 for overflow) */
+ " payload INTEGER," /* 5 Bytes of payload on this page */
+ " unused INTEGER," /* 6 Bytes of unused space on this page */
+ " mx_payload INTEGER," /* 7 Largest payload size of all cells */
+ " pgoffset INTEGER," /* 8 Offset of page in file (NULL for agg) */
+ " pgsize INTEGER," /* 9 Size of the page (sum for aggregate) */
+ " schema TEXT HIDDEN," /* 10 Database schema being analyzed */
+ " aggregate BOOLEAN HIDDEN" /* 11 aggregate info for each table */
+ ")"
+;
+/* Forward reference to data structured used in this module */
typedef struct StatTable StatTable;
typedef struct StatCursor StatCursor;
typedef struct StatPage StatPage;
typedef struct StatCell StatCell;
+/* Size information for a single cell within a btree page */
struct StatCell {
int nLocal; /* Bytes of local payload */
u32 iChildPg; /* Child node (or 0 if this is a leaf) */
@@ -86,10 +89,11 @@ struct StatCell {
int iOvfl; /* Iterates through aOvfl[] */
};
+/* Size information for a single btree page */
struct StatPage {
- u32 iPgno;
- DbPage *pPg;
- int iCell;
+ u32 iPgno; /* Page number */
+ DbPage *pPg; /* Page content */
+ int iCell; /* Current cell */
char *zPath; /* Path to this page */
@@ -99,34 +103,38 @@ struct StatPage {
int nUnused; /* Number of unused bytes on page */
StatCell *aCell; /* Array of parsed cells */
u32 iRightChildPg; /* Right-child page number (or 0) */
- int nMxPayload; /* Largest payload of any cell on this page */
+ int nMxPayload; /* Largest payload of any cell on the page */
};
+/* The cursor for scanning the dbstat virtual table */
struct StatCursor {
- sqlite3_vtab_cursor base;
+ sqlite3_vtab_cursor base; /* base class. MUST BE FIRST! */
sqlite3_stmt *pStmt; /* Iterates through set of root pages */
- int isEof; /* After pStmt has returned SQLITE_DONE */
+ u8 isEof; /* After pStmt has returned SQLITE_DONE */
+ u8 isAgg; /* Aggregate results for each table */
int iDb; /* Schema used for this query */
- StatPage aPage[32];
+ StatPage aPage[32]; /* Pages in path to current page */
int iPage; /* Current entry in aPage[] */
/* Values to return. */
+ u32 iPageno; /* Value of 'pageno' column */
char *zName; /* Value of 'name' column */
char *zPath; /* Value of 'path' column */
- u32 iPageno; /* Value of 'pageno' column */
char *zPagetype; /* Value of 'pagetype' column */
+ int nPage; /* Number of pages in current btree */
int nCell; /* Value of 'ncell' column */
- int nPayload; /* Value of 'payload' column */
- int nUnused; /* Value of 'unused' column */
int nMxPayload; /* Value of 'mx_payload' column */
+ i64 nUnused; /* Value of 'unused' column */
+ i64 nPayload; /* Value of 'payload' column */
i64 iOffset; /* Value of 'pgOffset' column */
- int szPage; /* Value of 'pgSize' column */
+ i64 szPage; /* Value of 'pgSize' column */
};
+/* An instance of the DBSTAT virtual table */
struct StatTable {
- sqlite3_vtab base;
- sqlite3 *db;
+ sqlite3_vtab base; /* base class. MUST BE FIRST! */
+ sqlite3 *db; /* Database connection that owns this vtab */
int iDb; /* Index of database to analyze */
};
@@ -135,7 +143,7 @@ struct StatTable {
#endif
/*
-** Connect to or create a statvfs virtual table.
+** Connect to or create a new DBSTAT virtual table.
*/
static int statConnect(
sqlite3 *db,
@@ -159,7 +167,8 @@ static int statConnect(
}else{
iDb = 0;
}
- rc = sqlite3_declare_vtab(db, VTAB_SCHEMA);
+ sqlite3_vtab_config(db, SQLITE_VTAB_DIRECTONLY);
+ rc = sqlite3_declare_vtab(db, zDbstatSchema);
if( rc==SQLITE_OK ){
pTab = (StatTable *)sqlite3_malloc64(sizeof(StatTable));
if( pTab==0 ) rc = SQLITE_NOMEM_BKPT;
@@ -177,7 +186,7 @@ static int statConnect(
}
/*
-** Disconnect from or destroy a statvfs virtual table.
+** Disconnect from or destroy the DBSTAT virtual table.
*/
static int statDisconnect(sqlite3_vtab *pVtab){
sqlite3_free(pVtab);
@@ -185,14 +194,20 @@ static int statDisconnect(sqlite3_vtab *pVtab){
}
/*
-** There is no "best-index". This virtual table always does a linear
-** scan. However, a schema=? constraint should cause this table to
-** operate on a different database schema, so check for it.
+** Compute the best query strategy and return the result in idxNum.
**
-** idxNum is normally 0, but will be 1 if a schema=? constraint exists.
+** idxNum-Bit Meaning
+** ---------- ----------------------------------------------
+** 0x01 There is a schema=? term in the WHERE clause
+** 0x02 There is a name=? term in the WHERE clause
+** 0x04 There is an aggregate=? term in the WHERE clause
+** 0x08 Output should be ordered by name and path
*/
static int statBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
int i;
+ int iSchema = -1;
+ int iName = -1;
+ int iAgg = -1;
/* Look for a valid schema=? constraint. If found, change the idxNum to
** 1 and request the value of that constraint be sent to xFilter. And
@@ -200,16 +215,40 @@ static int statBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
** used.
*/
for(i=0; inConstraint; i++){
- if( pIdxInfo->aConstraint[i].iColumn!=10 ) continue;
- if( pIdxInfo->aConstraint[i].usable==0 ) return SQLITE_CONSTRAINT;
if( pIdxInfo->aConstraint[i].op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue;
- pIdxInfo->idxNum = 1;
- pIdxInfo->estimatedCost = 1.0;
- pIdxInfo->aConstraintUsage[i].argvIndex = 1;
- pIdxInfo->aConstraintUsage[i].omit = 1;
- break;
+ if( pIdxInfo->aConstraint[i].usable==0 ){
+ /* Force DBSTAT table should always be the right-most table in a join */
+ return SQLITE_CONSTRAINT;
+ }
+ switch( pIdxInfo->aConstraint[i].iColumn ){
+ case 0: { /* name */
+ iName = i;
+ break;
+ }
+ case 10: { /* schema */
+ iSchema = i;
+ break;
+ }
+ case 11: { /* aggregate */
+ iAgg = i;
+ break;
+ }
+ }
}
-
+ i = 0;
+ if( iSchema>=0 ){
+ pIdxInfo->aConstraintUsage[iSchema].argvIndex = ++i;
+ pIdxInfo->idxNum |= 0x01;
+ }
+ if( iName>=0 ){
+ pIdxInfo->aConstraintUsage[iName].argvIndex = ++i;
+ pIdxInfo->idxNum |= 0x02;
+ }
+ if( iAgg>=0 ){
+ pIdxInfo->aConstraintUsage[iAgg].argvIndex = ++i;
+ pIdxInfo->idxNum |= 0x04;
+ }
+ pIdxInfo->estimatedCost = 1.0;
/* Records are always returned in ascending order of (name, path).
** If this will satisfy the client, set the orderByConsumed flag so that
@@ -227,13 +266,14 @@ static int statBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
)
){
pIdxInfo->orderByConsumed = 1;
+ pIdxInfo->idxNum |= 0x08;
}
return SQLITE_OK;
}
/*
-** Open a new statvfs cursor.
+** Open a new DBSTAT cursor.
*/
static int statOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
StatTable *pTab = (StatTable *)pVTab;
@@ -283,8 +323,18 @@ static void statResetCsr(StatCursor *pCsr){
pCsr->isEof = 0;
}
+/* Resize the space-used counters inside of the cursor */
+static void statResetCounts(StatCursor *pCsr){
+ pCsr->nCell = 0;
+ pCsr->nMxPayload = 0;
+ pCsr->nUnused = 0;
+ pCsr->nPayload = 0;
+ pCsr->szPage = 0;
+ pCsr->nPage = 0;
+}
+
/*
-** Close a statvfs cursor.
+** Close a DBSTAT cursor.
*/
static int statClose(sqlite3_vtab_cursor *pCursor){
StatCursor *pCsr = (StatCursor *)pCursor;
@@ -294,11 +344,15 @@ static int statClose(sqlite3_vtab_cursor *pCursor){
return SQLITE_OK;
}
-static void getLocalPayload(
+/*
+** For a single cell on a btree page, compute the number of bytes of
+** content (payload) stored on that page. That is to say, compute the
+** number of bytes of content not found on overflow pages.
+*/
+static int getLocalPayload(
int nUsable, /* Usable bytes per page */
u8 flags, /* Page flags */
- int nTotal, /* Total record (payload) size */
- int *pnLocal /* OUT: Bytes stored locally */
+ int nTotal /* Total record (payload) size */
){
int nLocal;
int nMinLocal;
@@ -314,9 +368,12 @@ static void getLocalPayload(
nLocal = nMinLocal + (nTotal - nMinLocal) % (nUsable - 4);
if( nLocal>nMaxLocal ) nLocal = nMinLocal;
- *pnLocal = nLocal;
+ return nLocal;
}
+/* Populate the StatPage object with information about the all
+** cells found on the page currently under analysis.
+*/
static int statDecodePage(Btree *pBt, StatPage *p){
int nUnused;
int iOff;
@@ -387,7 +444,7 @@ static int statDecodePage(Btree *pBt, StatPage *p){
iOff += sqlite3GetVarint(&aData[iOff], &dummy);
}
if( nPayload>(u32)p->nMxPayload ) p->nMxPayload = nPayload;
- getLocalPayload(nUsable, p->flags, nPayload, &nLocal);
+ nLocal = getLocalPayload(nUsable, p->flags, nPayload);
if( nLocal<0 ) goto statPageIsCorrupt;
pCell->nLocal = nLocal;
assert( nPayload>=(u32)nLocal );
@@ -437,23 +494,25 @@ static void statSizeAndOffset(StatCursor *pCsr){
sqlite3_file *fd;
sqlite3_int64 x[2];
- /* The default page size and offset */
- pCsr->szPage = sqlite3BtreeGetPageSize(pBt);
- pCsr->iOffset = (i64)pCsr->szPage * (pCsr->iPageno - 1);
-
- /* If connected to a ZIPVFS backend, override the page size and
- ** offset with actual values obtained from ZIPVFS.
+ /* If connected to a ZIPVFS backend, find the page size and
+ ** offset from ZIPVFS.
*/
fd = sqlite3PagerFile(pPager);
x[0] = pCsr->iPageno;
if( sqlite3OsFileControl(fd, 230440, &x)==SQLITE_OK ){
pCsr->iOffset = x[0];
- pCsr->szPage = (int)x[1];
+ pCsr->szPage += x[1];
+ }else{
+ /* Not ZIPVFS: The default page size and offset */
+ pCsr->szPage += sqlite3BtreeGetPageSize(pBt);
+ pCsr->iOffset = (i64)pCsr->szPage * (pCsr->iPageno - 1);
}
}
/*
-** Move a statvfs cursor to the next entry in the file.
+** Move a DBSTAT cursor to the next entry. Normally, the next
+** entry will be the next page, but in aggregated mode (pCsr->isAgg!=0),
+** the next entry is the next btree.
*/
static int statNext(sqlite3_vtab_cursor *pCursor){
int rc;
@@ -469,6 +528,8 @@ static int statNext(sqlite3_vtab_cursor *pCursor){
statNextRestart:
if( pCsr->aPage[0].pPg==0 ){
+ /* Start measuring space on the next btree */
+ statResetCounts(pCsr);
rc = sqlite3_step(pCsr->pStmt);
if( rc==SQLITE_ROW ){
int nPage;
@@ -481,44 +542,47 @@ statNextRestart:
rc = sqlite3PagerGet(pPager, iRoot, &pCsr->aPage[0].pPg, 0);
pCsr->aPage[0].iPgno = iRoot;
pCsr->aPage[0].iCell = 0;
- pCsr->aPage[0].zPath = z = sqlite3_mprintf("/");
+ if( !pCsr->isAgg ){
+ pCsr->aPage[0].zPath = z = sqlite3_mprintf("/");
+ if( z==0 ) rc = SQLITE_NOMEM_BKPT;
+ }
pCsr->iPage = 0;
- if( z==0 ) rc = SQLITE_NOMEM_BKPT;
+ pCsr->nPage = 1;
}else{
pCsr->isEof = 1;
return sqlite3_reset(pCsr->pStmt);
}
}else{
-
- /* Page p itself has already been visited. */
+ /* Continue analyzing the btree previously started */
StatPage *p = &pCsr->aPage[pCsr->iPage];
-
+ if( !pCsr->isAgg ) statResetCounts(pCsr);
while( p->iCellnCell ){
StatCell *pCell = &p->aCell[p->iCell];
- if( pCell->iOvflnOvfl ){
- int nUsable;
+ while( pCell->iOvflnOvfl ){
+ int nUsable, iOvfl;
sqlite3BtreeEnter(pBt);
nUsable = sqlite3BtreeGetPageSize(pBt) -
sqlite3BtreeGetReserveNoMutex(pBt);
sqlite3BtreeLeave(pBt);
- pCsr->zName = (char *)sqlite3_column_text(pCsr->pStmt, 0);
- pCsr->iPageno = pCell->aOvfl[pCell->iOvfl];
- pCsr->zPagetype = "overflow";
- pCsr->nCell = 0;
- pCsr->nMxPayload = 0;
- pCsr->zPath = z = sqlite3_mprintf(
- "%s%.3x+%.6x", p->zPath, p->iCell, pCell->iOvfl
- );
- if( pCell->iOvflnOvfl-1 ){
- pCsr->nUnused = 0;
- pCsr->nPayload = nUsable - 4;
- }else{
- pCsr->nPayload = pCell->nLastOvfl;
- pCsr->nUnused = nUsable - 4 - pCsr->nPayload;
- }
- pCell->iOvfl++;
+ pCsr->nPage++;
statSizeAndOffset(pCsr);
- return z==0 ? SQLITE_NOMEM_BKPT : SQLITE_OK;
+ if( pCell->iOvflnOvfl-1 ){
+ pCsr->nPayload += nUsable - 4;
+ }else{
+ pCsr->nPayload += pCell->nLastOvfl;
+ pCsr->nUnused += nUsable - 4 - pCell->nLastOvfl;
+ }
+ iOvfl = pCell->iOvfl;
+ pCell->iOvfl++;
+ if( !pCsr->isAgg ){
+ pCsr->zName = (char *)sqlite3_column_text(pCsr->pStmt, 0);
+ pCsr->iPageno = pCell->aOvfl[iOvfl];
+ pCsr->zPagetype = "overflow";
+ pCsr->zPath = z = sqlite3_mprintf(
+ "%s%.3x+%.6x", p->zPath, p->iCell, iOvfl
+ );
+ return z==0 ? SQLITE_NOMEM_BKPT : SQLITE_OK;
+ }
}
if( p->iRightChildPg ) break;
p->iCell++;
@@ -526,8 +590,13 @@ statNextRestart:
if( !p->iRightChildPg || p->iCell>p->nCell ){
statClearPage(p);
- if( pCsr->iPage==0 ) return statNext(pCursor);
- pCsr->iPage--;
+ if( pCsr->iPage>0 ){
+ pCsr->iPage--;
+ }else if( pCsr->isAgg ){
+ /* label-statNext-done: When computing aggregate space usage over
+ ** an entire btree, this is the exit point from this function */
+ return SQLITE_OK;
+ }
goto statNextRestart; /* Tail recursion */
}
pCsr->iPage++;
@@ -543,10 +612,13 @@ statNextRestart:
p[1].iPgno = p->aCell[p->iCell].iChildPg;
}
rc = sqlite3PagerGet(pPager, p[1].iPgno, &p[1].pPg, 0);
+ pCsr->nPage++;
p[1].iCell = 0;
- p[1].zPath = z = sqlite3_mprintf("%s%.3x/", p->zPath, p->iCell);
+ if( !pCsr->isAgg ){
+ p[1].zPath = z = sqlite3_mprintf("%s%.3x/", p->zPath, p->iCell);
+ if( z==0 ) rc = SQLITE_NOMEM_BKPT;
+ }
p->iCell++;
- if( z==0 ) rc = SQLITE_NOMEM_BKPT;
}
@@ -576,16 +648,23 @@ statNextRestart:
pCsr->zPagetype = "corrupted";
break;
}
- pCsr->nCell = p->nCell;
- pCsr->nUnused = p->nUnused;
- pCsr->nMxPayload = p->nMxPayload;
- pCsr->zPath = z = sqlite3_mprintf("%s", p->zPath);
- if( z==0 ) rc = SQLITE_NOMEM_BKPT;
+ pCsr->nCell += p->nCell;
+ pCsr->nUnused += p->nUnused;
+ if( p->nMxPayload>pCsr->nMxPayload ) pCsr->nMxPayload = p->nMxPayload;
+ if( !pCsr->isAgg ){
+ pCsr->zPath = z = sqlite3_mprintf("%s", p->zPath);
+ if( z==0 ) rc = SQLITE_NOMEM_BKPT;
+ }
nPayload = 0;
for(i=0; inCell; i++){
nPayload += p->aCell[i].nLocal;
}
- pCsr->nPayload = nPayload;
+ pCsr->nPayload += nPayload;
+
+ /* If computing aggregate space usage by btree, continue with the
+ ** next page. The loop will exit via the return at label-statNext-done
+ */
+ if( pCsr->isAgg ) goto statNextRestart;
}
}
@@ -597,6 +676,10 @@ static int statEof(sqlite3_vtab_cursor *pCursor){
return pCsr->isEof;
}
+/* Initialize a cursor according to the query plan idxNum using the
+** arguments in argv[0]. See statBestIndex() for a description of the
+** meaning of the bits in idxNum.
+*/
static int statFilter(
sqlite3_vtab_cursor *pCursor,
int idxNum, const char *idxStr,
@@ -604,29 +687,52 @@ static int statFilter(
){
StatCursor *pCsr = (StatCursor *)pCursor;
StatTable *pTab = (StatTable*)(pCursor->pVtab);
- char *zSql;
- int rc = SQLITE_OK;
+ sqlite3_str *pSql; /* Query of btrees to analyze */
+ char *zSql; /* String value of pSql */
+ int iArg = 0; /* Count of argv[] parameters used so far */
+ int rc = SQLITE_OK; /* Result of this operation */
+ const char *zName = 0; /* Only provide analysis of this table */
- if( idxNum==1 ){
- const char *zDbase = (const char*)sqlite3_value_text(argv[0]);
+ statResetCsr(pCsr);
+ sqlite3_finalize(pCsr->pStmt);
+ pCsr->pStmt = 0;
+ if( idxNum & 0x01 ){
+ /* schema=? constraint is present. Get its value */
+ const char *zDbase = (const char*)sqlite3_value_text(argv[iArg++]);
pCsr->iDb = sqlite3FindDbName(pTab->db, zDbase);
if( pCsr->iDb<0 ){
- sqlite3_free(pCursor->pVtab->zErrMsg);
- pCursor->pVtab->zErrMsg = sqlite3_mprintf("no such schema: %s", zDbase);
- return pCursor->pVtab->zErrMsg ? SQLITE_ERROR : SQLITE_NOMEM_BKPT;
+ pCsr->iDb = 0;
+ pCsr->isEof = 1;
+ return SQLITE_OK;
}
}else{
pCsr->iDb = pTab->iDb;
}
- statResetCsr(pCsr);
- sqlite3_finalize(pCsr->pStmt);
- pCsr->pStmt = 0;
- zSql = sqlite3_mprintf(
- "SELECT 'sqlite_master' AS name, 1 AS rootpage, 'table' AS type"
- " UNION ALL "
- "SELECT name, rootpage, type"
- " FROM \"%w\".sqlite_master WHERE rootpage!=0"
- " ORDER BY name", pTab->db->aDb[pCsr->iDb].zDbSName);
+ if( idxNum & 0x02 ){
+ /* name=? constraint is present */
+ zName = (const char*)sqlite3_value_text(argv[iArg++]);
+ }
+ if( idxNum & 0x04 ){
+ /* aggregate=? constraint is present */
+ pCsr->isAgg = sqlite3_value_double(argv[iArg++])!=0.0;
+ }else{
+ pCsr->isAgg = 0;
+ }
+ pSql = sqlite3_str_new(pTab->db);
+ sqlite3_str_appendf(pSql,
+ "SELECT * FROM ("
+ "SELECT 'sqlite_master' AS name,1 AS rootpage,'table' AS type"
+ " UNION ALL "
+ "SELECT name,rootpage,type"
+ " FROM \"%w\".sqlite_master WHERE rootpage!=0)",
+ pTab->db->aDb[pCsr->iDb].zDbSName);
+ if( zName ){
+ sqlite3_str_appendf(pSql, "WHERE name=%Q", zName);
+ }
+ if( idxNum & 0x08 ){
+ sqlite3_str_appendf(pSql, " ORDER BY name");
+ }
+ zSql = sqlite3_str_finish(pSql);
if( zSql==0 ){
return SQLITE_NOMEM_BKPT;
}else{
@@ -651,13 +757,21 @@ static int statColumn(
sqlite3_result_text(ctx, pCsr->zName, -1, SQLITE_TRANSIENT);
break;
case 1: /* path */
- sqlite3_result_text(ctx, pCsr->zPath, -1, SQLITE_TRANSIENT);
+ if( !pCsr->isAgg ){
+ sqlite3_result_text(ctx, pCsr->zPath, -1, SQLITE_TRANSIENT);
+ }
break;
case 2: /* pageno */
- sqlite3_result_int64(ctx, pCsr->iPageno);
+ if( pCsr->isAgg ){
+ sqlite3_result_int64(ctx, pCsr->nPage);
+ }else{
+ sqlite3_result_int64(ctx, pCsr->iPageno);
+ }
break;
case 3: /* pagetype */
- sqlite3_result_text(ctx, pCsr->zPagetype, -1, SQLITE_STATIC);
+ if( !pCsr->isAgg ){
+ sqlite3_result_text(ctx, pCsr->zPagetype, -1, SQLITE_STATIC);
+ }
break;
case 4: /* ncell */
sqlite3_result_int(ctx, pCsr->nCell);
@@ -672,17 +786,23 @@ static int statColumn(
sqlite3_result_int(ctx, pCsr->nMxPayload);
break;
case 8: /* pgoffset */
- sqlite3_result_int64(ctx, pCsr->iOffset);
+ if( !pCsr->isAgg ){
+ sqlite3_result_int64(ctx, pCsr->iOffset);
+ }
break;
case 9: /* pgsize */
sqlite3_result_int(ctx, pCsr->szPage);
break;
- default: { /* schema */
+ case 10: { /* schema */
sqlite3 *db = sqlite3_context_db_handle(ctx);
int iDb = pCsr->iDb;
sqlite3_result_text(ctx, db->aDb[iDb].zDbSName, -1, SQLITE_STATIC);
break;
}
+ default: { /* aggregate */
+ sqlite3_result_int(ctx, pCsr->isAgg);
+ break;
+ }
}
return SQLITE_OK;
}
diff --git a/src/delete.c b/src/delete.c
index e3a0abc2c0..0a83f1b640 100644
--- a/src/delete.c
+++ b/src/delete.c
@@ -70,11 +70,7 @@ static int tabIsReadOnly(Parse *pParse, Table *pTab){
return sqlite3WritableSchema(db)==0 && pParse->nested==0;
}
assert( pTab->tabFlags & TF_Shadow );
- return (db->flags & SQLITE_Defensive)!=0
-#ifndef SQLITE_OMIT_VIRTUALTABLE
- && db->pVtabCtx==0
-#endif
- && db->nVdbeExec==0;
+ return sqlite3ReadOnlyShadowTables(db);
}
/*
@@ -737,7 +733,8 @@ void sqlite3GenerateRowDelete(
testcase( mask!=0xffffffff && iCol==31 );
testcase( mask!=0xffffffff && iCol==32 );
if( mask==0xffffffff || (iCol<=31 && (mask & MASKBIT32(iCol))!=0) ){
- sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, iCol, iOld+iCol+1);
+ int kk = sqlite3TableColumnToStorage(pTab, iCol);
+ sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, iCol, iOld+kk+1);
}
}
@@ -917,6 +914,8 @@ int sqlite3GenerateIndexKey(
sqlite3ExprIfFalseDup(pParse, pIdx->pPartIdxWhere, *piPartIdxLabel,
SQLITE_JUMPIFNULL);
pParse->iSelfTab = 0;
+ pPrior = 0; /* Ticket a9efb42811fa41ee 2019-11-02;
+ ** pPartIdxWhere may have corrupted regPrior registers */
}else{
*piPartIdxLabel = 0;
}
diff --git a/src/expr.c b/src/expr.c
index 3b625a2de6..d82ef8b8c7 100644
--- a/src/expr.c
+++ b/src/expr.c
@@ -70,6 +70,9 @@ char sqlite3ExprAffinity(Expr *pExpr){
pExpr->pLeft->x.pSelect->pEList->a[pExpr->iColumn].pExpr
);
}
+ if( op==TK_VECTOR ){
+ return sqlite3ExprAffinity(pExpr->x.pList->a[0].pExpr);
+ }
return pExpr->affExpr;
}
@@ -172,6 +175,10 @@ CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr){
p = p->pLeft;
continue;
}
+ if( op==TK_VECTOR ){
+ p = p->x.pList->a[0].pExpr;
+ continue;
+ }
if( op==TK_COLLATE ){
pColl = sqlite3GetCollSeq(pParse, ENC(db), 0, p->u.zToken);
break;
@@ -183,12 +190,12 @@ CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr){
Expr *pNext = p->pRight;
/* The Expr.x union is never used at the same time as Expr.pRight */
assert( p->x.pList==0 || p->pRight==0 );
- /* p->flags holds EP_Collate and p->pLeft->flags does not. And
- ** p->x.pSelect cannot. So if p->x.pLeft exists, it must hold at
- ** least one EP_Collate. Thus the following two ALWAYS. */
- if( p->x.pList!=0 && ALWAYS(!ExprHasProperty(p, EP_xIsSelect)) ){
+ if( p->x.pList!=0
+ && !db->mallocFailed
+ && ALWAYS(!ExprHasProperty(p, EP_xIsSelect))
+ ){
int i;
- for(i=0; ALWAYS(ix.pList->nExpr); i++){
+ for(i=0; ix.pList->nExpr; i++){
if( ExprHasProperty(p->x.pList->a[i].pExpr, EP_Collate) ){
pNext = p->x.pList->a[i].pExpr;
break;
@@ -336,6 +343,22 @@ CollSeq *sqlite3BinaryCompareCollSeq(
return pColl;
}
+/* Expresssion p is a comparison operator. Return a collation sequence
+** appropriate for the comparison operator.
+**
+** This is normally just a wrapper around sqlite3BinaryCompareCollSeq().
+** However, if the OP_Commuted flag is set, then the order of the operands
+** is reversed in the sqlite3BinaryCompareCollSeq() call so that the
+** correct collating sequence is found.
+*/
+CollSeq *sqlite3ExprCompareCollSeq(Parse *pParse, Expr *p){
+ if( ExprHasProperty(p, EP_Commuted) ){
+ return sqlite3BinaryCompareCollSeq(pParse, p->pRight, p->pLeft);
+ }else{
+ return sqlite3BinaryCompareCollSeq(pParse, p->pLeft, p->pRight);
+ }
+}
+
/*
** Generate code for a comparison operator.
*/
@@ -346,13 +369,19 @@ static int codeCompare(
int opcode, /* The comparison opcode */
int in1, int in2, /* Register holding operands */
int dest, /* Jump here if true. */
- int jumpIfNull /* If true, jump if either operand is NULL */
+ int jumpIfNull, /* If true, jump if either operand is NULL */
+ int isCommuted /* The comparison has been commuted */
){
int p5;
int addr;
CollSeq *p4;
- p4 = sqlite3BinaryCompareCollSeq(pParse, pLeft, pRight);
+ if( pParse->nErr ) return 0;
+ if( isCommuted ){
+ p4 = sqlite3BinaryCompareCollSeq(pParse, pRight, pLeft);
+ }else{
+ p4 = sqlite3BinaryCompareCollSeq(pParse, pLeft, pRight);
+ }
p5 = binaryCompareP5(pLeft, pRight, jumpIfNull);
addr = sqlite3VdbeAddOp4(pParse->pVdbe, opcode, in2, dest, in1,
(void*)p4, P4_COLLSEQ);
@@ -563,7 +592,9 @@ static void codeVectorCompare(
int regRight = 0;
u8 opx = op;
int addrDone = sqlite3VdbeMakeLabel(pParse);
+ int isCommuted = ExprHasProperty(pExpr,EP_Commuted);
+ if( pParse->nErr ) return;
if( nLeft!=sqlite3ExprVectorSize(pRight) ){
sqlite3ErrorMsg(pParse, "row value misused");
return;
@@ -592,7 +623,7 @@ static void codeVectorCompare(
assert( i>=0 && ifuncFlags & (SQLITE_FUNC_DIRECT|SQLITE_FUNC_UNSAFE))!=0 );
+ if( ExprHasProperty(pExpr, EP_FromDDL) ){
+ if( (pDef->funcFlags & SQLITE_FUNC_DIRECT)!=0
+ || (pParse->db->flags & SQLITE_TrustedSchema)==0
+ ){
+ /* Functions prohibited in triggers and views if:
+ ** (1) tagged with SQLITE_DIRECTONLY
+ ** (2) not tagged with SQLITE_INNOCUOUS (which means it
+ ** is tagged with SQLITE_FUNC_UNSAFE) and
+ ** SQLITE_DBCONFIG_TRUSTED_SCHEMA is off (meaning
+ ** that the schema is possibly tainted).
+ */
+ sqlite3ErrorMsg(pParse, "unsafe use of %s()", pDef->zName);
+ }
+ }
+}
+
/*
** Assign a variable number to an expression that encodes a wildcard
** in the original SQL statement.
@@ -1407,12 +1474,11 @@ ExprList *sqlite3ExprListDup(sqlite3 *db, ExprList *p, int flags){
pNewExpr->pLeft = pPriorSelectCol;
}
}
- pItem->zName = sqlite3DbStrDup(db, pOldItem->zName);
- pItem->zSpan = sqlite3DbStrDup(db, pOldItem->zSpan);
+ pItem->zEName = sqlite3DbStrDup(db, pOldItem->zEName);
pItem->sortFlags = pOldItem->sortFlags;
+ pItem->eEName = pOldItem->eEName;
pItem->done = 0;
pItem->bNulls = pOldItem->bNulls;
- pItem->bSpanIsTab = pOldItem->bSpanIsTab;
pItem->bSorterRef = pOldItem->bSorterRef;
pItem->u = pOldItem->u;
}
@@ -1579,9 +1645,9 @@ ExprList *sqlite3ExprListAppend(
pList = pNew;
}
pItem = &pList->a[pList->nExpr++];
- assert( offsetof(struct ExprList_item,zName)==sizeof(pItem->pExpr) );
+ assert( offsetof(struct ExprList_item,zEName)==sizeof(pItem->pExpr) );
assert( offsetof(struct ExprList_item,pExpr)==0 );
- memset(&pItem->zName,0,sizeof(*pItem)-offsetof(struct ExprList_item,zName));
+ memset(&pItem->zEName,0,sizeof(*pItem)-offsetof(struct ExprList_item,zEName));
pItem->pExpr = pExpr;
return pList;
@@ -1638,7 +1704,7 @@ ExprList *sqlite3ExprListAppendVector(
pList = sqlite3ExprListAppend(pParse, pList, pSubExpr);
if( pList ){
assert( pList->nExpr==iFirst+i+1 );
- pList->a[pList->nExpr-1].zName = pColumns->a[i].zName;
+ pList->a[pList->nExpr-1].zEName = pColumns->a[i].zName;
pColumns->a[i].zName = 0;
}
}
@@ -1698,7 +1764,7 @@ void sqlite3ExprListSetSortOrder(ExprList *p, int iSortOrder, int eNulls){
}
/*
-** Set the ExprList.a[].zName element of the most recently added item
+** Set the ExprList.a[].zEName element of the most recently added item
** on the expression list.
**
** pList might be NULL following an OOM error. But pName should never be
@@ -1716,11 +1782,12 @@ void sqlite3ExprListSetName(
struct ExprList_item *pItem;
assert( pList->nExpr>0 );
pItem = &pList->a[pList->nExpr-1];
- assert( pItem->zName==0 );
- pItem->zName = sqlite3DbStrNDup(pParse->db, pName->z, pName->n);
- if( dequote ) sqlite3Dequote(pItem->zName);
+ assert( pItem->zEName==0 );
+ assert( pItem->eEName==ENAME_NAME );
+ pItem->zEName = sqlite3DbStrNDup(pParse->db, pName->z, pName->n);
+ if( dequote ) sqlite3Dequote(pItem->zEName);
if( IN_RENAME_OBJECT ){
- sqlite3RenameTokenMap(pParse, (void*)pItem->zName, pName);
+ sqlite3RenameTokenMap(pParse, (void*)pItem->zEName, pName);
}
}
}
@@ -1744,8 +1811,10 @@ void sqlite3ExprListSetSpan(
if( pList ){
struct ExprList_item *pItem = &pList->a[pList->nExpr-1];
assert( pList->nExpr>0 );
- sqlite3DbFree(db, pItem->zSpan);
- pItem->zSpan = sqlite3DbSpanDup(db, zStart, zEnd);
+ if( pItem->zEName==0 ){
+ pItem->zEName = sqlite3DbSpanDup(db, zStart, zEnd);
+ pItem->eEName = ENAME_SPAN;
+ }
}
}
@@ -1775,8 +1844,7 @@ static SQLITE_NOINLINE void exprListDeleteNN(sqlite3 *db, ExprList *pList){
assert( pList->nExpr>0 );
do{
sqlite3ExprDelete(db, pItem->pExpr);
- sqlite3DbFree(db, pItem->zName);
- sqlite3DbFree(db, pItem->zSpan);
+ sqlite3DbFree(db, pItem->zEName);
pItem++;
}while( --i>0 );
sqlite3DbFreeNN(db, pList);
@@ -1814,19 +1882,34 @@ int sqlite3SelectWalkFail(Walker *pWalker, Select *NotUsed){
return WRC_Abort;
}
+/*
+** Check the input string to see if it is "true" or "false" (in any case).
+**
+** If the string is.... Return
+** "true" EP_IsTrue
+** "false" EP_IsFalse
+** anything else 0
+*/
+u32 sqlite3IsTrueOrFalse(const char *zIn){
+ if( sqlite3StrICmp(zIn, "true")==0 ) return EP_IsTrue;
+ if( sqlite3StrICmp(zIn, "false")==0 ) return EP_IsFalse;
+ return 0;
+}
+
+
/*
** If the input expression is an ID with the name "true" or "false"
** then convert it into an TK_TRUEFALSE term. Return non-zero if
** the conversion happened, and zero if the expression is unaltered.
*/
int sqlite3ExprIdToTrueFalse(Expr *pExpr){
+ u32 v;
assert( pExpr->op==TK_ID || pExpr->op==TK_STRING );
if( !ExprHasProperty(pExpr, EP_Quoted)
- && (sqlite3StrICmp(pExpr->u.zToken, "true")==0
- || sqlite3StrICmp(pExpr->u.zToken, "false")==0)
+ && (v = sqlite3IsTrueOrFalse(pExpr->u.zToken))!=0
){
pExpr->op = TK_TRUEFALSE;
- ExprSetProperty(pExpr, pExpr->u.zToken[4]==0 ? EP_IsTrue : EP_IsFalse);
+ ExprSetProperty(pExpr, v);
return 1;
}
return 0;
@@ -1888,10 +1971,11 @@ Expr *sqlite3ExprSimplifiedAndOr(Expr *pExpr){
** In all cases, the callbacks set Walker.eCode=0 and abort if the expression
** is found to not be a constant.
**
-** The sqlite3ExprIsConstantOrFunction() is used for evaluating expressions
-** in a CREATE TABLE statement. The Walker.eCode value is 5 when parsing
-** an existing schema and 4 when processing a new statement. A bound
-** parameter raises an error for new statements, but is silently converted
+** 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 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
** contain a bound parameter because they were generated by older versions
** of SQLite to be parsed by newer versions of SQLite without raising a
@@ -1912,7 +1996,10 @@ static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){
** and either pWalker->eCode==4 or 5 or the function has the
** SQLITE_FUNC_CONST flag. */
case TK_FUNCTION:
- if( pWalker->eCode>=4 || ExprHasProperty(pExpr,EP_ConstFunc) ){
+ if( (pWalker->eCode>=4 || ExprHasProperty(pExpr,EP_ConstFunc))
+ && !ExprHasProperty(pExpr, EP_WinFunc)
+ ){
+ if( pWalker->eCode==5 ) ExprSetProperty(pExpr, EP_FromDDL);
return WRC_Continue;
}else{
pWalker->eCode = 0;
@@ -2076,9 +2163,21 @@ int sqlite3ExprIsConstantOrGroupBy(Parse *pParse, Expr *p, ExprList *pGroupBy){
}
/*
-** Walk an expression tree. Return non-zero if the expression is constant
-** or a function call with constant arguments. Return and 0 if there
-** are any variables.
+** Walk an expression tree for the DEFAULT field of a column definition
+** in a CREATE TABLE statement. Return non-zero if the expression is
+** acceptable for use as a DEFAULT. That is to say, return non-zero if
+** 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
+** 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
+** backwards compatibility.
+**
+** If isInit is true, set EP_FromDDL on every TK_FUNCTION node.
**
** For the purposes of this function, a double-quoted string (ex: "abc")
** is considered a variable but a single-quoted string (ex: 'abc') is
@@ -2175,7 +2274,9 @@ int sqlite3ExprCanBeNull(const Expr *p){
case TK_COLUMN:
return ExprHasProperty(p, EP_CanBeNull) ||
p->y.pTab==0 || /* Reference to column of index on expression */
- (p->iColumn>=0 && p->y.pTab->aCol[p->iColumn].notNull==0);
+ (p->iColumn>=0
+ && ALWAYS(p->y.pTab->aCol!=0) /* Defense against OOM problems */
+ && p->y.pTab->aCol[p->iColumn].notNull==0);
default:
return 1;
}
@@ -2652,8 +2753,10 @@ static char *exprINAffinity(Parse *pParse, Expr *pExpr){
** "sub-select returns N columns - expected M"
*/
void sqlite3SubselectError(Parse *pParse, int nActual, int nExpect){
- const char *zFmt = "sub-select returns %d columns - expected %d";
- sqlite3ErrorMsg(pParse, zFmt, nActual, nExpect);
+ if( pParse->nErr==0 ){
+ const char *zFmt = "sub-select returns %d columns - expected %d";
+ sqlite3ErrorMsg(pParse, zFmt, nActual, nExpect);
+ }
}
#endif
@@ -3154,19 +3257,25 @@ static void sqlite3ExprCodeIN(
if( regCkNull && sqlite3ExprCanBeNull(pList->a[ii].pExpr) ){
sqlite3VdbeAddOp3(v, OP_BitAnd, regCkNull, r2, regCkNull);
}
+ sqlite3ReleaseTempReg(pParse, regToFree);
if( iinExpr-1 || destIfNull!=destIfFalse ){
- sqlite3VdbeAddOp4(v, OP_Eq, rLhs, labelOk, r2,
+ int op = rLhs!=r2 ? OP_Eq : OP_NotNull;
+ sqlite3VdbeAddOp4(v, op, rLhs, labelOk, r2,
(void*)pColl, P4_COLLSEQ);
- VdbeCoverageIf(v, iinExpr-1);
- VdbeCoverageIf(v, ii==pList->nExpr-1);
+ VdbeCoverageIf(v, iinExpr-1 && op==OP_Eq);
+ VdbeCoverageIf(v, ii==pList->nExpr-1 && op==OP_Eq);
+ VdbeCoverageIf(v, iinExpr-1 && op==OP_NotNull);
+ VdbeCoverageIf(v, ii==pList->nExpr-1 && op==OP_NotNull);
sqlite3VdbeChangeP5(v, zAff[0]);
}else{
+ int op = rLhs!=r2 ? OP_Ne : OP_IsNull;
assert( destIfNull==destIfFalse );
- sqlite3VdbeAddOp4(v, OP_Ne, rLhs, destIfFalse, r2,
- (void*)pColl, P4_COLLSEQ); VdbeCoverage(v);
+ sqlite3VdbeAddOp4(v, op, rLhs, destIfFalse, r2,
+ (void*)pColl, P4_COLLSEQ);
+ VdbeCoverageIf(v, op==OP_Ne);
+ VdbeCoverageIf(v, op==OP_IsNull);
sqlite3VdbeChangeP5(v, zAff[0] | SQLITE_JUMPIFNULL);
}
- sqlite3ReleaseTempReg(pParse, regToFree);
}
if( regCkNull ){
sqlite3VdbeAddOp2(v, OP_IsNull, regCkNull, destIfNull); VdbeCoverage(v);
@@ -3186,6 +3295,7 @@ static void sqlite3ExprCodeIN(
}else{
destStep2 = destStep6 = sqlite3VdbeMakeLabel(pParse);
}
+ if( pParse->nErr ) goto sqlite3ExprCodeIN_finished;
for(i=0; ipLeft, i);
if( sqlite3ExprCanBeNull(p) ){
@@ -3367,16 +3477,45 @@ void sqlite3ExprCodeLoadIndexColumn(
}
}
+#ifndef SQLITE_OMIT_GENERATED_COLUMNS
+/*
+** Generate code that will compute the value of generated column pCol
+** and store the result in register regOut
+*/
+void sqlite3ExprCodeGeneratedColumn(
+ Parse *pParse,
+ Column *pCol,
+ int regOut
+){
+ int iAddr;
+ Vdbe *v = pParse->pVdbe;
+ assert( v!=0 );
+ assert( pParse->iSelfTab!=0 );
+ if( pParse->iSelfTab>0 ){
+ iAddr = sqlite3VdbeAddOp3(v, OP_IfNullRow, pParse->iSelfTab-1, 0, regOut);
+ }else{
+ iAddr = 0;
+ }
+ sqlite3ExprCode(pParse, pCol->pDflt, regOut);
+ if( pCol->affinity>=SQLITE_AFF_TEXT ){
+ sqlite3VdbeAddOp4(v, OP_Affinity, regOut, 1, 0, &pCol->affinity, 1);
+ }
+ if( iAddr ) sqlite3VdbeJumpHere(v, iAddr);
+}
+#endif /* SQLITE_OMIT_GENERATED_COLUMNS */
+
/*
** Generate code to extract the value of the iCol-th column of a table.
*/
void sqlite3ExprCodeGetColumnOfTable(
- Vdbe *v, /* The VDBE under construction */
+ Vdbe *v, /* Parsing context */
Table *pTab, /* The table containing the value */
int iTabCur, /* The table cursor. Or the PK cursor for WITHOUT ROWID */
int iCol, /* Index of the column to extract */
int regOut /* Extract the value into this register */
){
+ Column *pCol;
+ assert( v!=0 );
if( pTab==0 ){
sqlite3VdbeAddOp3(v, OP_Column, iTabCur, iCol, regOut);
return;
@@ -3384,14 +3523,36 @@ void sqlite3ExprCodeGetColumnOfTable(
if( iCol<0 || iCol==pTab->iPKey ){
sqlite3VdbeAddOp2(v, OP_Rowid, iTabCur, regOut);
}else{
- int op = IsVirtual(pTab) ? OP_VColumn : OP_Column;
- int x = iCol;
- if( !HasRowid(pTab) && !IsVirtual(pTab) ){
- x = sqlite3ColumnOfIndex(sqlite3PrimaryKeyIndex(pTab), iCol);
+ int op;
+ int x;
+ if( IsVirtual(pTab) ){
+ op = OP_VColumn;
+ x = iCol;
+#ifndef SQLITE_OMIT_GENERATED_COLUMNS
+ }else if( (pCol = &pTab->aCol[iCol])->colFlags & COLFLAG_VIRTUAL ){
+ Parse *pParse = sqlite3VdbeParser(v);
+ if( pCol->colFlags & COLFLAG_BUSY ){
+ sqlite3ErrorMsg(pParse, "generated column loop on \"%s\"", pCol->zName);
+ }else{
+ int savedSelfTab = pParse->iSelfTab;
+ pCol->colFlags |= COLFLAG_BUSY;
+ pParse->iSelfTab = iTabCur+1;
+ sqlite3ExprCodeGeneratedColumn(pParse, pCol, regOut);
+ pParse->iSelfTab = savedSelfTab;
+ pCol->colFlags &= ~COLFLAG_BUSY;
+ }
+ return;
+#endif
+ }else if( !HasRowid(pTab) ){
+ testcase( iCol!=sqlite3TableColumnToStorage(pTab, iCol) );
+ x = sqlite3TableColumnToIndex(sqlite3PrimaryKeyIndex(pTab), iCol);
+ op = OP_Column;
+ }else{
+ x = sqlite3TableColumnToStorage(pTab,iCol);
+ testcase( x!=iCol );
+ op = OP_Column;
}
sqlite3VdbeAddOp3(v, op, iTabCur, x, regOut);
- }
- if( iCol>=0 ){
sqlite3ColumnDefault(v, pTab, iCol, regOut);
}
}
@@ -3411,11 +3572,11 @@ int sqlite3ExprCodeGetColumn(
int iReg, /* Store results here */
u8 p5 /* P5 value for OP_Column + FLAGS */
){
- Vdbe *v = pParse->pVdbe;
- assert( v!=0 );
- sqlite3ExprCodeGetColumnOfTable(v, pTab, iTable, iColumn, iReg);
+ assert( pParse->pVdbe!=0 );
+ sqlite3ExprCodeGetColumnOfTable(pParse->pVdbe, pTab, iTable, iColumn, iReg);
if( p5 ){
- sqlite3VdbeChangeP5(v, p5);
+ VdbeOp *pOp = sqlite3VdbeGetOp(pParse->pVdbe,-1);
+ if( pOp->opcode==OP_Column ) pOp->p5 = p5;
}
return iReg;
}
@@ -3425,7 +3586,6 @@ int sqlite3ExprCodeGetColumn(
** over to iTo..iTo+nReg-1.
*/
void sqlite3ExprCodeMove(Parse *pParse, int iFrom, int iTo, int nReg){
- assert( iFrom>=iTo+nReg || iFrom+nReg<=iTo );
sqlite3VdbeAddOp3(pParse->pVdbe, OP_Move, iFrom, iTo, nReg);
}
@@ -3477,6 +3637,109 @@ static int exprCodeVector(Parse *pParse, Expr *p, int *piFreeable){
return iResult;
}
+/*
+** Generate code to implement special SQL functions that are implemented
+** in-line rather than by using the usual callbacks.
+*/
+static int exprCodeInlineFunction(
+ Parse *pParse, /* Parsing context */
+ ExprList *pFarg, /* List of function arguments */
+ int iFuncId, /* Function ID. One of the INTFUNC_... values */
+ int target /* Store function result in this register */
+){
+ int nFarg;
+ Vdbe *v = pParse->pVdbe;
+ assert( v!=0 );
+ assert( pFarg!=0 );
+ nFarg = pFarg->nExpr;
+ assert( nFarg>0 ); /* All in-line functions have at least one argument */
+ switch( iFuncId ){
+ case INLINEFUNC_coalesce: {
+ /* Attempt a direct implementation of the built-in COALESCE() and
+ ** IFNULL() functions. This avoids unnecessary evaluation of
+ ** arguments past the first non-NULL argument.
+ */
+ int endCoalesce = sqlite3VdbeMakeLabel(pParse);
+ int i;
+ assert( nFarg>=2 );
+ sqlite3ExprCode(pParse, pFarg->a[0].pExpr, target);
+ for(i=1; ia[i].pExpr, target);
+ }
+ if( sqlite3VdbeGetOp(v, -1)->opcode==OP_Copy ){
+ sqlite3VdbeChangeP5(v, 1); /* Tag trailing OP_Copy as not mergable */
+ }
+ sqlite3VdbeResolveLabel(v, endCoalesce);
+ break;
+ }
+
+ default: {
+ /* The UNLIKELY() function is a no-op. The result is the value
+ ** of the first argument.
+ */
+ assert( nFarg==1 || nFarg==2 );
+ target = sqlite3ExprCodeTarget(pParse, pFarg->a[0].pExpr, target);
+ break;
+ }
+
+ /***********************************************************************
+ ** Test-only SQL functions that are only usable if enabled
+ ** via SQLITE_TESTCTRL_INTERNAL_FUNCTIONS
+ */
+ case INLINEFUNC_expr_compare: {
+ /* Compare two expressions using sqlite3ExprCompare() */
+ assert( nFarg==2 );
+ sqlite3VdbeAddOp2(v, OP_Integer,
+ sqlite3ExprCompare(0,pFarg->a[0].pExpr, pFarg->a[1].pExpr,-1),
+ target);
+ break;
+ }
+
+ case INLINEFUNC_expr_implies_expr: {
+ /* Compare two expressions using sqlite3ExprImpliesExpr() */
+ assert( nFarg==2 );
+ sqlite3VdbeAddOp2(v, OP_Integer,
+ sqlite3ExprImpliesExpr(pParse,pFarg->a[0].pExpr, pFarg->a[1].pExpr,-1),
+ target);
+ break;
+ }
+
+ case INLINEFUNC_implies_nonnull_row: {
+ /* REsult of sqlite3ExprImpliesNonNullRow() */
+ Expr *pA1;
+ assert( nFarg==2 );
+ pA1 = pFarg->a[1].pExpr;
+ if( pA1->op==TK_COLUMN ){
+ sqlite3VdbeAddOp2(v, OP_Integer,
+ sqlite3ExprImpliesNonNullRow(pFarg->a[0].pExpr,pA1->iTable),
+ target);
+ }else{
+ sqlite3VdbeAddOp2(v, OP_Null, 0, target);
+ }
+ break;
+ }
+
+#ifdef SQLITE_DEBUG
+ case INLINEFUNC_affinity: {
+ /* The AFFINITY() function evaluates to a string that describes
+ ** the type affinity of the argument. This is used for testing of
+ ** the SQLite type logic.
+ */
+ const char *azAff[] = { "blob", "text", "numeric", "integer", "real" };
+ char aff;
+ assert( nFarg==1 );
+ aff = sqlite3ExprAffinity(pFarg->a[0].pExpr);
+ sqlite3VdbeLoadString(v, target,
+ (aff<=SQLITE_AFF_NONE) ? "none" : azAff[aff-SQLITE_AFF_BLOB]);
+ break;
+ }
+#endif
+ }
+ return target;
+}
+
/*
** Generate code into the current Vdbe to evaluate the given
@@ -3527,6 +3790,7 @@ expr_code_doover:
}
case TK_COLUMN: {
int iTab = pExpr->iTable;
+ int iReg;
if( ExprHasProperty(pExpr, EP_FixedCol) ){
/* This COLUMN expression is really a constant due to WHERE clause
** constraints, and that constant is coded by the pExpr->pLeft
@@ -3534,8 +3798,13 @@ expr_code_doover:
** datatype by applying the Affinity of the table column to the
** constant.
*/
- int iReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft,target);
- int aff = sqlite3TableColumnAffinity(pExpr->y.pTab, pExpr->iColumn);
+ int aff;
+ iReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft,target);
+ if( pExpr->y.pTab ){
+ aff = sqlite3TableColumnAffinity(pExpr->y.pTab, pExpr->iColumn);
+ }else{
+ aff = pExpr->affExpr;
+ }
if( aff>SQLITE_AFF_BLOB ){
static const char zAff[] = "B\000C\000D\000E";
assert( SQLITE_AFF_BLOB=='A' );
@@ -3551,19 +3820,46 @@ expr_code_doover:
}
if( iTab<0 ){
if( pParse->iSelfTab<0 ){
- /* Generating CHECK constraints or inserting into partial index */
- assert( pExpr->y.pTab!=0 );
- assert( pExpr->iColumn>=XN_ROWID );
- assert( pExpr->iColumny.pTab->nCol );
- if( pExpr->iColumn>=0
- && pExpr->y.pTab->aCol[pExpr->iColumn].affinity==SQLITE_AFF_REAL
- ){
- sqlite3VdbeAddOp2(v, OP_SCopy, pExpr->iColumn - pParse->iSelfTab,
- target);
+ /* Other columns in the same row for CHECK constraints or
+ ** generated columns or for inserting into partial index.
+ ** The row is unpacked into registers beginning at
+ ** 0-(pParse->iSelfTab). The rowid (if any) is in a register
+ ** immediately prior to the first column.
+ */
+ Column *pCol;
+ Table *pTab = pExpr->y.pTab;
+ int iSrc;
+ int iCol = pExpr->iColumn;
+ assert( pTab!=0 );
+ assert( iCol>=XN_ROWID );
+ assert( iColnCol );
+ if( iCol<0 ){
+ return -1-pParse->iSelfTab;
+ }
+ pCol = pTab->aCol + iCol;
+ testcase( iCol!=sqlite3TableColumnToStorage(pTab,iCol) );
+ iSrc = sqlite3TableColumnToStorage(pTab, iCol) - pParse->iSelfTab;
+#ifndef SQLITE_OMIT_GENERATED_COLUMNS
+ if( pCol->colFlags & COLFLAG_GENERATED ){
+ if( pCol->colFlags & COLFLAG_BUSY ){
+ sqlite3ErrorMsg(pParse, "generated column loop on \"%s\"",
+ pCol->zName);
+ return 0;
+ }
+ pCol->colFlags |= COLFLAG_BUSY;
+ if( pCol->colFlags & COLFLAG_NOTAVAIL ){
+ sqlite3ExprCodeGeneratedColumn(pParse, pCol, iSrc);
+ }
+ pCol->colFlags &= ~(COLFLAG_BUSY|COLFLAG_NOTAVAIL);
+ return iSrc;
+ }else
+#endif /* SQLITE_OMIT_GENERATED_COLUMNS */
+ if( pCol->affinity==SQLITE_AFF_REAL ){
+ sqlite3VdbeAddOp2(v, OP_SCopy, iSrc, target);
sqlite3VdbeAddOp1(v, OP_RealAffinity, target);
return target;
}else{
- return pExpr->iColumn - pParse->iSelfTab;
+ return iSrc;
}
}else{
/* Coding an expression that is part of an index where column names
@@ -3571,9 +3867,13 @@ expr_code_doover:
iTab = pParse->iSelfTab - 1;
}
}
- return sqlite3ExprCodeGetColumn(pParse, pExpr->y.pTab,
+ iReg = sqlite3ExprCodeGetColumn(pParse, pExpr->y.pTab,
pExpr->iColumn, iTab, target,
pExpr->op2);
+ if( pExpr->y.pTab==0 && pExpr->affExpr==SQLITE_AFF_REAL ){
+ sqlite3VdbeAddOp1(v, OP_RealAffinity, iReg);
+ }
+ return iReg;
}
case TK_INTEGER: {
codeInteger(pParse, pExpr, 0, target);
@@ -3595,7 +3895,12 @@ expr_code_doover:
sqlite3VdbeLoadString(v, target, pExpr->u.zToken);
return target;
}
- case TK_NULL: {
+ default: {
+ /* Make NULL the default case so that if a bug causes an illegal
+ ** Expr node to be passed into this function, it will be handled
+ ** sanely and not crash. But keep the assert() to bring the problem
+ ** to the attention of the developers. */
+ assert( op==TK_NULL );
sqlite3VdbeAddOp2(v, OP_Null, 0, target);
return target;
}
@@ -3622,7 +3927,7 @@ expr_code_doover:
sqlite3VdbeAddOp2(v, OP_Variable, pExpr->iColumn, target);
if( pExpr->u.zToken[1]!=0 ){
const char *z = sqlite3VListNumToName(pParse->pVList, pExpr->iColumn);
- assert( pExpr->u.zToken[0]=='?' || strcmp(pExpr->u.zToken, z)==0 );
+ assert( pExpr->u.zToken[0]=='?' || (z && !strcmp(pExpr->u.zToken, z)) );
pParse->pVList[0] = 0; /* Indicate VList may no longer be enlarged */
sqlite3VdbeAppendP4(v, (char*)z, P4_STATIC);
}
@@ -3662,7 +3967,8 @@ expr_code_doover:
r1 = sqlite3ExprCodeTemp(pParse, pLeft, ®Free1);
r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, ®Free2);
codeCompare(pParse, pLeft, pExpr->pRight, op,
- r1, r2, inReg, SQLITE_STOREP2 | p5);
+ r1, r2, inReg, SQLITE_STOREP2 | p5,
+ ExprHasProperty(pExpr,EP_Commuted));
assert(TK_LT==OP_Lt); testcase(op==OP_Lt); VdbeCoverageIf(v,op==OP_Lt);
assert(TK_LE==OP_Le); testcase(op==OP_Le); VdbeCoverageIf(v,op==OP_Le);
assert(TK_GT==OP_Gt); testcase(op==OP_Gt); VdbeCoverageIf(v,op==OP_Gt);
@@ -3814,48 +4120,15 @@ expr_code_doover:
sqlite3ErrorMsg(pParse, "unknown function: %s()", zId);
break;
}
-
- /* Attempt a direct implementation of the built-in COALESCE() and
- ** IFNULL() functions. This avoids unnecessary evaluation of
- ** arguments past the first non-NULL argument.
- */
- if( pDef->funcFlags & SQLITE_FUNC_COALESCE ){
- int endCoalesce = sqlite3VdbeMakeLabel(pParse);
- assert( nFarg>=2 );
- sqlite3ExprCode(pParse, pFarg->a[0].pExpr, target);
- for(i=1; ia[i].pExpr, target);
- }
- sqlite3VdbeResolveLabel(v, endCoalesce);
- break;
+ if( pDef->funcFlags & SQLITE_FUNC_INLINE ){
+ assert( (pDef->funcFlags & SQLITE_FUNC_UNSAFE)==0 );
+ assert( (pDef->funcFlags & SQLITE_FUNC_DIRECT)==0 );
+ return exprCodeInlineFunction(pParse, pFarg,
+ SQLITE_PTR_TO_INT(pDef->pUserData), target);
+ }else if( pDef->funcFlags & (SQLITE_FUNC_DIRECT|SQLITE_FUNC_UNSAFE) ){
+ sqlite3ExprFunctionUsable(pParse, pExpr, pDef);
}
- /* The UNLIKELY() function is a no-op. The result is the value
- ** of the first argument.
- */
- if( pDef->funcFlags & SQLITE_FUNC_UNLIKELY ){
- assert( nFarg>=1 );
- return sqlite3ExprCodeTarget(pParse, pFarg->a[0].pExpr, target);
- }
-
-#ifdef SQLITE_DEBUG
- /* The AFFINITY() function evaluates to a string that describes
- ** the type affinity of the argument. This is used for testing of
- ** the SQLite type logic.
- */
- if( pDef->funcFlags & SQLITE_FUNC_AFFINITY ){
- const char *azAff[] = { "blob", "text", "numeric", "integer", "real" };
- char aff;
- assert( nFarg==1 );
- aff = sqlite3ExprAffinity(pFarg->a[0].pExpr);
- sqlite3VdbeLoadString(v, target,
- (aff<=SQLITE_AFF_NONE) ? "none" : azAff[aff-SQLITE_AFF_BLOB]);
- return target;
- }
-#endif
-
for(i=0; ia[i].pExpr) ){
testcase( i==31 );
@@ -3931,12 +4204,15 @@ expr_code_doover:
}else
#endif
{
- sqlite3VdbeAddOp4(v, pParse->iSelfTab ? OP_PureFunc0 : OP_Function0,
- constMask, r1, target, (char*)pDef, P4_FUNCDEF);
- sqlite3VdbeChangeP5(v, (u8)nFarg);
+ sqlite3VdbeAddFunctionCall(pParse, constMask, r1, target, nFarg,
+ pDef, pExpr->op2);
}
- if( nFarg && constMask==0 ){
- sqlite3ReleaseTempRange(pParse, r1, nFarg);
+ if( nFarg ){
+ if( constMask==0 ){
+ sqlite3ReleaseTempRange(pParse, r1, nFarg);
+ }else{
+ sqlite3VdbeReleaseRegisters(pParse, r1, nFarg, constMask, 1);
+ }
}
return target;
}
@@ -4030,17 +4306,19 @@ expr_code_doover:
** p1==2 -> old.b p1==5 -> new.b
*/
Table *pTab = pExpr->y.pTab;
- int p1 = pExpr->iTable * (pTab->nCol+1) + 1 + pExpr->iColumn;
+ int iCol = pExpr->iColumn;
+ int p1 = pExpr->iTable * (pTab->nCol+1) + 1
+ + sqlite3TableColumnToStorage(pTab, iCol);
assert( pExpr->iTable==0 || pExpr->iTable==1 );
- assert( pExpr->iColumn>=-1 && pExpr->iColumnnCol );
- assert( pTab->iPKey<0 || pExpr->iColumn!=pTab->iPKey );
+ assert( iCol>=-1 && iColnCol );
+ assert( pTab->iPKey<0 || iCol!=pTab->iPKey );
assert( p1>=0 && p1<(pTab->nCol*2+2) );
sqlite3VdbeAddOp2(v, OP_Param, p1, target);
VdbeComment((v, "r[%d]=%s.%s", target,
(pExpr->iTable ? "new" : "old"),
- (pExpr->iColumn<0 ? "rowid" : pExpr->y.pTab->aCol[pExpr->iColumn].zName)
+ (pExpr->iColumn<0 ? "rowid" : pExpr->y.pTab->aCol[iCol].zName)
));
#ifndef SQLITE_OMIT_FLOATING_POINT
@@ -4049,9 +4327,7 @@ expr_code_doover:
**
** EVIDENCE-OF: R-60985-57662 SQLite will convert the value back to
** floating point when extracting it from the record. */
- if( pExpr->iColumn>=0
- && pTab->aCol[pExpr->iColumn].affinity==SQLITE_AFF_REAL
- ){
+ if( iCol>=0 && pTab->aCol[iCol].affinity==SQLITE_AFF_REAL ){
sqlite3VdbeAddOp1(v, OP_RealAffinity, target);
}
#endif
@@ -4106,7 +4382,7 @@ expr_code_doover:
** or if there is no matching Ei, the ELSE term Y, or if there is
** no ELSE term, NULL.
*/
- default: assert( op==TK_CASE ); {
+ case TK_CASE: {
int endLabel; /* GOTO label for end of CASE stmt */
int nextCase; /* GOTO label for next WHEN clause */
int nExpr; /* 2x number of WHEN terms */
@@ -4284,14 +4560,16 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){
int inReg;
assert( target>0 && target<=pParse->nMem );
- if( pExpr && pExpr->op==TK_REGISTER ){
- sqlite3VdbeAddOp2(pParse->pVdbe, OP_Copy, pExpr->iTable, target);
- }else{
- inReg = sqlite3ExprCodeTarget(pParse, pExpr, target);
- assert( pParse->pVdbe!=0 || pParse->db->mallocFailed );
- if( inReg!=target && pParse->pVdbe ){
- sqlite3VdbeAddOp2(pParse->pVdbe, OP_SCopy, inReg, target);
+ inReg = sqlite3ExprCodeTarget(pParse, pExpr, target);
+ assert( pParse->pVdbe!=0 || pParse->db->mallocFailed );
+ if( inReg!=target && pParse->pVdbe ){
+ u8 op;
+ if( ExprHasProperty(pExpr,EP_Subquery) ){
+ op = OP_Copy;
+ }else{
+ op = OP_SCopy;
}
+ sqlite3VdbeAddOp2(pParse->pVdbe, op, inReg, target);
}
}
@@ -4321,30 +4599,6 @@ void sqlite3ExprCodeFactorable(Parse *pParse, Expr *pExpr, int target){
}
}
-/*
-** Generate code that evaluates the given expression and puts the result
-** in register target.
-**
-** Also make a copy of the expression results into another "cache" register
-** and modify the expression so that the next time it is evaluated,
-** the result is a copy of the cache register.
-**
-** This routine is used for expressions that are used multiple
-** times. They are evaluated once and the results of the expression
-** are reused.
-*/
-void sqlite3ExprCodeAndCache(Parse *pParse, Expr *pExpr, int target){
- Vdbe *v = pParse->pVdbe;
- int iMem;
-
- assert( target>0 );
- assert( pExpr->op!=TK_REGISTER );
- sqlite3ExprCode(pParse, pExpr, target);
- iMem = ++pParse->nMem;
- sqlite3VdbeAddOp2(v, OP_Copy, target, iMem);
- exprToRegister(pExpr, iMem);
-}
-
/*
** Generate code that pushes the value of every element of the given
** expression list into a sequence of registers beginning at target.
@@ -4408,6 +4662,7 @@ int sqlite3ExprCodeExprList(
&& (pOp=sqlite3VdbeGetOp(v, -1))->opcode==OP_Copy
&& pOp->p1+pOp->p3+1==inReg
&& pOp->p2+pOp->p3+1==target+i
+ && pOp->p5==0 /* The do-not-merge flag must be clear */
){
pOp->p3++;
}else{
@@ -4582,7 +4837,7 @@ void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1);
r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, ®Free2);
codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op,
- r1, r2, dest, jumpIfNull);
+ r1, r2, dest, jumpIfNull, ExprHasProperty(pExpr,EP_Commuted));
assert(TK_LT==OP_Lt); testcase(op==OP_Lt); VdbeCoverageIf(v,op==OP_Lt);
assert(TK_LE==OP_Le); testcase(op==OP_Le); VdbeCoverageIf(v,op==OP_Le);
assert(TK_GT==OP_Gt); testcase(op==OP_Gt); VdbeCoverageIf(v,op==OP_Gt);
@@ -4757,7 +5012,7 @@ void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1);
r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, ®Free2);
codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op,
- r1, r2, dest, jumpIfNull);
+ r1, r2, dest, jumpIfNull,ExprHasProperty(pExpr,EP_Commuted));
assert(TK_LT==OP_Lt); testcase(op==OP_Lt); VdbeCoverageIf(v,op==OP_Lt);
assert(TK_LE==OP_Le); testcase(op==OP_Le); VdbeCoverageIf(v,op==OP_Le);
assert(TK_GT==OP_Gt); testcase(op==OP_Gt); VdbeCoverageIf(v,op==OP_Gt);
@@ -4943,7 +5198,8 @@ int sqlite3ExprCompare(Parse *pParse, Expr *pA, Expr *pB, int iTab){
return 2;
}
}
- if( (pA->flags & EP_Distinct)!=(pB->flags & EP_Distinct) ) return 2;
+ if( (pA->flags & (EP_Distinct|EP_Commuted))
+ != (pB->flags & (EP_Distinct|EP_Commuted)) ) return 2;
if( (combinedFlags & EP_TokenOnly)==0 ){
if( combinedFlags & EP_xIsSelect ) return 2;
if( (combinedFlags & EP_FixedCol)==0
@@ -4955,18 +5211,33 @@ int sqlite3ExprCompare(Parse *pParse, Expr *pA, Expr *pB, int iTab){
&& (combinedFlags & EP_Reduced)==0
){
if( pA->iColumn!=pB->iColumn ) return 2;
- if( pA->op2!=pB->op2 ) return 2;
- if( pA->op!=TK_IN
- && pA->iTable!=pB->iTable
- && (pA->iTable!=iTab || NEVER(pB->iTable>=0)) ) return 2;
+ if( pA->op2!=pB->op2 ){
+ if( pA->op==TK_TRUTH ) return 2;
+ if( pA->op==TK_FUNCTION && iTab<0 ){
+ /* Ex: CREATE TABLE t1(a CHECK( aop!=TK_IN && pA->iTable!=pB->iTable && pA->iTable!=iTab ){
+ return 2;
+ }
}
}
return 0;
}
/*
-** Compare two ExprList objects. Return 0 if they are identical and
-** non-zero if they differ in any way.
+** Compare two ExprList objects. Return 0 if they are identical, 1
+** if they are certainly different, or 2 if it is not possible to
+** determine if they are identical or not.
**
** If any subelement of pB has Expr.iTable==(-1) then it is allowed
** to compare equal to an equivalent element in pA with Expr.iTable==iTab.
@@ -4985,10 +5256,11 @@ int sqlite3ExprListCompare(ExprList *pA, ExprList *pB, int iTab){
if( pA==0 || pB==0 ) return 1;
if( pA->nExpr!=pB->nExpr ) return 1;
for(i=0; inExpr; i++){
+ int res;
Expr *pExprA = pA->a[i].pExpr;
Expr *pExprB = pB->a[i].pExpr;
if( pA->a[i].sortFlags!=pB->a[i].sortFlags ) return 1;
- if( sqlite3ExprCompare(0, pExprA, pExprB, iTab) ) return 1;
+ if( (res = sqlite3ExprCompare(0, pExprA, pExprB, iTab)) ) return res;
}
return 0;
}
@@ -5125,7 +5397,7 @@ int sqlite3ExprImpliesExpr(Parse *pParse, Expr *pE1, Expr *pE2, int iTab){
}
/*
-** This is the Expr node callback for sqlite3ExprImpliesNotNullRow().
+** This is the Expr node callback for sqlite3ExprImpliesNonNullRow().
** If the expression node requires that the table at pWalker->iCur
** have one or more non-NULL column, then set pWalker->eCode to 1 and abort.
**
@@ -5143,17 +5415,21 @@ static int impliesNotNullRow(Walker *pWalker, Expr *pExpr){
case TK_NOTNULL:
case TK_IS:
case TK_OR:
+ case TK_VECTOR:
case TK_CASE:
case TK_IN:
case TK_FUNCTION:
+ case TK_TRUTH:
testcase( pExpr->op==TK_ISNOT );
testcase( pExpr->op==TK_ISNULL );
testcase( pExpr->op==TK_NOTNULL );
testcase( pExpr->op==TK_IS );
testcase( pExpr->op==TK_OR );
+ testcase( pExpr->op==TK_VECTOR );
testcase( pExpr->op==TK_CASE );
testcase( pExpr->op==TK_IN );
testcase( pExpr->op==TK_FUNCTION );
+ testcase( pExpr->op==TK_TRUTH );
return WRC_Prune;
case TK_COLUMN:
if( pWalker->u.iCur==pExpr->iTable ){
@@ -5163,15 +5439,20 @@ static int impliesNotNullRow(Walker *pWalker, Expr *pExpr){
return WRC_Prune;
case TK_AND:
- if( sqlite3ExprImpliesNonNullRow(pExpr->pLeft, pWalker->u.iCur)
- && sqlite3ExprImpliesNonNullRow(pExpr->pRight, pWalker->u.iCur)
- ){
- pWalker->eCode = 1;
+ if( pWalker->eCode==0 ){
+ sqlite3WalkExpr(pWalker, pExpr->pLeft);
+ if( pWalker->eCode ){
+ pWalker->eCode = 0;
+ sqlite3WalkExpr(pWalker, pExpr->pRight);
+ }
}
return WRC_Prune;
case TK_BETWEEN:
- sqlite3WalkExpr(pWalker, pExpr->pLeft);
+ if( sqlite3WalkExpr(pWalker, pExpr->pLeft)==WRC_Abort ){
+ assert( pWalker->eCode );
+ return WRC_Abort;
+ }
return WRC_Prune;
/* Virtual tables are allowed to use constraints like x=NULL. So
@@ -5225,14 +5506,13 @@ static int impliesNotNullRow(Walker *pWalker, Expr *pExpr){
int sqlite3ExprImpliesNonNullRow(Expr *p, int iTab){
Walker w;
p = sqlite3ExprSkipCollateAndLikely(p);
- while( p ){
- if( p->op==TK_NOTNULL ){
- p = p->pLeft;
- }else if( p->op==TK_AND ){
+ if( p==0 ) return 0;
+ if( p->op==TK_NOTNULL ){
+ p = p->pLeft;
+ }else{
+ while( p->op==TK_AND ){
if( sqlite3ExprImpliesNonNullRow(p->pLeft, iTab) ) return 1;
p = p->pRight;
- }else{
- break;
}
}
w.xExprCallback = impliesNotNullRow;
@@ -5264,7 +5544,7 @@ struct IdxCover {
static int exprIdxCover(Walker *pWalker, Expr *pExpr){
if( pExpr->op==TK_COLUMN
&& pExpr->iTable==pWalker->u.pIdxCover->iCur
- && sqlite3ColumnOfIndex(pWalker->u.pIdxCover->pIdx, pExpr->iColumn)<0
+ && sqlite3TableColumnToIndex(pWalker->u.pIdxCover->pIdx, pExpr->iColumn)<0
){
pWalker->eCode = 1;
return WRC_Abort;
@@ -5315,12 +5595,13 @@ struct SrcCount {
** Count the number of references to columns.
*/
static int exprSrcCount(Walker *pWalker, Expr *pExpr){
- /* The NEVER() on the second term is because sqlite3FunctionUsesThisSrc()
- ** is always called before sqlite3ExprAnalyzeAggregates() and so the
- ** TK_COLUMNs have not yet been converted into TK_AGG_COLUMN. If
- ** sqlite3FunctionUsesThisSrc() is used differently in the future, the
- ** NEVER() will need to be removed. */
- if( pExpr->op==TK_COLUMN || NEVER(pExpr->op==TK_AGG_COLUMN) ){
+ /* There was once a NEVER() on the second term on the grounds that
+ ** sqlite3FunctionUsesThisSrc() was always called before
+ ** sqlite3ExprAnalyzeAggregates() and so the TK_COLUMNs have not yet
+ ** been converted into TK_AGG_COLUMN. But this is no longer true due
+ ** to window functions - sqlite3WindowRewrite() may now indirectly call
+ ** FunctionUsesThisSrc() when creating a new sub-select. */
+ if( pExpr->op==TK_COLUMN || pExpr->op==TK_AGG_COLUMN ){
int i;
struct SrcCount *p = pWalker->u.pSrcCount;
SrcList *pSrc = p->pSrc;
@@ -5358,6 +5639,11 @@ int sqlite3FunctionUsesThisSrc(Expr *pExpr, SrcList *pSrcList){
cnt.nThis = 0;
cnt.nOther = 0;
sqlite3WalkExprList(&w, pExpr->x.pList);
+#ifndef SQLITE_OMIT_WINDOWFUNC
+ if( ExprHasProperty(pExpr, EP_WinFunc) ){
+ sqlite3WalkExpr(&w, pExpr->y.pWin->pFilter);
+ }
+#endif
return cnt.nThis>0 || cnt.nOther==0;
}
@@ -5586,8 +5872,11 @@ int sqlite3GetTempReg(Parse *pParse){
** purpose.
*/
void sqlite3ReleaseTempReg(Parse *pParse, int iReg){
- if( iReg && pParse->nTempRegaTempReg) ){
- pParse->aTempReg[pParse->nTempReg++] = iReg;
+ if( iReg ){
+ sqlite3VdbeReleaseRegisters(pParse, iReg, 1, 0, 0);
+ if( pParse->nTempRegaTempReg) ){
+ pParse->aTempReg[pParse->nTempReg++] = iReg;
+ }
}
}
@@ -5613,6 +5902,7 @@ void sqlite3ReleaseTempRange(Parse *pParse, int iReg, int nReg){
sqlite3ReleaseTempReg(pParse, iReg);
return;
}
+ sqlite3VdbeReleaseRegisters(pParse, iReg, nReg, 0, 0);
if( nReg>pParse->nRangeReg ){
pParse->nRangeReg = nReg;
pParse->iRangeReg = iReg;
diff --git a/src/fkey.c b/src/fkey.c
index fc75023669..9698d343ce 100644
--- a/src/fkey.c
+++ b/src/fkey.c
@@ -349,7 +349,7 @@ static void fkLookupParent(
VdbeCoverage(v);
}
for(i=0; inCol; i++){
- int iReg = aiCol[i] + regData + 1;
+ int iReg = sqlite3TableColumnToStorage(pFKey->pFrom,aiCol[i]) + regData + 1;
sqlite3VdbeAddOp2(v, OP_IsNull, iReg, iOk); VdbeCoverage(v);
}
@@ -365,7 +365,8 @@ static void fkLookupParent(
** is no matching parent key. Before using MustBeInt, make a copy of
** the value. Otherwise, the value inserted into the child key column
** will have INTEGER affinity applied to it, which may not be correct. */
- sqlite3VdbeAddOp2(v, OP_SCopy, aiCol[0]+1+regData, regTemp);
+ sqlite3VdbeAddOp2(v, OP_SCopy,
+ sqlite3TableColumnToStorage(pFKey->pFrom,aiCol[0])+1+regData, regTemp);
iMustBeInt = sqlite3VdbeAddOp2(v, OP_MustBeInt, regTemp, 0);
VdbeCoverage(v);
@@ -392,7 +393,9 @@ static void fkLookupParent(
sqlite3VdbeAddOp3(v, OP_OpenRead, iCur, pIdx->tnum, iDb);
sqlite3VdbeSetP4KeyInfo(pParse, pIdx);
for(i=0; ipFrom, aiCol[i])+1+regData,
+ regTemp+i);
}
/* If the parent table is the same as the child table, and we are about
@@ -408,8 +411,11 @@ static void fkLookupParent(
if( pTab==pFKey->pFrom && nIncr==1 ){
int iJump = sqlite3VdbeCurrentAddr(v) + nCol + 1;
for(i=0; iaiColumn[i]+1+regData;
+ int iChild = sqlite3TableColumnToStorage(pFKey->pFrom,aiCol[i])
+ +1+regData;
+ int iParent = 1+regData;
+ iParent += sqlite3TableColumnToStorage(pIdx->pTable,
+ pIdx->aiColumn[i]);
assert( pIdx->aiColumn[i]>=0 );
assert( aiCol[i]!=pTab->iPKey );
if( pIdx->aiColumn[i]==pTab->iPKey ){
@@ -477,7 +483,7 @@ static Expr *exprTableRegister(
if( pExpr ){
if( iCol>=0 && iCol!=pTab->iPKey ){
pCol = &pTab->aCol[iCol];
- pExpr->iTable = regBase + iCol + 1;
+ pExpr->iTable = regBase + sqlite3TableColumnToStorage(pTab,iCol) + 1;
pExpr->affExpr = pCol->affinity;
zColl = pCol->zColl;
if( zColl==0 ) zColl = db->pDfltColl->zName;
@@ -926,7 +932,9 @@ void sqlite3FkCheck(
Vdbe *v = sqlite3GetVdbe(pParse);
int iJump = sqlite3VdbeCurrentAddr(v) + pFKey->nCol + 1;
for(i=0; inCol; i++){
- int iReg = pFKey->aCol[i].iFrom + regOld + 1;
+ int iFromCol, iReg;
+ iFromCol = pFKey->aCol[i].iFrom;
+ iReg = sqlite3TableColumnToStorage(pFKey->pFrom,iFromCol) + regOld+1;
sqlite3VdbeAddOp2(v, OP_IsNull, iReg, iJump); VdbeCoverage(v);
}
sqlite3VdbeAddOp2(v, OP_FkCounter, pFKey->isDeferred, -1);
@@ -1261,7 +1269,15 @@ static Trigger *fkActionTrigger(
sqlite3ExprAlloc(db, TK_ID, &tNew, 0),
sqlite3ExprAlloc(db, TK_ID, &tToCol, 0));
}else if( action==OE_SetDflt ){
- Expr *pDflt = pFKey->pFrom->aCol[iFromCol].pDflt;
+ Column *pCol = pFKey->pFrom->aCol + iFromCol;
+ Expr *pDflt;
+ if( pCol->colFlags & COLFLAG_GENERATED ){
+ testcase( pCol->colFlags & COLFLAG_VIRTUAL );
+ testcase( pCol->colFlags & COLFLAG_STORED );
+ pDflt = 0;
+ }else{
+ pDflt = pCol->pDflt;
+ }
if( pDflt ){
pNew = sqlite3ExprDup(db, pDflt, 0);
}else{
@@ -1299,7 +1315,7 @@ static Trigger *fkActionTrigger(
}
/* Disable lookaside memory allocation */
- db->lookaside.bDisable++;
+ DisableLookaside;
pTrigger = (Trigger *)sqlite3DbMallocZero(db,
sizeof(Trigger) + /* struct Trigger */
@@ -1321,7 +1337,7 @@ static Trigger *fkActionTrigger(
}
/* Re-enable the lookaside buffer, if it was disabled earlier. */
- db->lookaside.bDisable--;
+ EnableLookaside;
sqlite3ExprDelete(db, pWhere);
sqlite3ExprDelete(db, pWhen);
diff --git a/src/func.c b/src/func.c
index 3201b6df86..be4975afcc 100644
--- a/src/func.c
+++ b/src/func.c
@@ -1907,12 +1907,20 @@ void sqlite3RegisterBuiltinFunctions(void){
** For peak efficiency, put the most frequently used function last.
*/
static FuncDef aBuiltinFunc[] = {
+/***** Functions only available with SQLITE_TESTCTRL_INTERNAL_FUNCTIONS *****/
+ TEST_FUNC(implies_nonnull_row, 2, INLINEFUNC_implies_nonnull_row, 0),
+ TEST_FUNC(expr_compare, 2, INLINEFUNC_expr_compare, 0),
+ TEST_FUNC(expr_implies_expr, 2, INLINEFUNC_expr_implies_expr, 0),
+#ifdef SQLITE_DEBUG
+ TEST_FUNC(affinity, 1, INLINEFUNC_affinity, 0),
+#endif
+/***** Regular functions *****/
#ifdef SQLITE_SOUNDEX
FUNCTION(soundex, 1, 0, 0, soundexFunc ),
#endif
#ifndef SQLITE_OMIT_LOAD_EXTENSION
- VFUNCTION(load_extension, 1, 0, 0, loadExt ),
- VFUNCTION(load_extension, 2, 0, 0, loadExt ),
+ SFUNCTION(load_extension, 1, 0, 0, loadExt ),
+ SFUNCTION(load_extension, 2, 0, 0, loadExt ),
#endif
#if SQLITE_USER_AUTHENTICATION
FUNCTION(sqlite_crypt, 2, 0, 0, sqlite3CryptFunc ),
@@ -1921,12 +1929,9 @@ void sqlite3RegisterBuiltinFunctions(void){
DFUNCTION(sqlite_compileoption_used,1, 0, 0, compileoptionusedFunc ),
DFUNCTION(sqlite_compileoption_get, 1, 0, 0, compileoptiongetFunc ),
#endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */
- FUNCTION2(unlikely, 1, 0, 0, noopFunc, SQLITE_FUNC_UNLIKELY),
- FUNCTION2(likelihood, 2, 0, 0, noopFunc, SQLITE_FUNC_UNLIKELY),
- FUNCTION2(likely, 1, 0, 0, noopFunc, SQLITE_FUNC_UNLIKELY),
-#ifdef SQLITE_DEBUG
- FUNCTION2(affinity, 1, 0, 0, noopFunc, SQLITE_FUNC_AFFINITY),
-#endif
+ INLINE_FUNC(unlikely, 1, INLINEFUNC_unlikely, SQLITE_FUNC_UNLIKELY),
+ INLINE_FUNC(likelihood, 2, INLINEFUNC_unlikely, SQLITE_FUNC_UNLIKELY),
+ INLINE_FUNC(likely, 1, INLINEFUNC_unlikely, SQLITE_FUNC_UNLIKELY),
#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
FUNCTION2(sqlite_offset, 1, 0, 0, noopFunc, SQLITE_FUNC_OFFSET|
SQLITE_FUNC_TYPEOF),
@@ -1959,7 +1964,7 @@ void sqlite3RegisterBuiltinFunctions(void){
FUNCTION(upper, 1, 0, 0, upperFunc ),
FUNCTION(lower, 1, 0, 0, lowerFunc ),
FUNCTION(hex, 1, 0, 0, hexFunc ),
- FUNCTION2(ifnull, 2, 0, 0, noopFunc, SQLITE_FUNC_COALESCE),
+ INLINE_FUNC(ifnull, 2, INLINEFUNC_coalesce, SQLITE_FUNC_COALESCE),
VFUNCTION(random, 0, 0, 0, randomFunc ),
VFUNCTION(randomblob, 1, 0, 0, randomBlob ),
FUNCTION(nullif, 2, 0, 1, nullifFunc ),
@@ -1999,7 +2004,7 @@ void sqlite3RegisterBuiltinFunctions(void){
#endif
FUNCTION(coalesce, 1, 0, 0, 0 ),
FUNCTION(coalesce, 0, 0, 0, 0 ),
- FUNCTION2(coalesce, -1, 0, 0, noopFunc, SQLITE_FUNC_COALESCE),
+ INLINE_FUNC(coalesce, -1, INLINEFUNC_coalesce, SQLITE_FUNC_COALESCE),
};
#ifndef SQLITE_OMIT_ALTERTABLE
sqlite3AlterFunctions();
diff --git a/src/global.c b/src/global.c
index 4689e94bb4..a2c51f41fb 100644
--- a/src/global.c
+++ b/src/global.c
@@ -87,7 +87,6 @@ const unsigned char sqlite3UpperToLower[] = {
** non-ASCII UTF character. Hence the test for whether or not a character is
** part of an identifier is 0x46.
*/
-#ifdef SQLITE_ASCII
const unsigned char sqlite3CtypeMap[256] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 00..07 ........ */
0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, /* 08..0f ........ */
@@ -125,7 +124,6 @@ const unsigned char sqlite3CtypeMap[256] = {
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* f0..f7 ........ */
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40 /* f8..ff ........ */
};
-#endif
/* EVIDENCE-OF: R-02982-34736 In order to maintain full backwards
** compatibility for legacy applications, the URI filename capability is
@@ -190,9 +188,18 @@ const unsigned char sqlite3CtypeMap[256] = {
** changed as start-time using sqlite3_config(SQLITE_CONFIG_LOOKASIDE)
** or at run-time for an individual database connection using
** sqlite3_db_config(db, SQLITE_DBCONFIG_LOOKASIDE);
+**
+** With the two-size-lookaside enhancement, less lookaside is required.
+** The default configuration of 1200,40 actually provides 30 1200-byte slots
+** and 93 128-byte slots, which is more lookaside than is available
+** using the older 1200,100 configuration without two-size-lookaside.
*/
#ifndef SQLITE_DEFAULT_LOOKASIDE
-# define SQLITE_DEFAULT_LOOKASIDE 1200,100
+# ifdef SQLITE_OMIT_TWOSIZE_LOOKASIDE
+# define SQLITE_DEFAULT_LOOKASIDE 1200,100 /* 120KB of memory */
+# else
+# define SQLITE_DEFAULT_LOOKASIDE 1200,40 /* 48KB of memory */
+# endif
#endif
@@ -258,7 +265,6 @@ SQLITE_WSD struct Sqlite3Config sqlite3Config = {
0, /* xTestCallback */
#endif
0, /* bLocaltimeFault */
- 0, /* bInternalFunctions */
0x7ffffffe, /* iOnceResetThreshold */
SQLITE_DEFAULT_SORTERREF_SIZE, /* szSorterRef */
0, /* iPrngSeed */
diff --git a/src/hwtime.h b/src/hwtime.h
index 5b209db8af..037c55a977 100644
--- a/src/hwtime.h
+++ b/src/hwtime.h
@@ -11,7 +11,7 @@
******************************************************************************
**
** This file contains inline asm code for retrieving "high-performance"
-** counters for x86 class CPUs.
+** counters for x86 and x86_64 class CPUs.
*/
#ifndef SQLITE_HWTIME_H
#define SQLITE_HWTIME_H
@@ -22,8 +22,9 @@
** processor and returns that value. This can be used for high-res
** profiling.
*/
-#if (defined(__GNUC__) || defined(_MSC_VER)) && \
- (defined(i386) || defined(__i386__) || defined(_M_IX86))
+#if !defined(__STRICT_ANSI__) && \
+ (defined(__GNUC__) || defined(_MSC_VER)) && \
+ (defined(i386) || defined(__i386__) || defined(_M_IX86))
#if defined(__GNUC__)
@@ -44,7 +45,7 @@
#endif
-#elif (defined(__GNUC__) && defined(__x86_64__))
+#elif !defined(__STRICT_ANSI__) && (defined(__GNUC__) && defined(__x86_64__))
__inline__ sqlite_uint64 sqlite3Hwtime(void){
unsigned long val;
@@ -52,7 +53,7 @@
return val;
}
-#elif (defined(__GNUC__) && defined(__ppc__))
+#elif !defined(__STRICT_ANSI__) && (defined(__GNUC__) && defined(__ppc__))
__inline__ sqlite_uint64 sqlite3Hwtime(void){
unsigned long long retval;
@@ -69,14 +70,13 @@
#else
- #error Need implementation of sqlite3Hwtime() for your platform.
-
/*
- ** To compile without implementing sqlite3Hwtime() for your platform,
- ** you can remove the above #error and use the following
- ** stub function. You will lose timing support for many
- ** of the debugging and testing utilities, but it should at
- ** least compile and run.
+ ** asm() is needed for hardware timing support. Without asm(),
+ ** disable the sqlite3Hwtime() routine.
+ **
+ ** sqlite3Hwtime() is only used for some obscure debugging
+ ** and analysis configurations, not in any deliverable, so this
+ ** should not be a great loss.
*/
sqlite_uint64 sqlite3Hwtime(void){ return ((sqlite_uint64)0); }
diff --git a/src/insert.c b/src/insert.c
index d9078b89db..e3035c8d0a 100644
--- a/src/insert.c
+++ b/src/insert.c
@@ -37,7 +37,7 @@ void sqlite3OpenTable(
sqlite3TableLock(pParse, iDb, pTab->tnum,
(opcode==OP_OpenWrite)?1:0, pTab->zName);
if( HasRowid(pTab) ){
- sqlite3VdbeAddOp4Int(v, opcode, iCur, pTab->tnum, iDb, pTab->nCol);
+ sqlite3VdbeAddOp4Int(v, opcode, iCur, pTab->tnum, iDb, pTab->nNVCol);
VdbeComment((v, "%s", pTab->zName));
}else{
Index *pPk = sqlite3PrimaryKeyIndex(pTab);
@@ -129,7 +129,7 @@ const char *sqlite3IndexAffinityStr(sqlite3 *db, Index *pIdx){
** 'E' REAL
*/
void sqlite3TableAffinity(Vdbe *v, Table *pTab, int iReg){
- int i;
+ int i, j;
char *zColAff = pTab->zColAff;
if( zColAff==0 ){
sqlite3 *db = sqlite3VdbeDb(v);
@@ -139,13 +139,15 @@ void sqlite3TableAffinity(Vdbe *v, Table *pTab, int iReg){
return;
}
- for(i=0; inCol; i++){
+ for(i=j=0; inCol; i++){
assert( pTab->aCol[i].affinity!=0 );
- zColAff[i] = pTab->aCol[i].affinity;
+ if( (pTab->aCol[i].colFlags & COLFLAG_VIRTUAL)==0 ){
+ zColAff[j++] = pTab->aCol[i].affinity;
+ }
}
do{
- zColAff[i--] = 0;
- }while( i>=0 && zColAff[i]<=SQLITE_AFF_BLOB );
+ zColAff[j--] = 0;
+ }while( j>=0 && zColAff[j]<=SQLITE_AFF_BLOB );
pTab->zColAff = zColAff;
}
assert( zColAff!=0 );
@@ -199,6 +201,119 @@ static int readsTable(Parse *p, int iDb, Table *pTab){
return 0;
}
+/* This walker callback will compute the union of colFlags flags for all
+** referenced columns in a CHECK constraint or generated column expression.
+*/
+static int exprColumnFlagUnion(Walker *pWalker, Expr *pExpr){
+ if( pExpr->op==TK_COLUMN && pExpr->iColumn>=0 ){
+ assert( pExpr->iColumn < pWalker->u.pTab->nCol );
+ pWalker->eCode |= pWalker->u.pTab->aCol[pExpr->iColumn].colFlags;
+ }
+ return WRC_Continue;
+}
+
+#ifndef SQLITE_OMIT_GENERATED_COLUMNS
+/*
+** All regular columns for table pTab have been puts into registers
+** starting with iRegStore. The registers that correspond to STORED
+** or VIRTUAL columns have not yet been initialized. This routine goes
+** back and computes the values for those columns based on the previously
+** computed normal columns.
+*/
+void sqlite3ComputeGeneratedColumns(
+ Parse *pParse, /* Parsing context */
+ int iRegStore, /* Register holding the first column */
+ Table *pTab /* The table */
+){
+ int i;
+ Walker w;
+ Column *pRedo;
+ int eProgress;
+ VdbeOp *pOp;
+
+ assert( pTab->tabFlags & TF_HasGenerated );
+ testcase( pTab->tabFlags & TF_HasVirtual );
+ testcase( pTab->tabFlags & TF_HasStored );
+
+ /* Before computing generated columns, first go through and make sure
+ ** that appropriate affinity has been applied to the regular columns
+ */
+ sqlite3TableAffinity(pParse->pVdbe, pTab, iRegStore);
+ if( (pTab->tabFlags & TF_HasStored)!=0
+ && (pOp = sqlite3VdbeGetOp(pParse->pVdbe,-1))->opcode==OP_Affinity
+ ){
+ /* Change the OP_Affinity argument to '@' (NONE) for all stored
+ ** columns. '@' is the no-op affinity and those columns have not
+ ** yet been computed. */
+ int ii, jj;
+ char *zP4 = pOp->p4.z;
+ assert( zP4!=0 );
+ assert( pOp->p4type==P4_DYNAMIC );
+ for(ii=jj=0; zP4[jj]; ii++){
+ if( pTab->aCol[ii].colFlags & COLFLAG_VIRTUAL ){
+ continue;
+ }
+ if( pTab->aCol[ii].colFlags & COLFLAG_STORED ){
+ zP4[jj] = SQLITE_AFF_NONE;
+ }
+ jj++;
+ }
+ }
+
+ /* Because there can be multiple generated columns that refer to one another,
+ ** this is a two-pass algorithm. On the first pass, mark all generated
+ ** columns as "not available".
+ */
+ for(i=0; inCol; i++){
+ if( pTab->aCol[i].colFlags & COLFLAG_GENERATED ){
+ testcase( pTab->aCol[i].colFlags & COLFLAG_VIRTUAL );
+ testcase( pTab->aCol[i].colFlags & COLFLAG_STORED );
+ pTab->aCol[i].colFlags |= COLFLAG_NOTAVAIL;
+ }
+ }
+
+ w.u.pTab = pTab;
+ w.xExprCallback = exprColumnFlagUnion;
+ w.xSelectCallback = 0;
+ w.xSelectCallback2 = 0;
+
+ /* On the second pass, compute the value of each NOT-AVAILABLE column.
+ ** Companion code in the TK_COLUMN case of sqlite3ExprCodeTarget() will
+ ** compute dependencies and mark remove the COLSPAN_NOTAVAIL mark, as
+ ** they are needed.
+ */
+ pParse->iSelfTab = -iRegStore;
+ do{
+ eProgress = 0;
+ pRedo = 0;
+ for(i=0; inCol; i++){
+ Column *pCol = pTab->aCol + i;
+ if( (pCol->colFlags & COLFLAG_NOTAVAIL)!=0 ){
+ int x;
+ pCol->colFlags |= COLFLAG_BUSY;
+ w.eCode = 0;
+ sqlite3WalkExpr(&w, pCol->pDflt);
+ pCol->colFlags &= ~COLFLAG_BUSY;
+ if( w.eCode & COLFLAG_NOTAVAIL ){
+ pRedo = pCol;
+ continue;
+ }
+ eProgress = 1;
+ assert( pCol->colFlags & COLFLAG_GENERATED );
+ x = sqlite3TableColumnToStorage(pTab, i) + iRegStore;
+ sqlite3ExprCodeGeneratedColumn(pParse, pCol, x);
+ pCol->colFlags &= ~COLFLAG_NOTAVAIL;
+ }
+ }
+ }while( pRedo && eProgress );
+ if( pRedo ){
+ sqlite3ErrorMsg(pParse, "generated column loop on \"%s\"", pRedo->zName);
+ }
+ pParse->iSelfTab = 0;
+}
+#endif /* SQLITE_OMIT_GENERATED_COLUMNS */
+
+
#ifndef SQLITE_OMIT_AUTOINCREMENT
/*
** Locate or create an AutoincInfo structure associated with table pTab
@@ -506,7 +621,7 @@ void sqlite3Insert(
Parse *pParse, /* Parser context */
SrcList *pTabList, /* Name of table into which we are inserting */
Select *pSelect, /* A SELECT statement to use as the data source */
- IdList *pColumn, /* Column names corresponding to IDLIST. */
+ IdList *pColumn, /* Column names corresponding to IDLIST, or NULL. */
int onError, /* How to handle constraint errors */
Upsert *pUpsert /* ON CONFLICT clauses for upsert, or NULL */
){
@@ -531,6 +646,7 @@ void sqlite3Insert(
u8 withoutRowid; /* 0 for normal table. 1 for WITHOUT ROWID table */
u8 bIdListInOrder; /* True if IDLIST is in table order */
ExprList *pList = 0; /* List of VALUES() to be inserted */
+ int iRegStore; /* Register in which to store next column */
/* Register allocations */
int regFromSelect = 0;/* Base register for data coming from SELECT */
@@ -638,8 +754,8 @@ void sqlite3Insert(
*/
regAutoinc = autoIncBegin(pParse, iDb, pTab);
- /* Allocate registers for holding the rowid of the new row,
- ** the content of the new row, and the assembled row record.
+ /* Allocate a block registers to hold the rowid and the values
+ ** for all columns of the new row.
*/
regRowid = regIns = pParse->nMem+1;
pParse->nMem += pTab->nCol + 1;
@@ -658,9 +774,17 @@ void sqlite3Insert(
** the index into IDLIST of the primary key column. ipkColumn is
** the index of the primary key as it appears in IDLIST, not as
** is appears in the original table. (The index of the INTEGER
- ** PRIMARY KEY in the original table is pTab->iPKey.)
+ ** PRIMARY KEY in the original table is pTab->iPKey.) After this
+ ** loop, if ipkColumn==(-1), that means that integer primary key
+ ** is unspecified, and hence the table is either WITHOUT ROWID or
+ ** it will automatically generated an integer primary key.
+ **
+ ** bIdListInOrder is true if the columns in IDLIST are in storage
+ ** order. This enables an optimization that avoids shuffling the
+ ** columns into storage order. False negatives are harmless,
+ ** but false positives will cause database corruption.
*/
- bIdListInOrder = (pTab->tabFlags & TF_OOOHidden)==0;
+ bIdListInOrder = (pTab->tabFlags & (TF_OOOHidden|TF_HasStored))==0;
if( pColumn ){
for(i=0; inId; i++){
pColumn->a[i].idx = -1;
@@ -673,6 +797,14 @@ void sqlite3Insert(
if( j==pTab->iPKey ){
ipkColumn = i; assert( !withoutRowid );
}
+#ifndef SQLITE_OMIT_GENERATED_COLUMNS
+ if( pTab->aCol[j].colFlags & (COLFLAG_STORED|COLFLAG_VIRTUAL) ){
+ sqlite3ErrorMsg(pParse,
+ "cannot INSERT into generated column \"%s\"",
+ pTab->aCol[j].zName);
+ goto insert_cleanup;
+ }
+#endif
break;
}
}
@@ -782,13 +914,26 @@ void sqlite3Insert(
*/
if( pColumn==0 && nColumn>0 ){
ipkColumn = pTab->iPKey;
+#ifndef SQLITE_OMIT_GENERATED_COLUMNS
+ if( ipkColumn>=0 && (pTab->tabFlags & TF_HasGenerated)!=0 ){
+ testcase( pTab->tabFlags & TF_HasVirtual );
+ testcase( pTab->tabFlags & TF_HasStored );
+ for(i=ipkColumn-1; i>=0; i--){
+ if( pTab->aCol[i].colFlags & COLFLAG_GENERATED ){
+ testcase( pTab->aCol[i].colFlags & COLFLAG_VIRTUAL );
+ testcase( pTab->aCol[i].colFlags & COLFLAG_STORED );
+ ipkColumn--;
+ }
+ }
+ }
+#endif
}
/* Make sure the number of columns in the source data matches the number
** of columns to be inserted into the table.
*/
for(i=0; inCol; i++){
- nHidden += (IsHiddenColumn(&pTab->aCol[i]) ? 1 : 0);
+ if( pTab->aCol[i].colFlags & COLFLAG_NOINSERT ) nHidden++;
}
if( pColumn==0 && nColumn && nColumn!=(pTab->nCol-nHidden) ){
sqlite3ErrorMsg(pParse,
@@ -834,6 +979,10 @@ void sqlite3Insert(
pTab->zName);
goto insert_cleanup;
}
+ if( pTab->pSelect ){
+ sqlite3ErrorMsg(pParse, "cannot UPSERT a view");
+ goto insert_cleanup;
+ }
if( sqlite3HasExplicitNulls(pParse, pUpsert->pUpsertTarget) ){
goto insert_cleanup;
}
@@ -871,10 +1020,91 @@ void sqlite3Insert(
** goto C
** D: ...
*/
+ sqlite3VdbeReleaseRegisters(pParse, regData, pTab->nCol, 0, 0);
addrInsTop = addrCont = sqlite3VdbeAddOp1(v, OP_Yield, dest.iSDParm);
VdbeCoverage(v);
+ if( ipkColumn>=0 ){
+ /* tag-20191021-001: If the INTEGER PRIMARY KEY is being generated by the
+ ** SELECT, go ahead and copy the value into the rowid slot now, so that
+ ** the value does not get overwritten by a NULL at tag-20191021-002. */
+ sqlite3VdbeAddOp2(v, OP_Copy, regFromSelect+ipkColumn, regRowid);
+ }
}
+ /* Compute data for ordinary columns of the new entry. Values
+ ** are written in storage order into registers starting with regData.
+ ** Only ordinary columns are computed in this loop. The rowid
+ ** (if there is one) is computed later and generated columns are
+ ** computed after the rowid since they might depend on the value
+ ** of the rowid.
+ */
+ nHidden = 0;
+ iRegStore = regData; assert( regData==regRowid+1 );
+ for(i=0; inCol; i++, iRegStore++){
+ int k;
+ u32 colFlags;
+ assert( i>=nHidden );
+ if( i==pTab->iPKey ){
+ /* tag-20191021-002: References to the INTEGER PRIMARY KEY are filled
+ ** using the rowid. So put a NULL in the IPK slot of the record to avoid
+ ** using excess space. The file format definition requires this extra
+ ** NULL - we cannot optimize further by skipping the column completely */
+ sqlite3VdbeAddOp1(v, OP_SoftNull, iRegStore);
+ continue;
+ }
+ if( ((colFlags = pTab->aCol[i].colFlags) & COLFLAG_NOINSERT)!=0 ){
+ nHidden++;
+ if( (colFlags & COLFLAG_VIRTUAL)!=0 ){
+ /* Virtual columns do not participate in OP_MakeRecord. So back up
+ ** iRegStore by one slot to compensate for the iRegStore++ in the
+ ** outer for() loop */
+ iRegStore--;
+ continue;
+ }else if( (colFlags & COLFLAG_STORED)!=0 ){
+ /* Stored columns are computed later. But if there are BEFORE
+ ** triggers, the slots used for stored columns will be OP_Copy-ed
+ ** to a second block of registers, so the register needs to be
+ ** initialized to NULL to avoid an uninitialized register read */
+ if( tmask & TRIGGER_BEFORE ){
+ sqlite3VdbeAddOp1(v, OP_SoftNull, iRegStore);
+ }
+ continue;
+ }else if( pColumn==0 ){
+ /* Hidden columns that are not explicitly named in the INSERT
+ ** get there default value */
+ sqlite3ExprCodeFactorable(pParse, pTab->aCol[i].pDflt, iRegStore);
+ continue;
+ }
+ }
+ if( pColumn ){
+ for(j=0; jnId && pColumn->a[j].idx!=i; j++){}
+ if( j>=pColumn->nId ){
+ /* A column not named in the insert column list gets its
+ ** default value */
+ sqlite3ExprCodeFactorable(pParse, pTab->aCol[i].pDflt, iRegStore);
+ continue;
+ }
+ k = j;
+ }else if( nColumn==0 ){
+ /* This is INSERT INTO ... DEFAULT VALUES. Load the default value. */
+ sqlite3ExprCodeFactorable(pParse, pTab->aCol[i].pDflt, iRegStore);
+ continue;
+ }else{
+ k = i - nHidden;
+ }
+
+ if( useTempTable ){
+ sqlite3VdbeAddOp3(v, OP_Column, srcTab, k, iRegStore);
+ }else if( pSelect ){
+ if( regFromSelect!=regData ){
+ sqlite3VdbeAddOp2(v, OP_SCopy, regFromSelect+k, iRegStore);
+ }
+ }else{
+ sqlite3ExprCode(pParse, pList->a[k].pExpr, iRegStore);
+ }
+ }
+
+
/* Run the BEFORE and INSTEAD OF triggers, if there are any
*/
endOfLoop = sqlite3VdbeMakeLabel(pParse);
@@ -909,25 +1139,21 @@ void sqlite3Insert(
*/
assert( !IsVirtual(pTab) );
- /* Create the new column data
- */
- for(i=j=0; inCol; i++){
- if( pColumn ){
- for(j=0; jnId; j++){
- if( pColumn->a[j].idx==i ) break;
- }
- }
- if( (!useTempTable && !pList) || (pColumn && j>=pColumn->nId)
- || (pColumn==0 && IsOrdinaryHiddenColumn(&pTab->aCol[i])) ){
- sqlite3ExprCode(pParse, pTab->aCol[i].pDflt, regCols+i+1);
- }else if( useTempTable ){
- sqlite3VdbeAddOp3(v, OP_Column, srcTab, j, regCols+i+1);
- }else{
- assert( pSelect==0 ); /* Otherwise useTempTable is true */
- sqlite3ExprCodeAndCache(pParse, pList->a[j].pExpr, regCols+i+1);
- }
- if( pColumn==0 && !IsOrdinaryHiddenColumn(&pTab->aCol[i]) ) j++;
+ /* Copy the new data already generated. */
+ assert( pTab->nNVCol>0 );
+ sqlite3VdbeAddOp3(v, OP_Copy, regRowid+1, regCols+1, pTab->nNVCol-1);
+
+#ifndef SQLITE_OMIT_GENERATED_COLUMNS
+ /* Compute the new value for generated columns after all other
+ ** columns have already been computed. This must be done after
+ ** computing the ROWID in case one of the generated columns
+ ** refers to the ROWID. */
+ if( pTab->tabFlags & TF_HasGenerated ){
+ testcase( pTab->tabFlags & TF_HasVirtual );
+ testcase( pTab->tabFlags & TF_HasStored );
+ sqlite3ComputeGeneratedColumns(pParse, regCols+1, pTab);
}
+#endif
/* If this is an INSERT on a view with an INSTEAD OF INSERT trigger,
** do not attempt any conversions before assembling the record.
@@ -945,19 +1171,17 @@ void sqlite3Insert(
sqlite3ReleaseTempRange(pParse, regCols, pTab->nCol+1);
}
- /* Compute the content of the next row to insert into a range of
- ** registers beginning at regIns.
- */
if( !isView ){
if( IsVirtual(pTab) ){
/* The row that the VUpdate opcode will delete: none */
sqlite3VdbeAddOp2(v, OP_Null, 0, regIns);
}
if( ipkColumn>=0 ){
+ /* Compute the new rowid */
if( useTempTable ){
sqlite3VdbeAddOp3(v, OP_Column, srcTab, ipkColumn, regRowid);
}else if( pSelect ){
- sqlite3VdbeAddOp2(v, OP_Copy, regFromSelect+ipkColumn, regRowid);
+ /* Rowid already initialized at tag-20191021-001 */
}else{
Expr *pIpk = pList->a[ipkColumn].pExpr;
if( pIpk->op==TK_NULL && !IsVirtual(pTab) ){
@@ -990,45 +1214,15 @@ void sqlite3Insert(
}
autoIncStep(pParse, regAutoinc, regRowid);
- /* Compute data for all columns of the new entry, beginning
- ** with the first column.
- */
- nHidden = 0;
- for(i=0; inCol; i++){
- int iRegStore = regRowid+1+i;
- if( i==pTab->iPKey ){
- /* The value of the INTEGER PRIMARY KEY column is always a NULL.
- ** Whenever this column is read, the rowid will be substituted
- ** in its place. Hence, fill this column with a NULL to avoid
- ** taking up data space with information that will never be used.
- ** As there may be shallow copies of this value, make it a soft-NULL */
- sqlite3VdbeAddOp1(v, OP_SoftNull, iRegStore);
- continue;
- }
- if( pColumn==0 ){
- if( IsHiddenColumn(&pTab->aCol[i]) ){
- j = -1;
- nHidden++;
- }else{
- j = i - nHidden;
- }
- }else{
- for(j=0; jnId; j++){
- if( pColumn->a[j].idx==i ) break;
- }
- }
- if( j<0 || nColumn==0 || (pColumn && j>=pColumn->nId) ){
- sqlite3ExprCodeFactorable(pParse, pTab->aCol[i].pDflt, iRegStore);
- }else if( useTempTable ){
- sqlite3VdbeAddOp3(v, OP_Column, srcTab, j, iRegStore);
- }else if( pSelect ){
- if( regFromSelect!=regData ){
- sqlite3VdbeAddOp2(v, OP_SCopy, regFromSelect+j, iRegStore);
- }
- }else{
- sqlite3ExprCode(pParse, pList->a[j].pExpr, iRegStore);
- }
+#ifndef SQLITE_OMIT_GENERATED_COLUMNS
+ /* Compute the new value for generated columns after all other
+ ** columns have already been computed. This must be done after
+ ** computing the ROWID in case one of the generated columns
+ ** is derived from the INTEGER PRIMARY KEY. */
+ if( pTab->tabFlags & TF_HasGenerated ){
+ sqlite3ComputeGeneratedColumns(pParse, regRowid+1, pTab);
}
+#endif
/* Generate code to check constraints and generate index keys and
** do the insertion.
@@ -1058,9 +1252,7 @@ void sqlite3Insert(
** cursor that is disturbed. And these instructions both clear the
** VdbeCursor.seekResult variable, disabling the OPFLAG_USESEEKRESULT
** functionality. */
- bUseSeek = (isReplace==0 || (pTrigger==0 &&
- ((db->flags & SQLITE_ForeignKeys)==0 || sqlite3FkReferences(pTab)==0)
- ));
+ bUseSeek = (isReplace==0 || !sqlite3VdbeHasSubProgram(v));
sqlite3CompleteInsertion(pParse, pTab, iDataCur, iIdxCur,
regIns, aRegIdx, 0, appendFlag, bUseSeek
);
@@ -1089,6 +1281,15 @@ void sqlite3Insert(
sqlite3VdbeAddOp1(v, OP_Close, srcTab);
}else if( pSelect ){
sqlite3VdbeGoto(v, addrCont);
+#ifdef SQLITE_DEBUG
+ /* If we are jumping back to an OP_Yield that is preceded by an
+ ** OP_ReleaseReg, set the p5 flag on the OP_Goto so that the
+ ** OP_ReleaseReg will be included in the loop. */
+ if( sqlite3VdbeGetOp(v, addrCont-1)->opcode==OP_ReleaseReg ){
+ assert( sqlite3VdbeGetOp(v, addrCont)->opcode==OP_Yield );
+ sqlite3VdbeChangeP5(v, 1);
+ }
+#endif
sqlite3VdbeJumpHere(v, addrInsTop);
}
@@ -1311,7 +1512,6 @@ void sqlite3GenerateConstraintChecks(
int ix; /* Index loop counter */
int nCol; /* Number of columns */
int onError; /* Conflict resolution strategy */
- int addr1; /* Address of jump instruction */
int seenReplace = 0; /* True if REPLACE is used to resolve INT PK conflict */
int nPkField; /* Number of fields in PRIMARY KEY. 1 for ROWID tables */
Index *pUpIdx = 0; /* Index to which to apply the upsert */
@@ -1321,6 +1521,13 @@ void sqlite3GenerateConstraintChecks(
int upsertJump = 0; /* Address of Goto that jumps into upsert subroutine */
int ipkTop = 0; /* Top of the IPK uniqueness check */
int ipkBottom = 0; /* OP_Goto at the end of the IPK uniqueness check */
+ /* Variables associated with retesting uniqueness constraints after
+ ** replace triggers fire have run */
+ int regTrigCnt; /* Register used to count replace trigger invocations */
+ int addrRecheck = 0; /* Jump here to recheck all uniqueness constraints */
+ int lblRecheckOk = 0; /* Each recheck jumps to this label if it passes */
+ Trigger *pTrigger; /* List of DELETE triggers on the table pTab */
+ int nReplaceTrig = 0; /* Number of replace triggers coded */
isUpdate = regOldData!=0;
db = pParse->db;
@@ -1347,63 +1554,101 @@ void sqlite3GenerateConstraintChecks(
/* Test all NOT NULL constraints.
*/
- for(i=0; iiPKey ){
- continue; /* ROWID is never NULL */
- }
- if( aiChng && aiChng[i]<0 ){
- /* Don't bother checking for NOT NULL on columns that do not change */
- continue;
- }
- onError = pTab->aCol[i].notNull;
- if( onError==OE_None ) continue; /* This column is allowed to be NULL */
- if( overrideError!=OE_Default ){
- onError = overrideError;
- }else if( onError==OE_Default ){
- onError = OE_Abort;
- }
- if( onError==OE_Replace && pTab->aCol[i].pDflt==0 ){
- onError = OE_Abort;
- }
- assert( onError==OE_Rollback || onError==OE_Abort || onError==OE_Fail
- || onError==OE_Ignore || onError==OE_Replace );
- addr1 = 0;
- switch( onError ){
- case OE_Replace: {
- assert( onError==OE_Replace );
- addr1 = sqlite3VdbeMakeLabel(pParse);
- sqlite3VdbeAddOp2(v, OP_NotNull, regNewData+1+i, addr1);
- VdbeCoverage(v);
- sqlite3ExprCode(pParse, pTab->aCol[i].pDflt, regNewData+1+i);
- sqlite3VdbeAddOp2(v, OP_NotNull, regNewData+1+i, addr1);
- VdbeCoverage(v);
- onError = OE_Abort;
- /* Fall through into the OE_Abort case to generate code that runs
- ** if both the input and the default value are NULL */
- }
- case OE_Abort:
- sqlite3MayAbort(pParse);
- /* Fall through */
- case OE_Rollback:
- case OE_Fail: {
- char *zMsg = sqlite3MPrintf(db, "%s.%s", pTab->zName,
- pTab->aCol[i].zName);
- sqlite3VdbeAddOp3(v, OP_HaltIfNull, SQLITE_CONSTRAINT_NOTNULL, onError,
- regNewData+1+i);
- sqlite3VdbeAppendP4(v, zMsg, P4_DYNAMIC);
- sqlite3VdbeChangeP5(v, P5_ConstraintNotNull);
- VdbeCoverage(v);
- if( addr1 ) sqlite3VdbeResolveLabel(v, addr1);
+ if( pTab->tabFlags & TF_HasNotNull ){
+ int b2ndPass = 0; /* True if currently running 2nd pass */
+ int nSeenReplace = 0; /* Number of ON CONFLICT REPLACE operations */
+ int nGenerated = 0; /* Number of generated columns with NOT NULL */
+ while(1){ /* Make 2 passes over columns. Exit loop via "break" */
+ for(i=0; iaCol[i]; /* The column to check for NOT NULL */
+ int isGenerated; /* non-zero if column is generated */
+ onError = pCol->notNull;
+ if( onError==OE_None ) continue; /* No NOT NULL on this column */
+ if( i==pTab->iPKey ){
+ continue; /* ROWID is never NULL */
+ }
+ isGenerated = pCol->colFlags & COLFLAG_GENERATED;
+ if( isGenerated && !b2ndPass ){
+ nGenerated++;
+ continue; /* Generated columns processed on 2nd pass */
+ }
+ if( aiChng && aiChng[i]<0 && !isGenerated ){
+ /* Do not check NOT NULL on columns that do not change */
+ continue;
+ }
+ if( overrideError!=OE_Default ){
+ onError = overrideError;
+ }else if( onError==OE_Default ){
+ onError = OE_Abort;
+ }
+ if( onError==OE_Replace ){
+ if( b2ndPass /* REPLACE becomes ABORT on the 2nd pass */
+ || pCol->pDflt==0 /* REPLACE is ABORT if no DEFAULT value */
+ ){
+ testcase( pCol->colFlags & COLFLAG_VIRTUAL );
+ testcase( pCol->colFlags & COLFLAG_STORED );
+ testcase( pCol->colFlags & COLFLAG_GENERATED );
+ onError = OE_Abort;
+ }else{
+ assert( !isGenerated );
+ }
+ }else if( b2ndPass && !isGenerated ){
+ continue;
+ }
+ assert( onError==OE_Rollback || onError==OE_Abort || onError==OE_Fail
+ || onError==OE_Ignore || onError==OE_Replace );
+ testcase( i!=sqlite3TableColumnToStorage(pTab, i) );
+ iReg = sqlite3TableColumnToStorage(pTab, i) + regNewData + 1;
+ switch( onError ){
+ case OE_Replace: {
+ int addr1 = sqlite3VdbeAddOp1(v, OP_NotNull, iReg);
+ VdbeCoverage(v);
+ assert( (pCol->colFlags & COLFLAG_GENERATED)==0 );
+ nSeenReplace++;
+ sqlite3ExprCode(pParse, pCol->pDflt, iReg);
+ sqlite3VdbeJumpHere(v, addr1);
+ break;
+ }
+ case OE_Abort:
+ sqlite3MayAbort(pParse);
+ /* Fall through */
+ case OE_Rollback:
+ case OE_Fail: {
+ char *zMsg = sqlite3MPrintf(db, "%s.%s", pTab->zName,
+ pCol->zName);
+ sqlite3VdbeAddOp3(v, OP_HaltIfNull, SQLITE_CONSTRAINT_NOTNULL,
+ onError, iReg);
+ sqlite3VdbeAppendP4(v, zMsg, P4_DYNAMIC);
+ sqlite3VdbeChangeP5(v, P5_ConstraintNotNull);
+ VdbeCoverage(v);
+ break;
+ }
+ default: {
+ assert( onError==OE_Ignore );
+ sqlite3VdbeAddOp2(v, OP_IsNull, iReg, ignoreDest);
+ VdbeCoverage(v);
+ break;
+ }
+ } /* end switch(onError) */
+ } /* end loop i over columns */
+ if( nGenerated==0 && nSeenReplace==0 ){
+ /* If there are no generated columns with NOT NULL constraints
+ ** and no NOT NULL ON CONFLICT REPLACE constraints, then a single
+ ** pass is sufficient */
break;
}
- default: {
- assert( onError==OE_Ignore );
- sqlite3VdbeAddOp2(v, OP_IsNull, regNewData+1+i, ignoreDest);
- VdbeCoverage(v);
- break;
+ if( b2ndPass ) break; /* Never need more than 2 passes */
+ b2ndPass = 1;
+ if( nSeenReplace>0 && (pTab->tabFlags & TF_HasGenerated)!=0 ){
+ /* If any NOT NULL ON CONFLICT REPLACE constraints fired on the
+ ** first pass, recomputed values for all generated columns, as
+ ** those values might depend on columns affected by the REPLACE.
+ */
+ sqlite3ComputeGeneratedColumns(pParse, regNewData+1, pTab);
}
- }
- }
+ } /* end of 2-pass loop */
+ } /* end if( has-not-null-constraints ) */
/* Test all CHECK constraints
*/
@@ -1428,7 +1673,7 @@ void sqlite3GenerateConstraintChecks(
if( onError==OE_Ignore ){
sqlite3VdbeGoto(v, ignoreDest);
}else{
- char *zName = pCheck->a[i].zName;
+ char *zName = pCheck->a[i].zEName;
if( zName==0 ) zName = pTab->zName;
if( onError==OE_Replace ) onError = OE_Abort; /* IMP: R-26383-51744 */
sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_CHECK,
@@ -1485,6 +1730,50 @@ void sqlite3GenerateConstraintChecks(
}
}
+ /* Determine if it is possible that triggers (either explicitly coded
+ ** triggers or FK resolution actions) might run as a result of deletes
+ ** that happen when OE_Replace conflict resolution occurs. (Call these
+ ** "replace triggers".) If any replace triggers run, we will need to
+ ** recheck all of the uniqueness constraints after they have all run.
+ ** But on the recheck, the resolution is OE_Abort instead of OE_Replace.
+ **
+ ** If replace triggers are a possibility, then
+ **
+ ** (1) Allocate register regTrigCnt and initialize it to zero.
+ ** That register will count the number of replace triggers that
+ ** fire. Constraint recheck only occurs if the number is positive.
+ ** (2) Initialize pTrigger to the list of all DELETE triggers on pTab.
+ ** (3) Initialize addrRecheck and lblRecheckOk
+ **
+ ** The uniqueness rechecking code will create a series of tests to run
+ ** in a second pass. The addrRecheck and lblRecheckOk variables are
+ ** used to link together these tests which are separated from each other
+ ** in the generate bytecode.
+ */
+ if( (db->flags & (SQLITE_RecTriggers|SQLITE_ForeignKeys))==0 ){
+ /* There are not DELETE triggers nor FK constraints. No constraint
+ ** rechecks are needed. */
+ pTrigger = 0;
+ regTrigCnt = 0;
+ }else{
+ if( db->flags&SQLITE_RecTriggers ){
+ pTrigger = sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0, 0);
+ regTrigCnt = pTrigger!=0 || sqlite3FkRequired(pParse, pTab, 0, 0);
+ }else{
+ pTrigger = 0;
+ regTrigCnt = sqlite3FkRequired(pParse, pTab, 0, 0);
+ }
+ if( regTrigCnt ){
+ /* Replace triggers might exist. Allocate the counter and
+ ** initialize it to zero. */
+ regTrigCnt = ++pParse->nMem;
+ sqlite3VdbeAddOp2(v, OP_Integer, 0, regTrigCnt);
+ VdbeComment((v, "trigger count"));
+ lblRecheckOk = sqlite3VdbeMakeLabel(pParse);
+ addrRecheck = lblRecheckOk;
+ }
+ }
+
/* If rowid is changing, make sure the new rowid does not previously
** exist in the table.
*/
@@ -1574,14 +1863,12 @@ void sqlite3GenerateConstraintChecks(
** to run without a statement journal if there are no indexes on the
** table.
*/
- Trigger *pTrigger = 0;
- if( db->flags&SQLITE_RecTriggers ){
- pTrigger = sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0, 0);
- }
- if( pTrigger || sqlite3FkRequired(pParse, pTab, 0, 0) ){
+ if( regTrigCnt ){
sqlite3MultiWrite(pParse);
sqlite3GenerateRowDelete(pParse, pTab, pTrigger, iDataCur, iIdxCur,
regNewData, 1, 0, OE_Replace, 1, -1);
+ sqlite3VdbeAddOp2(v, OP_AddImm, regTrigCnt, 1); /* incr trigger cnt */
+ nReplaceTrig++;
}else{
#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
assert( HasRowid(pTab) );
@@ -1631,6 +1918,7 @@ void sqlite3GenerateConstraintChecks(
int regR; /* Range of registers holding conflicting PK */
int iThisCur; /* Cursor for this UNIQUE index */
int addrUniqueOk; /* Jump here if the UNIQUE constraint is satisfied */
+ int addrConflictCk; /* First opcode in the conflict check logic */
if( aRegIdx[ix]==0 ) continue; /* Skip indices that do not change */
if( pUpIdx==pIdx ){
@@ -1670,14 +1958,15 @@ void sqlite3GenerateConstraintChecks(
sqlite3ExprCodeCopy(pParse, pIdx->aColExpr->a[i].pExpr, regIdx+i);
pParse->iSelfTab = 0;
VdbeComment((v, "%s column %d", pIdx->zName, i));
+ }else if( iField==XN_ROWID || iField==pTab->iPKey ){
+ x = regNewData;
+ sqlite3VdbeAddOp2(v, OP_IntCopy, x, regIdx+i);
+ VdbeComment((v, "rowid"));
}else{
- if( iField==XN_ROWID || iField==pTab->iPKey ){
- x = regNewData;
- }else{
- x = iField + regNewData + 1;
- }
- sqlite3VdbeAddOp2(v, iField<0 ? OP_IntCopy : OP_SCopy, x, regIdx+i);
- VdbeComment((v, "%s", iField<0 ? "rowid" : pTab->aCol[iField].zName));
+ testcase( sqlite3TableColumnToStorage(pTab, iField)!=iField );
+ x = sqlite3TableColumnToStorage(pTab, iField) + regNewData + 1;
+ sqlite3VdbeAddOp2(v, OP_SCopy, x, regIdx+i);
+ VdbeComment((v, "%s", pTab->aCol[iField].zName));
}
}
sqlite3VdbeAddOp3(v, OP_MakeRecord, regIdx, pIdx->nColumn, aRegIdx[ix]);
@@ -1687,6 +1976,7 @@ void sqlite3GenerateConstraintChecks(
sqlite3SetMakeRecordP5(v, pIdx->pTable);
}
#endif
+ sqlite3VdbeReleaseRegisters(pParse, regIdx, pIdx->nColumn, 0, 0);
/* In an UPDATE operation, if this index is the PRIMARY KEY index
** of a WITHOUT ROWID table and there has been no change the
@@ -1744,8 +2034,9 @@ void sqlite3GenerateConstraintChecks(
/* Check to see if the new index entry will be unique */
sqlite3VdbeVerifyAbortable(v, onError);
- sqlite3VdbeAddOp4Int(v, OP_NoConflict, iThisCur, addrUniqueOk,
- regIdx, pIdx->nKeyCol); VdbeCoverage(v);
+ addrConflictCk =
+ sqlite3VdbeAddOp4Int(v, OP_NoConflict, iThisCur, addrUniqueOk,
+ regIdx, pIdx->nKeyCol); VdbeCoverage(v);
/* Generate code to handle collisions */
regR = (pIdx==pPk) ? regIdx : sqlite3GetTempRange(pParse, nPkField);
@@ -1766,7 +2057,7 @@ void sqlite3GenerateConstraintChecks(
if( pIdx!=pPk ){
for(i=0; inKeyCol; i++){
assert( pPk->aiColumn[i]>=0 );
- x = sqlite3ColumnOfIndex(pIdx, pPk->aiColumn[i]);
+ x = sqlite3TableColumnToIndex(pIdx, pPk->aiColumn[i]);
sqlite3VdbeAddOp3(v, OP_Column, iThisCur, x, regR+i);
VdbeComment((v, "%s.%s", pTab->zName,
pTab->aCol[pPk->aiColumn[i]].zName));
@@ -1792,6 +2083,7 @@ void sqlite3GenerateConstraintChecks(
addrJump = addrUniqueOk;
op = OP_Eq;
}
+ x = sqlite3TableColumnToStorage(pTab, x);
sqlite3VdbeAddOp4(v, op,
regOldData+1+x, addrJump, regCmp+i, p4, P4_COLLSEQ
);
@@ -1828,17 +2120,71 @@ void sqlite3GenerateConstraintChecks(
break;
}
default: {
- Trigger *pTrigger = 0;
+ int nConflictCk; /* Number of opcodes in conflict check logic */
+
assert( onError==OE_Replace );
- if( db->flags&SQLITE_RecTriggers ){
- pTrigger = sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0, 0);
- }
- if( pTrigger || sqlite3FkRequired(pParse, pTab, 0, 0) ){
+ nConflictCk = sqlite3VdbeCurrentAddr(v) - addrConflictCk;
+ assert( nConflictCk>0 );
+ testcase( nConflictCk>1 );
+ if( regTrigCnt ){
sqlite3MultiWrite(pParse);
+ nReplaceTrig++;
+ }
+ if( pTrigger && isUpdate ){
+ sqlite3VdbeAddOp1(v, OP_CursorLock, iDataCur);
}
sqlite3GenerateRowDelete(pParse, pTab, pTrigger, iDataCur, iIdxCur,
regR, nPkField, 0, OE_Replace,
(pIdx==pPk ? ONEPASS_SINGLE : ONEPASS_OFF), iThisCur);
+ if( pTrigger && isUpdate ){
+ sqlite3VdbeAddOp1(v, OP_CursorUnlock, iDataCur);
+ }
+ if( regTrigCnt ){
+ int addrBypass; /* Jump destination to bypass recheck logic */
+
+ sqlite3VdbeAddOp2(v, OP_AddImm, regTrigCnt, 1); /* incr trigger cnt */
+ addrBypass = sqlite3VdbeAddOp0(v, OP_Goto); /* Bypass recheck */
+ VdbeComment((v, "bypass recheck"));
+
+ /* Here we insert code that will be invoked after all constraint
+ ** checks have run, if and only if one or more replace triggers
+ ** fired. */
+ sqlite3VdbeResolveLabel(v, lblRecheckOk);
+ lblRecheckOk = sqlite3VdbeMakeLabel(pParse);
+ if( pIdx->pPartIdxWhere ){
+ /* Bypass the recheck if this partial index is not defined
+ ** for the current row */
+ sqlite3VdbeAddOp2(v, OP_IsNull, regIdx-1, lblRecheckOk);
+ VdbeCoverage(v);
+ }
+ /* Copy the constraint check code from above, except change
+ ** the constraint-ok jump destination to be the address of
+ ** the next retest block */
+ while( nConflictCk>0 ){
+ VdbeOp x; /* Conflict check opcode to copy */
+ /* The sqlite3VdbeAddOp4() call might reallocate the opcode array.
+ ** Hence, make a complete copy of the opcode, rather than using
+ ** a pointer to the opcode. */
+ x = *sqlite3VdbeGetOp(v, addrConflictCk);
+ if( x.opcode!=OP_IdxRowid ){
+ int p2; /* New P2 value for copied conflict check opcode */
+ if( sqlite3OpcodeProperty[x.opcode]&OPFLG_JUMP ){
+ p2 = lblRecheckOk;
+ }else{
+ p2 = x.p2;
+ }
+ sqlite3VdbeAddOp4(v, x.opcode, x.p1, p2, x.p3, x.p4.z, x.p4type);
+ sqlite3VdbeChangeP5(v, x.p5);
+ VdbeCoverageIf(v, p2!=x.p2);
+ }
+ nConflictCk--;
+ addrConflictCk++;
+ }
+ /* If the retest fails, issue an abort */
+ sqlite3UniqueConstraint(pParse, OE_Abort, pIdx);
+
+ sqlite3VdbeJumpHere(v, addrBypass); /* Terminate the recheck bypass */
+ }
seenReplace = 1;
break;
}
@@ -1859,10 +2205,30 @@ void sqlite3GenerateConstraintChecks(
sqlite3VdbeJumpHere(v, ipkBottom);
}
+ /* Recheck all uniqueness constraints after replace triggers have run */
+ testcase( regTrigCnt!=0 && nReplaceTrig==0 );
+ assert( regTrigCnt!=0 || nReplaceTrig==0 );
+ if( nReplaceTrig ){
+ sqlite3VdbeAddOp2(v, OP_IfNot, regTrigCnt, lblRecheckOk);VdbeCoverage(v);
+ if( !pPk ){
+ if( isUpdate ){
+ sqlite3VdbeAddOp3(v, OP_Eq, regNewData, addrRecheck, regOldData);
+ sqlite3VdbeChangeP5(v, SQLITE_NOTNULL);
+ VdbeCoverage(v);
+ }
+ sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, addrRecheck, regNewData);
+ VdbeCoverage(v);
+ sqlite3RowidConstraint(pParse, OE_Abort, pTab);
+ }else{
+ sqlite3VdbeGoto(v, addrRecheck);
+ }
+ sqlite3VdbeResolveLabel(v, lblRecheckOk);
+ }
+
/* Generate the table record */
if( HasRowid(pTab) ){
int regRec = aRegIdx[ix];
- sqlite3VdbeAddOp3(v, OP_MakeRecord, regNewData+1, pTab->nCol, regRec);
+ sqlite3VdbeAddOp3(v, OP_MakeRecord, regNewData+1, pTab->nNVCol, regRec);
sqlite3SetMakeRecordP5(v, pTab);
if( !bAffinityDone ){
sqlite3TableAffinity(v, pTab, 0);
@@ -1929,6 +2295,10 @@ void sqlite3CompleteInsertion(
assert( v!=0 );
assert( pTab->pSelect==0 ); /* This table is not a VIEW */
for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
+ /* All REPLACE indexes are at the end of the list */
+ assert( pIdx->onError!=OE_Replace
+ || pIdx->pNext==0
+ || pIdx->pNext->onError==OE_Replace );
if( aRegIdx[i]==0 ) continue;
if( pIdx->pPartIdxWhere ){
sqlite3VdbeAddOp2(v, OP_IsNull, aRegIdx[i], sqlite3VdbeCurrentAddr(v)+2);
@@ -2079,7 +2449,7 @@ static int xferCompatibleIndex(Index *pDest, Index *pSrc){
int i;
assert( pDest && pSrc );
assert( pDest->pTable!=pSrc->pTable );
- if( pDest->nKeyCol!=pSrc->nKeyCol ){
+ if( pDest->nKeyCol!=pSrc->nKeyCol || pDest->nColumn!=pSrc->nColumn ){
return 0; /* Different number of columns */
}
if( pDest->onError!=pSrc->onError ){
@@ -2256,6 +2626,39 @@ static int xferOptimization(
){
return 0; /* Neither table may have __hidden__ columns */
}
+#endif
+#ifndef SQLITE_OMIT_GENERATED_COLUMNS
+ /* Even if tables t1 and t2 have identical schemas, if they contain
+ ** generated columns, then this statement is semantically incorrect:
+ **
+ ** INSERT INTO t2 SELECT * FROM t1;
+ **
+ ** The reason is that generated column values are returned by the
+ ** the SELECT statement on the right but the INSERT statement on the
+ ** left wants them to be omitted.
+ **
+ ** Nevertheless, this is a useful notational shorthand to tell SQLite
+ ** to do a bulk transfer all of the content from t1 over to t2.
+ **
+ ** We could, in theory, disable this (except for internal use by the
+ ** VACUUM command where it is actually needed). But why do that? It
+ ** seems harmless enough, and provides a useful service.
+ */
+ if( (pDestCol->colFlags & COLFLAG_GENERATED) !=
+ (pSrcCol->colFlags & COLFLAG_GENERATED) ){
+ return 0; /* Both columns have the same generated-column type */
+ }
+ /* But the transfer is only allowed if both the source and destination
+ ** tables have the exact same expressions for generated columns.
+ ** This requirement could be relaxed for VIRTUAL columns, I suppose.
+ */
+ if( (pDestCol->colFlags & COLFLAG_GENERATED)!=0 ){
+ if( sqlite3ExprCompare(0, pSrcCol->pDflt, pDestCol->pDflt, -1)!=0 ){
+ testcase( pDestCol->colFlags & COLFLAG_VIRTUAL );
+ testcase( pDestCol->colFlags & COLFLAG_STORED );
+ return 0; /* Different generator expressions */
+ }
+ }
#endif
if( pDestCol->affinity!=pSrcCol->affinity ){
return 0; /* Affinity must be the same on all columns */
@@ -2267,7 +2670,7 @@ static int xferOptimization(
return 0; /* tab2 must be NOT NULL if tab1 is */
}
/* Default values for second and subsequent columns need to match. */
- if( i>0 ){
+ if( (pDestCol->colFlags & COLFLAG_GENERATED)==0 && i>0 ){
assert( pDestCol->pDflt==0 || pDestCol->pDflt->op==TK_SPAN );
assert( pSrcCol->pDflt==0 || pSrcCol->pDflt->op==TK_SPAN );
if( (pDestCol->pDflt==0)!=(pSrcCol->pDflt==0)
diff --git a/src/loadext.c b/src/loadext.c
index 423a16fde9..245e9b004d 100644
--- a/src/loadext.c
+++ b/src/loadext.c
@@ -468,6 +468,12 @@ static const sqlite3_api_routines sqlite3Apis = {
#else
0,
#endif
+ /* Version 3.31.0 and later */
+ sqlite3_hard_heap_limit64,
+ sqlite3_uri_key,
+ sqlite3_filename_database,
+ sqlite3_filename_journal,
+ sqlite3_filename_wal,
};
/*
diff --git a/src/main.c b/src/main.c
index 3ef3a3d9fb..995061fec7 100644
--- a/src/main.c
+++ b/src/main.c
@@ -683,6 +683,9 @@ int sqlite3_config(int op, ...){
static int setupLookaside(sqlite3 *db, void *pBuf, int sz, int cnt){
#ifndef SQLITE_OMIT_LOOKASIDE
void *pStart;
+ sqlite3_int64 szAlloc = sz*(sqlite3_int64)cnt;
+ int nBig; /* Number of full-size slots */
+ int nSm; /* Number smaller LOOKASIDE_SMALL-byte slots */
if( sqlite3LookasideUsed(db,0)>0 ){
return SQLITE_BUSY;
@@ -705,37 +708,71 @@ static int setupLookaside(sqlite3 *db, void *pBuf, int sz, int cnt){
pStart = 0;
}else if( pBuf==0 ){
sqlite3BeginBenignMalloc();
- pStart = sqlite3Malloc( sz*(sqlite3_int64)cnt ); /* IMP: R-61949-35727 */
+ pStart = sqlite3Malloc( szAlloc ); /* IMP: R-61949-35727 */
sqlite3EndBenignMalloc();
- if( pStart ) cnt = sqlite3MallocSize(pStart)/sz;
+ if( pStart ) szAlloc = sqlite3MallocSize(pStart);
}else{
pStart = pBuf;
}
+#ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE
+ if( sz>=LOOKASIDE_SMALL*3 ){
+ nBig = szAlloc/(3*LOOKASIDE_SMALL+sz);
+ nSm = (szAlloc - sz*nBig)/LOOKASIDE_SMALL;
+ }else if( sz>=LOOKASIDE_SMALL*2 ){
+ nBig = szAlloc/(LOOKASIDE_SMALL+sz);
+ nSm = (szAlloc - sz*nBig)/LOOKASIDE_SMALL;
+ }else
+#endif /* SQLITE_OMIT_TWOSIZE_LOOKASIDE */
+ if( sz>0 ){
+ nBig = szAlloc/sz;
+ nSm = 0;
+ }else{
+ nBig = nSm = 0;
+ }
db->lookaside.pStart = pStart;
db->lookaside.pInit = 0;
db->lookaside.pFree = 0;
db->lookaside.sz = (u16)sz;
+ db->lookaside.szTrue = (u16)sz;
if( pStart ){
int i;
LookasideSlot *p;
assert( sz > (int)sizeof(LookasideSlot*) );
- db->lookaside.nSlot = cnt;
p = (LookasideSlot*)pStart;
- for(i=cnt-1; i>=0; i--){
+ for(i=0; ipNext = db->lookaside.pInit;
db->lookaside.pInit = p;
p = (LookasideSlot*)&((u8*)p)[sz];
}
+#ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE
+ db->lookaside.pSmallInit = 0;
+ db->lookaside.pSmallFree = 0;
+ db->lookaside.pMiddle = p;
+ for(i=0; ipNext = db->lookaside.pSmallInit;
+ db->lookaside.pSmallInit = p;
+ p = (LookasideSlot*)&((u8*)p)[LOOKASIDE_SMALL];
+ }
+#endif /* SQLITE_OMIT_TWOSIZE_LOOKASIDE */
+ assert( ((uptr)p)<=szAlloc + (uptr)pStart );
db->lookaside.pEnd = p;
db->lookaside.bDisable = 0;
db->lookaside.bMalloced = pBuf==0 ?1:0;
+ db->lookaside.nSlot = nBig+nSm;
}else{
db->lookaside.pStart = db;
+#ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE
+ db->lookaside.pSmallInit = 0;
+ db->lookaside.pSmallFree = 0;
+ db->lookaside.pMiddle = db;
+#endif /* SQLITE_OMIT_TWOSIZE_LOOKASIDE */
db->lookaside.pEnd = db;
db->lookaside.bDisable = 1;
+ db->lookaside.sz = 0;
db->lookaside.bMalloced = 0;
db->lookaside.nSlot = 0;
}
+ assert( sqlite3LookasideUsed(db,0)==0 );
#endif /* SQLITE_OMIT_LOOKASIDE */
return SQLITE_OK;
}
@@ -849,6 +886,8 @@ int sqlite3_db_config(sqlite3 *db, int op, ...){
{ SQLITE_DBCONFIG_LEGACY_ALTER_TABLE, SQLITE_LegacyAlter },
{ SQLITE_DBCONFIG_DQS_DDL, SQLITE_DqsDDL },
{ SQLITE_DBCONFIG_DQS_DML, SQLITE_DqsDML },
+ { SQLITE_DBCONFIG_LEGACY_FILE_FORMAT, SQLITE_LegacyFileFmt },
+ { SQLITE_DBCONFIG_TRUSTED_SCHEMA, SQLITE_TrustedSchema },
};
unsigned int i;
rc = SQLITE_ERROR; /* IMP: R-42790-23372 */
@@ -1387,6 +1426,7 @@ const char *sqlite3ErrName(int rc){
case SQLITE_CANTOPEN_ISDIR: zName = "SQLITE_CANTOPEN_ISDIR"; break;
case SQLITE_CANTOPEN_FULLPATH: zName = "SQLITE_CANTOPEN_FULLPATH"; break;
case SQLITE_CANTOPEN_CONVPATH: zName = "SQLITE_CANTOPEN_CONVPATH"; break;
+ case SQLITE_CANTOPEN_SYMLINK: zName = "SQLITE_CANTOPEN_SYMLINK"; break;
case SQLITE_PROTOCOL: zName = "SQLITE_PROTOCOL"; break;
case SQLITE_EMPTY: zName = "SQLITE_EMPTY"; break;
case SQLITE_SCHEMA: zName = "SQLITE_SCHEMA"; break;
@@ -1719,8 +1759,15 @@ int sqlite3CreateFunc(
assert( SQLITE_FUNC_CONSTANT==SQLITE_DETERMINISTIC );
assert( SQLITE_FUNC_DIRECT==SQLITE_DIRECTONLY );
- extraFlags = enc & (SQLITE_DETERMINISTIC|SQLITE_DIRECTONLY|SQLITE_SUBTYPE);
+ extraFlags = enc & (SQLITE_DETERMINISTIC|SQLITE_DIRECTONLY|
+ SQLITE_SUBTYPE|SQLITE_INNOCUOUS);
enc &= (SQLITE_FUNC_ENCMASK|SQLITE_ANY);
+
+ /* The SQLITE_INNOCUOUS flag is the same bit as SQLITE_FUNC_UNSAFE. But
+ ** the meaning is inverted. So flip the bit. */
+ assert( SQLITE_FUNC_UNSAFE==SQLITE_INNOCUOUS );
+ extraFlags ^= SQLITE_FUNC_UNSAFE;
+
#ifndef SQLITE_OMIT_UTF16
/* If SQLITE_UTF16 is specified as the encoding type, transform this
@@ -1734,11 +1781,13 @@ int sqlite3CreateFunc(
enc = SQLITE_UTF16NATIVE;
}else if( enc==SQLITE_ANY ){
int rc;
- rc = sqlite3CreateFunc(db, zFunctionName, nArg, SQLITE_UTF8|extraFlags,
+ rc = sqlite3CreateFunc(db, zFunctionName, nArg,
+ (SQLITE_UTF8|extraFlags)^SQLITE_FUNC_UNSAFE,
pUserData, xSFunc, xStep, xFinal, xValue, xInverse, pDestructor);
if( rc==SQLITE_OK ){
- rc = sqlite3CreateFunc(db, zFunctionName, nArg, SQLITE_UTF16LE|extraFlags,
- pUserData, xSFunc, xStep, xFinal, xValue, xInverse, pDestructor);
+ rc = sqlite3CreateFunc(db, zFunctionName, nArg,
+ (SQLITE_UTF16LE|extraFlags)^SQLITE_FUNC_UNSAFE,
+ pUserData, xSFunc, xStep, xFinal, xValue, xInverse, pDestructor);
}
if( rc!=SQLITE_OK ){
return rc;
@@ -3064,6 +3113,7 @@ static int openDatabase(
db->magic = SQLITE_MAGIC_BUSY;
db->aDb = db->aDbStatic;
db->lookaside.bDisable = 1;
+ db->lookaside.sz = 0;
assert( sizeof(db->aLimit)==sizeof(aHardLimit) );
memcpy(db->aLimit, aHardLimit, sizeof(db->aLimit));
@@ -3077,7 +3127,9 @@ static int openDatabase(
| SQLITE_EnableTrigger
| SQLITE_EnableView
| SQLITE_CacheSpill
-
+#if !defined(SQLITE_TRUSTED_SCHEMA) || SQLITE_TRUSTED_SCHEMA+0!=0
+ | SQLITE_TrustedSchema
+#endif
/* The SQLITE_DQS compile-time option determines the default settings
** for SQLITE_DBCONFIG_DQS_DDL and SQLITE_DBCONFIG_DQS_DML.
**
@@ -3307,6 +3359,13 @@ static int openDatabase(
}
#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.
+ ** Testing use only!!! */
+ db->mDbFlags |= DBFLAG_InternalFunc;
+#endif
+
/* -DSQLITE_DEFAULT_LOCKING_MODE=1 makes EXCLUSIVE the default locking
** mode. -DSQLITE_DEFAULT_LOCKING_MODE=0 make NORMAL the default locking
** mode. Doing nothing at all also makes NORMAL the default.
@@ -4039,15 +4098,14 @@ int sqlite3_test_control(int op, ...){
break;
}
- /* sqlite3_test_control(SQLITE_TESTCTRL_INTERNAL_FUNCS, int onoff);
+ /* sqlite3_test_control(SQLITE_TESTCTRL_INTERNAL_FUNCTIONS, sqlite3*);
**
- ** If parameter onoff is non-zero, internal-use-only SQL functions
- ** are visible to ordinary SQL. This is useful for testing but is
- ** unsafe because invalid parameters to those internal-use-only functions
- ** can result in crashes or segfaults.
+ ** Toggle the ability to use internal functions on or off for
+ ** the database connection given in the argument.
*/
case SQLITE_TESTCTRL_INTERNAL_FUNCTIONS: {
- sqlite3GlobalConfig.bInternalFunctions = va_arg(ap, int);
+ sqlite3 *db = va_arg(ap, sqlite3*);
+ db->mDbFlags ^= DBFLAG_InternalFunc;
break;
}
@@ -4206,6 +4264,19 @@ const char *sqlite3_uri_parameter(const char *zFilename, const char *zParam){
return 0;
}
+/*
+** Return a pointer to the name of Nth query parameter of the filename.
+*/
+const char *sqlite3_uri_key(const char *zFilename, int N){
+ if( zFilename==0 || N<0 ) return 0;
+ zFilename += sqlite3Strlen30(zFilename) + 1;
+ while( zFilename[0] && (N--)>0 ){
+ zFilename += sqlite3Strlen30(zFilename) + 1;
+ zFilename += sqlite3Strlen30(zFilename) + 1;
+ }
+ return zFilename[0] ? zFilename : 0;
+}
+
/*
** Return a boolean value for a query parameter.
*/
@@ -4231,6 +4302,46 @@ sqlite3_int64 sqlite3_uri_int64(
return bDflt;
}
+/*
+** The Pager stores the Journal filename, WAL filename, and Database filename
+** consecutively in memory, in that order, with prefixes \000\001\000,
+** \002\000, and \003\000, in that order. Thus the three names look like query
+** parameters if you start at the first prefix.
+**
+** This routine backs up a filename to the start of the first prefix.
+**
+** This only works if the filenamed passed in was obtained from the Pager.
+*/
+static const char *startOfNameList(const char *zName){
+ while( zName[0]!='\001' || zName[1]!=0 ){
+ zName -= 3;
+ while( zName[0]!='\000' ){ zName--; }
+ zName++;
+ }
+ return zName-1;
+}
+
+/*
+** Translate a filename that was handed to a VFS routine into the corresponding
+** database, journal, or WAL file.
+**
+** It is an error to pass this routine a filename string that was not
+** passed into the VFS from the SQLite core. Doing so is similar to
+** passing free() a pointer that was not obtained from malloc() - it is
+** an error that we cannot easily detect but that will likely cause memory
+** corruption.
+*/
+const char *sqlite3_filename_database(const char *zFilename){
+ return sqlite3_uri_parameter(zFilename - 3, "\003");
+}
+const char *sqlite3_filename_journal(const char *zFilename){
+ const char *z = sqlite3_uri_parameter(startOfNameList(zFilename), "\001");
+ return ALWAYS(z) && z[0] ? z : 0;
+}
+const char *sqlite3_filename_wal(const char *zFilename){
+ return sqlite3_uri_parameter(startOfNameList(zFilename), "\002");
+}
+
/*
** Return the Btree pointer identified by zDbName. Return NULL if not found.
*/
diff --git a/src/malloc.c b/src/malloc.c
index 559e7259ce..9dd400a3ba 100644
--- a/src/malloc.c
+++ b/src/malloc.c
@@ -32,19 +32,27 @@ int sqlite3_release_memory(int n){
#endif
}
+/*
+** Default value of the hard heap limit. 0 means "no limit".
+*/
+#ifndef SQLITE_MAX_MEMORY
+# define SQLITE_MAX_MEMORY 0
+#endif
+
/*
** State information local to the memory allocation subsystem.
*/
static SQLITE_WSD struct Mem0Global {
sqlite3_mutex *mutex; /* Mutex to serialize access */
sqlite3_int64 alarmThreshold; /* The soft heap limit */
+ sqlite3_int64 hardLimit; /* The hard upper bound on memory */
/*
** True if heap is nearly "full" where "full" is defined by the
** sqlite3_soft_heap_limit() setting.
*/
int nearlyFull;
-} mem0 = { 0, 0, 0 };
+} mem0 = { 0, SQLITE_MAX_MEMORY, SQLITE_MAX_MEMORY, 0 };
#define mem0 GLOBAL(struct Mem0Global, mem0)
@@ -74,8 +82,15 @@ int sqlite3_memory_alarm(
#endif
/*
-** Set the soft heap-size limit for the library. Passing a zero or
-** negative value indicates no limit.
+** Set the soft heap-size limit for the library. An argument of
+** zero disables the limit. A negative argument is a no-op used to
+** obtain the return value.
+**
+** The return value is the value of the heap limit just before this
+** interface was called.
+**
+** If the hard heap limit is enabled, then the soft heap limit cannot
+** be disabled nor raised above the hard heap limit.
*/
sqlite3_int64 sqlite3_soft_heap_limit64(sqlite3_int64 n){
sqlite3_int64 priorLimit;
@@ -91,6 +106,9 @@ sqlite3_int64 sqlite3_soft_heap_limit64(sqlite3_int64 n){
sqlite3_mutex_leave(mem0.mutex);
return priorLimit;
}
+ if( mem0.hardLimit>0 && (n>mem0.hardLimit || n==0) ){
+ n = mem0.hardLimit;
+ }
mem0.alarmThreshold = n;
nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED);
mem0.nearlyFull = (n>0 && n<=nUsed);
@@ -104,6 +122,37 @@ void sqlite3_soft_heap_limit(int n){
sqlite3_soft_heap_limit64(n);
}
+/*
+** Set the hard heap-size limit for the library. An argument of zero
+** disables the hard heap limit. A negative argument is a no-op used
+** to obtain the return value without affecting the hard heap limit.
+**
+** The return value is the value of the hard heap limit just prior to
+** calling this interface.
+**
+** Setting the hard heap limit will also activate the soft heap limit
+** and constrain the soft heap limit to be no more than the hard heap
+** limit.
+*/
+sqlite3_int64 sqlite3_hard_heap_limit64(sqlite3_int64 n){
+ sqlite3_int64 priorLimit;
+#ifndef SQLITE_OMIT_AUTOINIT
+ int rc = sqlite3_initialize();
+ if( rc ) return -1;
+#endif
+ sqlite3_mutex_enter(mem0.mutex);
+ priorLimit = mem0.hardLimit;
+ if( n>=0 ){
+ mem0.hardLimit = n;
+ if( nSQLITE_MAX_MEMORY ){
- *pp = 0;
- return;
- }
-#endif
-
sqlite3StatusHighwater(SQLITE_STATUS_MALLOC_SIZE, n);
if( mem0.alarmThreshold>0 ){
sqlite3_int64 nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED);
if( nUsed >= mem0.alarmThreshold - nFull ){
mem0.nearlyFull = 1;
sqlite3MallocAlarm(nFull);
+ if( mem0.hardLimit ){
+ nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED);
+ if( nUsed >= mem0.hardLimit - nFull ){
+ *pp = 0;
+ return;
+ }
+ }
}else{
mem0.nearlyFull = 0;
}
@@ -283,10 +332,17 @@ int sqlite3MallocSize(void *p){
assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) );
return sqlite3GlobalConfig.m.xSize(p);
}
+static int lookasideMallocSize(sqlite3 *db, void *p){
+#ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE
+ return plookaside.pMiddle ? db->lookaside.szTrue : LOOKASIDE_SMALL;
+#else
+ return db->lookaside.szTrue;
+#endif
+}
int sqlite3DbMallocSize(sqlite3 *db, void *p){
assert( p!=0 );
- if( db==0 || !isLookaside(db,p) ){
#ifdef SQLITE_DEBUG
+ if( db==0 || !isLookaside(db,p) ){
if( db==0 ){
assert( sqlite3MemdebugNoType(p, (u8)~MEMTYPE_HEAP) );
assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) );
@@ -294,12 +350,23 @@ int sqlite3DbMallocSize(sqlite3 *db, void *p){
assert( sqlite3MemdebugHasType(p, (MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
assert( sqlite3MemdebugNoType(p, (u8)~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
}
-#endif
- return sqlite3GlobalConfig.m.xSize(p);
- }else{
- assert( sqlite3_mutex_held(db->mutex) );
- return db->lookaside.sz;
}
+#endif
+ if( db ){
+ if( ((uptr)p)<(uptr)(db->lookaside.pEnd) ){
+#ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE
+ if( ((uptr)p)>=(uptr)(db->lookaside.pMiddle) ){
+ assert( sqlite3_mutex_held(db->mutex) );
+ return LOOKASIDE_SMALL;
+ }
+#endif
+ if( ((uptr)p)>=(uptr)(db->lookaside.pStart) ){
+ assert( sqlite3_mutex_held(db->mutex) );
+ return db->lookaside.szTrue;
+ }
+ }
+ }
+ return sqlite3GlobalConfig.m.xSize(p);
}
sqlite3_uint64 sqlite3_msize(void *p){
assert( sqlite3MemdebugNoType(p, (u8)~MEMTYPE_HEAP) );
@@ -346,15 +413,27 @@ void sqlite3DbFreeNN(sqlite3 *db, void *p){
measureAllocationSize(db, p);
return;
}
- if( isLookaside(db, p) ){
- LookasideSlot *pBuf = (LookasideSlot*)p;
+ if( ((uptr)p)<(uptr)(db->lookaside.pEnd) ){
+#ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE
+ if( ((uptr)p)>=(uptr)(db->lookaside.pMiddle) ){
+ LookasideSlot *pBuf = (LookasideSlot*)p;
#ifdef SQLITE_DEBUG
- /* Trash all content in the buffer being freed */
- memset(p, 0xaa, db->lookaside.sz);
+ memset(p, 0xaa, LOOKASIDE_SMALL); /* Trash freed content */
#endif
- pBuf->pNext = db->lookaside.pFree;
- db->lookaside.pFree = pBuf;
- return;
+ pBuf->pNext = db->lookaside.pSmallFree;
+ db->lookaside.pSmallFree = pBuf;
+ return;
+ }
+#endif /* SQLITE_OMIT_TWOSIZE_LOOKASIDE */
+ if( ((uptr)p)>=(uptr)(db->lookaside.pStart) ){
+ LookasideSlot *pBuf = (LookasideSlot*)p;
+#ifdef SQLITE_DEBUG
+ memset(p, 0xaa, db->lookaside.szTrue); /* Trash freed content */
+#endif
+ pBuf->pNext = db->lookaside.pFree;
+ db->lookaside.pFree = pBuf;
+ return;
+ }
}
}
assert( sqlite3MemdebugHasType(p, (MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
@@ -510,23 +589,37 @@ void *sqlite3DbMallocRawNN(sqlite3 *db, u64 n){
assert( db!=0 );
assert( sqlite3_mutex_held(db->mutex) );
assert( db->pnBytesFreed==0 );
- if( db->lookaside.bDisable==0 ){
- assert( db->mallocFailed==0 );
- if( n>db->lookaside.sz ){
- db->lookaside.anStat[1]++;
- }else if( (pBuf = db->lookaside.pFree)!=0 ){
- db->lookaside.pFree = pBuf->pNext;
- db->lookaside.anStat[0]++;
- return (void*)pBuf;
- }else if( (pBuf = db->lookaside.pInit)!=0 ){
- db->lookaside.pInit = pBuf->pNext;
- db->lookaside.anStat[0]++;
- return (void*)pBuf;
- }else{
- db->lookaside.anStat[2]++;
+ if( n>db->lookaside.sz ){
+ if( !db->lookaside.bDisable ){
+ db->lookaside.anStat[1]++;
+ }else if( db->mallocFailed ){
+ return 0;
}
- }else if( db->mallocFailed ){
- return 0;
+ return dbMallocRawFinish(db, n);
+ }
+#ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE
+ if( n<=LOOKASIDE_SMALL ){
+ if( (pBuf = db->lookaside.pSmallFree)!=0 ){
+ db->lookaside.pSmallFree = pBuf->pNext;
+ db->lookaside.anStat[0]++;
+ return (void*)pBuf;
+ }else if( (pBuf = db->lookaside.pSmallInit)!=0 ){
+ db->lookaside.pSmallInit = pBuf->pNext;
+ db->lookaside.anStat[0]++;
+ return (void*)pBuf;
+ }
+ }
+#endif
+ if( (pBuf = db->lookaside.pFree)!=0 ){
+ db->lookaside.pFree = pBuf->pNext;
+ db->lookaside.anStat[0]++;
+ return (void*)pBuf;
+ }else if( (pBuf = db->lookaside.pInit)!=0 ){
+ db->lookaside.pInit = pBuf->pNext;
+ db->lookaside.anStat[0]++;
+ return (void*)pBuf;
+ }else{
+ db->lookaside.anStat[2]++;
}
#else
assert( db!=0 );
@@ -550,7 +643,16 @@ void *sqlite3DbRealloc(sqlite3 *db, void *p, u64 n){
assert( db!=0 );
if( p==0 ) return sqlite3DbMallocRawNN(db, n);
assert( sqlite3_mutex_held(db->mutex) );
- if( isLookaside(db,p) && n<=db->lookaside.sz ) return p;
+ if( ((uptr)p)<(uptr)db->lookaside.pEnd ){
+#ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE
+ if( ((uptr)p)>=(uptr)db->lookaside.pMiddle ){
+ if( n<=LOOKASIDE_SMALL ) return p;
+ }else
+#endif
+ if( ((uptr)p)>=(uptr)db->lookaside.pStart ){
+ if( n<=db->lookaside.szTrue ) return p;
+ }
+ }
return dbReallocFinish(db, p, n);
}
static SQLITE_NOINLINE void *dbReallocFinish(sqlite3 *db, void *p, u64 n){
@@ -561,7 +663,7 @@ static SQLITE_NOINLINE void *dbReallocFinish(sqlite3 *db, void *p, u64 n){
if( isLookaside(db, p) ){
pNew = sqlite3DbMallocRawNN(db, n);
if( pNew ){
- memcpy(pNew, p, db->lookaside.sz);
+ memcpy(pNew, p, lookasideMallocSize(db, p));
sqlite3DbFree(db, p);
}
}else{
@@ -660,7 +762,7 @@ void sqlite3OomFault(sqlite3 *db){
if( db->nVdbeExec>0 ){
db->u1.isInterrupted = 1;
}
- db->lookaside.bDisable++;
+ DisableLookaside;
if( db->pParse ){
db->pParse->rc = SQLITE_NOMEM_BKPT;
}
@@ -679,7 +781,7 @@ void sqlite3OomClear(sqlite3 *db){
db->mallocFailed = 0;
db->u1.isInterrupted = 0;
assert( db->lookaside.bDisable>0 );
- db->lookaside.bDisable--;
+ EnableLookaside;
}
}
diff --git a/src/os.c b/src/os.c
index b9ad29d4f8..b729e95e65 100644
--- a/src/os.c
+++ b/src/os.c
@@ -215,7 +215,7 @@ int sqlite3OsOpen(
** down into the VFS layer. Some SQLITE_OPEN_ flags (for example,
** SQLITE_OPEN_FULLMUTEX or SQLITE_OPEN_SHAREDCACHE) are blocked before
** reaching the VFS. */
- rc = pVfs->xOpen(pVfs, zPath, pFile, flags & 0x87f7f, pFlagsOut);
+ rc = pVfs->xOpen(pVfs, zPath, pFile, flags & 0x1087f7f, pFlagsOut);
assert( rc==SQLITE_OK || pFile->pMethods==0 );
return rc;
}
diff --git a/src/os_unix.c b/src/os_unix.c
index f2ac89f2cf..07ae4bc03a 100644
--- a/src/os_unix.c
+++ b/src/os_unix.c
@@ -3685,7 +3685,7 @@ static int openDirectory(const char *zFilename, int *pFd){
if( zDirname[0]!='/' ) zDirname[0] = '.';
zDirname[1] = 0;
}
- fd = robust_open(zDirname, O_RDONLY|O_BINARY, 0);
+ fd = robust_open(zDirname, O_RDONLY|O_BINARY|O_NOFOLLOW, 0);
if( fd>=0 ){
OSTRACE(("OPENDIR %-3d %s\n", fd, zDirname));
}
@@ -4576,10 +4576,12 @@ static int unixOpenSharedMemory(unixFile *pDbFd){
if( pInode->bProcessLock==0 ){
if( 0==sqlite3_uri_boolean(pDbFd->zPath, "readonly_shm", 0) ){
- pShmNode->hShm = robust_open(zShm, O_RDWR|O_CREAT,(sStat.st_mode&0777));
+ pShmNode->hShm = robust_open(zShm, O_RDWR|O_CREAT|O_NOFOLLOW,
+ (sStat.st_mode&0777));
}
if( pShmNode->hShm<0 ){
- pShmNode->hShm = robust_open(zShm, O_RDONLY, (sStat.st_mode&0777));
+ pShmNode->hShm = robust_open(zShm, O_RDONLY|O_NOFOLLOW,
+ (sStat.st_mode&0777));
if( pShmNode->hShm<0 ){
rc = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zShm);
goto shm_open_err;
@@ -5929,7 +5931,7 @@ static int unixOpen(
unixFile *p = (unixFile *)pFile;
int fd = -1; /* File descriptor returned by open() */
int openFlags = 0; /* Flags to pass to open() */
- int eType = flags&0xFFFFFF00; /* Type of file to open */
+ int eType = flags&0x0FFF00; /* Type of file to open */
int noLock; /* True to omit locking primitives */
int rc = SQLITE_OK; /* Function Return Code */
int ctrlFlags = 0; /* UNIXFILE_* flags */
@@ -6039,7 +6041,7 @@ static int unixOpen(
if( isReadWrite ) openFlags |= O_RDWR;
if( isCreate ) openFlags |= O_CREAT;
if( isExclusive ) openFlags |= (O_EXCL|O_NOFOLLOW);
- openFlags |= (O_LARGEFILE|O_BINARY);
+ openFlags |= (O_LARGEFILE|O_BINARY|O_NOFOLLOW);
if( fd<0 ){
mode_t openMode; /* Permissions to create file with */
@@ -6257,7 +6259,8 @@ static int unixAccess(
if( flags==SQLITE_ACCESS_EXISTS ){
struct stat buf;
- *pResOut = (0==osStat(zPath, &buf) && buf.st_size>0);
+ *pResOut = 0==osStat(zPath, &buf) &&
+ (!S_ISREG(buf.st_mode) || buf.st_size>0);
}else{
*pResOut = osAccess(zPath, W_OK|R_OK)==0;
}
@@ -6311,7 +6314,7 @@ static int unixFullPathname(
#else
int rc = SQLITE_OK;
int nByte;
- int nLink = 1; /* Number of symbolic links followed so far */
+ int nLink = 0; /* Number of symbolic links followed so far */
const char *zIn = zPath; /* Input path for each iteration of loop */
char *zDel = 0;
@@ -6340,10 +6343,11 @@ static int unixFullPathname(
}
if( bLink ){
+ nLink++;
if( zDel==0 ){
zDel = sqlite3_malloc(nOut);
if( zDel==0 ) rc = SQLITE_NOMEM_BKPT;
- }else if( ++nLink>SQLITE_MAX_SYMLINKS ){
+ }else if( nLink>=SQLITE_MAX_SYMLINKS ){
rc = SQLITE_CANTOPEN_BKPT;
}
@@ -6379,6 +6383,7 @@ static int unixFullPathname(
}while( rc==SQLITE_OK );
sqlite3_free(zDel);
+ if( rc==SQLITE_OK && nLink ) rc = SQLITE_OK_SYMLINK;
return rc;
#endif /* HAVE_READLINK && HAVE_LSTAT */
}
@@ -6864,7 +6869,7 @@ static int proxyCreateUnixFile(
int fd = -1;
unixFile *pNew;
int rc = SQLITE_OK;
- int openFlags = O_RDWR | O_CREAT;
+ int openFlags = O_RDWR | O_CREAT | O_NOFOLLOW;
sqlite3_vfs dummyVfs;
int terrno = 0;
UnixUnusedFd *pUnused = NULL;
@@ -6894,7 +6899,7 @@ static int proxyCreateUnixFile(
}
}
if( fd<0 ){
- openFlags = O_RDONLY;
+ openFlags = O_RDONLY | O_NOFOLLOW;
fd = robust_open(path, openFlags, 0);
terrno = errno;
}
@@ -7020,7 +7025,7 @@ static int proxyBreakConchLock(unixFile *pFile, uuid_t myHostID){
goto end_breaklock;
}
/* write it out to the temporary break file */
- fd = robust_open(tPath, (O_RDWR|O_CREAT|O_EXCL), 0);
+ fd = robust_open(tPath, (O_RDWR|O_CREAT|O_EXCL|O_NOFOLLOW), 0);
if( fd<0 ){
sqlite3_snprintf(sizeof(errmsg), errmsg, "create failed (%d)", errno);
goto end_breaklock;
diff --git a/src/pager.c b/src/pager.c
index f0f2de0393..ff7ebfb4cc 100644
--- a/src/pager.c
+++ b/src/pager.c
@@ -1161,6 +1161,7 @@ static int pagerUnlockDb(Pager *pPager, int eLock){
}
IOTRACE(("UNLOCK %p %d\n", pPager, eLock))
}
+ pPager->changeCountDone = pPager->tempFile; /* ticket fb3b3024ea238d5c */
return rc;
}
@@ -1348,6 +1349,7 @@ static int readMasterJournal(sqlite3_file *pJrnl, char *zMaster, u32 nMaster){
len = 0;
}
zMaster[len] = '\0';
+ zMaster[len+1] = '\0';
return SQLITE_OK;
}
@@ -1881,7 +1883,6 @@ static void pager_unlock(Pager *pPager){
** code is cleared and the cache reset in the block below.
*/
assert( pPager->errCode || pPager->eState!=PAGER_ERROR );
- pPager->changeCountDone = 0;
pPager->eState = PAGER_OPEN;
}
@@ -2146,7 +2147,6 @@ static int pager_end_transaction(Pager *pPager, int hasMaster, int bCommit){
&& (!pagerUseWal(pPager) || sqlite3WalExclusiveMode(pPager->pWal, 0))
){
rc2 = pagerUnlockDb(pPager, SHARED_LOCK);
- pPager->changeCountDone = 0;
}
pPager->eState = PAGER_READER;
pPager->setMaster = 0;
@@ -2585,15 +2585,16 @@ static int pager_delmaster(Pager *pPager, const char *zMaster){
rc = sqlite3OsFileSize(pMaster, &nMasterJournal);
if( rc!=SQLITE_OK ) goto delmaster_out;
nMasterPtr = pVfs->mxPathname+1;
- zMasterJournal = sqlite3Malloc(nMasterJournal + nMasterPtr + 1);
+ zMasterJournal = sqlite3Malloc(nMasterJournal + nMasterPtr + 2);
if( !zMasterJournal ){
rc = SQLITE_NOMEM_BKPT;
goto delmaster_out;
}
- zMasterPtr = &zMasterJournal[nMasterJournal+1];
+ 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;
zJournal = zMasterJournal;
while( (zJournal-zMasterJournal)=0 );
+ nUriByte = (int)(&z[1] - zUri);
+ assert( nUriByte>=1 );
if( rc==SQLITE_OK && nPathname+8>pVfs->mxPathname ){
/* This branch is taken when the journal path required by
** the database being opened will be more than pVfs->mxPathname
@@ -4820,50 +4832,86 @@ int sqlite3PagerOpen(
** Database file handle (pVfs->szOsFile bytes)
** Sub-journal file handle (journalFileSize bytes)
** Main journal file handle (journalFileSize bytes)
+ ** \0\1\0 journal prefix (3 bytes)
+ ** Journal filename (nPathname+8+1 bytes)
+ ** \2\0 WAL prefix (2 bytes)
+ ** WAL filename (nPathname+4+1 bytes)
+ ** \3\0 database prefix (2 bytes)
** Database file name (nPathname+1 bytes)
- ** Journal file name (nPathname+8+1 bytes)
+ ** URI query parameters (nUriByte bytes)
+ ** \0\0 terminator (2 bytes)
*/
pPtr = (u8 *)sqlite3MallocZero(
- ROUND8(sizeof(*pPager)) + /* Pager structure */
- ROUND8(pcacheSize) + /* PCache object */
- ROUND8(pVfs->szOsFile) + /* The main db file */
- journalFileSize * 2 + /* The two journal files */
- nPathname + 1 + nUri + /* zFilename */
- nPathname + 8 + 2 /* zJournal */
+ ROUND8(sizeof(*pPager)) + /* Pager structure */
+ ROUND8(pcacheSize) + /* PCache object */
+ ROUND8(pVfs->szOsFile) + /* The main db file */
+ journalFileSize * 2 + /* The two journal files */
+ 3 + /* Journal prefix */
+ nPathname + 8 + 1 + /* Journal filename */
#ifndef SQLITE_OMIT_WAL
- + nPathname + 4 + 2 /* zWal */
+ 2 + /* WAL prefix */
+ nPathname + 4 + 1 + /* WAL filename */
#endif
+ 2 + /* Database prefix */
+ nPathname + 1 + /* database filename */
+ nUriByte + /* query parameters */
+ 2 /* Terminator */
);
assert( EIGHT_BYTE_ALIGNMENT(SQLITE_INT_TO_PTR(journalFileSize)) );
if( !pPtr ){
sqlite3DbFree(0, zPathname);
return SQLITE_NOMEM_BKPT;
}
- pPager = (Pager*)(pPtr);
- pPager->pPCache = (PCache*)(pPtr += ROUND8(sizeof(*pPager)));
- pPager->fd = (sqlite3_file*)(pPtr += ROUND8(pcacheSize));
- pPager->sjfd = (sqlite3_file*)(pPtr += ROUND8(pVfs->szOsFile));
- pPager->jfd = (sqlite3_file*)(pPtr += journalFileSize);
- pPager->zFilename = (char*)(pPtr += journalFileSize);
+ pPager = (Pager*)pPtr; pPtr += ROUND8(sizeof(*pPager));
+ pPager->pPCache = (PCache*)pPtr; pPtr += ROUND8(pcacheSize);
+ pPager->fd = (sqlite3_file*)pPtr; pPtr += ROUND8(pVfs->szOsFile);
+ pPager->sjfd = (sqlite3_file*)pPtr; pPtr += journalFileSize;
+ pPager->jfd = (sqlite3_file*)pPtr; pPtr += journalFileSize;
assert( EIGHT_BYTE_ALIGNMENT(pPager->jfd) );
- /* Fill in the Pager.zFilename and Pager.zJournal buffers, if required. */
- if( zPathname ){
- assert( nPathname>0 );
- pPager->zJournal = (char*)(pPtr += nPathname + 1 + nUri);
- memcpy(pPager->zFilename, zPathname, nPathname);
- if( nUri ) memcpy(&pPager->zFilename[nPathname+1], zUri, nUri);
- memcpy(pPager->zJournal, zPathname, nPathname);
- memcpy(&pPager->zJournal[nPathname], "-journal\000", 8+2);
- sqlite3FileSuffix3(pPager->zFilename, pPager->zJournal);
-#ifndef SQLITE_OMIT_WAL
- pPager->zWal = &pPager->zJournal[nPathname+8+1];
- memcpy(pPager->zWal, zPathname, nPathname);
- memcpy(&pPager->zWal[nPathname], "-wal\000", 4+1);
- sqlite3FileSuffix3(pPager->zFilename, pPager->zWal);
+
+ /* Fill in Pager.zJournal */
+ pPtr[1] = '\001'; pPtr += 3;
+ if( nPathname>0 ){
+ pPager->zJournal = (char*)pPtr;
+ memcpy(pPtr, zPathname, nPathname); pPtr += nPathname;
+ memcpy(pPtr, "-journal",8); pPtr += 8 + 1;
+#ifdef SQLITE_ENABLE_8_3_NAMES
+ sqlite3FileSuffix3(zFilename,pPager->zJournal);
+ pPtr = (u8*)(pPager->zJournal + sqlite3Strlen30(pPager->zJournal)+1);
#endif
- sqlite3DbFree(0, zPathname);
+ }else{
+ pPager->zJournal = 0;
+ pPtr++;
}
+
+#ifndef SQLITE_OMIT_WAL
+ /* Fill in Pager.zWal */
+ pPtr[0] = '\002'; pPtr[1] = 0; pPtr += 2;
+ if( nPathname>0 ){
+ pPager->zWal = (char*)pPtr;
+ memcpy(pPtr, zPathname, nPathname); pPtr += nPathname;
+ memcpy(pPtr, "-wal", 4); pPtr += 4 + 1;
+#ifdef SQLITE_ENABLE_8_3_NAMES
+ sqlite3FileSuffix3(zFilename, pPager->zWal);
+ pPtr = (u8*)(pPager->zWal + sqlite3Strlen30(pPager->zWal)+1);
+#endif
+ }else{
+ pPager->zWal = 0;
+ pPtr++;
+ }
+#endif
+
+ /* Fill in the Pager.zFilename and pPager.zQueryParam fields */
+ pPtr[0] = '\003'; pPtr[1] = 0; pPtr += 2;
+ pPager->zFilename = (char*)pPtr;
+ memcpy(pPtr, zPathname, nPathname); pPtr += nPathname + 1;
+ if( zUri ){
+ memcpy(pPtr, zUri, nUriByte); /* pPtr += nUriByte; // not needed */
+ }
+ /* Double-zero terminator implied by the sqlite3MallocZero */
+
+ if( nPathname ) sqlite3DbFree(0, zPathname);
pPager->pVfs = pVfs;
pPager->vfsFlags = vfsFlags;
@@ -4912,9 +4960,9 @@ int sqlite3PagerOpen(
}
#endif
}
- pPager->noLock = sqlite3_uri_boolean(zFilename, "nolock", 0);
+ pPager->noLock = sqlite3_uri_boolean(pPager->zFilename, "nolock", 0);
if( (iDc & SQLITE_IOCAP_IMMUTABLE)!=0
- || sqlite3_uri_boolean(zFilename, "immutable", 0) ){
+ || sqlite3_uri_boolean(pPager->zFilename, "immutable", 0) ){
vfsFlags |= SQLITE_OPEN_READONLY;
goto act_like_temp_file;
}
@@ -6605,6 +6653,7 @@ int sqlite3PagerCommitPhaseTwo(Pager *pPager){
** But if (due to a coding error elsewhere in the system) it does get
** called, just return the same error code without doing anything. */
if( NEVER(pPager->errCode) ) return pPager->errCode;
+ pPager->iDataVersion++;
assert( pPager->eState==PAGER_WRITER_LOCKED
|| pPager->eState==PAGER_WRITER_FINISHED
@@ -6633,7 +6682,6 @@ int sqlite3PagerCommitPhaseTwo(Pager *pPager){
}
PAGERTRACE(("COMMIT %d\n", PAGERID(pPager)));
- pPager->iDataVersion++;
rc = pager_end_transaction(pPager, pPager->setMaster, 1);
return pager_error(pPager, rc);
}
@@ -6977,9 +7025,13 @@ int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint){
** behavior. But when the Btree needs to know the filename for matching to
** shared cache, it uses nullIfMemDb==0 so that in-memory databases can
** participate in shared-cache.
+**
+** The return value to this routine is always safe to use with
+** sqlite3_uri_parameter() and sqlite3_filename_database() and friends.
*/
-const char *sqlite3PagerFilename(Pager *pPager, int nullIfMemDb){
- return (nullIfMemDb && pPager->memDb) ? "" : pPager->zFilename;
+const char *sqlite3PagerFilename(const Pager *pPager, int nullIfMemDb){
+ static const char zFake[] = { 0x01, 0x00, 0x00, 0x00 };
+ return (nullIfMemDb && pPager->memDb) ? &zFake[2] : pPager->zFilename;
}
/*
@@ -7641,6 +7693,8 @@ int sqlite3PagerCloseWal(Pager *pPager, sqlite3 *db){
return rc;
}
+
+
#ifdef SQLITE_ENABLE_SNAPSHOT
/*
** If this is a WAL database, obtain a snapshot handle for the snapshot
diff --git a/src/pager.h b/src/pager.h
index d363fef4c3..c0c39e47cc 100644
--- a/src/pager.h
+++ b/src/pager.h
@@ -220,7 +220,7 @@ u32 sqlite3PagerDataVersion(Pager*);
int sqlite3PagerRefcount(Pager*);
#endif
int sqlite3PagerMemUsed(Pager*);
-const char *sqlite3PagerFilename(Pager*, int);
+const char *sqlite3PagerFilename(const Pager*, int);
sqlite3_vfs *sqlite3PagerVfs(Pager*);
sqlite3_file *sqlite3PagerFile(Pager*);
sqlite3_file *sqlite3PagerJrnlFile(Pager*);
diff --git a/src/parse.y b/src/parse.y
index 2b69dd596d..5876a1aee3 100644
--- a/src/parse.y
+++ b/src/parse.y
@@ -106,8 +106,9 @@ struct FrameBound { int eType; Expr *pExpr; };
** shared across database connections.
*/
static void disableLookaside(Parse *pParse){
+ sqlite3 *db = pParse->db;
pParse->disableLookaside++;
- pParse->db->lookaside.bDisable++;
+ DisableLookaside;
}
} // end %include
@@ -119,7 +120,7 @@ cmdlist ::= ecmd.
ecmd ::= SEMI.
ecmd ::= cmdx SEMI.
%ifndef SQLITE_OMIT_EXPLAIN
-ecmd ::= explain cmdx.
+ecmd ::= explain cmdx SEMI. {NEVER-REDUCE}
explain ::= EXPLAIN. { pParse->explain = 1; }
explain ::= EXPLAIN QUERY PLAN. { pParse->explain = 2; }
%endif SQLITE_OMIT_EXPLAIN
@@ -219,6 +220,9 @@ columnname(A) ::= nm(A) typetoken(Y). {sqlite3AddColumn(pParse,&A,&Y);}
CURRENT FOLLOWING PARTITION PRECEDING RANGE UNBOUNDED
EXCLUDE GROUPS OTHERS TIES
%endif SQLITE_OMIT_WINDOWFUNC
+%ifndef SQLITE_OMIT_GENERATED_COLUMNS
+ GENERATED ALWAYS
+%endif
REINDEX RENAME CTIME_KW IF
.
%wildcard ANY.
@@ -346,6 +350,10 @@ ccons ::= REFERENCES nm(T) eidlist_opt(TA) refargs(R).
{sqlite3CreateForeignKey(pParse,0,&T,TA,R);}
ccons ::= defer_subclause(D). {sqlite3DeferForeignKey(pParse,D);}
ccons ::= COLLATE ids(C). {sqlite3AddCollateType(pParse, &C);}
+ccons ::= GENERATED ALWAYS AS generated.
+ccons ::= AS generated.
+generated ::= LP expr(E) RP. {sqlite3AddGenerated(pParse,E,0);}
+generated ::= LP expr(E) RP ID(TYPE). {sqlite3AddGenerated(pParse,E,&TYPE);}
// The optional AUTOINCREMENT keyword
%type autoinc {int}
@@ -1070,6 +1078,9 @@ expr(A) ::= LP nexprlist(X) COMMA expr(Y) RP. {
A = sqlite3PExpr(pParse, TK_VECTOR, 0, 0);
if( A ){
A->x.pList = pList;
+ if( ALWAYS(pList->nExpr) ){
+ A->flags |= pList->a[0].pExpr->flags & EP_Propagate;
+ }
}else{
sqlite3ExprListDelete(pParse->db, pList);
}
diff --git a/src/pcache1.c b/src/pcache1.c
index d0051433de..ed762ebf70 100644
--- a/src/pcache1.c
+++ b/src/pcache1.c
@@ -448,13 +448,15 @@ static PgHdr1 *pcache1AllocPage(PCache1 *pCache, int benignMalloc){
}
#else
pPg = pcache1Alloc(pCache->szAlloc);
- p = (PgHdr1 *)&((u8 *)pPg)[pCache->szPage];
#endif
if( benignMalloc ){ sqlite3EndBenignMalloc(); }
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
pcache1EnterMutex(pCache->pGroup);
#endif
if( pPg==0 ) return 0;
+#ifndef SQLITE_PCACHE_SEPARATE_HEADER
+ p = (PgHdr1 *)&((u8 *)pPg)[pCache->szPage];
+#endif
p->page.pBuf = pPg;
p->page.pExtra = &p[1];
p->isBulkLocal = 0;
diff --git a/src/pragma.c b/src/pragma.c
index 4e983949a7..b88637c51c 100644
--- a/src/pragma.c
+++ b/src/pragma.c
@@ -296,6 +296,55 @@ static const PragmaName *pragmaLocate(const char *zName){
return lwr>upr ? 0 : &aPragmaName[mid];
}
+/*
+** Create zero or more entries in the output for the SQL functions
+** defined by FuncDef p.
+*/
+static void pragmaFunclistLine(
+ Vdbe *v, /* The prepared statement being created */
+ FuncDef *p, /* A particular function definition */
+ int isBuiltin, /* True if this is a built-in function */
+ int showInternFuncs /* True if showing internal functions */
+){
+ for(; p; p=p->pNext){
+ const char *zType;
+ static const u32 mask =
+ SQLITE_DETERMINISTIC |
+ SQLITE_DIRECTONLY |
+ SQLITE_SUBTYPE |
+ SQLITE_INNOCUOUS |
+ SQLITE_FUNC_INTERNAL
+ ;
+ static const char *azEnc[] = { 0, "utf8", "utf16le", "utf16be" };
+
+ assert( SQLITE_FUNC_ENCMASK==0x3 );
+ assert( strcmp(azEnc[SQLITE_UTF8],"utf8")==0 );
+ assert( strcmp(azEnc[SQLITE_UTF16LE],"utf16le")==0 );
+ assert( strcmp(azEnc[SQLITE_UTF16BE],"utf16be")==0 );
+
+ if( p->xSFunc==0 ) continue;
+ if( (p->funcFlags & SQLITE_FUNC_INTERNAL)!=0
+ && showInternFuncs==0
+ ){
+ continue;
+ }
+ if( p->xValue!=0 ){
+ zType = "w";
+ }else if( p->xFinalize!=0 ){
+ zType = "a";
+ }else{
+ zType = "s";
+ }
+ sqlite3VdbeMultiLoad(v, 1, "sissii",
+ p->zName, isBuiltin,
+ zType, azEnc[p->funcFlags&SQLITE_FUNC_ENCMASK],
+ p->nArg,
+ (p->funcFlags & mask) ^ SQLITE_INNOCUOUS
+ );
+ }
+}
+
+
/*
** Helper subroutine for PRAGMA integrity_check:
**
@@ -1101,10 +1150,19 @@ void sqlite3Pragma(
sqlite3CodeVerifySchema(pParse, iTabDb);
sqlite3ViewGetColumnNames(pParse, pTab);
for(i=0, pCol=pTab->aCol; inCol; i++, pCol++){
- int isHidden = IsHiddenColumn(pCol);
- if( isHidden && pPragma->iArg==0 ){
- nHidden++;
- continue;
+ int isHidden = 0;
+ if( pCol->colFlags & COLFLAG_NOINSERT ){
+ if( pPragma->iArg==0 ){
+ nHidden++;
+ continue;
+ }
+ if( pCol->colFlags & COLFLAG_VIRTUAL ){
+ isHidden = 2; /* GENERATED ALWAYS AS ... VIRTUAL */
+ }else if( pCol->colFlags & COLFLAG_STORED ){
+ isHidden = 3; /* GENERATED ALWAYS AS ... STORED */
+ }else{ assert( pCol->colFlags & COLFLAG_HIDDEN );
+ isHidden = 1; /* HIDDEN */
+ }
}
if( (pCol->colFlags & COLFLAG_PRIMKEY)==0 ){
k = 0;
@@ -1113,13 +1171,13 @@ void sqlite3Pragma(
}else{
for(k=1; k<=pTab->nCol && pPk->aiColumn[k-1]!=i; k++){}
}
- assert( pCol->pDflt==0 || pCol->pDflt->op==TK_SPAN );
+ assert( pCol->pDflt==0 || pCol->pDflt->op==TK_SPAN || isHidden>=2 );
sqlite3VdbeMultiLoad(v, 1, pPragma->iArg ? "issisii" : "issisi",
i-nHidden,
pCol->zName,
sqlite3ColumnType(pCol,""),
pCol->notNull ? 1 : 0,
- pCol->pDflt ? pCol->pDflt->u.zToken : 0,
+ pCol->pDflt && isHidden<2 ? pCol->pDflt->u.zToken : 0,
k,
isHidden);
}
@@ -1251,16 +1309,16 @@ void sqlite3Pragma(
int i;
HashElem *j;
FuncDef *p;
- pParse->nMem = 2;
+ int showInternFunc = (db->mDbFlags & DBFLAG_InternalFunc)!=0;
+ pParse->nMem = 6;
for(i=0; iu.pHash ){
- if( p->funcFlags & SQLITE_FUNC_INTERNAL ) continue;
- sqlite3VdbeMultiLoad(v, 1, "si", p->zName, 1);
+ pragmaFunclistLine(v, p, 1, showInternFunc);
}
}
for(j=sqliteHashFirst(&db->aFunc); j; j=sqliteHashNext(j)){
p = (FuncDef*)sqliteHashData(j);
- sqlite3VdbeMultiLoad(v, 1, "si", p->zName, 0);
+ pragmaFunclistLine(v, p, 0, showInternFunc);
}
}
break;
@@ -1578,7 +1636,7 @@ void sqlite3Pragma(
loopTop = sqlite3VdbeAddOp2(v, OP_AddImm, 7, 1);
if( !isQuick ){
/* Sanity check on record header decoding */
- sqlite3VdbeAddOp3(v, OP_Column, iDataCur, pTab->nCol-1, 3);
+ sqlite3VdbeAddOp3(v, OP_Column, iDataCur, pTab->nNVCol-1,3);
sqlite3VdbeChangeP5(v, OPFLAG_TYPEOFARG);
}
/* Verify that all NOT NULL columns really are NOT NULL */
@@ -1588,7 +1646,9 @@ void sqlite3Pragma(
if( j==pTab->iPKey ) continue;
if( pTab->aCol[j].notNull==0 ) continue;
sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, j, 3);
- sqlite3VdbeChangeP5(v, OPFLAG_TYPEOFARG);
+ if( sqlite3VdbeGetOp(v,-1)->opcode==OP_Column ){
+ sqlite3VdbeChangeP5(v, OPFLAG_TYPEOFARG);
+ }
jmp2 = sqlite3VdbeAddOp1(v, OP_NotNull, 3); VdbeCoverage(v);
zErr = sqlite3MPrintf(db, "NULL value in %s.%s", pTab->zName,
pTab->aCol[j].zName);
@@ -2081,6 +2141,27 @@ void sqlite3Pragma(
break;
}
+ /*
+ ** PRAGMA hard_heap_limit
+ ** PRAGMA hard_heap_limit = N
+ **
+ ** Invoke sqlite3_hard_heap_limit64() to query or set the hard heap
+ ** limit. The hard heap limit can be activated or lowered by this
+ ** pragma, but not raised or deactivated. Only the
+ ** sqlite3_hard_heap_limit64() C-language API can raise or deactivate
+ ** the hard heap limit. This allows an application to set a heap limit
+ ** constraint that cannot be relaxed by an untrusted SQL script.
+ */
+ case PragTyp_HARD_HEAP_LIMIT: {
+ sqlite3_int64 N;
+ if( zRight && sqlite3DecOrHexToI64(zRight, &N)==SQLITE_OK ){
+ sqlite3_int64 iPrior = sqlite3_hard_heap_limit64(-1);
+ if( N>0 && (iPrior==0 || iPrior>N) ) sqlite3_hard_heap_limit64(N);
+ }
+ returnSingleInt(v, sqlite3_hard_heap_limit64(-1));
+ break;
+ }
+
/*
** PRAGMA threads
** PRAGMA threads = N
diff --git a/src/pragma.h b/src/pragma.h
index b7f3282ded..3edf5c1c30 100644
--- a/src/pragma.h
+++ b/src/pragma.h
@@ -21,34 +21,35 @@
#define PragTyp_FOREIGN_KEY_CHECK 13
#define PragTyp_FOREIGN_KEY_LIST 14
#define PragTyp_FUNCTION_LIST 15
-#define PragTyp_INCREMENTAL_VACUUM 16
-#define PragTyp_INDEX_INFO 17
-#define PragTyp_INDEX_LIST 18
-#define PragTyp_INTEGRITY_CHECK 19
-#define PragTyp_JOURNAL_MODE 20
-#define PragTyp_JOURNAL_SIZE_LIMIT 21
-#define PragTyp_LOCK_PROXY_FILE 22
-#define PragTyp_LOCKING_MODE 23
-#define PragTyp_PAGE_COUNT 24
-#define PragTyp_MMAP_SIZE 25
-#define PragTyp_MODULE_LIST 26
-#define PragTyp_OPTIMIZE 27
-#define PragTyp_PAGE_SIZE 28
-#define PragTyp_PRAGMA_LIST 29
-#define PragTyp_SECURE_DELETE 30
-#define PragTyp_SHRINK_MEMORY 31
-#define PragTyp_SOFT_HEAP_LIMIT 32
-#define PragTyp_SYNCHRONOUS 33
-#define PragTyp_TABLE_INFO 34
-#define PragTyp_TEMP_STORE 35
-#define PragTyp_TEMP_STORE_DIRECTORY 36
-#define PragTyp_THREADS 37
-#define PragTyp_WAL_AUTOCHECKPOINT 38
-#define PragTyp_WAL_CHECKPOINT 39
-#define PragTyp_ACTIVATE_EXTENSIONS 40
-#define PragTyp_KEY 41
-#define PragTyp_LOCK_STATUS 42
-#define PragTyp_STATS 43
+#define PragTyp_HARD_HEAP_LIMIT 16
+#define PragTyp_INCREMENTAL_VACUUM 17
+#define PragTyp_INDEX_INFO 18
+#define PragTyp_INDEX_LIST 19
+#define PragTyp_INTEGRITY_CHECK 20
+#define PragTyp_JOURNAL_MODE 21
+#define PragTyp_JOURNAL_SIZE_LIMIT 22
+#define PragTyp_LOCK_PROXY_FILE 23
+#define PragTyp_LOCKING_MODE 24
+#define PragTyp_PAGE_COUNT 25
+#define PragTyp_MMAP_SIZE 26
+#define PragTyp_MODULE_LIST 27
+#define PragTyp_OPTIMIZE 28
+#define PragTyp_PAGE_SIZE 29
+#define PragTyp_PRAGMA_LIST 30
+#define PragTyp_SECURE_DELETE 31
+#define PragTyp_SHRINK_MEMORY 32
+#define PragTyp_SOFT_HEAP_LIMIT 33
+#define PragTyp_SYNCHRONOUS 34
+#define PragTyp_TABLE_INFO 35
+#define PragTyp_TEMP_STORE 36
+#define PragTyp_TEMP_STORE_DIRECTORY 37
+#define PragTyp_THREADS 38
+#define PragTyp_WAL_AUTOCHECKPOINT 39
+#define PragTyp_WAL_CHECKPOINT 40
+#define PragTyp_ACTIVATE_EXTENSIONS 41
+#define PragTyp_KEY 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 */
@@ -87,35 +88,39 @@ static const char *const pragCName[] = {
/* 18 */ "desc",
/* 19 */ "coll",
/* 20 */ "key",
- /* 21 */ "tbl", /* Used by: stats */
- /* 22 */ "idx",
- /* 23 */ "wdth",
- /* 24 */ "hght",
- /* 25 */ "flgs",
- /* 26 */ "seq", /* Used by: index_list */
- /* 27 */ "name",
- /* 28 */ "unique",
- /* 29 */ "origin",
- /* 30 */ "partial",
- /* 31 */ "table", /* Used by: foreign_key_check */
- /* 32 */ "rowid",
- /* 33 */ "parent",
- /* 34 */ "fkid",
+ /* 21 */ "name", /* Used by: function_list */
+ /* 22 */ "builtin",
+ /* 23 */ "type",
+ /* 24 */ "enc",
+ /* 25 */ "narg",
+ /* 26 */ "flags",
+ /* 27 */ "tbl", /* Used by: stats */
+ /* 28 */ "idx",
+ /* 29 */ "wdth",
+ /* 30 */ "hght",
+ /* 31 */ "flgs",
+ /* 32 */ "seq", /* Used by: index_list */
+ /* 33 */ "name",
+ /* 34 */ "unique",
+ /* 35 */ "origin",
+ /* 36 */ "partial",
+ /* 37 */ "table", /* Used by: foreign_key_check */
+ /* 38 */ "rowid",
+ /* 39 */ "parent",
+ /* 40 */ "fkid",
/* index_info reuses 15 */
- /* 35 */ "seq", /* Used by: database_list */
- /* 36 */ "name",
- /* 37 */ "file",
- /* 38 */ "busy", /* Used by: wal_checkpoint */
- /* 39 */ "log",
- /* 40 */ "checkpointed",
- /* 41 */ "name", /* Used by: function_list */
- /* 42 */ "builtin",
- /* collation_list reuses 26 */
- /* 43 */ "database", /* Used by: lock_status */
- /* 44 */ "status",
- /* 45 */ "cache_size", /* Used by: default_cache_size */
+ /* 41 */ "seq", /* Used by: database_list */
+ /* 42 */ "name",
+ /* 43 */ "file",
+ /* 44 */ "busy", /* Used by: wal_checkpoint */
+ /* 45 */ "log",
+ /* 46 */ "checkpointed",
+ /* collation_list reuses 32 */
+ /* 47 */ "database", /* Used by: lock_status */
+ /* 48 */ "status",
+ /* 49 */ "cache_size", /* Used by: default_cache_size */
/* module_list pragma_list reuses 9 */
- /* 46 */ "timeout", /* Used by: busy_timeout */
+ /* 50 */ "timeout", /* Used by: busy_timeout */
};
/* Definitions of all built-in pragmas */
@@ -161,7 +166,7 @@ static const PragmaName aPragmaName[] = {
{/* zName: */ "busy_timeout",
/* ePragTyp: */ PragTyp_BUSY_TIMEOUT,
/* ePragFlg: */ PragFlg_Result0,
- /* ColNames: */ 46, 1,
+ /* ColNames: */ 50, 1,
/* iArg: */ 0 },
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
{/* zName: */ "cache_size",
@@ -200,7 +205,7 @@ static const PragmaName aPragmaName[] = {
{/* zName: */ "collation_list",
/* ePragTyp: */ PragTyp_COLLATION_LIST,
/* ePragFlg: */ PragFlg_Result0,
- /* ColNames: */ 26, 2,
+ /* ColNames: */ 32, 2,
/* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_COMPILEOPTION_DIAGS)
@@ -235,14 +240,14 @@ static const PragmaName aPragmaName[] = {
{/* zName: */ "database_list",
/* ePragTyp: */ PragTyp_DATABASE_LIST,
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0,
- /* ColNames: */ 35, 3,
+ /* ColNames: */ 41, 3,
/* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && !defined(SQLITE_OMIT_DEPRECATED)
{/* zName: */ "default_cache_size",
/* ePragTyp: */ PragTyp_DEFAULT_CACHE_SIZE,
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1,
- /* ColNames: */ 45, 1,
+ /* ColNames: */ 49, 1,
/* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
@@ -272,7 +277,7 @@ static const PragmaName aPragmaName[] = {
{/* zName: */ "foreign_key_check",
/* ePragTyp: */ PragTyp_FOREIGN_KEY_CHECK,
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0,
- /* ColNames: */ 31, 4,
+ /* ColNames: */ 37, 4,
/* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_FOREIGN_KEY)
@@ -315,10 +320,15 @@ static const PragmaName aPragmaName[] = {
{/* zName: */ "function_list",
/* ePragTyp: */ PragTyp_FUNCTION_LIST,
/* ePragFlg: */ PragFlg_Result0,
- /* ColNames: */ 41, 2,
+ /* ColNames: */ 21, 6,
/* iArg: */ 0 },
#endif
#endif
+ {/* zName: */ "hard_heap_limit",
+ /* ePragTyp: */ PragTyp_HARD_HEAP_LIMIT,
+ /* ePragFlg: */ PragFlg_Result0,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ 0 },
#if defined(SQLITE_HAS_CODEC)
{/* zName: */ "hexkey",
/* ePragTyp: */ PragTyp_KEY,
@@ -356,7 +366,7 @@ static const PragmaName aPragmaName[] = {
{/* zName: */ "index_list",
/* ePragTyp: */ PragTyp_INDEX_LIST,
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt,
- /* ColNames: */ 26, 5,
+ /* ColNames: */ 32, 5,
/* iArg: */ 0 },
{/* zName: */ "index_xinfo",
/* ePragTyp: */ PragTyp_INDEX_INFO,
@@ -396,11 +406,6 @@ static const PragmaName aPragmaName[] = {
/* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1,
/* ColNames: */ 0, 0,
/* iArg: */ SQLITE_LegacyAlter },
- {/* zName: */ "legacy_file_format",
- /* ePragTyp: */ PragTyp_FLAG,
- /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1,
- /* ColNames: */ 0, 0,
- /* iArg: */ SQLITE_LegacyFileFmt },
#endif
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && SQLITE_ENABLE_LOCKING_STYLE
{/* zName: */ "lock_proxy_file",
@@ -413,7 +418,7 @@ static const PragmaName aPragmaName[] = {
{/* zName: */ "lock_status",
/* ePragTyp: */ PragTyp_LOCK_STATUS,
/* ePragFlg: */ PragFlg_Result0,
- /* ColNames: */ 43, 2,
+ /* ColNames: */ 47, 2,
/* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
@@ -561,7 +566,7 @@ static const PragmaName aPragmaName[] = {
{/* zName: */ "stats",
/* ePragTyp: */ PragTyp_STATS,
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq,
- /* ColNames: */ 21, 5,
+ /* ColNames: */ 27, 5,
/* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
@@ -612,6 +617,13 @@ static const PragmaName aPragmaName[] = {
/* ePragFlg: */ PragFlg_Result0,
/* ColNames: */ 0, 0,
/* iArg: */ 0 },
+#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
+ {/* zName: */ "trusted_schema",
+ /* ePragTyp: */ PragTyp_FLAG,
+ /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ SQLITE_TrustedSchema },
+#endif
#if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)
{/* zName: */ "user_version",
/* ePragTyp: */ PragTyp_HEADER_VALUE,
@@ -657,7 +669,7 @@ static const PragmaName aPragmaName[] = {
{/* zName: */ "wal_checkpoint",
/* ePragTyp: */ PragTyp_WAL_CHECKPOINT,
/* ePragFlg: */ PragFlg_NeedSchema,
- /* ColNames: */ 38, 3,
+ /* ColNames: */ 44, 3,
/* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
@@ -668,4 +680,4 @@ static const PragmaName aPragmaName[] = {
/* iArg: */ SQLITE_WriteSchema|SQLITE_NoSchemaError },
#endif
};
-/* Number of pragmas: 65 on by default, 81 total. */
+/* Number of pragmas: 66 on by default, 82 total. */
diff --git a/src/prepare.c b/src/prepare.c
index 70c162658a..2d928f16e7 100644
--- a/src/prepare.c
+++ b/src/prepare.c
@@ -57,6 +57,18 @@ int sqlite3IndexHasDuplicateRootPage(Index *pIndex){
return 0;
}
+/* forward declaration */
+static int sqlite3Prepare(
+ sqlite3 *db, /* Database handle. */
+ const char *zSql, /* UTF-8 encoded SQL statement. */
+ int nBytes, /* Length of zSql in bytes. */
+ u32 prepFlags, /* Zero or more SQLITE_PREPARE_* flags */
+ Vdbe *pReprepare, /* VM being reprepared */
+ sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */
+ const char **pzTail /* OUT: End of parsed string */
+);
+
+
/*
** This is the callback routine for the code that initializes the
** database. See sqlite3Init() below for additional information.
@@ -106,7 +118,8 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){
db->init.newTnum = sqlite3Atoi(argv[3]);
db->init.orphanTrigger = 0;
db->init.azInit = argv;
- TESTONLY(rcp = ) sqlite3_prepare(db, argv[4], -1, &pStmt, 0);
+ pStmt = 0;
+ TESTONLY(rcp = ) sqlite3Prepare(db, argv[4], -1, 0, 0, &pStmt, 0);
rc = db->errCode;
assert( (rc&0xFF)==(rcp&0xFF) );
db->init.iDb = saved_iDb;
@@ -527,6 +540,7 @@ void sqlite3ParserReset(Parse *pParse){
if( db ){
assert( db->lookaside.bDisable >= pParse->disableLookaside );
db->lookaside.bDisable -= pParse->disableLookaside;
+ db->lookaside.sz = db->lookaside.bDisable ? 0 : db->lookaside.szTrue;
}
pParse->disableLookaside = 0;
}
@@ -560,7 +574,7 @@ static int sqlite3Prepare(
*/
if( prepFlags & SQLITE_PREPARE_PERSISTENT ){
sParse.disableLookaside++;
- db->lookaside.bDisable++;
+ DisableLookaside;
}
sParse.disableVtab = (prepFlags & SQLITE_PREPARE_NO_VTAB)!=0;
@@ -587,16 +601,18 @@ static int sqlite3Prepare(
** but it does *not* override schema lock detection, so this all still
** works even if READ_UNCOMMITTED is set.
*/
- for(i=0; inDb; i++) {
- Btree *pBt = db->aDb[i].pBt;
- if( pBt ){
- assert( sqlite3BtreeHoldsMutex(pBt) );
- rc = sqlite3BtreeSchemaLocked(pBt);
- if( rc ){
- const char *zDb = db->aDb[i].zDbSName;
- sqlite3ErrorWithMsg(db, rc, "database schema is locked: %s", zDb);
- testcase( db->flags & SQLITE_ReadUncommit );
- goto end_prepare;
+ if( !db->noSharedCache ){
+ for(i=0; inDb; i++) {
+ Btree *pBt = db->aDb[i].pBt;
+ if( pBt ){
+ assert( sqlite3BtreeHoldsMutex(pBt) );
+ rc = sqlite3BtreeSchemaLocked(pBt);
+ if( rc ){
+ const char *zDb = db->aDb[i].zDbSName;
+ sqlite3ErrorWithMsg(db, rc, "database schema is locked: %s", zDb);
+ testcase( db->flags & SQLITE_ReadUncommit );
+ goto end_prepare;
+ }
}
}
}
@@ -627,48 +643,24 @@ static int sqlite3Prepare(
}
assert( 0==sParse.nQueryLoop );
- if( sParse.rc==SQLITE_DONE ) sParse.rc = SQLITE_OK;
+ if( sParse.rc==SQLITE_DONE ){
+ sParse.rc = SQLITE_OK;
+ }
if( sParse.checkSchema ){
schemaIsValid(&sParse);
}
- if( db->mallocFailed ){
- sParse.rc = SQLITE_NOMEM_BKPT;
- }
if( pzTail ){
*pzTail = sParse.zTail;
}
- rc = sParse.rc;
-
-#ifndef SQLITE_OMIT_EXPLAIN
- /* Justification for the ALWAYS(): The only way for rc to be SQLITE_OK and
- ** sParse.pVdbe to be NULL is if the input SQL is an empty string, but in
- ** that case, sParse.explain will be false. */
- if( sParse.explain && rc==SQLITE_OK && ALWAYS(sParse.pVdbe) ){
- static const char * const azColName[] = {
- "addr", "opcode", "p1", "p2", "p3", "p4", "p5", "comment",
- "id", "parent", "notused", "detail"
- };
- int iFirst, mx;
- if( sParse.explain==2 ){
- sqlite3VdbeSetNumCols(sParse.pVdbe, 4);
- iFirst = 8;
- mx = 12;
- }else{
- sqlite3VdbeSetNumCols(sParse.pVdbe, 8);
- iFirst = 0;
- mx = 8;
- }
- for(i=iFirst; iinit.busy==0 ){
sqlite3VdbeSetSql(sParse.pVdbe, zSql, (int)(sParse.zTail-zSql), prepFlags);
}
- if( rc!=SQLITE_OK || db->mallocFailed ){
+ if( db->mallocFailed ){
+ sParse.rc = SQLITE_NOMEM_BKPT;
+ }
+ rc = sParse.rc;
+ if( rc!=SQLITE_OK ){
if( sParse.pVdbe ) sqlite3VdbeFinalize(sParse.pVdbe);
assert(!(*ppStmt));
}else{
diff --git a/src/resolve.c b/src/resolve.c
index e66dc18eb8..3e5ac16e2e 100644
--- a/src/resolve.c
+++ b/src/resolve.c
@@ -132,13 +132,16 @@ static int nameInUsingClause(IdList *pUsing, const char *zCol){
** and zCol. If any of zDb, zTab, and zCol are NULL then those fields will
** match anything.
*/
-int sqlite3MatchSpanName(
- const char *zSpan,
+int sqlite3MatchEName(
+ const struct ExprList_item *pItem,
const char *zCol,
const char *zTab,
const char *zDb
){
int n;
+ const char *zSpan;
+ if( NEVER(pItem->eEName!=ENAME_TAB) ) return 0;
+ zSpan = pItem->zEName;
for(n=0; ALWAYS(zSpan[n]) && zSpan[n]!='.'; n++){}
if( zDb && (sqlite3StrNICmp(zSpan, zDb, n)!=0 || zDb[n]!=0) ){
return 0;
@@ -267,7 +270,7 @@ static int lookupName(
int hit = 0;
pEList = pItem->pSelect->pEList;
for(j=0; jnExpr; j++){
- if( sqlite3MatchSpanName(pEList->a[j].zSpan, zCol, zTab, zDb) ){
+ if( sqlite3MatchEName(&pEList->a[j], zCol, zTab, zDb) ){
cnt++;
cntTab = 2;
pMatch = pItem;
@@ -414,7 +417,7 @@ static int lookupName(
if( cnt==0
&& cntTab==1
&& pMatch
- && (pNC->ncFlags & NC_IdxExpr)==0
+ && (pNC->ncFlags & (NC_IdxExpr|NC_GenCol))==0
&& sqlite3IsRowid(zCol)
&& VisibleRowid(pMatch->pTab)
){
@@ -448,8 +451,10 @@ static int lookupName(
pEList = pNC->uNC.pEList;
assert( pEList!=0 );
for(j=0; jnExpr; j++){
- char *zAs = pEList->a[j].zName;
- if( zAs!=0 && sqlite3StrICmp(zAs, zCol)==0 ){
+ char *zAs = pEList->a[j].zEName;
+ if( pEList->a[j].eEName==ENAME_NAME
+ && sqlite3_stricmp(zAs, zCol)==0
+ ){
Expr *pOrig;
assert( pExpr->pLeft==0 && pExpr->pRight==0 );
assert( pExpr->x.pList==0 );
@@ -459,7 +464,9 @@ static int lookupName(
sqlite3ErrorMsg(pParse, "misuse of aliased aggregate %s", zAs);
return WRC_Abort;
}
- if( (pNC->ncFlags&NC_AllowWin)==0 && ExprHasProperty(pOrig, EP_Win) ){
+ if( ExprHasProperty(pOrig, EP_Win)
+ && ((pNC->ncFlags&NC_AllowWin)==0 || pNC!=pTopNC )
+ ){
sqlite3ErrorMsg(pParse, "misuse of aliased window function %s",zAs);
return WRC_Abort;
}
@@ -551,18 +558,35 @@ static int lookupName(
/* If a column from a table in pSrcList is referenced, then record
** this fact in the pSrcList.a[].colUsed bitmask. Column 0 causes
- ** bit 0 to be set. Column 1 sets bit 1. And so forth. If the
- ** column number is greater than the number of bits in the bitmask
- ** then set the high-order bit of the bitmask.
+ ** bit 0 to be set. Column 1 sets bit 1. And so forth. Bit 63 is
+ ** set if the 63rd or any subsequent column is used.
+ **
+ ** The colUsed mask is an optimization used to help determine if an
+ ** index is a covering index. The correct answer is still obtained
+ ** if the mask contains extra set bits. However, it is important to
+ ** avoid setting bits beyond the maximum column number of the table.
+ ** (See ticket [b92e5e8ec2cdbaa1]).
+ **
+ ** If a generated column is referenced, set bits for every column
+ ** of the table.
*/
if( pExpr->iColumn>=0 && pMatch!=0 ){
int n = pExpr->iColumn;
- testcase( n==BMS-1 );
- if( n>=BMS ){
- n = BMS-1;
- }
+ Table *pExTab = pExpr->y.pTab;
+ assert( pExTab!=0 );
assert( pMatch->iCursor==pExpr->iTable );
- pMatch->colUsed |= ((Bitmask)1)<tabFlags & TF_HasGenerated)!=0
+ && (pExTab->aCol[n].colFlags & COLFLAG_GENERATED)!=0
+ ){
+ testcase( pExTab->nCol==BMS-1 );
+ testcase( pExTab->nCol==BMS );
+ pMatch->colUsed = pExTab->nCol>=BMS ? ALLBITS : MASKBIT(pExTab->nCol)-1;
+ }else{
+ testcase( n==BMS-1 );
+ testcase( n==BMS );
+ if( n>=BMS ) n = BMS-1;
+ pMatch->colUsed |= ((Bitmask)1)<a[iSrc];
- p->y.pTab = pItem->pTab;
+ Table *pTab = p->y.pTab = pItem->pTab;
p->iTable = pItem->iCursor;
if( p->y.pTab->iPKey==iCol ){
p->iColumn = -1;
}else{
p->iColumn = (ynVar)iCol;
- testcase( iCol==BMS );
- testcase( iCol==BMS-1 );
- pItem->colUsed |= ((Bitmask)1)<<(iCol>=BMS ? BMS-1 : iCol);
+ if( (pTab->tabFlags & TF_HasGenerated)!=0
+ && (pTab->aCol[iCol].colFlags & COLFLAG_GENERATED)!=0
+ ){
+ testcase( pTab->nCol==63 );
+ testcase( pTab->nCol==64 );
+ pItem->colUsed = pTab->nCol>=64 ? ALLBITS : MASKBIT(pTab->nCol)-1;
+ }else{
+ testcase( iCol==BMS );
+ testcase( iCol==BMS-1 );
+ pItem->colUsed |= ((Bitmask)1)<<(iCol>=BMS ? BMS-1 : iCol);
+ }
}
}
return p;
@@ -618,23 +650,39 @@ Expr *sqlite3CreateColumnExpr(sqlite3 *db, SrcList *pSrc, int iSrc, int iCol){
/*
** Report an error that an expression is not valid for some set of
** pNC->ncFlags values determined by validMask.
+**
+** static void notValid(
+** Parse *pParse, // Leave error message here
+** NameContext *pNC, // The name context
+** const char *zMsg, // Type of error
+** int validMask, // Set of contexts for which prohibited
+** Expr *pExpr // Invalidate this expression on error
+** ){...}
+**
+** As an optimization, since the conditional is almost always false
+** (because errors are rare), the conditional is moved outside of the
+** function call using a macro.
*/
-static void notValid(
- Parse *pParse, /* Leave error message here */
- NameContext *pNC, /* The name context */
- const char *zMsg, /* Type of error */
- int validMask /* Set of contexts for which prohibited */
+static void notValidImpl(
+ Parse *pParse, /* Leave error message here */
+ NameContext *pNC, /* The name context */
+ const char *zMsg, /* Type of error */
+ Expr *pExpr /* Invalidate this expression on error */
){
- assert( (validMask&~(NC_IsCheck|NC_PartIdx|NC_IdxExpr))==0 );
- if( (pNC->ncFlags & validMask)!=0 ){
- const char *zIn = "partial index WHERE clauses";
- if( pNC->ncFlags & NC_IdxExpr ) zIn = "index expressions";
+ const char *zIn = "partial index WHERE clauses";
+ if( pNC->ncFlags & NC_IdxExpr ) zIn = "index expressions";
#ifndef SQLITE_OMIT_CHECK
- else if( pNC->ncFlags & NC_IsCheck ) zIn = "CHECK constraints";
+ else if( pNC->ncFlags & NC_IsCheck ) zIn = "CHECK constraints";
#endif
- sqlite3ErrorMsg(pParse, "%s prohibited in %s", zMsg, zIn);
- }
+#ifndef SQLITE_OMIT_GENERATED_COLUMNS
+ else if( pNC->ncFlags & NC_GenCol ) zIn = "generated columns";
+#endif
+ sqlite3ErrorMsg(pParse, "%s prohibited in %s", zMsg, zIn);
+ if( pExpr ) pExpr->op = TK_NULL;
}
+#define sqlite3ResolveNotValid(P,N,M,X,E) \
+ assert( ((X)&~(NC_IsCheck|NC_PartIdx|NC_IdxExpr|NC_GenCol))==0 ); \
+ if( ((N)->ncFlags & (X))!=0 ) notValidImpl(P,N,M,E);
/*
** Expression p should encode a floating point value between 1.0 and 0.0.
@@ -723,7 +771,10 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
zColumn = pExpr->u.zToken;
}else{
Expr *pLeft = pExpr->pLeft;
- notValid(pParse, pNC, "the \".\" operator", NC_IdxExpr);
+ testcase( pNC->ncFlags & NC_IdxExpr );
+ testcase( pNC->ncFlags & NC_GenCol );
+ sqlite3ResolveNotValid(pParse, pNC, "the \".\" operator",
+ NC_IdxExpr|NC_GenCol, 0);
pRight = pExpr->pRight;
if( pRight->op==TK_ID ){
zDb = 0;
@@ -812,33 +863,36 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
if( pDef->funcFlags & (SQLITE_FUNC_CONSTANT|SQLITE_FUNC_SLOCHNG) ){
/* For the purposes of the EP_ConstFunc flag, date and time
** functions and other functions that change slowly are considered
- ** constant because they are constant for the duration of one query */
+ ** constant because they are constant for the duration of one query.
+ ** This allows them to be factored out of inner loops. */
ExprSetProperty(pExpr,EP_ConstFunc);
}
if( (pDef->funcFlags & SQLITE_FUNC_CONSTANT)==0 ){
/* Date/time functions that use 'now', and other functions like
** sqlite_version() that might change over time cannot be used
** in an index. */
- notValid(pParse, pNC, "non-deterministic functions",
- NC_IdxExpr|NC_PartIdx);
+ sqlite3ResolveNotValid(pParse, pNC, "non-deterministic functions",
+ NC_SelfRef, 0);
+ }else{
+ assert( (NC_SelfRef & 0xff)==NC_SelfRef ); /* Must fit in 8 bits */
+ pExpr->op2 = pNC->ncFlags & NC_SelfRef;
+ if( pNC->ncFlags & NC_FromDDL ) ExprSetProperty(pExpr, EP_FromDDL);
}
if( (pDef->funcFlags & SQLITE_FUNC_INTERNAL)!=0
&& pParse->nested==0
- && sqlite3Config.bInternalFunctions==0
+ && (pParse->db->mDbFlags & DBFLAG_InternalFunc)==0
){
/* Internal-use-only functions are disallowed unless the
- ** SQL is being compiled using sqlite3NestedParse() */
+ ** SQL is being compiled using sqlite3NestedParse() or
+ ** the SQLITE_TESTCTRL_INTERNAL_FUNCTIONS test-control has be
+ ** used to activate internal functionsn for testing purposes */
no_such_func = 1;
pDef = 0;
}else
- if( (pDef->funcFlags & SQLITE_FUNC_DIRECT)!=0
- && ExprHasProperty(pExpr, EP_Indirect)
+ if( (pDef->funcFlags & (SQLITE_FUNC_DIRECT|SQLITE_FUNC_UNSAFE))!=0
&& !IN_RENAME_OBJECT
){
- /* Functions tagged with SQLITE_DIRECTONLY may not be used
- ** inside of triggers and views */
- sqlite3ErrorMsg(pParse, "%s() prohibited in triggers and views",
- pDef->zName);
+ sqlite3ExprFunctionUsable(pParse, pExpr, pDef);
}
}
@@ -919,7 +973,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
Select *pSel = pNC->pWinSelect;
assert( pWin==pExpr->y.pWin );
if( IN_RENAME_OBJECT==0 ){
- sqlite3WindowUpdate(pParse, pSel->pWinDefn, pWin, pDef);
+ sqlite3WindowUpdate(pParse, pSel ? pSel->pWinDefn : 0, pWin, pDef);
}
sqlite3WalkExprList(pWalker, pWin->pPartition);
sqlite3WalkExprList(pWalker, pWin->pOrderBy);
@@ -964,7 +1018,12 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
testcase( pExpr->op==TK_IN );
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
int nRef = pNC->nRef;
- notValid(pParse, pNC, "subqueries", NC_IsCheck|NC_PartIdx|NC_IdxExpr);
+ testcase( pNC->ncFlags & NC_IsCheck );
+ testcase( pNC->ncFlags & NC_PartIdx );
+ testcase( pNC->ncFlags & NC_IdxExpr );
+ testcase( pNC->ncFlags & NC_GenCol );
+ sqlite3ResolveNotValid(pParse, pNC, "subqueries",
+ NC_IsCheck|NC_PartIdx|NC_IdxExpr|NC_GenCol, pExpr);
sqlite3WalkSelect(pWalker, pExpr->x.pSelect);
assert( pNC->nRef>=nRef );
if( nRef!=pNC->nRef ){
@@ -975,7 +1034,12 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
break;
}
case TK_VARIABLE: {
- notValid(pParse, pNC, "parameters", NC_IsCheck|NC_PartIdx|NC_IdxExpr);
+ testcase( pNC->ncFlags & NC_IsCheck );
+ testcase( pNC->ncFlags & NC_PartIdx );
+ testcase( pNC->ncFlags & NC_IdxExpr );
+ testcase( pNC->ncFlags & NC_GenCol );
+ sqlite3ResolveNotValid(pParse, pNC, "parameters",
+ NC_IsCheck|NC_PartIdx|NC_IdxExpr|NC_GenCol, pExpr);
break;
}
case TK_IS:
@@ -1057,8 +1121,9 @@ static int resolveAsName(
if( pE->op==TK_ID ){
char *zCol = pE->u.zToken;
for(i=0; inExpr; i++){
- char *zAs = pEList->a[i].zName;
- if( zAs!=0 && sqlite3StrICmp(zAs, zCol)==0 ){
+ if( pEList->a[i].eEName==ENAME_NAME
+ && sqlite3_stricmp(pEList->a[i].zEName, zCol)==0
+ ){
return i+1;
}
}
@@ -1784,10 +1849,13 @@ void sqlite3ResolveSelectNames(
** Resolve names in expressions that can only reference a single table
** or which cannot reference any tables at all. Examples:
**
-** (1) CHECK constraints
-** (2) WHERE clauses on partial indices
-** (3) Expressions in indexes on expressions
-** (4) Expression arguments to VACUUM INTO.
+** "type" flag
+** ------------
+** (1) CHECK constraints NC_IsCheck
+** (2) WHERE clauses on partial indices NC_PartIdx
+** (3) Expressions in indexes on expressions NC_IdxExpr
+** (4) Expression arguments to VACUUM INTO. 0
+** (5) GENERATED ALWAYS as expressions NC_GenCol
**
** In all cases except (4), the Expr.iTable value for Expr.op==TK_COLUMN
** nodes of the expression is set to -1 and the Expr.iColumn value is
@@ -1796,18 +1864,19 @@ void sqlite3ResolveSelectNames(
** Any errors cause an error message to be set in pParse.
*/
int sqlite3ResolveSelfReference(
- Parse *pParse, /* Parsing context */
- Table *pTab, /* The table being referenced, or NULL */
- int type, /* NC_IsCheck or NC_PartIdx or NC_IdxExpr, or 0 */
- Expr *pExpr, /* Expression to resolve. May be NULL. */
- ExprList *pList /* Expression list to resolve. May be NULL. */
+ Parse *pParse, /* Parsing context */
+ Table *pTab, /* The table being referenced, or NULL */
+ int type, /* NC_IsCheck, NC_PartIdx, NC_IdxExpr, NC_GenCol, or 0 */
+ Expr *pExpr, /* Expression to resolve. May be NULL. */
+ ExprList *pList /* Expression list to resolve. May be NULL. */
){
SrcList sSrc; /* Fake SrcList for pParse->pNewTable */
NameContext sNC; /* Name context for pParse->pNewTable */
int rc;
assert( type==0 || pTab!=0 );
- assert( type==NC_IsCheck || type==NC_PartIdx || type==NC_IdxExpr || pTab==0 );
+ assert( type==NC_IsCheck || type==NC_PartIdx || type==NC_IdxExpr
+ || type==NC_GenCol || pTab==0 );
memset(&sNC, 0, sizeof(sNC));
memset(&sSrc, 0, sizeof(sSrc));
if( pTab ){
@@ -1815,6 +1884,11 @@ int sqlite3ResolveSelfReference(
sSrc.a[0].zName = pTab->zName;
sSrc.a[0].pTab = pTab;
sSrc.a[0].iCursor = -1;
+ if( pTab->pSchema!=pParse->db->aDb[1].pSchema ){
+ /* Cause EP_FromDDL to be set on TK_FUNCTION nodes of non-TEMP
+ ** schema elements */
+ type |= NC_FromDDL;
+ }
}
sNC.pParse = pParse;
sNC.pSrcList = &sSrc;
diff --git a/src/select.c b/src/select.c
index 6d18f75245..8df63dfffe 100644
--- a/src/select.c
+++ b/src/select.c
@@ -84,7 +84,10 @@ struct SortCtx {
/*
** Delete all the content of a Select structure. Deallocate the structure
-** itself only if bFree is true.
+** itself depending on the value of bFree
+**
+** If bFree==1, call sqlite3DbFree() on the p object.
+** If bFree==0, Leave the first Select object unfreed
*/
static void clearSelect(sqlite3 *db, Select *p, int bFree){
while( p ){
@@ -100,9 +103,9 @@ static void clearSelect(sqlite3 *db, Select *p, int bFree){
if( OK_IF_ALWAYS_TRUE(p->pWinDefn) ){
sqlite3WindowListDelete(db, p->pWinDefn);
}
+ assert( p->pWin==0 );
#endif
if( OK_IF_ALWAYS_TRUE(p->pWith) ) sqlite3WithDelete(db, p->pWith);
- assert( p->pWin==0 );
if( bFree ) sqlite3DbFreeNN(db, p);
p = pPrior;
bFree = 1;
@@ -188,6 +191,21 @@ void sqlite3SelectDelete(sqlite3 *db, Select *p){
if( OK_IF_ALWAYS_TRUE(p) ) clearSelect(db, p, 1);
}
+/*
+** 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.
*/
@@ -296,7 +314,8 @@ static int tableAndColumnIndex(
int N, /* Number of tables in pSrc->a[] to search */
const char *zCol, /* Name of the column we are looking for */
int *piTab, /* Write index of pSrc->a[] here */
- int *piCol /* Write index of pSrc->a[*piTab].pTab->aCol[] here */
+ int *piCol, /* Write index of pSrc->a[*piTab].pTab->aCol[] here */
+ int bIgnoreHidden /* True to ignore hidden columns */
){
int i; /* For looping over tables in pSrc */
int iCol; /* Index of column matching zCol */
@@ -304,7 +323,9 @@ static int tableAndColumnIndex(
assert( (piTab==0)==(piCol==0) ); /* Both or neither are NULL */
for(i=0; ia[i].pTab, zCol);
- if( iCol>=0 ){
+ if( iCol>=0
+ && (bIgnoreHidden==0 || IsHiddenColumn(&pSrc->a[i].pTab->aCol[iCol])==0)
+ ){
if( piTab ){
*piTab = i;
*piCol = iCol;
@@ -385,7 +406,7 @@ static void addWhereTerm(
** after the t1 loop and rows with t1.x!=5 will never appear in
** the output, which is incorrect.
*/
-static void setJoinExpr(Expr *p, int iTable){
+void sqlite3SetJoinExpr(Expr *p, int iTable){
while( p ){
ExprSetProperty(p, EP_FromJoin);
assert( !ExprHasProperty(p, EP_TokenOnly|EP_Reduced) );
@@ -394,15 +415,15 @@ static void setJoinExpr(Expr *p, int iTable){
if( p->op==TK_FUNCTION && p->x.pList ){
int i;
for(i=0; ix.pList->nExpr; i++){
- setJoinExpr(p->x.pList->a[i].pExpr, iTable);
+ sqlite3SetJoinExpr(p->x.pList->a[i].pExpr, iTable);
}
}
- setJoinExpr(p->pLeft, iTable);
+ sqlite3SetJoinExpr(p->pLeft, iTable);
p = p->pRight;
}
}
-/* Undo the work of setJoinExpr(). In the expression tree p, convert every
+/* Undo the work of sqlite3SetJoinExpr(). In the expression p, convert every
** term that is marked with EP_FromJoin and iRightJoinTable==iTable into
** an ordinary term that omits the EP_FromJoin mark.
**
@@ -469,10 +490,11 @@ static int sqliteProcessJoin(Parse *pParse, Select *p){
int iLeft; /* Matching left table */
int iLeftCol; /* Matching column in the left table */
+ if( IsHiddenColumn(&pRightTab->aCol[j]) ) continue;
zName = pRightTab->aCol[j].zName;
- if( tableAndColumnIndex(pSrc, i+1, zName, &iLeft, &iLeftCol) ){
+ if( tableAndColumnIndex(pSrc, i+1, zName, &iLeft, &iLeftCol, 1) ){
addWhereTerm(pParse, pSrc, iLeft, iLeftCol, i+1, j,
- isOuter, &p->pWhere);
+ isOuter, &p->pWhere);
}
}
}
@@ -489,7 +511,7 @@ static int sqliteProcessJoin(Parse *pParse, Select *p){
** an AND operator.
*/
if( pRight->pOn ){
- if( isOuter ) setJoinExpr(pRight->pOn, pRight->iCursor);
+ if( isOuter ) sqlite3SetJoinExpr(pRight->pOn, pRight->iCursor);
p->pWhere = sqlite3ExprAnd(pParse, p->pWhere, pRight->pOn);
pRight->pOn = 0;
}
@@ -512,7 +534,7 @@ static int sqliteProcessJoin(Parse *pParse, Select *p){
zName = pList->a[j].zName;
iRightCol = columnIndex(pRightTab, zName);
if( iRightCol<0
- || !tableAndColumnIndex(pSrc, i+1, zName, &iLeft, &iLeftCol)
+ || !tableAndColumnIndex(pSrc, i+1, zName, &iLeft, &iLeftCol, 0)
){
sqlite3ErrorMsg(pParse, "cannot join using column %s - column "
"not present in both tables", zName);
@@ -669,6 +691,7 @@ static void pushOntoSorter(
testcase( pKI->nAllField > pKI->nKeyField+2 );
pOp->p4.pKeyInfo = sqlite3KeyInfoFromExprList(pParse,pSort->pOrderBy,nOBSat,
pKI->nAllField-pKI->nKeyField-1);
+ pOp = 0; /* Ensure pOp not used after sqltie3VdbeAddOp3() */
addrJmp = sqlite3VdbeCurrentAddr(v);
sqlite3VdbeAddOp3(v, OP_Jump, addrJmp+1, 0, addrJmp+1); VdbeCoverage(v);
pSort->labelBkOut = sqlite3VdbeMakeLabel(pParse);
@@ -917,7 +940,7 @@ static void selectInnerLoop(
if( srcTab>=0 ){
for(i=0; ipEList->a[i].zName));
+ VdbeComment((v, "%s", p->pEList->a[i].zEName));
}
}else if( eDest!=SRT_Exists ){
#ifdef SQLITE_ENABLE_SORTER_REFERENCES
@@ -1031,6 +1054,7 @@ static void selectInnerLoop(
pOp->opcode = OP_Null;
pOp->p1 = 1;
pOp->p2 = regPrev;
+ pOp = 0; /* Ensure pOp is not used after sqlite3VdbeAddOp() */
iJump = sqlite3VdbeCurrentAddr(v) + nResultCol;
for(i=0; iop!=TK_AGG_COLUMN ); /* Agg processing has not run yet */
assert( p->op!=TK_COLUMN || p->y.pTab!=0 ); /* Covering idx not yet coded */
- if( pEList->a[i].zName ){
+ if( pEList->a[i].zEName && pEList->a[i].eEName==ENAME_NAME ){
/* An AS clause always takes first priority */
- char *zName = pEList->a[i].zName;
+ char *zName = pEList->a[i].zEName;
sqlite3VdbeSetColName(v, i, COLNAME_NAME, zName, SQLITE_TRANSIENT);
}else if( srcName && p->op==TK_COLUMN ){
char *zCol;
@@ -1895,7 +1919,7 @@ static void generateColumnNames(
sqlite3VdbeSetColName(v, i, COLNAME_NAME, zCol, SQLITE_TRANSIENT);
}
}else{
- const char *z = pEList->a[i].zSpan;
+ const char *z = pEList->a[i].zEName;
z = z==0 ? sqlite3MPrintf(db, "column%d", i+1) : sqlite3DbStrDup(db, z);
sqlite3VdbeSetColName(v, i, COLNAME_NAME, z, SQLITE_DYNAMIC);
}
@@ -1957,7 +1981,7 @@ int sqlite3ColumnsFromExprList(
for(i=0, pCol=aCol; imallocFailed; i++, pCol++){
/* Get an appropriate name for the column
*/
- if( (zName = pEList->a[i].zName)!=0 ){
+ if( (zName = pEList->a[i].zEName)!=0 && pEList->a[i].eEName==ENAME_NAME ){
/* If the column contains an "AS " phrase, use as the name */
}else{
Expr *pColExpr = sqlite3ExprSkipCollateAndLikely(pEList->a[i].pExpr);
@@ -1977,10 +2001,10 @@ int sqlite3ColumnsFromExprList(
zName = pColExpr->u.zToken;
}else{
/* Use the original text of the column expression as its name */
- zName = pEList->a[i].zSpan;
+ zName = pEList->a[i].zEName;
}
}
- if( zName ){
+ if( zName && !sqlite3IsTrueOrFalse(zName) ){
zName = sqlite3DbStrDup(db, zName);
}else{
zName = sqlite3MPrintf(db,"column%d",i+1);
@@ -2472,6 +2496,7 @@ static int multiSelectValues(
assert( p->selFlags & SF_Values );
assert( p->op==TK_ALL || (p->op==TK_SELECT && p->pPrior==0) );
assert( p->pNext==0 || p->pEList->nExpr==p->pNext->pEList->nExpr );
+ if( p->pWin ) return -1;
if( p->pPrior==0 ) break;
assert( p->pPrior->pNext==p );
p = p->pPrior;
@@ -2562,7 +2587,8 @@ static int multiSelect(
*/
if( p->selFlags & SF_MultiValue ){
rc = multiSelectValues(pParse, p, &dest);
- goto multi_select_end;
+ if( rc>=0 ) goto multi_select_end;
+ rc = SQLITE_OK;
}
/* Make sure all SELECTs in the statement have the same number of elements
@@ -2707,9 +2733,9 @@ static int multiSelect(
** it is that we currently need.
*/
assert( unionTab==dest.iSDParm || dest.eDest!=priorOp );
- if( dest.eDest!=priorOp ){
+ assert( p->pEList || db->mallocFailed );
+ if( dest.eDest!=priorOp && db->mallocFailed==0 ){
int iCont, iBreak, iStart;
- assert( p->pEList );
iBreak = sqlite3VdbeMakeLabel(pParse);
iCont = sqlite3VdbeMakeLabel(pParse);
computeLimitRegisters(pParse, p, iBreak);
@@ -2805,6 +2831,7 @@ static int multiSelect(
}
#endif
}
+ if( pParse->nErr ) goto multi_select_end;
/* Compute collating sequences used by
** temporary tables needed to implement the compound select.
@@ -3503,6 +3530,14 @@ static Expr *substExpr(
}else{
substExprList(pSubst, pExpr->x.pList);
}
+#ifndef SQLITE_OMIT_WINDOWFUNC
+ if( ExprHasProperty(pExpr, EP_WinFunc) ){
+ Window *pWin = pExpr->y.pWin;
+ pWin->pFilter = substExpr(pSubst, pWin->pFilter);
+ substExprList(pSubst, pWin->pPartition);
+ substExprList(pSubst, pWin->pOrderBy);
+ }
+#endif
}
return pExpr;
}
@@ -3588,6 +3623,7 @@ static void substSelect(
** (3b) the FROM clause of the subquery may not contain a virtual
** table and
** (3c) the outer query may not be an aggregate.
+** (3d) the outer query may not be DISTINCT.
**
** (4) The subquery can not be DISTINCT.
**
@@ -3638,6 +3674,7 @@ static void substSelect(
** (17d1) aggregate, or
** (17d2) DISTINCT, or
** (17d3) a join.
+** (17e) the subquery may not contain window functions
**
** The parent and sub-query may contain WHERE clauses. Subject to
** rules (11), (13) and (14), they may also contain ORDER BY,
@@ -3784,8 +3821,11 @@ static int flattenSubquery(
*/
if( (pSubitem->fg.jointype & JT_OUTER)!=0 ){
isLeftJoin = 1;
- if( pSubSrc->nSrc>1 || isAgg || IsVirtual(pSubSrc->a[0].pTab) ){
- /* (3a) (3c) (3b) */
+ if( pSubSrc->nSrc>1 /* (3a) */
+ || isAgg /* (3b) */
+ || IsVirtual(pSubSrc->a[0].pTab) /* (3c) */
+ || (p->selFlags & SF_Distinct)!=0 /* (3d) */
+ ){
return 0;
}
}
@@ -3819,6 +3859,7 @@ static int flattenSubquery(
if( (pSub1->selFlags & (SF_Distinct|SF_Aggregate))!=0 /* (17b) */
|| (pSub1->pPrior && pSub1->op!=TK_ALL) /* (17a) */
|| pSub1->pSrc->nSrc<1 /* (17c) */
+ || pSub1->pWin /* (17e) */
){
return 0;
}
@@ -4045,7 +4086,7 @@ static int flattenSubquery(
pWhere = pSub->pWhere;
pSub->pWhere = 0;
if( isLeftJoin>0 ){
- setJoinExpr(pWhere, iNewParent);
+ sqlite3SetJoinExpr(pWhere, iNewParent);
}
pParent->pWhere = sqlite3ExprAnd(pParse, pWhere, pParent->pWhere);
if( db->mallocFailed==0 ){
@@ -4105,23 +4146,36 @@ struct WhereConst {
/*
** Add a new entry to the pConst object. Except, do not add duplicate
-** pColumn entires.
+** pColumn entires. Also, do not add if doing so would not be appropriate.
+**
+** The caller guarantees the pColumn is a column and pValue is a constant.
+** This routine has to do some additional checks before completing the
+** insert.
*/
static void constInsert(
- WhereConst *pConst, /* The WhereConst into which we are inserting */
- Expr *pColumn, /* The COLUMN part of the constraint */
- Expr *pValue /* The VALUE part of the constraint */
+ WhereConst *pConst, /* The WhereConst into which we are inserting */
+ Expr *pColumn, /* The COLUMN part of the constraint */
+ Expr *pValue, /* The VALUE part of the constraint */
+ Expr *pExpr /* Overall expression: COLUMN=VALUE or VALUE=COLUMN */
){
int i;
assert( pColumn->op==TK_COLUMN );
+ assert( sqlite3ExprIsConstant(pValue) );
+
+ if( !ExprHasProperty(pValue, EP_FixedCol) && sqlite3ExprAffinity(pValue)!=0 ){
+ return;
+ }
+ if( !sqlite3IsBinary(sqlite3ExprCompareCollSeq(pConst->pParse,pExpr)) ){
+ return;
+ }
/* 2018-10-25 ticket [cf5ed20f]
** Make sure the same pColumn is not inserted more than once */
for(i=0; inConst; i++){
- const Expr *pExpr = pConst->apExpr[i*2];
- assert( pExpr->op==TK_COLUMN );
- if( pExpr->iTable==pColumn->iTable
- && pExpr->iColumn==pColumn->iColumn
+ const Expr *pE2 = pConst->apExpr[i*2];
+ assert( pE2->op==TK_COLUMN );
+ if( pE2->iTable==pColumn->iTable
+ && pE2->iColumn==pColumn->iColumn
){
return; /* Already present. Return without doing anything. */
}
@@ -4133,7 +4187,9 @@ static void constInsert(
if( pConst->apExpr==0 ){
pConst->nConst = 0;
}else{
- if( ExprHasProperty(pValue, EP_FixedCol) ) pValue = pValue->pLeft;
+ if( ExprHasProperty(pValue, EP_FixedCol) ){
+ pValue = pValue->pLeft;
+ }
pConst->apExpr[pConst->nConst*2-2] = pColumn;
pConst->apExpr[pConst->nConst*2-1] = pValue;
}
@@ -4159,19 +4215,11 @@ static void findConstInWhere(WhereConst *pConst, Expr *pExpr){
pLeft = pExpr->pLeft;
assert( pRight!=0 );
assert( pLeft!=0 );
- if( pRight->op==TK_COLUMN
- && !ExprHasProperty(pRight, EP_FixedCol)
- && sqlite3ExprIsConstant(pLeft)
- && sqlite3IsBinary(sqlite3BinaryCompareCollSeq(pConst->pParse,pLeft,pRight))
- ){
- constInsert(pConst, pRight, pLeft);
- }else
- if( pLeft->op==TK_COLUMN
- && !ExprHasProperty(pLeft, EP_FixedCol)
- && sqlite3ExprIsConstant(pRight)
- && sqlite3IsBinary(sqlite3BinaryCompareCollSeq(pConst->pParse,pLeft,pRight))
- ){
- constInsert(pConst, pLeft, pRight);
+ if( pRight->op==TK_COLUMN && sqlite3ExprIsConstant(pLeft) ){
+ constInsert(pConst,pRight,pLeft,pExpr);
+ }
+ if( pLeft->op==TK_COLUMN && sqlite3ExprIsConstant(pRight) ){
+ constInsert(pConst,pLeft,pRight,pExpr);
}
}
@@ -4207,10 +4255,9 @@ static int propagateConstantExprRewrite(Walker *pWalker, Expr *pExpr){
** The WHERE-clause constant propagation optimization.
**
** If the WHERE clause contains terms of the form COLUMN=CONSTANT or
-** CONSTANT=COLUMN that must be tree (in other words, if the terms top-level
-** AND-connected terms that are not part of a ON clause from a LEFT JOIN)
-** then throughout the query replace all other occurrences of COLUMN
-** with CONSTANT within the WHERE clause.
+** CONSTANT=COLUMN that are top-level AND-connected terms that are not
+** part of a ON clause from a LEFT JOIN, then throughout the query
+** replace all other occurrences of COLUMN with CONSTANT.
**
** For example, the query:
**
@@ -4559,6 +4606,9 @@ static int convertCompoundSelectToSubquery(Walker *pWalker, Select *p){
p->pPrior = 0;
p->pNext = 0;
p->pWith = 0;
+#ifndef SQLITE_OMIT_WINDOWFUNC
+ p->pWinDefn = 0;
+#endif
p->selFlags &= ~SF_Compound;
assert( (p->selFlags & SF_Converted)==0 );
p->selFlags |= SF_Converted;
@@ -4658,6 +4708,9 @@ static int withExpand(
With *pWith; /* WITH clause that pCte belongs to */
assert( pFrom->pTab==0 );
+ if( pParse->nErr ){
+ return SQLITE_ERROR;
+ }
pCte = searchWith(pParse->pWith, pFrom, &pWith);
if( pCte ){
@@ -4917,7 +4970,15 @@ static int selectExpander(Walker *pWalker, Select *p){
assert( pFrom->pSelect==0 );
if( pTab->pSelect && (db->flags & SQLITE_EnableView)==0 ){
sqlite3ErrorMsg(pParse, "access to view \"%s\" prohibited",
- pTab->zName);
+ pTab->zName);
+ }
+ if( IsVirtual(pTab)
+ && pFrom->fg.fromDDL
+ && ALWAYS(pTab->pVTable!=0)
+ && pTab->pVTable->eVtabRisk > ((db->flags & SQLITE_TrustedSchema)!=0)
+ ){
+ sqlite3ErrorMsg(pParse, "unsafe use of virtual table \"%s\"",
+ pTab->zName);
}
pFrom->pSelect = sqlite3SelectDup(db, pTab->pSelect, 0);
nCol = pTab->nCol;
@@ -4938,7 +4999,7 @@ static int selectExpander(Walker *pWalker, Select *p){
/* Process NATURAL keywords, and ON and USING clauses of joins.
*/
- if( db->mallocFailed || sqliteProcessJoin(pParse, p) ){
+ if( pParse->nErr || db->mallocFailed || sqliteProcessJoin(pParse, p) ){
return WRC_Abort;
}
@@ -4985,10 +5046,9 @@ static int selectExpander(Walker *pWalker, Select *p){
*/
pNew = sqlite3ExprListAppend(pParse, pNew, a[k].pExpr);
if( pNew ){
- pNew->a[pNew->nExpr-1].zName = a[k].zName;
- pNew->a[pNew->nExpr-1].zSpan = a[k].zSpan;
- a[k].zName = 0;
- a[k].zSpan = 0;
+ pNew->a[pNew->nExpr-1].zEName = a[k].zEName;
+ pNew->a[pNew->nExpr-1].eEName = a[k].eEName;
+ a[k].zEName = 0;
}
a[k].pExpr = 0;
}else{
@@ -5027,7 +5087,7 @@ static int selectExpander(Walker *pWalker, Select *p){
assert( zName );
if( zTName && pSub
- && sqlite3MatchSpanName(pSub->pEList->a[j].zSpan, 0, zTName, 0)==0
+ && sqlite3MatchEName(&pSub->pEList->a[j], 0, zTName, 0)==0
){
continue;
}
@@ -5045,7 +5105,7 @@ static int selectExpander(Walker *pWalker, Select *p){
if( i>0 && zTName==0 ){
if( (pFrom->fg.jointype & JT_NATURAL)!=0
- && tableAndColumnIndex(pTabList, i, zName, 0, 0)
+ && tableAndColumnIndex(pTabList, i, zName, 0, 0, 1)
){
/* In a NATURAL join, omit the join columns from the
** table to the right of the join */
@@ -5080,15 +5140,16 @@ static int selectExpander(Walker *pWalker, Select *p){
sqlite3ExprListSetName(pParse, pNew, &sColname, 0);
if( pNew && (p->selFlags & SF_NestedFrom)!=0 ){
struct ExprList_item *pX = &pNew->a[pNew->nExpr-1];
+ sqlite3DbFree(db, pX->zEName);
if( pSub ){
- pX->zSpan = sqlite3DbStrDup(db, pSub->pEList->a[j].zSpan);
- testcase( pX->zSpan==0 );
+ pX->zEName = sqlite3DbStrDup(db, pSub->pEList->a[j].zEName);
+ testcase( pX->zEName==0 );
}else{
- pX->zSpan = sqlite3MPrintf(db, "%s.%s.%s",
+ pX->zEName = sqlite3MPrintf(db, "%s.%s.%s",
zSchemaName, zTabName, zColname);
- testcase( pX->zSpan==0 );
+ testcase( pX->zEName==0 );
}
- pX->bSpanIsTab = 1;
+ pX->eEName = ENAME_TAB;
}
sqlite3DbFree(db, zToFree);
}
@@ -5715,11 +5776,13 @@ int sqlite3Select(
}
#ifndef SQLITE_OMIT_WINDOWFUNC
- if( sqlite3WindowRewrite(pParse, p) ){
+ rc = sqlite3WindowRewrite(pParse, p);
+ if( rc ){
+ assert( db->mallocFailed || pParse->nErr>0 );
goto select_end;
}
#if SELECTTRACE_ENABLED
- if( sqlite3SelectTrace & 0x108 ){
+ if( p->pWin && (sqlite3SelectTrace & 0x108)!=0 ){
SELECTTRACE(0x104,pParse,p, ("after window rewrite:\n"));
sqlite3TreeViewSelect(0, p, 0);
}
@@ -6051,9 +6114,11 @@ int sqlite3Select(
*/
if( (p->selFlags & (SF_Distinct|SF_Aggregate))==SF_Distinct
&& sqlite3ExprListCompare(sSort.pOrderBy, pEList, -1)==0
+ && p->pWin==0
){
p->selFlags &= ~SF_Distinct;
pGroupBy = p->pGroupBy = sqlite3ExprListDup(db, pEList, 0);
+ p->selFlags |= SF_Aggregate;
/* Notice that even thought SF_Distinct has been cleared from p->selFlags,
** the sDistinct.isTnct is still set. Hence, isTnct represents the
** original setting of the SF_Distinct flag, not the current setting */
@@ -6128,7 +6193,7 @@ int sqlite3Select(
#ifndef SQLITE_OMIT_WINDOWFUNC
Window *pWin = p->pWin; /* Master window object (or NULL) */
if( pWin ){
- sqlite3WindowCodeInit(pParse, pWin);
+ sqlite3WindowCodeInit(pParse, p);
}
#endif
assert( WHERE_USE_LIMIT==SF_FixedLimit );
diff --git a/src/shell.c.in b/src/shell.c.in
index 7f82675e35..f355737f59 100644
--- a/src/shell.c.in
+++ b/src/shell.c.in
@@ -1021,6 +1021,7 @@ struct ShellState {
int outCount; /* Revert to stdout when reaching zero */
int cnt; /* Number of records displayed so far */
int lineno; /* Line number of last line read from in */
+ int openFlags; /* Additional flags to open. (SQLITE_OPEN_NOFOLLOW) */
FILE *in; /* Read commands from this stream */
FILE *out; /* Write results here */
FILE *traceOut; /* Output for sqlite3_trace() */
@@ -1855,19 +1856,22 @@ static int shell_callback(
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;
}
if( p->cnt++==0 ){
for(i=0; icolWidth) ){
+ if( iopenMode ){
case SHELL_OPEN_APPENDVFS: {
sqlite3_open_v2(p->zDbFilename, &p->db,
- SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE, "apndvfs");
+ SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|p->openFlags, "apndvfs");
break;
}
case SHELL_OPEN_HEXDB:
@@ -4138,12 +4141,14 @@ static void open_db(ShellState *p, int openFlags){
break;
}
case SHELL_OPEN_READONLY: {
- sqlite3_open_v2(p->zDbFilename, &p->db, SQLITE_OPEN_READONLY, 0);
+ sqlite3_open_v2(p->zDbFilename, &p->db,
+ SQLITE_OPEN_READONLY|p->openFlags, 0);
break;
}
case SHELL_OPEN_UNSPEC:
case SHELL_OPEN_NORMAL: {
- sqlite3_open(p->zDbFilename, &p->db);
+ sqlite3_open_v2(p->zDbFilename, &p->db,
+ SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|p->openFlags, 0);
break;
}
}
@@ -4917,7 +4922,7 @@ static unsigned int get4byteInt(unsigned char *a){
}
/*
-** Implementation of the ".info" command.
+** Implementation of the ".dbinfo" command.
**
** Return 1 on error, 2 to exit, and 0 otherwise.
*/
@@ -7154,20 +7159,22 @@ static int do_meta_command(char *zLine, ShellState *p){
const char *zName;
int op;
} aDbConfig[] = {
+ { "defensive", SQLITE_DBCONFIG_DEFENSIVE },
+ { "dqs_ddl", SQLITE_DBCONFIG_DQS_DDL },
+ { "dqs_dml", SQLITE_DBCONFIG_DQS_DML },
{ "enable_fkey", SQLITE_DBCONFIG_ENABLE_FKEY },
+ { "enable_qpsg", SQLITE_DBCONFIG_ENABLE_QPSG },
{ "enable_trigger", SQLITE_DBCONFIG_ENABLE_TRIGGER },
{ "enable_view", SQLITE_DBCONFIG_ENABLE_VIEW },
{ "fts3_tokenizer", SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER },
+ { "legacy_alter_table", SQLITE_DBCONFIG_LEGACY_ALTER_TABLE },
+ { "legacy_file_format", SQLITE_DBCONFIG_LEGACY_FILE_FORMAT },
{ "load_extension", SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION },
{ "no_ckpt_on_close", SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE },
- { "enable_qpsg", SQLITE_DBCONFIG_ENABLE_QPSG },
- { "trigger_eqp", SQLITE_DBCONFIG_TRIGGER_EQP },
{ "reset_database", SQLITE_DBCONFIG_RESET_DATABASE },
- { "defensive", SQLITE_DBCONFIG_DEFENSIVE },
+ { "trigger_eqp", SQLITE_DBCONFIG_TRIGGER_EQP },
+ { "trusted_schema", SQLITE_DBCONFIG_TRUSTED_SCHEMA },
{ "writable_schema", SQLITE_DBCONFIG_WRITABLE_SCHEMA },
- { "legacy_alter_table", SQLITE_DBCONFIG_LEGACY_ALTER_TABLE },
- { "dqs_dml", SQLITE_DBCONFIG_DQS_DML },
- { "dqs_ddl", SQLITE_DBCONFIG_DQS_DDL },
};
int ii, v;
open_db(p, 0);
@@ -7177,7 +7184,7 @@ static int do_meta_command(char *zLine, ShellState *p){
sqlite3_db_config(p->db, aDbConfig[ii].op, booleanValue(azArg[2]), 0);
}
sqlite3_db_config(p->db, aDbConfig[ii].op, -1, &v);
- utf8_printf(p->out, "%18s %s\n", aDbConfig[ii].zName, v ? "on" : "off");
+ utf8_printf(p->out, "%19s %s\n", aDbConfig[ii].zName, v ? "on" : "off");
if( nArg>1 ) break;
}
if( nArg>1 && ii==ArraySize(aDbConfig) ){
@@ -7758,10 +7765,19 @@ static int do_meta_command(char *zLine, ShellState *p){
char *zCollist = 0;
sqlite3_stmt *pStmt;
int tnum = 0;
+ int isWO = 0; /* True if making an imposter of a WITHOUT ROWID table */
+ int lenPK = 0; /* Length of the PRIMARY KEY string for isWO tables */
int i;
if( !(nArg==3 || (nArg==2 && sqlite3_stricmp(azArg[1],"off")==0)) ){
utf8_printf(stderr, "Usage: .imposter INDEX IMPOSTER\n"
" .imposter off\n");
+ /* Also allowed, but not documented:
+ **
+ ** .imposter TABLE IMPOSTER
+ **
+ ** where TABLE is a WITHOUT ROWID table. In that case, the
+ ** imposter is another WITHOUT ROWID table with the columns in
+ ** storage order. */
rc = 1;
goto meta_command_exit;
}
@@ -7770,19 +7786,22 @@ static int do_meta_command(char *zLine, ShellState *p){
sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->db, "main", 0, 1);
goto meta_command_exit;
}
- zSql = sqlite3_mprintf("SELECT rootpage FROM sqlite_master"
- " WHERE name='%q' AND type='index'", azArg[1]);
+ zSql = sqlite3_mprintf(
+ "SELECT rootpage, 0 FROM sqlite_master"
+ " WHERE name='%q' AND type='index'"
+ "UNION ALL "
+ "SELECT rootpage, 1 FROM sqlite_master"
+ " WHERE name='%q' AND type='table'"
+ " AND sql LIKE '%%without%%rowid%%'",
+ azArg[1], azArg[1]
+ );
sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
sqlite3_free(zSql);
if( sqlite3_step(pStmt)==SQLITE_ROW ){
tnum = sqlite3_column_int(pStmt, 0);
+ isWO = sqlite3_column_int(pStmt, 1);
}
sqlite3_finalize(pStmt);
- if( tnum==0 ){
- utf8_printf(stderr, "no such index: \"%s\"\n", azArg[1]);
- rc = 1;
- goto meta_command_exit;
- }
zSql = sqlite3_mprintf("PRAGMA index_xinfo='%q'", azArg[1]);
rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
sqlite3_free(zSql);
@@ -7799,6 +7818,9 @@ static int do_meta_command(char *zLine, ShellState *p){
zCol = zLabel;
}
}
+ if( isWO && lenPK==0 && sqlite3_column_int(pStmt,5)==0 && zCollist ){
+ lenPK = (int)strlen(zCollist);
+ }
if( zCollist==0 ){
zCollist = sqlite3_mprintf("\"%w\"", zCol);
}else{
@@ -7806,9 +7828,16 @@ static int do_meta_command(char *zLine, ShellState *p){
}
}
sqlite3_finalize(pStmt);
+ if( i==0 || tnum==0 ){
+ utf8_printf(stderr, "no such index: \"%s\"\n", azArg[1]);
+ rc = 1;
+ sqlite3_free(zCollist);
+ goto meta_command_exit;
+ }
+ if( lenPK==0 ) lenPK = 100000;
zSql = sqlite3_mprintf(
- "CREATE TABLE \"%w\"(%s,PRIMARY KEY(%s))WITHOUT ROWID",
- azArg[2], zCollist, zCollist);
+ "CREATE TABLE \"%w\"(%s,PRIMARY KEY(%.*s))WITHOUT ROWID",
+ azArg[2], zCollist, lenPK, zCollist);
sqlite3_free(zCollist);
rc = sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->db, "main", 1, tnum);
if( rc==SQLITE_OK ){
@@ -7819,7 +7848,8 @@ static int do_meta_command(char *zLine, ShellState *p){
}else{
utf8_printf(stdout, "%s;\n", zSql);
raw_printf(stdout,
- "WARNING: writing to an imposter table will corrupt the index!\n"
+ "WARNING: writing to an imposter table will corrupt the \"%s\" %s!\n",
+ azArg[1], isWO ? "table" : "index"
);
}
}else{
@@ -8017,6 +8047,7 @@ static int do_meta_command(char *zLine, ShellState *p){
sqlite3_free(p->zFreeOnClose);
p->zFreeOnClose = 0;
p->openMode = SHELL_OPEN_UNSPEC;
+ p->openFlags = 0;
p->szMax = 0;
/* Check for command-line arguments */
for(iName=1; iNameopenMode = SHELL_OPEN_APPENDVFS;
}else if( optionMatch(z, "readonly") ){
p->openMode = SHELL_OPEN_READONLY;
+ }else if( optionMatch(z, "nofollow") ){
+ p->openFlags |= SQLITE_OPEN_NOFOLLOW;
#ifdef SQLITE_ENABLE_DESERIALIZE
}else if( optionMatch(z, "deserialize") ){
p->openMode = SHELL_OPEN_DESERIALIZE;
@@ -9187,7 +9220,7 @@ static int do_meta_command(char *zLine, ShellState *p){
{ "extra_schema_checks",SQLITE_TESTCTRL_EXTRA_SCHEMA_CHECKS,"BOOLEAN" },
/*{ "fault_install", SQLITE_TESTCTRL_FAULT_INSTALL, "" },*/
{ "imposter", SQLITE_TESTCTRL_IMPOSTER, "SCHEMA ON/OFF ROOTPAGE"},
- { "internal_functions", SQLITE_TESTCTRL_INTERNAL_FUNCTIONS, "BOOLEAN" },
+ { "internal_functions", SQLITE_TESTCTRL_INTERNAL_FUNCTIONS, "" },
{ "localtime_fault", SQLITE_TESTCTRL_LOCALTIME_FAULT,"BOOLEAN" },
{ "never_corrupt", SQLITE_TESTCTRL_NEVER_CORRUPT, "BOOLEAN" },
{ "optimizations", SQLITE_TESTCTRL_OPTIMIZATIONS, "DISABLE-MASK" },
@@ -9303,7 +9336,6 @@ static int do_meta_command(char *zLine, ShellState *p){
/* sqlite3_test_control(int, int) */
case SQLITE_TESTCTRL_ASSERT:
case SQLITE_TESTCTRL_ALWAYS:
- case SQLITE_TESTCTRL_INTERNAL_FUNCTIONS:
if( nArg==3 ){
int opt = booleanValue(azArg[2]);
rc2 = sqlite3_test_control(testctrl, opt);
@@ -9321,6 +9353,12 @@ static int do_meta_command(char *zLine, ShellState *p){
}
break;
+ /* sqlite3_test_control(sqlite3*) */
+ case SQLITE_TESTCTRL_INTERNAL_FUNCTIONS:
+ rc2 = sqlite3_test_control(testctrl, p->db);
+ isOk = 3;
+ break;
+
case SQLITE_TESTCTRL_IMPOSTER:
if( nArg==5 ){
rc2 = sqlite3_test_control(testctrl, p->db,
@@ -9951,6 +9989,7 @@ static const char zOptions[] =
" -multiplex enable the multiplexor VFS\n"
#endif
" -newline SEP set output row separator. Default: '\\n'\n"
+ " -nofollow refuse to open symbolic links to database files\n"
" -nullvalue TEXT set text string for NULL values. Default ''\n"
" -pagecache SIZE N use N slots of SZ bytes each for page cache memory\n"
" -quote set output mode to 'quote'\n"
@@ -10261,6 +10300,8 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
#endif
}else if( strcmp(z,"-readonly")==0 ){
data.openMode = SHELL_OPEN_READONLY;
+ }else if( strcmp(z,"-nofollow")==0 ){
+ data.openFlags = SQLITE_OPEN_NOFOLLOW;
#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB)
}else if( strncmp(z, "-A",2)==0 ){
/* All remaining command-line arguments are passed to the ".archive"
@@ -10364,6 +10405,8 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
#endif
}else if( strcmp(z,"-readonly")==0 ){
data.openMode = SHELL_OPEN_READONLY;
+ }else if( strcmp(z,"-nofollow")==0 ){
+ data.openFlags |= SQLITE_OPEN_NOFOLLOW;
}else if( strcmp(z,"-ascii")==0 ){
data.mode = MODE_Ascii;
sqlite3_snprintf(sizeof(data.colSeparator), data.colSeparator,
diff --git a/src/sqlite.h.in b/src/sqlite.h.in
index 9dbc80764f..c61c0e8b31 100644
--- a/src/sqlite.h.in
+++ b/src/sqlite.h.in
@@ -516,6 +516,7 @@ int sqlite3_exec(
#define SQLITE_CANTOPEN_FULLPATH (SQLITE_CANTOPEN | (3<<8))
#define SQLITE_CANTOPEN_CONVPATH (SQLITE_CANTOPEN | (4<<8))
#define SQLITE_CANTOPEN_DIRTYWAL (SQLITE_CANTOPEN | (5<<8)) /* Not Used */
+#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_READONLY_RECOVERY (SQLITE_READONLY | (1<<8))
@@ -535,11 +536,13 @@ int sqlite3_exec(
#define SQLITE_CONSTRAINT_UNIQUE (SQLITE_CONSTRAINT | (8<<8))
#define SQLITE_CONSTRAINT_VTAB (SQLITE_CONSTRAINT | (9<<8))
#define SQLITE_CONSTRAINT_ROWID (SQLITE_CONSTRAINT |(10<<8))
+#define SQLITE_CONSTRAINT_PINNED (SQLITE_CONSTRAINT |(11<<8))
#define SQLITE_NOTICE_RECOVER_WAL (SQLITE_NOTICE | (1<<8))
#define SQLITE_NOTICE_RECOVER_ROLLBACK (SQLITE_NOTICE | (2<<8))
#define SQLITE_WARNING_AUTOINDEX (SQLITE_WARNING | (1<<8))
#define SQLITE_AUTH_USER (SQLITE_AUTH | (1<<8))
#define SQLITE_OK_LOAD_PERMANENTLY (SQLITE_OK | (1<<8))
+#define SQLITE_OK_SYMLINK (SQLITE_OK | (2<<8))
/*
** CAPI3REF: Flags For File Open Operations
@@ -568,6 +571,7 @@ int sqlite3_exec(
#define SQLITE_OPEN_SHAREDCACHE 0x00020000 /* Ok for sqlite3_open_v2() */
#define SQLITE_OPEN_PRIVATECACHE 0x00040000 /* Ok for sqlite3_open_v2() */
#define SQLITE_OPEN_WAL 0x00080000 /* VFS only */
+#define SQLITE_OPEN_NOFOLLOW 0x01000000 /* Ok for sqlite3_open_v2() */
/* Reserved: 0x00F00000 */
@@ -979,16 +983,16 @@ struct sqlite3_io_methods {
** ^The [SQLITE_FCNTL_BUSYHANDLER]
** file-control may be invoked by SQLite on the database file handle
** shortly after it is opened in order to provide a custom VFS with access
-** to the connections busy-handler callback. The argument is of type (void **)
+** to the connection's busy-handler callback. The argument is of type (void**)
** - an array of two (void *) values. The first (void *) actually points
-** to a function of type (int (*)(void *)). In order to invoke the connections
+** to a function of type (int (*)(void *)). In order to invoke the connection's
** busy-handler, this function should be invoked with the second (void *) in
** the array as the only argument. If it returns non-zero, then the operation
** should be retried. If it returns zero, the custom VFS should abandon the
** current operation.
**
**
- [[SQLITE_FCNTL_TEMPFILENAME]]
-** ^Application can invoke the [SQLITE_FCNTL_TEMPFILENAME] file-control
+** ^Applications can invoke the [SQLITE_FCNTL_TEMPFILENAME] file-control
** to have SQLite generate a
** temporary filename using the same algorithm that is followed to generate
** temporary filenames for TEMP tables and other internal uses. The
@@ -1101,7 +1105,7 @@ struct sqlite3_io_methods {
** not provide a mechanism to detect changes to MAIN only. Also, the
** [sqlite3_total_changes()] interface responds to internal changes only and
** omits changes made by other database connections. The
-** [PRAGMA data_version] command provide a mechanism to detect changes to
+** [PRAGMA data_version] command provides a mechanism to detect changes to
** a single attached database that occur due to other database connections,
** but omits changes implemented by the database connection on which it is
** called. This file control is the only mechanism to detect changes that
@@ -1189,10 +1193,10 @@ typedef struct sqlite3_api_routines sqlite3_api_routines;
** to 3 with SQLite [version 3.7.6] on [dateof:3.7.6]. Additional fields
** may be appended to the sqlite3_vfs object and the iVersion value
** may increase again in future versions of SQLite.
-** Note that the structure
-** of the sqlite3_vfs object changes in the transition from
+** Note that due to an oversight, the structure
+** of the sqlite3_vfs object changed in the transition from
** SQLite [version 3.5.9] to [version 3.6.0] on [dateof:3.6.0]
-** and yet the iVersion field was not modified.
+** and yet the iVersion field was not increased.
**
** The szOsFile field is the size of the subclassed [sqlite3_file]
** structure used by this VFS. mxPathname is the maximum length of
@@ -1283,7 +1287,7 @@ typedef struct sqlite3_api_routines sqlite3_api_routines;
** for exclusive access.
**
** ^At least szOsFile bytes of memory are allocated by SQLite
-** to hold the [sqlite3_file] structure passed as the third
+** to hold the [sqlite3_file] structure passed as the third
** argument to xOpen. The xOpen method does not have to
** allocate the structure; it should just fill it in. Note that
** the xOpen method must set the sqlite3_file.pMethods to either
@@ -1620,7 +1624,7 @@ int sqlite3_db_config(sqlite3*, int op, ...);
** that causes the corresponding memory allocation to fail.
**
** The xInit method initializes the memory allocator. For example,
-** it might allocate any require mutexes or initialize internal data
+** it might allocate any required mutexes or initialize internal data
** structures. The xShutdown method is invoked (indirectly) by
** [sqlite3_shutdown()] and should deallocate any resources acquired
** by xInit. The pAppData pointer is used as the only parameter to
@@ -1742,6 +1746,7 @@ struct sqlite3_mem_methods {
** memory allocation statistics. ^(When memory allocation statistics are
** disabled, the following SQLite interfaces become non-operational:
**
+** - [sqlite3_hard_heap_limit64()]
**
- [sqlite3_memory_used()]
**
- [sqlite3_memory_highwater()]
**
- [sqlite3_soft_heap_limit64()]
@@ -1760,7 +1765,7 @@ struct sqlite3_mem_methods {
**
- ^The SQLITE_CONFIG_PAGECACHE option specifies a memory pool
** that SQLite can use for the database page cache with the default page
** cache implementation.
-** This configuration option is a no-op if an application-define page
+** This configuration option is a no-op if an application-defined page
** cache implementation is loaded using the [SQLITE_CONFIG_PCACHE2].
** ^There are three arguments to SQLITE_CONFIG_PAGECACHE: A pointer to
** 8-byte aligned memory (pMem), the size of each page cache line (sz),
@@ -2245,7 +2250,7 @@ struct sqlite3_mem_methods {
** [[SQLITE_DBCONFIG_DQS_DML]]
**
- SQLITE_DBCONFIG_DQS_DML
**
- The SQLITE_DBCONFIG_DQS_DML option activates or deactivates
-** the legacy [double-quoted string literal] misfeature for DML statement
+** the legacy [double-quoted string literal] misfeature for DML statements
** only, that is DELETE, INSERT, SELECT, and UPDATE statements. The
** default value of this setting is determined by the [-DSQLITE_DQS]
** compile-time option.
@@ -2259,6 +2264,49 @@ struct sqlite3_mem_methods {
** default value of this setting is determined by the [-DSQLITE_DQS]
** compile-time option.
**
+**
+** [[SQLITE_DBCONFIG_TRUSTED_SCHEMA]]
+** - SQLITE_DBCONFIG_TRUSTED_SCHEMA
+**
- 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.
+** When the SQLITE_DBCONFIG_TRUSTED_SCHEMA option is disabled, SQLite
+** takes additional defensive steps to protect the application from harm
+** including:
+**
+** - Prohibit the use of SQL functions inside triggers, views,
+** CHECK constraints, DEFAULT clauses, expression indexes,
+** partial indexes, or generated columns
+** unless those functions are tagged with [SQLITE_INNOCUOUS].
+**
- Prohibit the use of virtual tables inside of triggers or views
+** unless those virtual tables are tagged with [SQLITE_VTAB_INNOCUOUS].
+**
+** This setting defaults to "on" for legacy compatibility, however
+** all applications are advised to turn it off if possible. This setting
+** can also be controlled using the [PRAGMA trusted_schema] statement.
+**
+**
+** [[SQLITE_DBCONFIG_LEGACY_FILE_FORMAT]]
+** - SQLITE_DBCONFIG_LEGACY_FILE_FORMAT
+**
- The SQLITE_DBCONFIG_LEGACY_FILE_FORMAT option activates or deactivates
+** the legacy file format flag. When activated, this flag causes all newly
+** created database file to have a schema format version number (the 4-byte
+** integer found at offset 44 into the database header) of 1. This in turn
+** means that the resulting database file will be readable and writable by
+** any SQLite version back to 3.0.0 ([dateof:3.0.0]). Without this setting,
+** newly created databases are generally not understandable by SQLite versions
+** prior to 3.3.0 ([dateof:3.3.0]). As these words are written, there
+** is now scarcely any need to generated database files that are compatible
+** all the way back to version 3.0.0, and so this setting is of little
+** practical use, but is provided so that SQLite can continue to claim the
+** ability to generate new database files that are compatible with version
+** 3.0.0.
+**
Note that when the SQLITE_DBCONFIG_LEGACY_FILE_FORMAT setting is on,
+** the [VACUUM] command will fail with an obscure error when attempting to
+** process a table with generated columns and a descending index. This is
+** not considered a bug since SQLite versions 3.3.0 and earlier do not support
+** either generated columns or decending indexes.
+**
**
*/
#define SQLITE_DBCONFIG_MAINDBNAME 1000 /* const char* */
@@ -2277,7 +2325,9 @@ struct sqlite3_mem_methods {
#define SQLITE_DBCONFIG_DQS_DML 1013 /* int int* */
#define SQLITE_DBCONFIG_DQS_DDL 1014 /* int int* */
#define SQLITE_DBCONFIG_ENABLE_VIEW 1015 /* int int* */
-#define SQLITE_DBCONFIG_MAX 1015 /* Largest DBCONFIG */
+#define SQLITE_DBCONFIG_LEGACY_FILE_FORMAT 1016 /* int int* */
+#define SQLITE_DBCONFIG_TRUSTED_SCHEMA 1017 /* int int* */
+#define SQLITE_DBCONFIG_MAX 1017 /* Largest DBCONFIG */
/*
** CAPI3REF: Enable Or Disable Extended Result Codes
@@ -2483,7 +2533,7 @@ int sqlite3_total_changes(sqlite3*);
** ^The sqlite3_interrupt(D) call is in effect until all currently running
** SQL statements on [database connection] D complete. ^Any new SQL statements
** that are started after the sqlite3_interrupt() call and before the
-** running statements reaches zero are interrupted as if they had been
+** running statement count reaches zero are interrupted as if they had been
** running prior to the sqlite3_interrupt() call. ^New SQL statements
** that are started after the running statement count reaches zero are
** not effected by the sqlite3_interrupt().
@@ -2651,9 +2701,9 @@ int sqlite3_busy_timeout(sqlite3*, int ms);
** Cindy | 21
**
**
-** There are two column (M==2) and three rows (N==3). Thus the
+** There are two columns (M==2) and three rows (N==3). Thus the
** result table has 8 entries. Suppose the result table is stored
-** in an array names azResult. Then azResult holds this content:
+** in an array named azResult. Then azResult holds this content:
**
**
** azResult[0] = "Name";
@@ -2746,7 +2796,7 @@ char *sqlite3_vsnprintf(int,char*,const char*, va_list);
**
** The SQLite core uses these three routines for all of its own
** internal memory allocation needs. "Core" in the previous sentence
-** does not include operating-system specific VFS implementation. The
+** does not include operating-system specific [VFS] implementation. The
** Windows VFS uses native malloc() and free() for some operations.
**
** ^The sqlite3_malloc() routine returns a pointer to a block
@@ -2807,19 +2857,6 @@ char *sqlite3_vsnprintf(int,char*,const char*, va_list);
** 4 byte boundary if the [SQLITE_4_BYTE_ALIGNED_MALLOC] compile-time
** option is used.
**
-** In SQLite version 3.5.0 and 3.5.1, it was possible to define
-** the SQLITE_OMIT_MEMORY_ALLOCATION which would cause the built-in
-** implementation of these routines to be omitted. That capability
-** is no longer provided. Only built-in memory allocators can be used.
-**
-** Prior to SQLite version 3.7.10, the Windows OS interface layer called
-** the system malloc() and free() directly when converting
-** filenames between the UTF-8 encoding used by SQLite
-** and whatever filename encoding is used by the particular Windows
-** installation. Memory allocation errors were detected, but
-** they were reported back as [SQLITE_CANTOPEN] or
-** [SQLITE_IOERR] rather than [SQLITE_NOMEM].
-**
** The pointer arguments to [sqlite3_free()] and [sqlite3_realloc()]
** must be either NULL or else pointers obtained from a prior
** invocation of [sqlite3_malloc()] or [sqlite3_realloc()] that have
@@ -2868,7 +2905,7 @@ sqlite3_int64 sqlite3_memory_highwater(int resetFlag);
** SQLite contains a high-quality pseudo-random number generator (PRNG) used to
** select random [ROWID | ROWIDs] when inserting new records into a table that
** already uses the largest possible [ROWID]. The PRNG is also used for
-** the build-in random() and randomblob() SQL functions. This interface allows
+** the built-in random() and randomblob() SQL functions. This interface allows
** applications to access the same PRNG for other purposes.
**
** ^A call to this routine stores N bytes of randomness into buffer P.
@@ -3242,10 +3279,8 @@ void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
** The sqlite3_open_v2() interface works like sqlite3_open()
** except that it accepts two additional parameters for additional control
** over the new database connection. ^(The flags parameter to
-** sqlite3_open_v2() can take one of
-** the following three values, optionally combined with the
-** [SQLITE_OPEN_NOMUTEX], [SQLITE_OPEN_FULLMUTEX], [SQLITE_OPEN_SHAREDCACHE],
-** [SQLITE_OPEN_PRIVATECACHE], and/or [SQLITE_OPEN_URI] flags:)^
+** sqlite3_open_v2() must include, at a minimum, one of the following
+** three flag combinations:)^
**
**
** ^(- [SQLITE_OPEN_READONLY]
@@ -3263,23 +3298,51 @@ void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
** sqlite3_open() and sqlite3_open16().)^
**
**
+** In addition to the required flags, the following optional flags are
+** also supported:
+**
+**
+** ^(- [SQLITE_OPEN_URI]
+** - The filename can be interpreted as a URI if this flag is set.
)^
+**
+** ^(- [SQLITE_OPEN_MEMORY]
+** - The database will be opened as an in-memory database. The database
+** is named by the "filename" argument for the purposes of cache-sharing,
+** if shared cache mode is enabled, but the "filename" is otherwise ignored.
+**
)^
+**
+** ^(- [SQLITE_OPEN_NOMUTEX]
+** - The new database connection will use the "multi-thread"
+** [threading mode].)^ This means that separate threads are allowed
+** to use SQLite at the same time, as long as each thread is using
+** a different [database connection].
+**
+** ^(
- [SQLITE_OPEN_FULLMUTEX]
+** - The new database connection will use the "serialized"
+** [threading mode].)^ This means the multiple threads can safely
+** attempt to use the same database connection at the same time.
+** (Mutexes will block any actual concurrency, but in this mode
+** there is no harm in trying.)
+**
+** ^(
- [SQLITE_OPEN_SHAREDCACHE]
+** - The database is opened [shared cache] enabled, overriding
+** the default shared cache setting provided by
+** [sqlite3_enable_shared_cache()].)^
+**
+** ^(
- [SQLITE_OPEN_PRIVATECACHE]
+** - The database is opened [shared cache] disabled, overriding
+** the default shared cache setting provided by
+** [sqlite3_enable_shared_cache()].)^
+**
+** [[OPEN_NOFOLLOW]] ^(
- [SQLITE_OPEN_NOFOLLOW]
+** - The database filename is not allowed to be a symbolic link
+**
)^
+**
** If the 3rd parameter to sqlite3_open_v2() is not one of the
-** combinations shown above optionally combined with other
+** required combinations shown above optionally combined with other
** [SQLITE_OPEN_READONLY | SQLITE_OPEN_* bits]
** then the behavior is undefined.
**
-** ^If the [SQLITE_OPEN_NOMUTEX] flag is set, then the database connection
-** opens in the multi-thread [threading mode] as long as the single-thread
-** mode has not been set at compile-time or start-time. ^If the
-** [SQLITE_OPEN_FULLMUTEX] flag is set then the database connection opens
-** in the serialized [threading mode] unless single-thread was
-** previously selected at compile-time or start-time.
-** ^The [SQLITE_OPEN_SHAREDCACHE] flag causes the database connection to be
-** eligible to use [shared cache mode], regardless of whether or not shared
-** cache is enabled using [sqlite3_enable_shared_cache()]. ^The
-** [SQLITE_OPEN_PRIVATECACHE] flag causes the database connection to not
-** participate in [shared cache mode] even if it is enabled.
-**
** ^The fourth parameter to sqlite3_open_v2() is the name of the
** [sqlite3_vfs] object that defines the operating system interface that
** the new database connection should use. ^If the fourth parameter is
@@ -3459,17 +3522,16 @@ int sqlite3_open_v2(
/*
** CAPI3REF: Obtain Values For URI Parameters
**
-** These are utility routines, useful to VFS implementations, that check
-** to see if a database file was a URI that contained a specific query
+** These are utility routines, useful to [VFS|custom VFS implementations],
+** 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 when the flags parameter to xOpen() has one or
-** more of the [SQLITE_OPEN_URI] or [SQLITE_OPEN_MAIN_DB] bits set and
-** P is the name of the query parameter, then
+** a VFS implementation or it is the return value of [sqlite3_db_filename()]
+** 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
-** query parameter on F. If P is a query parameter of F
+** query parameter on F. If P is a query parameter of F and it
** has no explicit value, then sqlite3_uri_parameter(F,P) returns
** a pointer to an empty string.
**
@@ -3481,25 +3543,72 @@ int sqlite3_open_v2(
** sqlite3_uri_boolean(F,P,B) routines returns false (0) if the value of
** query parameter P is one of "no", "false", or "off" in any case or
** if the value begins with a numeric zero. If P is not a query
-** parameter on F or if the value of P is does not match any of the
+** parameter on F or if the value of P does not match any of the
** above, then sqlite3_uri_boolean(F,P,B) returns (B!=0).
**
** The sqlite3_uri_int64(F,P,D) routine converts the value of P into a
** 64-bit signed integer and returns that integer, or D if P does not
** exist. If the value of P is something other than an integer, then
** zero is returned.
+**
+** The sqlite3_uri_key(F,N) returns a pointer to the name (not
+** the value) of the N-th query parameter for filename F, or a NULL
+** pointer if N is less than zero or greater than the number of query
+** parameters minus 1. The N value is zero-based so N should be 0 to obtain
+** the name of the first query parameter, 1 for the second parameter, and
+** so forth.
**
** If F is a NULL pointer, then sqlite3_uri_parameter(F,P) returns NULL and
** sqlite3_uri_boolean(F,P,B) returns B. If F is not a NULL pointer and
-** is not a database file pathname pointer that SQLite passed into the xOpen
-** VFS method, then the behavior of this routine is undefined and probably
-** undesirable.
+** is not a database file pathname pointer that the SQLite core passed
+** into the xOpen VFS method, then the behavior of this routine is undefined
+** and probably undesirable.
+**
+** Beginning with SQLite [version 3.31.0] ([dateof:3.31.0]) the input F
+** parameter can also be the name of a rollback journal file or WAL file
+** in addition to the main database file. Prior to version 3.31.0, these
+** routines would only work if F was the name of the main database file.
+** When the F parameter is the name of the rollback journal or WAL file,
+** it has access to all the same query parameters as were found on the
+** main database file.
**
** See the [URI filename] documentation for additional information.
*/
const char *sqlite3_uri_parameter(const char *zFilename, const char *zParam);
int sqlite3_uri_boolean(const char *zFile, const char *zParam, int bDefault);
sqlite3_int64 sqlite3_uri_int64(const char*, const char*, sqlite3_int64);
+const char *sqlite3_uri_key(const char *zFilename, int N);
+
+/*
+** CAPI3REF: Translate filenames
+**
+** These routines are available to [VFS|custom VFS implementations] for
+** translating filenames between the main database file, the journal file,
+** and the WAL file.
+**
+** If F is the name of an sqlite database file, journal file, or WAL file
+** passed by the SQLite core into the VFS, then sqlite3_filename_database(F)
+** returns the name of the corresponding database file.
+**
+** If F is the name of an sqlite database file, journal file, or WAL file
+** passed by the SQLite core into the VFS, or if F is a database filename
+** obtained from [sqlite3_db_filename()], then sqlite3_filename_journal(F)
+** returns the name of the corresponding rollback journal file.
+**
+** If F is the name of an sqlite database file, journal file, or WAL file
+** that was passed by the SQLite core into the VFS, or if F is a database
+** filename obtained from [sqlite3_db_filename()], then
+** sqlite3_filename_wal(F) returns the name of the corresponding
+** WAL file.
+**
+** In all of the above, if F is not the name of a database, journal or WAL
+** filename passed into the VFS from the SQLite core and F is not the
+** return value from [sqlite3_db_filename()], then the result is
+** undefined and is likely a memory access violation.
+*/
+const char *sqlite3_filename_database(const char*);
+const char *sqlite3_filename_journal(const char*);
+const char *sqlite3_filename_wal(const char*);
/*
@@ -3818,12 +3927,12 @@ int sqlite3_limit(sqlite3*, int id, int newVal);
**
**
** -
-** ^If the specific value bound to [parameter | host parameter] in the
+** ^If the specific value bound to a [parameter | 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 following any change
+** a schema change, on the first [sqlite3_step()] call following any change
** to the [sqlite3_bind_text | bindings] of that [parameter].
-** ^The specific value of WHERE-clause [parameter] might influence the
+** ^The specific value of a WHERE-clause [parameter] might influence the
** choice of query plan if the parameter is the left-hand side of a [LIKE]
** or [GLOB] operator or if the parameter is compared to an indexed column
** and the [SQLITE_ENABLE_STAT4] compile-time option is enabled.
@@ -4332,7 +4441,7 @@ const void *sqlite3_column_name16(sqlite3_stmt*, int N);
**
** ^If the Nth column returned by the statement is an expression or
** subquery and is not a column value, then all of these functions return
-** NULL. ^These routine might also return NULL if a memory allocation error
+** NULL. ^These routines might also return NULL if a memory allocation error
** occurs. ^Otherwise, they return the name of the attached database, table,
** or column that query result column was extracted from.
**
@@ -4342,10 +4451,6 @@ const void *sqlite3_column_name16(sqlite3_stmt*, int N);
** ^These APIs are only available if the library was compiled with the
** [SQLITE_ENABLE_COLUMN_METADATA] C-preprocessor symbol.
**
-** If two or more threads call one or more of these routines against the same
-** prepared statement and column at the same time then the results are
-** undefined.
-**
** If two or more threads call one or more
** [sqlite3_column_database_name | column metadata interfaces]
** for the same [prepared statement] and result column
@@ -4482,7 +4587,7 @@ int sqlite3_step(sqlite3_stmt*);
** ^The sqlite3_data_count(P) interface returns the number of columns in the
** current row of the result set of [prepared statement] P.
** ^If prepared statement P does not have results ready to return
-** (via calls to the [sqlite3_column_int | sqlite3_column_*()] of
+** (via calls to the [sqlite3_column_int | sqlite3_column()] family of
** interfaces) then sqlite3_data_count(P) returns 0.
** ^The sqlite3_data_count(P) routine also returns 0 if P is a NULL pointer.
** ^The sqlite3_data_count(P) routine returns 0 if the previous call to
@@ -4806,8 +4911,6 @@ int sqlite3_reset(sqlite3_stmt *pStmt);
/*
** CAPI3REF: Create Or Redefine SQL Functions
** KEYWORDS: {function creation routines}
-** KEYWORDS: {application-defined SQL function}
-** KEYWORDS: {application-defined SQL functions}
** METHOD: sqlite3
**
** ^These functions (collectively known as "function creation routines")
@@ -4984,18 +5087,51 @@ int sqlite3_create_window_function(
** to [sqlite3_create_function()], [sqlite3_create_function16()], or
** [sqlite3_create_function_v2()].
**
-** The SQLITE_DETERMINISTIC flag means that the new function will always
-** maps the same inputs into the same output. The abs() function is
-** deterministic, for example, but randomblob() is not.
-**
+**
+** [[SQLITE_DETERMINISTIC]] - SQLITE_DETERMINISTIC
-
+** The SQLITE_DETERMINISTIC flag means that the new function always gives
+** the same output when the input parameters are the same.
+** The [abs|abs() function] is deterministic, for example, but
+** [randomblob|randomblob()] is not. Functions must
+** be deterministic in order to be used in certain contexts such as
+** [CHECK constraints] or [generated columns]. SQLite might also optimize
+** deterministic functions by factoring them out of inner loops.
+**
+**
+** [[SQLITE_DIRECTONLY]] - SQLITE_DIRECTONLY
-
** The SQLITE_DIRECTONLY flag means that the function may only be invoked
-** from top-level SQL, and cannot be used in VIEWs or TRIGGERs. This is
+** from top-level SQL, and cannot be used in VIEWs or TRIGGERs nor in
+** schema structures such as [CHECK constraints], [DEFAULT clauses],
+** [expression indexes], [partial indexes], or [generated columns]. This is
** a security feature which is recommended for all
-** [application-defined SQL functions] that have side-effects. This flag
-** prevents an attacker from adding triggers and views to a schema then
-** tricking a high-privilege application into causing unintended side-effects
-** while performing ordinary queries.
+** [application-defined SQL functions] that have side-effects or that
+** could potentially leak sensitive information.
+**
**
+** [[SQLITE_INNOCUOUS]] - SQLITE_INNOCUOUS
-
+** The SQLITE_INNOCUOUS flag means that the function is unlikely
+** to cause problems even if misused. An innocuous function should have
+** no side effects and should not depend on any values other than its
+** input parameters. The [abs|abs() function] is an example of an
+** innocuous function.
+** The [load_extension() SQL function] is not innocuous because of its
+** side effects.
+**
SQLITE_INNOCUOUS is similar to SQLITE_DETERMINISTIC, but is not
+** exactly the same. The [random|random() function] is an example of a
+** function that is innocuous but not deterministic.
+**
Some heightened security settings
+** ([SQLITE_DBCONFIG_TRUSTED_SCHEMA] and [PRAGMA trusted_schema=OFF])
+** disable the use of SQL functions inside views and triggers and in
+** schema structures such as [CHECK constraints], [DEFAULT clauses],
+** [expression indexes], [partial indexes], and [generated columns] unless
+** the function is tagged with SQLITE_INNOCUOUS. Most built-in functions
+** are innocuous. Developers are advised to avoid using the
+** SQLITE_INNOCUOUS flag for application-defined functions unless the
+** function has been carefully audited and found to be free of potentially
+** security-adverse side-effects and information-leaks.
+**
+**
+** [[SQLITE_SUBTYPE]] - SQLITE_SUBTYPE
-
** The SQLITE_SUBTYPE flag indicates to SQLite that a function may call
** [sqlite3_value_subtype()] to inspect the sub-types of its arguments.
** Specifying this flag makes no difference for scalar or aggregate user
@@ -5003,10 +5139,13 @@ int sqlite3_create_window_function(
** function, then any sub-types belonging to arguments passed to the window
** function may be discarded before the window function is called (i.e.
** sqlite3_value_subtype() will always return 0).
+**
+**
*/
#define SQLITE_DETERMINISTIC 0x000000800
#define SQLITE_DIRECTONLY 0x000080000
#define SQLITE_SUBTYPE 0x000100000
+#define SQLITE_INNOCUOUS 0x000200000
/*
** CAPI3REF: Deprecated Functions
@@ -5065,8 +5204,8 @@ SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int64,int),
**
** These routines extract type, size, and content information from
** [protected sqlite3_value] objects. Protected sqlite3_value objects
-** are used to pass parameter information into implementation of
-** [application-defined SQL functions] and [virtual tables].
+** are used to pass parameter information into the functions that
+** implement [application-defined SQL functions] and [virtual tables].
**
** These routines work only with [protected sqlite3_value] objects.
** Any attempt to use these routines on an [unprotected sqlite3_value]
@@ -5123,7 +5262,7 @@ SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int64,int),
** ^The sqlite3_value_frombind(X) interface returns non-zero if the
** value X originated from one of the [sqlite3_bind_int|sqlite3_bind()]
** interfaces. ^If X comes from an SQL literal value, or a table column,
-** and expression, then sqlite3_value_frombind(X) returns zero.
+** or an expression, then sqlite3_value_frombind(X) returns zero.
**
** Please pay particular attention to the fact that the pointer returned
** from [sqlite3_value_blob()], [sqlite3_value_text()], or
@@ -5209,8 +5348,8 @@ void sqlite3_value_free(sqlite3_value*);
** routine to allocate memory for storing their state.
**
** ^The first time the sqlite3_aggregate_context(C,N) routine is called
-** for a particular aggregate function, SQLite
-** allocates N of memory, zeroes out that memory, and returns a pointer
+** for a particular aggregate function, SQLite allocates
+** N bytes of memory, zeroes out that memory, and returns a pointer
** to the new memory. ^On second and subsequent calls to
** sqlite3_aggregate_context() for the same aggregate function instance,
** the same buffer is returned. Sqlite3_aggregate_context() is normally
@@ -5227,7 +5366,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 subsequent call to sqlite3_aggregate_context() within
+** value of N in any subsequents 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
@@ -5538,7 +5677,7 @@ void sqlite3_result_subtype(sqlite3_context*,unsigned int);
** - [SQLITE_UTF16_ALIGNED].
**
)^
** ^The eTextRep argument determines the encoding of strings passed
-** to the collating function callback, xCallback.
+** to the collating function callback, xCompare.
** ^The [SQLITE_UTF16] and [SQLITE_UTF16_ALIGNED] values for eTextRep
** force strings to be UTF16 with native byte order.
** ^The [SQLITE_UTF16_ALIGNED] value for eTextRep forces strings to begin
@@ -5547,18 +5686,19 @@ void sqlite3_result_subtype(sqlite3_context*,unsigned int);
** ^The fourth argument, pArg, is an application data pointer that is passed
** through as the first argument to the collating function callback.
**
-** ^The fifth argument, xCallback, is a pointer to the collating function.
+** ^The fifth argument, xCompare, is a pointer to the collating function.
** ^Multiple collating functions can be registered using the same name but
** with different eTextRep parameters and SQLite will use whichever
** function requires the least amount of data transformation.
-** ^If the xCallback argument is NULL then the collating function is
+** ^If the xCompare argument is NULL then the collating function is
** deleted. ^When all collating functions having the same name are deleted,
** that collation is no longer usable.
**
** ^The collating function callback is invoked with a copy of the pArg
** application data pointer and with two strings in the encoding specified
-** by the eTextRep argument. The collating function must return an
-** integer that is negative, zero, or positive
+** by the eTextRep argument. The two integer parameters to the collating
+** function callback are the length of the two strings, in bytes. The collating
+** function must return an integer that is negative, zero, or positive
** if the first string is less than, equal to, or greater than the second,
** respectively. A collating function must always return the same answer
** given the same inputs. If two or more collating functions are registered
@@ -5575,7 +5715,7 @@ void sqlite3_result_subtype(sqlite3_context*,unsigned int);
**
**
** If a collating function fails any of the above constraints and that
-** collating function is registered and used, then the behavior of SQLite
+** collating function is registered and used, then the behavior of SQLite
** is undefined.
**
** ^The sqlite3_create_collation_v2() works like sqlite3_create_collation()
@@ -5902,16 +6042,31 @@ sqlite3 *sqlite3_db_handle(sqlite3_stmt*);
** CAPI3REF: Return The Filename For A Database Connection
** METHOD: sqlite3
**
-** ^The sqlite3_db_filename(D,N) interface returns a pointer to a filename
-** associated with database N of connection D. ^The main database file
-** has the name "main". If there is no attached database N on the database
+** ^The sqlite3_db_filename(D,N) interface returns a pointer to the filename
+** associated with database N of connection D.
+** ^If there is no attached database N on the database
** connection D, or if database N is a temporary or in-memory database, then
** this function will return either a NULL pointer or an empty string.
**
+** ^The string value returned by this routine is owned and managed by
+** the database connection. ^The value will be valid until the database N
+** is [DETACH]-ed or until the database connection closes.
+**
** ^The filename returned by this function is the output of the
** xFullPathname method of the [VFS]. ^In other words, the filename
** will be an absolute pathname, even if the filename used
** to open the database originally was a URI or relative pathname.
+**
+** If the filename pointer returned by this routine is not NULL, then it
+** can be used as the filename input parameter to these routines:
+**
+** - [sqlite3_uri_parameter()]
+**
- [sqlite3_uri_boolean()]
+**
- [sqlite3_uri_int64()]
+**
- [sqlite3_filename_database()]
+**
- [sqlite3_filename_journal()]
+**
- [sqlite3_filename_wal()]
+**
*/
const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName);
@@ -6061,15 +6216,19 @@ void *sqlite3_update_hook(
**
** ^(The cache sharing mode set by this interface effects all subsequent
** calls to [sqlite3_open()], [sqlite3_open_v2()], and [sqlite3_open16()].
-** Existing database connections continue use the sharing mode
+** Existing database connections continue to use the sharing mode
** that was in effect at the time they were opened.)^
**
** ^(This routine returns [SQLITE_OK] if shared cache was enabled or disabled
** successfully. An [error code] is returned otherwise.)^
**
-** ^Shared cache is disabled by default. But this might change in
-** future releases of SQLite. Applications that care about shared
-** cache setting should set it explicitly.
+** ^Shared cache is disabled by default. It is recommended that it stay
+** that way. In other words, do not use this routine. This interface
+** continues to be provided for historical compatibility, but its use is
+** discouraged. Any use of shared cache is discouraged. If shared cache
+** must be used, it is recommended that shared cache only be enabled for
+** individual database connections using the [sqlite3_open_v2()] interface
+** with the [SQLITE_OPEN_SHAREDCACHE] flag.
**
** Note: This method is disabled on MacOS X 10.7 and iOS version 5.0
** and will always return SQLITE_MISUSE. On those systems,
@@ -6116,6 +6275,9 @@ int sqlite3_db_release_memory(sqlite3*);
/*
** CAPI3REF: Impose A Limit On Heap Size
**
+** These interfaces impose limits on the amount of heap memory that will be
+** by all database connections within a single process.
+**
** ^The sqlite3_soft_heap_limit64() interface sets and/or queries the
** soft limit on the amount of heap memory that may be allocated by SQLite.
** ^SQLite strives to keep heap memory utilization below the soft heap
@@ -6126,20 +6288,41 @@ int sqlite3_db_release_memory(sqlite3*);
** an [SQLITE_NOMEM] error. In other words, the soft heap limit
** is advisory only.
**
-** ^The return value from sqlite3_soft_heap_limit64() is the size of
-** the soft heap limit prior to the call, or negative in the case of an
+** ^The sqlite3_hard_heap_limit64(N) interface sets a hard upper bound of
+** N bytes on the amount of memory that will be allocated. ^The
+** sqlite3_hard_heap_limit64(N) interface is similar to
+** sqlite3_soft_heap_limit64(N) except that memory allocations will fail
+** when the hard heap limit is reached.
+**
+** ^The return value from both sqlite3_soft_heap_limit64() and
+** sqlite3_hard_heap_limit64() is the size of
+** the heap limit prior to the call, or negative in the case of an
** error. ^If the argument N is negative
-** then no change is made to the soft heap limit. Hence, the current
-** size of the soft heap limit can be determined by invoking
-** sqlite3_soft_heap_limit64() with a negative argument.
+** then no change is made to the heap limit. Hence, the current
+** size of heap limits can be determined by invoking
+** sqlite3_soft_heap_limit64(-1) or sqlite3_hard_heap_limit(-1).
**
-** ^If the argument N is zero then the soft heap limit is disabled.
+** ^Setting the heap limits to zero disables the heap limiter mechanism.
**
-** ^(The soft heap limit is not enforced in the current implementation
+** ^The soft heap limit may not be greater than the hard heap limit.
+** ^If the hard heap limit is enabled and if sqlite3_soft_heap_limit(N)
+** is invoked with a value of N that is greater than the hard heap limit,
+** the the soft heap limit is set to the value of the hard heap limit.
+** ^The soft heap limit is automatically enabled whenever the hard heap
+** limit is enabled. ^When sqlite3_hard_heap_limit64(N) is invoked and
+** the soft heap limit is outside the range of 1..N, then the soft heap
+** limit is set to N. ^Invoking sqlite3_soft_heap_limit64(0) when the
+** hard heap limit is enabled makes the soft heap limit equal to the
+** hard heap limit.
+**
+** The memory allocation limits can also be adjusted using
+** [PRAGMA soft_heap_limit] and [PRAGMA hard_heap_limit].
+**
+** ^(The heap limits are not enforced in the current implementation
** if one or more of following conditions are true:
**
**
-** - The soft heap limit is set to zero.
+**
- The limit value is set to zero.
**
- Memory accounting is disabled using a combination of the
** [sqlite3_config]([SQLITE_CONFIG_MEMSTATUS],...) start-time option and
** the [SQLITE_DEFAULT_MEMSTATUS] compile-time option.
@@ -6150,21 +6333,11 @@ int sqlite3_db_release_memory(sqlite3*);
** from the heap.
**
)^
**
-** Beginning with SQLite [version 3.7.3] ([dateof:3.7.3]),
-** the soft heap limit is enforced
-** regardless of whether or not the [SQLITE_ENABLE_MEMORY_MANAGEMENT]
-** compile-time option is invoked. With [SQLITE_ENABLE_MEMORY_MANAGEMENT],
-** the soft heap limit is enforced on every memory allocation. Without
-** [SQLITE_ENABLE_MEMORY_MANAGEMENT], the soft heap limit is only enforced
-** when memory is allocated by the page cache. Testing suggests that because
-** the page cache is the predominate memory user in SQLite, most
-** applications will achieve adequate soft heap limit enforcement without
-** the use of [SQLITE_ENABLE_MEMORY_MANAGEMENT].
-**
-** The circumstances under which SQLite will enforce the soft heap limit may
+** The circumstances under which SQLite will enforce the heap limits may
** changes in future releases of SQLite.
*/
sqlite3_int64 sqlite3_soft_heap_limit64(sqlite3_int64 N);
+sqlite3_int64 sqlite3_hard_heap_limit64(sqlite3_int64 N);
/*
** CAPI3REF: Deprecated Soft Heap Limit Interface
@@ -6188,7 +6361,7 @@ SQLITE_DEPRECATED void sqlite3_soft_heap_limit(int N);
** interface returns SQLITE_OK and fills in the non-NULL pointers in
** the final five arguments with appropriate values if the specified
** column exists. ^The sqlite3_table_column_metadata() interface returns
-** SQLITE_ERROR and if the specified column does not exist.
+** SQLITE_ERROR if the specified column does not exist.
** ^If the column-name parameter to sqlite3_table_column_metadata() is a
** NULL pointer, then this routine simply checks for the existence of the
** table and returns SQLITE_OK if the table exists and SQLITE_ERROR if it
@@ -6330,7 +6503,7 @@ int sqlite3_load_extension(
** to enable or disable only the C-API.)^
**
** Security warning: It is recommended that extension loading
-** be disabled using the [SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION] method
+** be enabled using the [SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION] method
** rather than this interface, so the [load_extension()] SQL function
** remains disabled. This will prevent SQL injections from giving attackers
** access to extension loading capabilities.
@@ -6417,7 +6590,7 @@ typedef struct sqlite3_module sqlite3_module;
** KEYWORDS: sqlite3_module {virtual table module}
**
** This structure, sometimes called a "virtual table module",
-** defines the implementation of a [virtual tables].
+** defines the implementation of a [virtual table].
** This structure consists mostly of methods for the module.
**
** ^A virtual table module is created by filling in a persistent
@@ -6514,7 +6687,13 @@ struct sqlite3_module {
** the right-hand side of the corresponding aConstraint[] is evaluated
** and becomes the argvIndex-th entry in argv. ^(If aConstraintUsage[].omit
** is true, then the constraint is assumed to be fully handled by the
-** virtual table and is not checked again by SQLite.)^
+** virtual table and might not be checked again by the byte code.)^ ^(The
+** aConstraintUsage[].omit flag is an optimization hint. When the omit flag
+** is left in its default setting of false, the constraint will always be
+** checked separately in byte code. If the omit flag is change to true, then
+** the constraint may or may not be checked in byte code. In other words,
+** when the omit flag is true there is no guarantee that the constraint will
+** not be checked again using byte code.)^
**
** ^The idxNum and idxPtr values are recorded and passed into the
** [xFilter] method.
@@ -6554,7 +6733,7 @@ struct sqlite3_module {
** If a virtual table extension is
** used with an SQLite version earlier than 3.8.2, the results of attempting
** to read or write the estimatedRows field are undefined (but are likely
-** to included crashing the application). The estimatedRows field should
+** to include crashing the application). The estimatedRows field should
** therefore only be used if [sqlite3_libversion_number()] returns a
** value greater than or equal to 3008002. Similarly, the idxFlags field
** was added for [version 3.9.0] ([dateof:3.9.0]).
@@ -6606,7 +6785,7 @@ struct sqlite3_index_info {
/*
** CAPI3REF: Virtual Table Constraint Operator Codes
**
-** These macros defined the allowed values for the
+** These macros define the allowed values for the
** [sqlite3_index_info].aConstraint[].op field. Each value represents
** an operator that is part of a constraint term in the wHERE clause of
** a query that uses a [virtual table].
@@ -7216,7 +7395,7 @@ void sqlite3_mutex_leave(sqlite3_mutex*);
** The only difference is that the public sqlite3_XXX functions enumerated
** above silently ignore any invocations that pass a NULL pointer instead
** of a valid mutex handle. The implementations of the methods defined
-** by this structure are not required to handle this case, the results
+** by this structure are not required to handle this case. The results
** of passing a NULL pointer instead of a valid mutex handle are undefined
** (i.e. it is acceptable to provide an implementation that segfaults if
** it is passed a NULL pointer).
@@ -7689,7 +7868,7 @@ int sqlite3_status64(
**
** [[SQLITE_STATUS_PAGECACHE_SIZE]] ^(- SQLITE_STATUS_PAGECACHE_SIZE
** - This parameter records the largest memory allocation request
-** handed to [pagecache memory allocator]. Only the value returned in the
+** handed to the [pagecache memory allocator]. Only the value returned in the
** *pHighwater parameter to [sqlite3_status()] is of interest.
** The value written into the *pCurrent parameter is undefined.
)^
**
@@ -7765,7 +7944,7 @@ int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg);
** checked out.)^
**
** [[SQLITE_DBSTATUS_LOOKASIDE_HIT]] ^(- SQLITE_DBSTATUS_LOOKASIDE_HIT
-** - This parameter returns the number malloc attempts that were
+**
- This parameter returns the number of malloc attempts that were
** satisfied using lookaside memory. Only the high-water value is meaningful;
** the current value is always zero.)^
**
@@ -7847,7 +8026,7 @@ int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg);
** cache overflowing. Transactions are more efficient if they are written
** to disk all at once. When pages spill mid-transaction, that introduces
** additional overhead. This parameter can be used help identify
-** inefficiencies that can be resolve by increasing the cache size.
+** inefficiencies that can be resolved by increasing the cache size.
**
**
** [[SQLITE_DBSTATUS_DEFERRED_FKS]] ^( - SQLITE_DBSTATUS_DEFERRED_FKS
@@ -7936,7 +8115,7 @@ int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg);
**
** [[SQLITE_STMTSTATUS_REPREPARE]] - SQLITE_STMTSTATUS_REPREPARE
** - ^This is the number of times that the prepare statement has been
-** automatically regenerated due to schema changes or change to
+** automatically regenerated due to schema changes or changes to
** [bound parameters] that might affect the query plan.
**
** [[SQLITE_STMTSTATUS_RUN]]
- SQLITE_STMTSTATUS_RUN
@@ -8107,7 +8286,7 @@ struct sqlite3_pcache_page {
**
** ^(SQLite will normally invoke xFetch() with a createFlag of 0 or 1. SQLite
** will only use a createFlag of 2 after a prior call with a createFlag of 1
-** failed.)^ In between the to xFetch() calls, SQLite may
+** failed.)^ In between the xFetch() calls, SQLite may
** attempt to unpin one or more cache pages by spilling the content of
** pinned pages to disk and synching the operating system disk cache.
**
@@ -8425,7 +8604,7 @@ int sqlite3_backup_pagecount(sqlite3_backup *p);
** the first argument to register for a callback that will be invoked
** when the blocking connections current transaction is concluded. ^The
** callback is invoked from within the [sqlite3_step] or [sqlite3_close]
-** call that concludes the blocking connections transaction.
+** call that concludes the blocking connection's transaction.
**
** ^(If sqlite3_unlock_notify() is called in a multi-threaded application,
** there is a chance that the blocking connection will have already
@@ -8463,7 +8642,7 @@ int sqlite3_backup_pagecount(sqlite3_backup *p);
** an unlock-notify callback is a pointer to an array of void* pointers,
** and the second is the number of entries in the array.
**
-** When a blocking connections transaction is concluded, there may be
+** When a blocking connection's transaction is concluded, there may be
** more than one blocked connection that has registered for an unlock-notify
** callback. ^If two or more such blocked connections have specified the
** same callback function, then instead of invoking the callback function
@@ -8826,7 +9005,7 @@ int sqlite3_vtab_config(sqlite3*, int op, ...);
**
**
** [[SQLITE_VTAB_CONSTRAINT_SUPPORT]]
-** - SQLITE_VTAB_CONSTRAINT_SUPPORT
+**
- SQLITE_VTAB_CONSTRAINT_SUPPORT
** - Calls of the form
** [sqlite3_vtab_config](db,SQLITE_VTAB_CONSTRAINT_SUPPORT,X) are supported,
** where X is an integer. If X is zero, then the [virtual table] whose
@@ -8855,9 +9034,31 @@ int sqlite3_vtab_config(sqlite3*, int op, ...);
** return SQLITE_OK. Or, if this is not possible, it may return
** SQLITE_CONSTRAINT, in which case SQLite falls back to OR ABORT
** constraint handling.
+**
+**
+** [[SQLITE_VTAB_DIRECTONLY]]- SQLITE_VTAB_DIRECTONLY
+** - Calls of the form
+** [sqlite3_vtab_config](db,SQLITE_VTAB_DIRECTONLY) from within the
+** the [xConnect] or [xCreate] methods of a [virtual table] implmentation
+** prohibits that virtual table from being used from within triggers and
+** views.
+**
+**
+** [[SQLITE_VTAB_INNOCUOUS]]- SQLITE_VTAB_INNOCUOUS
+** - Calls of the form
+** [sqlite3_vtab_config](db,SQLITE_VTAB_INNOCUOUS) from within the
+** the [xConnect] or [xCreate] methods of a [virtual table] implmentation
+** identify that virtual table as being safe to use from within triggers
+** and views. Conceptually, the SQLITE_VTAB_INNOCUOUS tag means that the
+** virtual table can do no serious harm even if it is controlled by a
+** malicious hacker. Developers should avoid setting the SQLITE_VTAB_INNOCUOUS
+** flag unless absolutely necessary.
+**
**
*/
#define SQLITE_VTAB_CONSTRAINT_SUPPORT 1
+#define SQLITE_VTAB_INNOCUOUS 2
+#define SQLITE_VTAB_DIRECTONLY 3
/*
** CAPI3REF: Determine The Virtual Table Conflict Policy
@@ -8937,15 +9138,15 @@ SQLITE_EXPERIMENTAL const char *sqlite3_vtab_collation(sqlite3_index_info*,int);
**
**
** [[SQLITE_SCANSTAT_NLOOP]] - SQLITE_SCANSTAT_NLOOP
-** - ^The [sqlite3_int64] variable pointed to by the T parameter will be
+**
- ^The [sqlite3_int64] variable pointed to by the V parameter will be
** set to the total number of times that the X-th loop has run.
**
** [[SQLITE_SCANSTAT_NVISIT]] - SQLITE_SCANSTAT_NVISIT
-** - ^The [sqlite3_int64] variable pointed to by the T parameter will be set
+**
- ^The [sqlite3_int64] variable pointed to by the V parameter will be set
** to the total number of rows examined by all iterations of the X-th loop.
**
** [[SQLITE_SCANSTAT_EST]] - SQLITE_SCANSTAT_EST
-** - ^The "double" variable pointed to by the T parameter will be set to the
+**
- ^The "double" variable pointed to by the V parameter will be set to the
** query planner's estimate for the average number of rows output from each
** iteration of the X-th loop. If the query planner's estimates was accurate,
** then this value will approximate the quotient NVISIT/NLOOP and the
@@ -8953,17 +9154,17 @@ SQLITE_EXPERIMENTAL const char *sqlite3_vtab_collation(sqlite3_index_info*,int);
** be the NLOOP value for the current loop.
**
** [[SQLITE_SCANSTAT_NAME]]
- SQLITE_SCANSTAT_NAME
-** - ^The "const char *" variable pointed to by the T parameter will be set
+**
- ^The "const char *" variable pointed to by the V parameter will be set
** to a zero-terminated UTF-8 string containing the name of the index or table
** used for the X-th loop.
**
** [[SQLITE_SCANSTAT_EXPLAIN]]
- SQLITE_SCANSTAT_EXPLAIN
-** - ^The "const char *" variable pointed to by the T parameter will be set
+**
- ^The "const char *" variable pointed to by the V parameter will be set
** to a zero-terminated UTF-8 string containing the [EXPLAIN QUERY PLAN]
** description for the X-th loop.
**
** [[SQLITE_SCANSTAT_SELECTID]]
- SQLITE_SCANSTAT_SELECT
-** - ^The "int" variable pointed to by the T parameter will be set to the
+**
- ^The "int" variable pointed to by the V parameter will be set to the
** "select-id" for the X-th loop. The select-id identifies which query or
** subquery the loop is part of. The main query has a select-id of zero.
** The select-id is the same value as is output in the first column
diff --git a/src/sqlite3ext.h b/src/sqlite3ext.h
index 416ac94231..b5258e0da0 100644
--- a/src/sqlite3ext.h
+++ b/src/sqlite3ext.h
@@ -324,6 +324,12 @@ struct sqlite3_api_routines {
int (*value_frombind)(sqlite3_value*);
/* Version 3.30.0 and later */
int (*drop_modules)(sqlite3*,const char**);
+ /* Version 3.31.0 and later */
+ sqlite3_int64 (*hard_heap_limit64)(sqlite3_int64);
+ const char *(*uri_key)(const char*,int);
+ const char *(*filename_database)(const char*);
+ const char *(*filename_journal)(const char*);
+ const char *(*filename_wal)(const char*);
};
/*
@@ -618,6 +624,12 @@ typedef int (*sqlite3_loadext_entry)(
#define sqlite3_value_frombind sqlite3_api->frombind
/* Version 3.30.0 and later */
#define sqlite3_drop_modules sqlite3_api->drop_modules
+/* Version 3.31.0 andn later */
+#define sqlite3_hard_heap_limit64 sqlite3_api->hard_heap_limit64
+#define sqlite3_uri_key sqlite3_api->uri_key
+#define sqlite3_filename_database sqlite3_api->filename_database
+#define sqlite3_filename_journal sqlite3_api->filename_journal
+#define sqlite3_filename_wal sqlite3_api->filename_wal
#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index 9e8c864c62..53e7095daa 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -446,6 +446,26 @@
# define NEVER(X) (X)
#endif
+/*
+** The harmless(X) macro indicates that expression X is usually false
+** but can be true without causing any problems, but we don't know of
+** any way to cause X to be true.
+**
+** In debugging and testing builds, this macro will abort if X is ever
+** true. In this way, developers are alerted to a possible test case
+** that causes X to be true. If a harmless macro ever fails, that is
+** an opportunity to change the macro into a testcase() and add a new
+** test case to the test suite.
+**
+** For normal production builds, harmless(X) is a no-op, since it does
+** not matter whether expression X is true or false.
+*/
+#ifdef SQLITE_DEBUG
+# define harmless(X) assert(!(X));
+#else
+# define harmless(X)
+#endif
+
/*
** Some conditionals are optimizations only. In other words, if the
** conditionals are replaced with a constant 1 (true) or 0 (false) then
@@ -1122,6 +1142,7 @@ typedef struct With With;
** A bit in a Bitmask
*/
#define MASKBIT(n) (((Bitmask)1)<<(n))
+#define MASKBIT64(n) (((u64)1)<<(n))
#define MASKBIT32(n) (((unsigned int)1)<<(n))
#define ALLBITS ((Bitmask)-1)
@@ -1271,15 +1292,47 @@ struct Schema {
** is shared by multiple database connections. Therefore, while parsing
** schema information, the Lookaside.bEnabled flag is cleared so that
** lookaside allocations are not used to construct the schema objects.
+**
+** New lookaside allocations are only allowed if bDisable==0. When
+** bDisable is greater than zero, sz is set to zero which effectively
+** disables lookaside without adding a new test for the bDisable flag
+** in a performance-critical path. sz should be set by to szTrue whenever
+** bDisable changes back to zero.
+**
+** Lookaside buffers are initially held on the pInit list. As they are
+** used and freed, they are added back to the pFree list. New allocations
+** come off of pFree first, then pInit as a fallback. This dual-list
+** allows use to compute a high-water mark - the maximum number of allocations
+** outstanding at any point in the past - by subtracting the number of
+** allocations on the pInit list from the total number of allocations.
+**
+** Enhancement on 2019-12-12: Two-size-lookaside
+** The default lookaside configuration is 100 slots of 1200 bytes each.
+** The larger slot sizes are important for performance, but they waste
+** a lot of space, as most lookaside allocations are less than 128 bytes.
+** The two-size-lookaside enhancement breaks up the lookaside allocation
+** into two pools: One of 128-byte slots and the other of the default size
+** (1200-byte) slots. Allocations are filled from the small-pool first,
+** failing over to the full-size pool if that does not work. Thus more
+** lookaside slots are available while also using less memory.
+** This enhancement can be omitted by compiling with
+** SQLITE_OMIT_TWOSIZE_LOOKASIDE.
*/
struct Lookaside {
u32 bDisable; /* Only operate the lookaside when zero */
u16 sz; /* Size of each buffer in bytes */
+ u16 szTrue; /* True value of sz, even if disabled */
u8 bMalloced; /* True if pStart obtained from sqlite3_malloc() */
u32 nSlot; /* Number of lookaside slots allocated */
u32 anStat[3]; /* 0: hits. 1: size misses. 2: full misses */
LookasideSlot *pInit; /* List of buffers not previously used */
LookasideSlot *pFree; /* List of available buffers */
+#ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE
+ LookasideSlot *pSmallInit; /* List of small buffers not prediously used */
+ LookasideSlot *pSmallFree; /* List of available small buffers */
+ void *pMiddle; /* First byte past end of full-size buffers and
+ ** the first byte of LOOKASIDE_SMALL buffers */
+#endif /* SQLITE_OMIT_TWOSIZE_LOOKASIDE */
void *pStart; /* First byte of available memory space */
void *pEnd; /* First byte past end of available space */
};
@@ -1287,6 +1340,17 @@ struct LookasideSlot {
LookasideSlot *pNext; /* Next buffer in the list of free buffers */
};
+#define DisableLookaside db->lookaside.bDisable++;db->lookaside.sz=0
+#define EnableLookaside db->lookaside.bDisable--;\
+ db->lookaside.sz=db->lookaside.bDisable?0:db->lookaside.szTrue
+
+/* Size of the smaller allocations in two-size lookside */
+#ifdef SQLITE_OMIT_TWOSIZE_LOOKASIDE
+# define LOOKASIDE_SMALL 0
+#else
+# define LOOKASIDE_SMALL 128
+#endif
+
/*
** A hash table for built-in function definitions. (Application-defined
** functions use a regular table table from hash.h.)
@@ -1495,6 +1559,13 @@ struct sqlite3 {
#define SCHEMA_ENC(db) ((db)->aDb[0].pSchema->enc)
#define ENC(db) ((db)->enc)
+/*
+** A u64 constant where the lower 32 bits are all zeros. Only the
+** upper 32 bits are included in the argument. Necessary because some
+** C-compilers still do not accept LL integer literals.
+*/
+#define HI(X) ((u64)(X)<<32)
+
/*
** Possible values for the sqlite3.flags.
**
@@ -1510,9 +1581,8 @@ struct sqlite3 {
#define SQLITE_CkptFullFSync 0x00000010 /* Use full fsync for checkpoint */
#define SQLITE_CacheSpill 0x00000020 /* OK to spill pager cache */
#define SQLITE_ShortColNames 0x00000040 /* Show short columns names */
-#define SQLITE_CountRows 0x00000080 /* Count rows changed by INSERT, */
- /* DELETE, or UPDATE and return */
- /* the count using a callback. */
+#define SQLITE_TrustedSchema 0x00000080 /* Allow unsafe functions and
+ ** vtabs in the schema definition */
#define SQLITE_NullCallback 0x00000100 /* Invoke the callback once if the */
/* result set is empty */
#define SQLITE_IgnoreChecks 0x00000200 /* Do not enforce check constraints */
@@ -1538,9 +1608,11 @@ struct sqlite3 {
#define SQLITE_DqsDDL 0x20000000 /* dbl-quoted strings allowed in DDL*/
#define SQLITE_DqsDML 0x40000000 /* dbl-quoted strings allowed in DML*/
#define SQLITE_EnableView 0x80000000 /* Enable the use of views */
+#define SQLITE_CountRows HI(0x00001) /* Count rows changed by INSERT, */
+ /* DELETE, or UPDATE and return */
+ /* the count using a callback. */
/* Flags used only if debugging */
-#define HI(X) ((u64)(X)<<32)
#ifdef SQLITE_DEBUG
#define SQLITE_SqlTrace HI(0x0100000) /* Debug print SQL as it executes */
#define SQLITE_VdbeListing HI(0x0200000) /* Debug listings of VDBE progs */
@@ -1558,6 +1630,7 @@ struct sqlite3 {
#define DBFLAG_Vacuum 0x0004 /* Currently in a VACUUM */
#define DBFLAG_VacuumInto 0x0008 /* Currently running VACUUM INTO */
#define DBFLAG_SchemaKnownOk 0x0010 /* Schema is known to be valid */
+#define DBFLAG_InternalFunc 0x0020 /* Allow use of internal functions */
/*
** Bits of the sqlite3.dbOptFlags field that are used by the
@@ -1665,6 +1738,7 @@ struct FuncDestructor {
** SQLITE_FUNC_TYPEOF == OPFLAG_TYPEOFARG
** SQLITE_FUNC_CONSTANT == SQLITE_DETERMINISTIC from the API
** SQLITE_FUNC_DIRECT == SQLITE_DIRECTONLY from the API
+** SQLITE_FUNC_UNSAFE == SQLITE_INNOCUOUS
** SQLITE_FUNC_ENCMASK depends on SQLITE_UTF* macros in the API
*/
#define SQLITE_FUNC_ENCMASK 0x0003 /* SQLITE_UTF8, SQLITE_UTF16BE or UTF16LE */
@@ -1681,12 +1755,22 @@ struct FuncDestructor {
#define SQLITE_FUNC_MINMAX 0x1000 /* True for min() and max() aggregates */
#define SQLITE_FUNC_SLOCHNG 0x2000 /* "Slow Change". Value constant during a
** single query - might change over time */
-#define SQLITE_FUNC_AFFINITY 0x4000 /* Built-in affinity() function */
+#define SQLITE_FUNC_TEST 0x4000 /* Built-in testing functions */
#define SQLITE_FUNC_OFFSET 0x8000 /* Built-in sqlite_offset() function */
#define SQLITE_FUNC_WINDOW 0x00010000 /* Built-in window-only function */
#define SQLITE_FUNC_INTERNAL 0x00040000 /* For use by NestedParse() only */
#define SQLITE_FUNC_DIRECT 0x00080000 /* Not for use in TRIGGERs or VIEWs */
#define SQLITE_FUNC_SUBTYPE 0x00100000 /* Result likely to have sub-type */
+#define SQLITE_FUNC_UNSAFE 0x00200000 /* Function has side effects */
+#define SQLITE_FUNC_INLINE 0x00400000 /* Functions implemented in-line */
+
+/* Identifier numbers for each in-line function */
+#define INLINEFUNC_coalesce 0
+#define INLINEFUNC_implies_nonnull_row 1
+#define INLINEFUNC_expr_implies_expr 2
+#define INLINEFUNC_expr_compare 3
+#define INLINEFUNC_affinity 4
+#define INLINEFUNC_unlikely 99 /* Default case */
/*
** The following three macros, FUNCTION(), LIKEFUNC() and AGGREGATE() are
@@ -1702,6 +1786,22 @@ struct FuncDestructor {
** VFUNCTION(zName, nArg, iArg, bNC, xFunc)
** Like FUNCTION except it omits the SQLITE_FUNC_CONSTANT flag.
**
+** SFUNCTION(zName, nArg, iArg, bNC, xFunc)
+** Like FUNCTION except it omits the SQLITE_FUNC_CONSTANT flag and
+** adds the SQLITE_DIRECTONLY flag.
+**
+** INLINE_FUNC(zName, nArg, iFuncId, mFlags)
+** zName is the name of a function that is implemented by in-line
+** byte code rather than by the usual callbacks. The iFuncId
+** parameter determines the function id. The mFlags parameter is
+** optional SQLITE_FUNC_ flags for this function.
+**
+** TEST_FUNC(zName, nArg, iFuncId, mFlags)
+** zName is the name of a test-only function implemented by in-line
+** byte code rather than by the usual callbacks. The iFuncId
+** parameter determines the function id. The mFlags parameter is
+** optional SQLITE_FUNC_ flags for this function.
+**
** DFUNCTION(zName, nArg, iArg, bNC, xFunc)
** Like FUNCTION except it omits the SQLITE_FUNC_CONSTANT flag and
** adds the SQLITE_FUNC_SLOCHNG flag. Used for date & time functions
@@ -1741,6 +1841,16 @@ struct FuncDestructor {
#define VFUNCTION(zName, nArg, iArg, bNC, xFunc) \
{nArg, SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \
SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, 0, #zName, {0} }
+#define SFUNCTION(zName, nArg, iArg, bNC, xFunc) \
+ {nArg, SQLITE_UTF8|SQLITE_DIRECTONLY|SQLITE_FUNC_UNSAFE, \
+ SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, 0, #zName, {0} }
+#define INLINE_FUNC(zName, nArg, iArg, mFlags) \
+ {nArg, SQLITE_UTF8|SQLITE_FUNC_INLINE|SQLITE_FUNC_CONSTANT|(mFlags), \
+ SQLITE_INT_TO_PTR(iArg), 0, noopFunc, 0, 0, 0, #zName, {0} }
+#define TEST_FUNC(zName, nArg, iArg, mFlags) \
+ {nArg, SQLITE_UTF8|SQLITE_FUNC_INTERNAL|SQLITE_FUNC_TEST| \
+ SQLITE_FUNC_INLINE|SQLITE_FUNC_CONSTANT|(mFlags), \
+ SQLITE_INT_TO_PTR(iArg), 0, noopFunc, 0, 0, 0, #zName, {0} }
#define DFUNCTION(zName, nArg, iArg, bNC, xFunc) \
{nArg, SQLITE_FUNC_SLOCHNG|SQLITE_UTF8, \
0, 0, xFunc, 0, 0, 0, #zName, {0} }
@@ -1756,12 +1866,6 @@ struct FuncDestructor {
#define LIKEFUNC(zName, nArg, arg, flags) \
{nArg, SQLITE_FUNC_CONSTANT|SQLITE_UTF8|flags, \
(void *)arg, 0, likeFunc, 0, 0, 0, #zName, {0} }
-#define AGGREGATE(zName, nArg, arg, nc, xStep, xFinal, xValue) \
- {nArg, SQLITE_UTF8|(nc*SQLITE_FUNC_NEEDCOLL), \
- SQLITE_INT_TO_PTR(arg), 0, xStep,xFinal,xValue,0,#zName, {0}}
-#define AGGREGATE2(zName, nArg, arg, nc, xStep, xFinal, extraFlags) \
- {nArg, SQLITE_UTF8|(nc*SQLITE_FUNC_NEEDCOLL)|extraFlags, \
- SQLITE_INT_TO_PTR(arg), 0, xStep,xFinal,xFinal,0,#zName, {0}}
#define WAGGREGATE(zName, nArg, arg, nc, xStep, xFinal, xValue, xInverse, f) \
{nArg, SQLITE_UTF8|(nc*SQLITE_FUNC_NEEDCOLL)|f, \
SQLITE_INT_TO_PTR(arg), 0, xStep,xFinal,xValue,xInverse,#zName, {0}}
@@ -1807,26 +1911,45 @@ struct Module {
};
/*
-** information about each column of an SQL table is held in an instance
-** of this structure.
+** Information about each column of an SQL table is held in an instance
+** of the Column structure, in the Table.aCol[] array.
+**
+** Definitions:
+**
+** "table column index" This is the index of the column in the
+** Table.aCol[] array, and also the index of
+** the column in the original CREATE TABLE stmt.
+**
+** "storage column index" This is the index of the column in the
+** record BLOB generated by the OP_MakeRecord
+** opcode. The storage column index is less than
+** or equal to the table column index. It is
+** equal if and only if there are no VIRTUAL
+** columns to the left.
*/
struct Column {
char *zName; /* Name of this column, \000, then the type */
- Expr *pDflt; /* Default value of this column */
+ Expr *pDflt; /* Default value or GENERATED ALWAYS AS value */
char *zColl; /* Collating sequence. If NULL, use the default */
u8 notNull; /* An OE_ code for handling a NOT NULL constraint */
char affinity; /* One of the SQLITE_AFF_... values */
u8 szEst; /* Estimated size of value in this column. sizeof(INT)==1 */
- u8 colFlags; /* Boolean properties. See COLFLAG_ defines below */
+ u16 colFlags; /* Boolean properties. See COLFLAG_ defines below */
};
/* Allowed values for Column.colFlags:
*/
-#define COLFLAG_PRIMKEY 0x0001 /* Column is part of the primary key */
-#define COLFLAG_HIDDEN 0x0002 /* A hidden column in a virtual table */
-#define COLFLAG_HASTYPE 0x0004 /* Type name follows column name */
-#define COLFLAG_UNIQUE 0x0008 /* Column def contains "UNIQUE" or "PK" */
+#define COLFLAG_PRIMKEY 0x0001 /* Column is part of the primary key */
+#define COLFLAG_HIDDEN 0x0002 /* A hidden column in a virtual table */
+#define COLFLAG_HASTYPE 0x0004 /* Type name follows column name */
+#define COLFLAG_UNIQUE 0x0008 /* Column def contains "UNIQUE" or "PK" */
#define COLFLAG_SORTERREF 0x0010 /* Use sorter-refs with this column */
+#define COLFLAG_VIRTUAL 0x0020 /* GENERATED ALWAYS AS ... VIRTUAL */
+#define COLFLAG_STORED 0x0040 /* GENERATED ALWAYS AS ... STORED */
+#define COLFLAG_NOTAVAIL 0x0080 /* STORED column not yet calculated */
+#define COLFLAG_BUSY 0x0100 /* Blocks recursion on GENERATED columns */
+#define COLFLAG_GENERATED 0x0060 /* Combo: _STORED, _VIRTUAL */
+#define COLFLAG_NOINSERT 0x0062 /* Combo: _HIDDEN, _STORED, _VIRTUAL */
/*
** A "Collating Sequence" is defined by an instance of the following
@@ -1944,10 +2067,17 @@ struct VTable {
sqlite3_vtab *pVtab; /* Pointer to vtab instance */
int nRef; /* Number of pointers to this structure */
u8 bConstraint; /* True if constraints are supported */
+ u8 eVtabRisk; /* Riskiness of allowing hacker access */
int iSavepoint; /* Depth of the SAVEPOINT stack */
VTable *pNext; /* Next in linked list (see above) */
};
+/* Allowed values for VTable.eVtabRisk
+*/
+#define SQLITE_VTABRISK_Low 0
+#define SQLITE_VTABRISK_Normal 1
+#define SQLITE_VTABRISK_High 2
+
/*
** The schema for each SQL table and view is represented in memory
** by an instance of the following structure.
@@ -1966,6 +2096,7 @@ struct Table {
u32 tabFlags; /* Mask of TF_* values */
i16 iPKey; /* If not negative, use aCol[iPKey] as the rowid */
i16 nCol; /* Number of columns in this table */
+ i16 nNVCol; /* Number of columns that are not VIRTUAL */
LogEst nRowLogEst; /* Estimated rows in table - from sqlite_stat1 table */
LogEst szTabRow; /* Estimated size of each table row in bytes */
#ifdef SQLITE_ENABLE_COSTMULT
@@ -1992,20 +2123,28 @@ struct Table {
** followed by non-hidden columns. Example: "CREATE VIRTUAL TABLE x USING
** vtab1(a HIDDEN, b);". Since "b" is a non-hidden column but "a" is hidden,
** the TF_OOOHidden attribute would apply in this case. Such tables require
-** special handling during INSERT processing.
+** special handling during INSERT processing. The "OOO" means "Out Of Order".
+**
+** Constraints:
+**
+** TF_HasVirtual == COLFLAG_Virtual
+** TF_HasStored == COLFLAG_Stored
*/
#define TF_Readonly 0x0001 /* Read-only system table */
#define TF_Ephemeral 0x0002 /* An ephemeral table */
#define TF_HasPrimaryKey 0x0004 /* Table has a primary key */
#define TF_Autoincrement 0x0008 /* Integer primary key is autoincrement */
#define TF_HasStat1 0x0010 /* nRowLogEst set from sqlite_stat1 */
-#define TF_WithoutRowid 0x0020 /* No rowid. PRIMARY KEY is the key */
-#define TF_NoVisibleRowid 0x0040 /* No user-visible "rowid" column */
-#define TF_OOOHidden 0x0080 /* Out-of-Order hidden columns */
+#define TF_HasVirtual 0x0020 /* Has one or more VIRTUAL columns */
+#define TF_HasStored 0x0040 /* Has one or more STORED columns */
+#define TF_HasGenerated 0x0060 /* Combo: HasVirtual + HasStored */
+#define TF_WithoutRowid 0x0080 /* No rowid. PRIMARY KEY is the key */
#define TF_StatsUsed 0x0100 /* Query planner decisions affected by
** Index.aiRowLogEst[] values */
-#define TF_HasNotNull 0x0200 /* Contains NOT NULL constraints */
-#define TF_Shadow 0x0400 /* True for a shadow table */
+#define TF_NoVisibleRowid 0x0200 /* No user-visible "rowid" column */
+#define TF_OOOHidden 0x0400 /* Out-of-Order hidden columns */
+#define TF_HasNotNull 0x0800 /* Contains NOT NULL constraints */
+#define TF_Shadow 0x1000 /* True for a shadow table */
/*
** Test to see whether or not a table is a virtual table. This is
@@ -2256,6 +2395,7 @@ struct Index {
unsigned hasStat1:1; /* aiRowLogEst values come from sqlite_stat1 */
unsigned bNoQuery:1; /* Do not use this index to optimize queries */
unsigned bAscKeyBug:1; /* True if the bba7b69f9849b5bf bug applies */
+ unsigned bHasVCol:1; /* Index references one or more VIRTUAL columns */
#ifdef SQLITE_ENABLE_STAT4
int nSample; /* Number of elements in aSample[] */
int nSampleCol; /* Size of IndexSample.anEq[] and so on */
@@ -2447,6 +2587,10 @@ typedef int ynVar;
struct Expr {
u8 op; /* Operation performed by this node */
char affExpr; /* affinity, or RAISE type */
+ u8 op2; /* TK_REGISTER/TK_TRUTH: original value of Expr.op
+ ** TK_COLUMN: the value of p5 for OP_Column
+ ** TK_AGG_FUNCTION: nesting depth
+ ** TK_FUNCTION: NC_SelfRef flag if needs OP_PureFunc */
u32 flags; /* Various flags. EP_* See below */
union {
char *zToken; /* Token value. Zero terminated and dequoted */
@@ -2485,9 +2629,6 @@ struct Expr {
** TK_SELECT_COLUMN: column of the result vector */
i16 iAgg; /* Which entry in pAggInfo->aCol[] or ->aFunc[] */
i16 iRightJoinTable; /* If EP_FromJoin, the right table of the join */
- u8 op2; /* TK_REGISTER/TK_TRUTH: original value of Expr.op
- ** TK_COLUMN: the value of p5 for OP_Column
- ** TK_AGG_FUNCTION: nesting depth */
AggInfo *pAggInfo; /* Used by TK_AGG_COLUMN and TK_AGG_FUNCTION */
union {
Table *pTab; /* TK_COLUMN: Table containing column. Can be NULL
@@ -2516,7 +2657,7 @@ struct Expr {
#define EP_DblQuoted 0x000040 /* token.z was originally in "..." */
#define EP_InfixFunc 0x000080 /* True for an infix function: LIKE, GLOB, etc */
#define EP_Collate 0x000100 /* Tree contains a TK_COLLATE operator */
- /* 0x000200 Available for reuse */
+#define EP_Commuted 0x000200 /* Comparison operator has been commuted */
#define EP_IntValue 0x000400 /* Integer value contained in u.iValue */
#define EP_xIsSelect 0x000800 /* x.pSelect is valid (otherwise x.pList is) */
#define EP_Skip 0x001000 /* Operator does not contribute to affinity */
@@ -2537,7 +2678,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_Indirect 0x40000000 /* Contained within a TRIGGER or a VIEW */
+#define EP_FromDDL 0x40000000 /* Originates from sqlite_master */
/*
** The EP_Propagate mask is a set of properties that automatically propagate
@@ -2585,9 +2726,13 @@ struct Expr {
** True if the expression passed as an argument was a function with
** an OVER() clause (a window function).
*/
-#define IsWindowFunc(p) ( \
+#ifdef SQLITE_OMIT_WINDOWFUNC
+# define IsWindowFunc(p) 0
+#else
+# define IsWindowFunc(p) ( \
ExprHasProperty((p), EP_WinFunc) && p->y.pWin->eFrmType!=TK_FILTER \
-)
+ )
+#endif
/*
** A list of expressions. Each expression may optionally have a
@@ -2597,23 +2742,28 @@ struct Expr {
** also be used as the argument to a function, in which case the a.zName
** field is not used.
**
-** By default the Expr.zSpan field holds a human-readable description of
-** the expression that is used in the generation of error messages and
-** column labels. In this case, Expr.zSpan is typically the text of a
-** column expression as it exists in a SELECT statement. However, if
-** the bSpanIsTab flag is set, then zSpan is overloaded to mean the name
-** of the result column in the form: DATABASE.TABLE.COLUMN. This later
-** form is used for name resolution with nested FROM clauses.
+** In order to try to keep memory usage down, the Expr.a.zEName field
+** is used for multiple purposes:
+**
+** eEName Usage
+** ---------- -------------------------
+** ENAME_NAME (1) the AS of result set column
+** (2) COLUMN= of an UPDATE
+**
+** ENAME_TAB DB.TABLE.NAME used to resolve names
+** of subqueries
+**
+** ENAME_SPAN Text of the original result set
+** expression.
*/
struct ExprList {
int nExpr; /* Number of expressions on the list */
struct ExprList_item { /* For each expression in the list */
Expr *pExpr; /* The parse tree for this expression */
- char *zName; /* Token associated with this expression */
- char *zSpan; /* Original text of the expression */
+ char *zEName; /* Token associated with this expression */
u8 sortFlags; /* Mask of KEYINFO_ORDER_* flags */
+ unsigned eEName :2; /* Meaning of zEName */
unsigned done :1; /* A flag to indicate when processing is finished */
- unsigned bSpanIsTab :1; /* zSpan holds DB.TABLE.COLUMN */
unsigned reusable :1; /* Constant expression is reusable */
unsigned bSorterRef :1; /* Defer evaluation until after sorting */
unsigned bNulls: 1; /* True if explicit "NULLS FIRST/LAST" */
@@ -2627,6 +2777,13 @@ struct ExprList {
} a[1]; /* One slot for each expression in the list */
};
+/*
+** Allowed values for Expr.a.eEName
+*/
+#define ENAME_NAME 0 /* The AS clause of a result set */
+#define ENAME_SPAN 1 /* Complete text of the result set expression */
+#define ENAME_TAB 2 /* "DB.TABLE.NAME" for the result set */
+
/*
** An instance of this structure can hold a simple list of identifiers,
** such as the list "a,b,c" in the following statements:
@@ -2690,6 +2847,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 */
} fg;
int iCursor; /* The VDBE cursor number used to access this table */
Expr *pOn; /* The ON clause of a join */
@@ -2793,21 +2951,24 @@ struct NameContext {
** NC_HasWin == EP_Win
**
*/
-#define NC_AllowAgg 0x0001 /* Aggregate functions are allowed here */
-#define NC_PartIdx 0x0002 /* True if resolving a partial index WHERE */
-#define NC_IsCheck 0x0004 /* True if resolving names in a CHECK constraint */
-#define NC_InAggFunc 0x0008 /* True if analyzing arguments to an agg func */
-#define NC_HasAgg 0x0010 /* One or more aggregate functions seen */
-#define NC_IdxExpr 0x0020 /* True if resolving columns of CREATE INDEX */
-#define NC_VarSelect 0x0040 /* A correlated subquery has been seen */
-#define NC_UEList 0x0080 /* True if uNC.pEList is used */
-#define NC_UAggInfo 0x0100 /* True if uNC.pAggInfo is used */
-#define NC_UUpsert 0x0200 /* True if uNC.pUpsert is used */
-#define NC_MinMaxAgg 0x1000 /* min/max aggregates seen. See note above */
-#define NC_Complex 0x2000 /* True if a function or subquery seen */
-#define NC_AllowWin 0x4000 /* Window functions are allowed here */
-#define NC_HasWin 0x8000 /* One or more window functions seen */
-#define NC_IsDDL 0x10000 /* Resolving names in a CREATE statement */
+#define NC_AllowAgg 0x00001 /* Aggregate functions are allowed here */
+#define NC_PartIdx 0x00002 /* True if resolving a partial index WHERE */
+#define NC_IsCheck 0x00004 /* True if resolving a CHECK constraint */
+#define NC_GenCol 0x00008 /* True for a GENERATED ALWAYS AS clause */
+#define NC_HasAgg 0x00010 /* One or more aggregate functions seen */
+#define NC_IdxExpr 0x00020 /* True if resolving columns of CREATE INDEX */
+#define NC_SelfRef 0x0002e /* Combo: PartIdx, isCheck, GenCol, and IdxExpr */
+#define NC_VarSelect 0x00040 /* A correlated subquery has been seen */
+#define NC_UEList 0x00080 /* True if uNC.pEList is used */
+#define NC_UAggInfo 0x00100 /* True if uNC.pAggInfo is used */
+#define NC_UUpsert 0x00200 /* True if uNC.pUpsert is used */
+#define NC_MinMaxAgg 0x01000 /* min/max aggregates seen. See note above */
+#define NC_Complex 0x02000 /* True if a function or subquery seen */
+#define NC_AllowWin 0x04000 /* Window functions are allowed here */
+#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 */
/*
** An instance of the following object describes a single ON CONFLICT
@@ -2857,13 +3018,13 @@ struct Upsert {
** sequences for the ORDER BY clause.
*/
struct Select {
- ExprList *pEList; /* The fields of the result */
u8 op; /* One of: TK_UNION TK_ALL TK_INTERSECT TK_EXCEPT */
LogEst nSelectRow; /* Estimated number of result rows */
u32 selFlags; /* Various SF_* values */
int iLimit, iOffset; /* Memory registers holding LIMIT & OFFSET counters */
u32 selId; /* Unique identifier number for this SELECT */
int addrOpenEphm[2]; /* OP_OpenEphem opcodes related to this select */
+ ExprList *pEList; /* The fields of the result */
SrcList *pSrc; /* The FROM clause */
Expr *pWhere; /* The WHERE clause */
ExprList *pGroupBy; /* The GROUP BY clause */
@@ -2888,26 +3049,28 @@ struct Select {
** SF_MinMaxAgg == NC_MinMaxAgg == SQLITE_FUNC_MINMAX
** SF_FixedLimit == WHERE_USE_LIMIT
*/
-#define SF_Distinct 0x00001 /* Output should be DISTINCT */
-#define SF_All 0x00002 /* Includes the ALL keyword */
-#define SF_Resolved 0x00004 /* Identifiers have been resolved */
-#define SF_Aggregate 0x00008 /* Contains agg functions or a GROUP BY */
-#define SF_HasAgg 0x00010 /* Contains aggregate functions */
-#define SF_UsesEphemeral 0x00020 /* Uses the OpenEphemeral opcode */
-#define SF_Expanded 0x00040 /* sqlite3SelectExpand() called on this */
-#define SF_HasTypeInfo 0x00080 /* FROM subqueries have Table metadata */
-#define SF_Compound 0x00100 /* Part of a compound query */
-#define SF_Values 0x00200 /* Synthesized from VALUES clause */
-#define SF_MultiValue 0x00400 /* Single VALUES term with multiple rows */
-#define SF_NestedFrom 0x00800 /* Part of a parenthesized FROM clause */
-#define SF_MinMaxAgg 0x01000 /* Aggregate containing min() or max() */
-#define SF_Recursive 0x02000 /* The recursive part of a recursive CTE */
-#define SF_FixedLimit 0x04000 /* nSelectRow set by a constant LIMIT */
-#define SF_MaybeConvert 0x08000 /* Need convertCompoundSelectToSubquery() */
-#define SF_Converted 0x10000 /* By convertCompoundSelectToSubquery() */
-#define SF_IncludeHidden 0x20000 /* Include hidden columns in output */
-#define SF_ComplexResult 0x40000 /* Result contains subquery or function */
-#define SF_WhereBegin 0x80000 /* Really a WhereBegin() call. Debug Only */
+#define SF_Distinct 0x0000001 /* Output should be DISTINCT */
+#define SF_All 0x0000002 /* Includes the ALL keyword */
+#define SF_Resolved 0x0000004 /* Identifiers have been resolved */
+#define SF_Aggregate 0x0000008 /* Contains agg functions or a GROUP BY */
+#define SF_HasAgg 0x0000010 /* Contains aggregate functions */
+#define SF_UsesEphemeral 0x0000020 /* Uses the OpenEphemeral opcode */
+#define SF_Expanded 0x0000040 /* sqlite3SelectExpand() called on this */
+#define SF_HasTypeInfo 0x0000080 /* FROM subqueries have Table metadata */
+#define SF_Compound 0x0000100 /* Part of a compound query */
+#define SF_Values 0x0000200 /* Synthesized from VALUES clause */
+#define SF_MultiValue 0x0000400 /* Single VALUES term with multiple rows */
+#define SF_NestedFrom 0x0000800 /* Part of a parenthesized FROM clause */
+#define SF_MinMaxAgg 0x0001000 /* Aggregate containing min() or max() */
+#define SF_Recursive 0x0002000 /* The recursive part of a recursive CTE */
+#define SF_FixedLimit 0x0004000 /* nSelectRow set by a constant LIMIT */
+#define SF_MaybeConvert 0x0008000 /* Need convertCompoundSelectToSubquery() */
+#define SF_Converted 0x0010000 /* By convertCompoundSelectToSubquery() */
+#define SF_IncludeHidden 0x0020000 /* Include hidden columns in output */
+#define SF_ComplexResult 0x0040000 /* Result contains subquery or function */
+#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 */
/*
** The results of a SELECT can be distributed in several ways, as defined
@@ -3187,8 +3350,8 @@ struct Parse {
#define PARSE_MODE_NORMAL 0
#define PARSE_MODE_DECLARE_VTAB 1
-#define PARSE_MODE_RENAME_COLUMN 2
-#define PARSE_MODE_RENAME_TABLE 3
+#define PARSE_MODE_RENAME 2
+#define PARSE_MODE_UNMAP 3
/*
** Sizes and pointers of various parts of the Parse object.
@@ -3210,7 +3373,7 @@ struct Parse {
#if defined(SQLITE_OMIT_ALTERTABLE)
#define IN_RENAME_OBJECT 0
#else
- #define IN_RENAME_OBJECT (pParse->eParseMode>=PARSE_MODE_RENAME_COLUMN)
+ #define IN_RENAME_OBJECT (pParse->eParseMode>=PARSE_MODE_RENAME)
#endif
#if defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_OMIT_ALTERTABLE)
@@ -3361,7 +3524,7 @@ typedef struct DbFixer DbFixer;
struct DbFixer {
Parse *pParse; /* The parsing context. Error messages written here */
Schema *pSchema; /* Fix items to this schema */
- int bVarOnly; /* Check for variable references only */
+ u8 bTemp; /* True for TEMP schema entries */
const char *zDb; /* Make sure all objects are contained in this database */
const char *zType; /* Type of the container - used for error messages */
const Token *pName; /* Name of the container - used for error messages */
@@ -3466,7 +3629,6 @@ struct Sqlite3Config {
int (*xTestCallback)(int); /* Invoked by sqlite3FaultSim() */
#endif
int bLocaltimeFault; /* True to fail localtime() calls */
- int bInternalFunctions; /* Internal SQL functions are visible */
int iOnceResetThreshold; /* When to reset OP_Once counters */
u32 szSorterRef; /* Min size in bytes to use sorter-refs */
unsigned int iPrngSeed; /* Alternative fixed seed for the PRNG */
@@ -3499,7 +3661,7 @@ struct Walker {
int (*xSelectCallback)(Walker*,Select*); /* Callback for SELECTs */
void (*xSelectCallback2)(Walker*,Select*);/* Second callback for SELECTs */
int walkerDepth; /* Number of subqueries */
- u8 eCode; /* A small processing code */
+ u16 eCode; /* A small processing code */
union { /* Extra data for callback */
NameContext *pNC; /* Naming context */
int n; /* A counter */
@@ -3515,6 +3677,7 @@ struct Walker {
struct WindowRewrite *pRewrite; /* Window rewrite context */
struct WhereConst *pConst; /* WHERE clause constants */
struct RenameCtx *pRename; /* RENAME COLUMN context */
+ struct Table *pTab; /* Table of generated column */
} u;
};
@@ -3628,7 +3791,7 @@ Window *sqlite3WindowAlloc(Parse*, int, int, Expr*, int , Expr*, u8);
void sqlite3WindowAttach(Parse*, Expr*, Window*);
void sqlite3WindowLink(Select *pSel, Window *pWin);
int sqlite3WindowCompare(Parse*, Window*, Window*, int);
-void sqlite3WindowCodeInit(Parse*, Window*);
+void sqlite3WindowCodeInit(Parse*, Select*);
void sqlite3WindowCodeStep(Parse*, Select*, WhereInfo*, int, int);
int sqlite3WindowRewrite(Parse*, Select*);
int sqlite3ExpandSubquery(Parse*, struct SrcList_item*);
@@ -3894,6 +4057,7 @@ void sqlite3PExprAddSelect(Parse*, Expr*, Select*);
Expr *sqlite3ExprAnd(Parse*,Expr*, Expr*);
Expr *sqlite3ExprSimplifiedAndOr(Expr*);
Expr *sqlite3ExprFunction(Parse*,ExprList*, Token*, int);
+void sqlite3ExprFunctionUsable(Parse*,Expr*,FuncDef*);
void sqlite3ExprAssignVarNumber(Parse*, Expr*, u32);
void sqlite3ExprDelete(sqlite3*, Expr*);
void sqlite3ExprUnmapAndDelete(Parse*, Expr*);
@@ -3922,7 +4086,14 @@ void sqlite3SelectAddColumnTypeAndCollation(Parse*,Table*,Select*,char);
Table *sqlite3ResultSetOfSelect(Parse*,Select*,char);
void sqlite3OpenMasterTable(Parse *, int);
Index *sqlite3PrimaryKeyIndex(Table*);
-i16 sqlite3ColumnOfIndex(Index*, i16);
+i16 sqlite3TableColumnToIndex(Index*, i16);
+#ifdef SQLITE_OMIT_GENERATED_COLUMNS
+# define sqlite3TableColumnToStorage(T,X) (X) /* No-op pass-through */
+# define sqlite3StorageColumnToTable(T,X) (X) /* No-op pass-through */
+#else
+ i16 sqlite3TableColumnToStorage(Table*, i16);
+ i16 sqlite3StorageColumnToTable(Table*, i16);
+#endif
void sqlite3StartTable(Parse*,Token*,Token*,int,int,int,int);
#if SQLITE_ENABLE_HIDDEN_COLUMNS
void sqlite3ColumnPropertiesFromName(Table*, Column*);
@@ -3935,6 +4106,7 @@ void sqlite3AddPrimaryKey(Parse*, ExprList*, int, int, int);
void sqlite3AddCheckConstraint(Parse*, Expr*);
void sqlite3AddDefaultValue(Parse*,Expr*,const char*,const char*);
void sqlite3AddCollateType(Parse*, Token*);
+void sqlite3AddGenerated(Parse*,Expr*,Token*);
void sqlite3EndTable(Parse*,Token*,Token*,u8,Select*);
int sqlite3ParseUri(const char*,const char*,unsigned int*,
sqlite3_vfs**,char**,char **);
@@ -3992,6 +4164,9 @@ void sqlite3FreeIndex(sqlite3*, Index*);
# define sqlite3AutoincrementEnd(X)
#endif
void sqlite3Insert(Parse*, SrcList*, Select*, IdList*, int, Upsert*);
+#ifndef SQLITE_OMIT_GENERATED_COLUMNS
+ void sqlite3ComputeGeneratedColumns(Parse*, int, Table*);
+#endif
void *sqlite3ArrayAllocate(sqlite3*,void*,int,int*,int*);
IdList *sqlite3IdListAppend(Parse*, IdList*, Token*);
int sqlite3IdListIndex(IdList*,const char*);
@@ -4014,6 +4189,7 @@ 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);
@@ -4036,17 +4212,20 @@ int sqlite3WhereOkOnePass(WhereInfo*, int*);
#define ONEPASS_OFF 0 /* Use of ONEPASS not allowed */
#define ONEPASS_SINGLE 1 /* ONEPASS valid for a single row update */
#define ONEPASS_MULTI 2 /* ONEPASS is valid for multiple rows */
+int sqlite3WhereUsesDeferredSeek(WhereInfo*);
void sqlite3ExprCodeLoadIndexColumn(Parse*, Index*, int, int, int);
int sqlite3ExprCodeGetColumn(Parse*, Table*, int, int, int, u8);
void sqlite3ExprCodeGetColumnOfTable(Vdbe*, Table*, int, int, int);
void sqlite3ExprCodeMove(Parse*, int, int, int);
void sqlite3ExprCode(Parse*, Expr*, int);
+#ifndef SQLITE_OMIT_GENERATED_COLUMNS
+void sqlite3ExprCodeGeneratedColumn(Parse*, Column*, int);
+#endif
void sqlite3ExprCodeCopy(Parse*, Expr*, int);
void sqlite3ExprCodeFactorable(Parse*, Expr*, int);
int sqlite3ExprCodeAtInit(Parse*, Expr*, int);
int sqlite3ExprCodeTemp(Parse*, Expr*, int*);
int sqlite3ExprCodeTarget(Parse*, Expr*, int);
-void sqlite3ExprCodeAndCache(Parse*, Expr*, int);
int sqlite3ExprCodeExprList(Parse*, ExprList*, int, int, u8);
#define SQLITE_ECEL_DUP 0x01 /* Deep, not shallow copies */
#define SQLITE_ECEL_FACTOR 0x02 /* Factor out constant terms */
@@ -4088,6 +4267,7 @@ void sqlite3EndTransaction(Parse*,int);
void sqlite3Savepoint(Parse*, int, Token*);
void sqlite3CloseSavepoints(sqlite3 *);
void sqlite3LeaveMutexAndCloseZombie(sqlite3*);
+u32 sqlite3IsTrueOrFalse(const char*);
int sqlite3ExprIdToTrueFalse(Expr*);
int sqlite3ExprTruthValue(const Expr*);
int sqlite3ExprIsConstant(Expr*);
@@ -4183,6 +4363,7 @@ void sqlite3MaterializeView(Parse*, Table*, Expr*, ExprList*,Expr*,int);
#endif
int sqlite3JoinType(Parse*, Token*, Token*, Token*);
+void sqlite3SetJoinExpr(Expr*,int);
void sqlite3CreateForeignKey(Parse*, ExprList*, Token*, ExprList*, int);
void sqlite3DeferForeignKey(Parse*, int);
#ifndef SQLITE_OMIT_AUTHORIZATION
@@ -4343,7 +4524,12 @@ void sqlite3CodeRhsOfIN(Parse*, Expr*, int);
int sqlite3CodeSubselect(Parse*, Expr*);
void sqlite3SelectPrep(Parse*, Select*, NameContext*);
void sqlite3SelectWrongNumTermsError(Parse *pParse, Select *p);
-int sqlite3MatchSpanName(const char*, const char*, const char*, const char*);
+int sqlite3MatchEName(
+ const struct ExprList_item*,
+ const char*,
+ const char*,
+ const char*
+);
int sqlite3ResolveExprNames(NameContext*, Expr*);
int sqlite3ResolveExprListNames(NameContext*, ExprList*);
void sqlite3ResolveSelectNames(Parse*, Select*, NameContext*);
@@ -4481,6 +4667,12 @@ void sqlite3AutoLoadExtensions(sqlite3*);
);
# define sqlite3VtabInSync(db) ((db)->nVTrans>0 && (db)->aVTrans==0)
#endif
+int sqlite3ReadOnlyShadowTables(sqlite3 *db);
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ int sqlite3ShadowTableName(sqlite3 *db, const char *zName);
+#else
+# define sqlite3ShadowTableName(A,B) 0
+#endif
int sqlite3VtabEponymousTableInit(Parse*,Module*);
void sqlite3VtabEponymousTableClear(sqlite3*,Module*);
void sqlite3VtabMakeWritable(Parse*,Table*);
@@ -4502,6 +4694,7 @@ char *sqlite3Normalize(Vdbe*, const char*);
#endif
int sqlite3Reprepare(Vdbe*);
void sqlite3ExprListCheckLength(Parse*, ExprList*, const char*);
+CollSeq *sqlite3ExprCompareCollSeq(Parse*,Expr*);
CollSeq *sqlite3BinaryCompareCollSeq(Parse *, Expr *, Expr *);
int sqlite3TempInMemory(const sqlite3*);
const char *sqlite3JournalModename(int);
diff --git a/src/status.c b/src/status.c
index a5a39f4c18..c42bcc2856 100644
--- a/src/status.c
+++ b/src/status.c
@@ -188,6 +188,10 @@ static u32 countLookasideSlots(LookasideSlot *p){
int sqlite3LookasideUsed(sqlite3 *db, int *pHighwater){
u32 nInit = countLookasideSlots(db->lookaside.pInit);
u32 nFree = countLookasideSlots(db->lookaside.pFree);
+#ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE
+ nInit += countLookasideSlots(db->lookaside.pSmallInit);
+ nFree += countLookasideSlots(db->lookaside.pSmallFree);
+#endif /* SQLITE_OMIT_TWOSIZE_LOOKASIDE */
if( pHighwater ) *pHighwater = db->lookaside.nSlot - nInit;
return db->lookaside.nSlot - (nInit+nFree);
}
@@ -220,6 +224,15 @@ int sqlite3_db_status(
db->lookaside.pInit = db->lookaside.pFree;
db->lookaside.pFree = 0;
}
+#ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE
+ p = db->lookaside.pSmallFree;
+ if( p ){
+ while( p->pNext ) p = p->pNext;
+ p->pNext = db->lookaside.pSmallInit;
+ db->lookaside.pSmallInit = db->lookaside.pSmallFree;
+ db->lookaside.pSmallFree = 0;
+ }
+#endif
}
break;
}
diff --git a/src/tclsqlite.c b/src/tclsqlite.c
index 80a0572622..6a8b52b6bc 100644
--- a/src/tclsqlite.c
+++ b/src/tclsqlite.c
@@ -2818,6 +2818,7 @@ deserialize_error:
** --argcount N Function has exactly N arguments
** --deterministic The function is pure
** --directonly Prohibit use inside triggers and views
+ ** --innocuous Has no side effects or information leaks
** --returntype TYPE Specify the return type of the function
*/
case DB_FUNCTION: {
@@ -2854,6 +2855,9 @@ deserialize_error:
if( n>1 && strncmp(z, "-directonly",n)==0 ){
flags |= SQLITE_DIRECTONLY;
}else
+ if( n>1 && strncmp(z, "-innocuous",n)==0 ){
+ flags |= SQLITE_INNOCUOUS;
+ }else
if( n>1 && strncmp(z, "-returntype", n)==0 ){
const char *azType[] = {"integer", "real", "text", "blob", "any", 0};
assert( SQLITE_INTEGER==1 && SQLITE_FLOAT==2 && SQLITE_TEXT==3 );
@@ -2870,7 +2874,7 @@ deserialize_error:
}else{
Tcl_AppendResult(interp, "bad option \"", z,
"\": must be -argcount, -deterministic, -directonly,"
- " or -returntype", (char*)0
+ " -innocuous, or -returntype", (char*)0
);
return TCL_ERROR;
}
@@ -3670,6 +3674,7 @@ static int sqliteCmdUsage(
){
Tcl_WrongNumArgs(interp, 1, objv,
"HANDLE ?FILENAME? ?-vfs VFSNAME? ?-readonly BOOLEAN? ?-create BOOLEAN?"
+ " ?-nofollow BOOLEAN?"
" ?-nomutex BOOLEAN? ?-fullmutex BOOLEAN? ?-uri BOOLEAN?"
#if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_CODEC_FROM_TCL)
" ?-key CODECKEY?"
@@ -3681,6 +3686,7 @@ static int sqliteCmdUsage(
/*
** sqlite3 DBNAME FILENAME ?-vfs VFSNAME? ?-key KEY? ?-readonly BOOLEAN?
** ?-create BOOLEAN? ?-nomutex BOOLEAN?
+** ?-nofollow BOOLEAN?
**
** This is the main Tcl command. When the "sqlite" Tcl command is
** invoked, this routine runs to process that command.
@@ -3779,6 +3785,14 @@ static int SQLITE_TCLAPI DbMain(
}else{
flags &= ~SQLITE_OPEN_CREATE;
}
+ }else if( strcmp(zArg, "-nofollow")==0 ){
+ int b;
+ if( Tcl_GetBooleanFromObj(interp, objv[i], &b) ) return TCL_ERROR;
+ if( b ){
+ flags |= SQLITE_OPEN_NOFOLLOW;
+ }else{
+ flags &= ~SQLITE_OPEN_NOFOLLOW;
+ }
}else if( strcmp(zArg, "-nomutex")==0 ){
int b;
if( Tcl_GetBooleanFromObj(interp, objv[i], &b) ) return TCL_ERROR;
diff --git a/src/test1.c b/src/test1.c
index ffd6091fa3..5b07aef2d5 100644
--- a/src/test1.c
+++ b/src/test1.c
@@ -5526,6 +5526,33 @@ static int SQLITE_TCLAPI test_soft_heap_limit(
return TCL_OK;
}
+/*
+** Usage: sqlite3_hard_heap_limit ?N?
+**
+** Query or set the hard heap limit for the current thread. The
+** limit is only changed if the N is present. The previous limit
+** is returned.
+*/
+static int SQLITE_TCLAPI test_hard_heap_limit(
+ void * clientData,
+ Tcl_Interp *interp,
+ int objc,
+ Tcl_Obj *CONST objv[]
+){
+ sqlite3_int64 amt;
+ Tcl_WideInt N = -1;
+ if( objc!=1 && objc!=2 ){
+ Tcl_WrongNumArgs(interp, 1, objv, "?N?");
+ return TCL_ERROR;
+ }
+ if( objc==2 ){
+ if( Tcl_GetWideIntFromObj(interp, objv[1], &N) ) return TCL_ERROR;
+ }
+ amt = sqlite3_hard_heap_limit64(N);
+ Tcl_SetObjResult(interp, Tcl_NewWideIntObj(amt));
+ return TCL_OK;
+}
+
/*
** Usage: sqlite3_thread_cleanup
**
@@ -6845,7 +6872,16 @@ static int SQLITE_TCLAPI test_test_control(
iFlag = aVerb[iVerb].i;
switch( iFlag ){
- case SQLITE_TESTCTRL_INTERNAL_FUNCTIONS:
+ case SQLITE_TESTCTRL_INTERNAL_FUNCTIONS: {
+ sqlite3 *db = 0;
+ if( objc!=3 ){
+ Tcl_WrongNumArgs(interp, 2, objv, "DB");
+ return TCL_ERROR;
+ }
+ if( getDbPointer(interp, Tcl_GetString(objv[2]), &db) ) return TCL_ERROR;
+ sqlite3_test_control(SQLITE_TESTCTRL_INTERNAL_FUNCTIONS, db);
+ break;
+ }
case SQLITE_TESTCTRL_LOCALTIME_FAULT: {
int val;
if( objc!=3 ){
@@ -7682,14 +7718,15 @@ static int SQLITE_TCLAPI test_sqlite3_db_config(
{ "LEGACY_ALTER_TABLE", SQLITE_DBCONFIG_LEGACY_ALTER_TABLE },
{ "DQS_DML", SQLITE_DBCONFIG_DQS_DML },
{ "DQS_DDL", SQLITE_DBCONFIG_DQS_DDL },
+ { "LEGACY_FILE_FORMAT", SQLITE_DBCONFIG_LEGACY_FILE_FORMAT },
};
int i;
- int v;
+ int v = 0;
const char *zSetting;
sqlite3 *db;
- if( objc!=4 ){
- Tcl_WrongNumArgs(interp, 1, objv, "DB SETTING VALUE");
+ if( objc!=4 && objc!=3 ){
+ Tcl_WrongNumArgs(interp, 1, objv, "DB SETTING [VALUE]");
return TCL_ERROR;
}
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
@@ -7705,7 +7742,11 @@ static int SQLITE_TCLAPI test_sqlite3_db_config(
Tcl_NewStringObj("unknown sqlite3_db_config setting", -1));
return TCL_ERROR;
}
- if( Tcl_GetIntFromObj(interp, objv[3], &v) ) return TCL_ERROR;
+ if( objc==4 ){
+ if( Tcl_GetIntFromObj(interp, objv[3], &v) ) return TCL_ERROR;
+ }else{
+ v = -1;
+ }
sqlite3_db_config(db, aSetting[i].eVal, v, &v);
Tcl_SetObjResult(interp, Tcl_NewIntObj(v));
return TCL_OK;
@@ -7973,6 +8014,8 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
{ "sqlite3_db_filename", test_db_filename, 0},
{ "sqlite3_db_readonly", test_db_readonly, 0},
{ "sqlite3_soft_heap_limit", test_soft_heap_limit, 0},
+ { "sqlite3_soft_heap_limit64", test_soft_heap_limit, 0},
+ { "sqlite3_hard_heap_limit64", test_hard_heap_limit, 0},
{ "sqlite3_thread_cleanup", test_thread_cleanup, 0},
{ "sqlite3_pager_refcounts", test_pager_refcounts, 0},
diff --git a/src/test_vfs.c b/src/test_vfs.c
index 3357a0a27d..9d753896e9 100644
--- a/src/test_vfs.c
+++ b/src/test_vfs.c
@@ -1390,7 +1390,9 @@ static void SQLITE_TCLAPI testvfs_obj_del(ClientData cd){
Testvfs *p = (Testvfs *)cd;
if( p->pScript ) Tcl_DecrRefCount(p->pScript);
sqlite3_vfs_unregister(p->pVfs);
+ memset(p->pVfs, 0, sizeof(sqlite3_vfs));
ckfree((char *)p->pVfs);
+ memset(p, 0, sizeof(Testvfs));
ckfree((char *)p);
}
diff --git a/src/tokenize.c b/src/tokenize.c
index 40f7b4aad9..48f92218d3 100644
--- a/src/tokenize.c
+++ b/src/tokenize.c
@@ -757,7 +757,7 @@ char *sqlite3Normalize(
int nParen; /* Number of nested levels of parentheses */
int iStartIN; /* Start of RHS of IN operator in z[] */
int nParenAtIN; /* Value of nParent at start of RHS of IN operator */
- int j; /* Bytes of normalized SQL generated so far */
+ u32 j; /* Bytes of normalized SQL generated so far */
sqlite3_str *pStr; /* The normalized SQL string under construction */
db = sqlite3VdbeDb(pVdbe);
@@ -801,7 +801,7 @@ char *sqlite3Normalize(
}
case TK_RP: {
if( iStartIN>0 && nParen==nParenAtIN ){
- assert( pStr->nChar>=iStartIN );
+ assert( pStr->nChar>=(u32)iStartIN );
pStr->nChar = iStartIN+1;
sqlite3_str_append(pStr, "?,?,?", 5);
iStartIN = 0;
diff --git a/src/treeview.c b/src/treeview.c
index 4979f59b58..90a1d2dcc9 100644
--- a/src/treeview.c
+++ b/src/treeview.c
@@ -66,7 +66,7 @@ static void sqlite3TreeViewLine(TreeView *p, const char *zFormat, ...){
va_start(ap, zFormat);
sqlite3_str_vappendf(&acc, zFormat, ap);
va_end(ap);
- assert( acc.nChar>0 );
+ assert( acc.nChar>0 || acc.accError );
sqlite3_str_append(&acc, "\n", 1);
}
sqlite3StrAccumFinish(&acc);
@@ -106,7 +106,7 @@ void sqlite3TreeViewWith(TreeView *pView, const With *pWith, u8 moreToFollow){
char cSep = '(';
int j;
for(j=0; jpCols->nExpr; j++){
- sqlite3_str_appendf(&x, "%c%s", cSep, pCte->pCols->a[j].zName);
+ sqlite3_str_appendf(&x, "%c%s", cSep, pCte->pCols->a[j].zEName);
cSep = ',';
}
sqlite3_str_appendf(&x, ")");
@@ -131,7 +131,7 @@ void sqlite3TreeViewSrcList(TreeView *pView, const SrcList *pSrc){
StrAccum x;
char zLine[100];
sqlite3StrAccumInit(&x, 0, zLine, sizeof(zLine), 0);
- sqlite3_str_appendf(&x, "{%d,*}", pItem->iCursor);
+ sqlite3_str_appendf(&x, "{%d:*}", pItem->iCursor);
if( pItem->zDatabase ){
sqlite3_str_appendf(&x, " %s.%s", pItem->zDatabase, pItem->zName);
}else if( pItem->zName ){
@@ -147,6 +147,9 @@ void sqlite3TreeViewSrcList(TreeView *pView, const SrcList *pSrc){
if( pItem->fg.jointype & JT_LEFT ){
sqlite3_str_appendf(&x, " LEFT-JOIN");
}
+ if( pItem->fg.fromDDL ){
+ sqlite3_str_appendf(&x, " DDL");
+ }
sqlite3StrAccumFinish(&x);
sqlite3TreeViewItem(pView, zLine, inSrc-1);
if( pItem->pSelect ){
@@ -403,14 +406,17 @@ void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){
return;
}
if( pExpr->flags || pExpr->affExpr ){
+ StrAccum x;
+ sqlite3StrAccumInit(&x, 0, zFlgs, sizeof(zFlgs), 0);
+ sqlite3_str_appendf(&x, " fg.af=%x.%c",
+ pExpr->flags, pExpr->affExpr ? pExpr->affExpr : 'n');
if( ExprHasProperty(pExpr, EP_FromJoin) ){
- sqlite3_snprintf(sizeof(zFlgs),zFlgs," fg.af=%x.%c iRJT=%d",
- pExpr->flags, pExpr->affExpr ? pExpr->affExpr : 'n',
- pExpr->iRightJoinTable);
- }else{
- sqlite3_snprintf(sizeof(zFlgs),zFlgs," fg.af=%x.%c",
- pExpr->flags, pExpr->affExpr ? pExpr->affExpr : 'n');
+ sqlite3_str_appendf(&x, " iRJT=%d", pExpr->iRightJoinTable);
}
+ if( ExprHasProperty(pExpr, EP_FromDDL) ){
+ sqlite3_str_appendf(&x, " DDL");
+ }
+ sqlite3StrAccumFinish(&x);
}else{
zFlgs[0] = 0;
}
@@ -423,10 +429,18 @@ void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){
case TK_COLUMN: {
if( pExpr->iTable<0 ){
/* This only happens when coding check constraints */
- sqlite3TreeViewLine(pView, "COLUMN(%d)%s", pExpr->iColumn, zFlgs);
+ char zOp2[16];
+ if( pExpr->op2 ){
+ sqlite3_snprintf(sizeof(zOp2),zOp2," op2=0x%02x",pExpr->op2);
+ }else{
+ zOp2[0] = 0;
+ }
+ sqlite3TreeViewLine(pView, "COLUMN(%d)%s%s",
+ pExpr->iColumn, zFlgs, zOp2);
}else{
- sqlite3TreeViewLine(pView, "{%d:%d}%s",
- pExpr->iTable, pExpr->iColumn, zFlgs);
+ sqlite3TreeViewLine(pView, "{%d:%d} pTab=%p%s",
+ pExpr->iTable, pExpr->iColumn,
+ pExpr->y.pTab, zFlgs);
}
if( ExprHasProperty(pExpr, EP_FixedCol) ){
sqlite3TreeViewExpr(pView, pExpr->pLeft, 0);
@@ -558,7 +572,7 @@ void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){
}else{
pFarg = pExpr->x.pList;
#ifndef SQLITE_OMIT_WINDOWFUNC
- pWin = pExpr->y.pWin;
+ pWin = ExprHasProperty(pExpr, EP_WinFunc) ? pExpr->y.pWin : 0;
#else
pWin = 0;
#endif
@@ -566,6 +580,17 @@ void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){
if( pExpr->op==TK_AGG_FUNCTION ){
sqlite3TreeViewLine(pView, "AGG_FUNCTION%d %Q%s",
pExpr->op2, pExpr->u.zToken, zFlgs);
+ }else if( pExpr->op2!=0 ){
+ const char *zOp2;
+ char zBuf[8];
+ sqlite3_snprintf(sizeof(zBuf),zBuf,"0x%02x",pExpr->op2);
+ zOp2 = zBuf;
+ if( pExpr->op2==NC_IsCheck ) zOp2 = "NC_IsCheck";
+ if( pExpr->op2==NC_IdxExpr ) zOp2 = "NC_IdxExpr";
+ if( pExpr->op2==NC_PartIdx ) zOp2 = "NC_PartIdx";
+ if( pExpr->op2==NC_GenCol ) zOp2 = "NC_GenCol";
+ sqlite3TreeViewLine(pView, "FUNCTION %Q%s op2=%s",
+ pExpr->u.zToken, zFlgs, zOp2);
}else{
sqlite3TreeViewLine(pView, "FUNCTION %Q%s", pExpr->u.zToken, zFlgs);
}
@@ -661,7 +686,9 @@ void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){
break;
}
case TK_VECTOR: {
- sqlite3TreeViewBareExprList(pView, pExpr->x.pList, "VECTOR");
+ char *z = sqlite3_mprintf("VECTOR%s",zFlgs);
+ sqlite3TreeViewBareExprList(pView, pExpr->x.pList, z);
+ sqlite3_free(z);
break;
}
case TK_SELECT_COLUMN: {
@@ -707,8 +734,9 @@ void sqlite3TreeViewBareExprList(
sqlite3TreeViewLine(pView, "%s", zLabel);
for(i=0; inExpr; i++){
int j = pList->a[i].u.x.iOrderByCol;
- char *zName = pList->a[i].zName;
+ char *zName = pList->a[i].zEName;
int moreToFollow = inExpr - 1;
+ if( pList->a[i].eEName!=ENAME_NAME ) zName = 0;
if( j || zName ){
sqlite3TreeViewPush(pView, moreToFollow);
moreToFollow = 0;
diff --git a/src/trigger.c b/src/trigger.c
index 83685a0aae..458aa2996c 100644
--- a/src/trigger.c
+++ b/src/trigger.c
@@ -662,8 +662,12 @@ void sqlite3UnlinkAndDeleteTrigger(sqlite3 *db, int iDb, const char *zName){
Table *pTab = tableOfTrigger(pTrigger);
if( pTab ){
Trigger **pp;
- for(pp=&pTab->pTrigger; *pp!=pTrigger; pp=&((*pp)->pNext));
- *pp = (*pp)->pNext;
+ for(pp=&pTab->pTrigger; *pp; pp=&((*pp)->pNext)){
+ if( *pp==pTrigger ){
+ *pp = (*pp)->pNext;
+ break;
+ }
+ }
}
}
sqlite3DeleteTrigger(db, pTrigger);
@@ -684,7 +688,7 @@ static int checkColumnOverlap(IdList *pIdList, ExprList *pEList){
int e;
if( pIdList==0 || NEVER(pEList==0) ) return 1;
for(e=0; enExpr; e++){
- if( sqlite3IdListIndex(pIdList, pEList->a[e].zName)>=0 ) return 1;
+ if( sqlite3IdListIndex(pIdList, pEList->a[e].zEName)>=0 ) return 1;
}
return 0;
}
diff --git a/src/update.c b/src/update.c
index 458550b95d..61b1740b42 100644
--- a/src/update.c
+++ b/src/update.c
@@ -147,7 +147,7 @@ void sqlite3Update(
Expr *pLimit, /* LIMIT clause. May be null */
Upsert *pUpsert /* ON CONFLICT clause, or null */
){
- int i, j; /* Loop counters */
+ int i, j, k; /* Loop counters */
Table *pTab; /* The table to be updated */
int addrTop = 0; /* VDBE instruction address of the start of the loop */
WhereInfo *pWInfo; /* Information about the WHERE clause */
@@ -191,6 +191,7 @@ void sqlite3Update(
int iPk = 0; /* First of nPk cells holding PRIMARY KEY value */
i16 nPk = 0; /* Number of components of the PRIMARY KEY */
int bReplace = 0; /* True if REPLACE conflict resolution might happen */
+ int bFinishSeek = 1; /* The OP_FinishSeek opcode is needed */
/* Register Allocations */
int regRowCount = 0; /* A count of rows changed */
@@ -289,6 +290,10 @@ void sqlite3Update(
sNC.uNC.pUpsert = pUpsert;
sNC.ncFlags = NC_UUpsert;
+ /* Begin generating code. */
+ v = sqlite3GetVdbe(pParse);
+ if( v==0 ) goto update_cleanup;
+
/* Resolve the column names in all the expressions of the
** of the UPDATE statement. Also find the column index
** for each column to be updated in the pChanges array. For each
@@ -301,24 +306,34 @@ void sqlite3Update(
goto update_cleanup;
}
for(j=0; jnCol; j++){
- if( sqlite3StrICmp(pTab->aCol[j].zName, pChanges->a[i].zName)==0 ){
+ if( sqlite3StrICmp(pTab->aCol[j].zName, pChanges->a[i].zEName)==0 ){
if( j==pTab->iPKey ){
chngRowid = 1;
pRowidExpr = pChanges->a[i].pExpr;
}else if( pPk && (pTab->aCol[j].colFlags & COLFLAG_PRIMKEY)!=0 ){
chngPk = 1;
}
+#ifndef SQLITE_OMIT_GENERATED_COLUMNS
+ else if( pTab->aCol[j].colFlags & COLFLAG_GENERATED ){
+ testcase( pTab->aCol[j].colFlags & COLFLAG_VIRTUAL );
+ testcase( pTab->aCol[j].colFlags & COLFLAG_STORED );
+ sqlite3ErrorMsg(pParse,
+ "cannot UPDATE generated column \"%s\"",
+ pTab->aCol[j].zName);
+ goto update_cleanup;
+ }
+#endif
aXRef[j] = i;
break;
}
}
if( j>=pTab->nCol ){
- if( pPk==0 && sqlite3IsRowid(pChanges->a[i].zName) ){
+ if( pPk==0 && sqlite3IsRowid(pChanges->a[i].zEName) ){
j = -1;
chngRowid = 1;
pRowidExpr = pChanges->a[i].pExpr;
}else{
- sqlite3ErrorMsg(pParse, "no such column: %s", pChanges->a[i].zName);
+ sqlite3ErrorMsg(pParse, "no such column: %s", pChanges->a[i].zEName);
pParse->checkSchema = 1;
goto update_cleanup;
}
@@ -342,6 +357,33 @@ void sqlite3Update(
assert( chngPk==0 || chngPk==1 );
chngKey = chngRowid + chngPk;
+#ifndef SQLITE_OMIT_GENERATED_COLUMNS
+ /* Mark generated columns as changing if their generator expressions
+ ** reference any changing column. The actual aXRef[] value for
+ ** generated expressions is not used, other than to check to see that it
+ ** is non-negative, so the value of aXRef[] for generated columns can be
+ ** set to any non-negative number. We use 99999 so that the value is
+ ** obvious when looking at aXRef[] in a symbolic debugger.
+ */
+ if( pTab->tabFlags & TF_HasGenerated ){
+ int bProgress;
+ testcase( pTab->tabFlags & TF_HasVirtual );
+ testcase( pTab->tabFlags & TF_HasStored );
+ do{
+ bProgress = 0;
+ for(i=0; inCol; i++){
+ if( aXRef[i]>=0 ) continue;
+ if( (pTab->aCol[i].colFlags & COLFLAG_GENERATED)==0 ) continue;
+ if( sqlite3ExprReferencesUpdatedColumn(pTab->aCol[i].pDflt,
+ aXRef, chngRowid) ){
+ aXRef[i] = 99999;
+ bProgress = 1;
+ }
+ }
+ }while( bProgress );
+ }
+#endif
+
/* The SET expressions are not actually used inside the WHERE loop.
** So reset the colUsed mask. Unless this is a virtual table. In that
** case, set all bits of the colUsed mask (to ensure that the virtual
@@ -386,9 +428,6 @@ void sqlite3Update(
memset(aToOpen, 1, nIdx+1);
}
- /* Begin generating code. */
- v = sqlite3GetVdbe(pParse);
- if( v==0 ) goto update_cleanup;
if( pParse->nested==0 ) sqlite3VdbeCountChanges(v);
sqlite3BeginWriteOperation(pParse, pTrigger || hasFK, iDb);
@@ -486,6 +525,7 @@ void sqlite3Update(
pWInfo = 0;
eOnePass = ONEPASS_SINGLE;
sqlite3ExprIfFalse(pParse, pWhere, labelBreak, SQLITE_JUMPIFNULL);
+ bFinishSeek = 0;
}else{
/* Begin the database scan.
**
@@ -512,6 +552,7 @@ void sqlite3Update(
** strategy that uses an index for which one or more columns are being
** updated. */
eOnePass = sqlite3WhereOkOnePass(pWInfo, aiCurOnePass);
+ bFinishSeek = sqlite3WhereUsesDeferredSeek(pWInfo);
if( eOnePass!=ONEPASS_SINGLE ){
sqlite3MultiWrite(pParse);
if( eOnePass==ONEPASS_MULTI ){
@@ -542,7 +583,8 @@ void sqlite3Update(
** is not required) and leave the PK fields in the array of registers. */
for(i=0; iaiColumn[i]>=0 );
- sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur,pPk->aiColumn[i],iPk+i);
+ sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur,
+ pPk->aiColumn[i], iPk+i);
}
if( eOnePass ){
if( addrOpen ) sqlite3VdbeChangeToNoop(v, addrOpen);
@@ -623,14 +665,16 @@ void sqlite3Update(
pTrigger, pChanges, 0, TRIGGER_BEFORE|TRIGGER_AFTER, pTab, onError
);
for(i=0; inCol; i++){
+ u32 colFlags = pTab->aCol[i].colFlags;
+ k = sqlite3TableColumnToStorage(pTab, i) + regOld;
if( oldmask==0xffffffff
|| (i<32 && (oldmask & MASKBIT32(i))!=0)
- || (pTab->aCol[i].colFlags & COLFLAG_PRIMKEY)!=0
+ || (colFlags & COLFLAG_PRIMKEY)!=0
){
testcase( oldmask!=0xffffffff && i==31 );
- sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, i, regOld+i);
+ sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, i, k);
}else{
- sqlite3VdbeAddOp2(v, OP_Null, 0, regOld+i);
+ sqlite3VdbeAddOp2(v, OP_Null, 0, k);
}
}
if( chngRowid==0 && pPk==0 ){
@@ -654,13 +698,15 @@ void sqlite3Update(
newmask = sqlite3TriggerColmask(
pParse, pTrigger, pChanges, 1, TRIGGER_BEFORE, pTab, onError
);
- for(i=0; inCol; i++){
+ for(i=0, k=regNew; inCol; i++, k++){
if( i==pTab->iPKey ){
- sqlite3VdbeAddOp2(v, OP_Null, 0, regNew+i);
+ sqlite3VdbeAddOp2(v, OP_Null, 0, k);
+ }else if( (pTab->aCol[i].colFlags & COLFLAG_GENERATED)!=0 ){
+ if( pTab->aCol[i].colFlags & COLFLAG_VIRTUAL ) k--;
}else{
j = aXRef[i];
if( j>=0 ){
- sqlite3ExprCode(pParse, pChanges->a[j].pExpr, regNew+i);
+ sqlite3ExprCode(pParse, pChanges->a[j].pExpr, k);
}else if( 0==(tmask&TRIGGER_BEFORE) || i>31 || (newmask & MASKBIT32(i)) ){
/* This branch loads the value of a column that will not be changed
** into a register. This is done if there are no BEFORE triggers, or
@@ -669,12 +715,20 @@ void sqlite3Update(
*/
testcase( i==31 );
testcase( i==32 );
- sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, i, regNew+i);
+ sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, i, k);
+ bFinishSeek = 0;
}else{
- sqlite3VdbeAddOp2(v, OP_Null, 0, regNew+i);
+ sqlite3VdbeAddOp2(v, OP_Null, 0, k);
}
}
}
+#ifndef SQLITE_OMIT_GENERATED_COLUMNS
+ if( pTab->tabFlags & TF_HasGenerated ){
+ testcase( pTab->tabFlags & TF_HasVirtual );
+ testcase( pTab->tabFlags & TF_HasStored );
+ sqlite3ComputeGeneratedColumns(pParse, regNew, pTab);
+ }
+#endif
/* Fire any BEFORE UPDATE triggers. This happens before constraints are
** verified. One could argue that this is wrong.
@@ -707,11 +761,20 @@ void sqlite3Update(
** BEFORE trigger runs. See test case trigger1-18.0 (added 2018-04-26)
** for an example.
*/
- for(i=0; inCol; i++){
- if( aXRef[i]<0 && i!=pTab->iPKey ){
- sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, i, regNew+i);
+ for(i=0, k=regNew; inCol; i++, k++){
+ if( pTab->aCol[i].colFlags & COLFLAG_GENERATED ){
+ if( pTab->aCol[i].colFlags & COLFLAG_VIRTUAL ) k--;
+ }else if( aXRef[i]<0 && i!=pTab->iPKey ){
+ sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, i, k);
}
}
+#ifndef SQLITE_OMIT_GENERATED_COLUMNS
+ if( pTab->tabFlags & TF_HasGenerated ){
+ testcase( pTab->tabFlags & TF_HasVirtual );
+ testcase( pTab->tabFlags & TF_HasStored );
+ sqlite3ComputeGeneratedColumns(pParse, regNew, pTab);
+ }
+#endif
}
if( !isView ){
@@ -741,6 +804,15 @@ void sqlite3Update(
/* Delete the index entries associated with the current record. */
sqlite3GenerateRowIndexDelete(pParse, pTab, iDataCur, iIdxCur, aRegIdx, -1);
+ /* We must run the OP_FinishSeek opcode to resolve a prior
+ ** OP_DeferredSeek if there is any possibility that there have been
+ ** no OP_Column opcodes since the OP_DeferredSeek was issued. But
+ ** we want to avoid the OP_FinishSeek if possible, as running it
+ ** costs CPU cycles. */
+ if( bFinishSeek ){
+ sqlite3VdbeAddOp1(v, OP_FinishSeek, iDataCur);
+ }
+
/* If changing the rowid value, or if there are foreign key constraints
** to process, delete the old record. Otherwise, add a noop OP_Delete
** to invoke the pre-update hook.
@@ -917,6 +989,7 @@ static void updateVirtualTable(
/* Populate the argument registers. */
for(i=0; inCol; i++){
+ assert( (pTab->aCol[i].colFlags & COLFLAG_GENERATED)==0 );
if( aXRef[i]>=0 ){
sqlite3ExprCode(pParse, pChanges->a[aXRef[i]].pExpr, regArg+2+i);
}else{
diff --git a/src/upsert.c b/src/upsert.c
index 7beb9ffaec..9a33f75d0a 100644
--- a/src/upsert.c
+++ b/src/upsert.c
@@ -226,7 +226,7 @@ void sqlite3UpsertDoUpdate(
for(i=0; iaiColumn[i]>=0 );
- k = sqlite3ColumnOfIndex(pIdx, pPk->aiColumn[i]);
+ k = sqlite3TableColumnToIndex(pIdx, pPk->aiColumn[i]);
sqlite3VdbeAddOp3(v, OP_Column, iCur, k, iPk+i);
VdbeComment((v, "%s.%s", pIdx->zName,
pTab->aCol[pPk->aiColumn[i]].zName));
@@ -236,6 +236,7 @@ void sqlite3UpsertDoUpdate(
VdbeCoverage(v);
sqlite3VdbeAddOp4(v, OP_Halt, SQLITE_CORRUPT, OE_Abort, 0,
"corrupt database", P4_STATIC);
+ sqlite3MayAbort(pParse);
sqlite3VdbeJumpHere(v, i);
}
}
diff --git a/src/utf.c b/src/utf.c
index 9191ed5cfd..f5fb3ef347 100644
--- a/src/utf.c
+++ b/src/utf.c
@@ -215,9 +215,11 @@ SQLITE_NOINLINE int sqlite3VdbeMemTranslate(Mem *pMem, u8 desiredEnc){
#if defined(TRANSLATE_TRACE) && defined(SQLITE_DEBUG)
{
- char zBuf[100];
- sqlite3VdbeMemPrettyPrint(pMem, zBuf);
- fprintf(stderr, "INPUT: %s\n", zBuf);
+ StrAccum acc;
+ char zBuf[1000];
+ sqlite3StrAccumInit(&acc, 0, zBuf, sizeof(zBuf), 0);
+ sqlite3VdbeMemPrettyPrint(pMem, &acc);
+ fprintf(stderr, "INPUT: %s\n", sqlite3StrAccumFinish(&acc));
}
#endif
@@ -325,9 +327,11 @@ SQLITE_NOINLINE int sqlite3VdbeMemTranslate(Mem *pMem, u8 desiredEnc){
translate_out:
#if defined(TRANSLATE_TRACE) && defined(SQLITE_DEBUG)
{
- char zBuf[100];
- sqlite3VdbeMemPrettyPrint(pMem, zBuf);
- fprintf(stderr, "OUTPUT: %s\n", zBuf);
+ StrAccum acc;
+ char zBuf[1000];
+ sqlite3StrAccumInit(&acc, 0, zBuf, sizeof(zBuf), 0);
+ sqlite3VdbeMemPrettyPrint(pMem, &acc);
+ fprintf(stderr, "OUTPUT: %s\n", sqlite3StrAccumFinish(&acc));
}
#endif
return SQLITE_OK;
diff --git a/src/util.c b/src/util.c
index 7adce4ef03..88ac6d39f8 100644
--- a/src/util.c
+++ b/src/util.c
@@ -192,6 +192,7 @@ void sqlite3ErrorMsg(Parse *pParse, const char *zFormat, ...){
sqlite3DbFree(db, pParse->zErrMsg);
pParse->zErrMsg = zMsg;
pParse->rc = SQLITE_ERROR;
+ pParse->pWith = 0;
}
}
@@ -382,10 +383,13 @@ static LONGDOUBLE_TYPE sqlite3Pow10(int E){
** returns FALSE but it still converts the prefix and writes the result
** into *pResult.
*/
+#if defined(_MSC_VER)
+#pragma warning(disable : 4756)
+#endif
int sqlite3AtoF(const char *z, double *pResult, int length, u8 enc){
#ifndef SQLITE_OMIT_FLOATING_POINT
int incr;
- const char *zEnd = z + length;
+ const char *zEnd;
/* sign * significand * (10 ^ (esign * exponent)) */
int sign = 1; /* sign of significand */
i64 s = 0; /* significand */
@@ -399,12 +403,15 @@ int sqlite3AtoF(const char *z, double *pResult, int length, u8 enc){
assert( enc==SQLITE_UTF8 || enc==SQLITE_UTF16LE || enc==SQLITE_UTF16BE );
*pResult = 0.0; /* Default return value, in case of an error */
+ if( length==0 ) return 0;
if( enc==SQLITE_UTF8 ){
incr = 1;
+ zEnd = z + length;
}else{
int i;
incr = 2;
+ length &= ~1;
assert( SQLITE_UTF16LE==2 && SQLITE_UTF16BE==3 );
testcase( enc==SQLITE_UTF16LE );
testcase( enc==SQLITE_UTF16BE );
@@ -569,6 +576,9 @@ do_atof_calc:
return !sqlite3Atoi64(z, pResult, length, enc);
#endif /* SQLITE_OMIT_FLOATING_POINT */
}
+#if defined(_MSC_VER)
+#pragma warning(default : 4756)
+#endif
/*
** Compare the 19-character string zNum against the text representation
diff --git a/src/vdbe.c b/src/vdbe.c
index 9954492d0d..86435c4646 100644
--- a/src/vdbe.c
+++ b/src/vdbe.c
@@ -117,6 +117,26 @@ int sqlite3_found_count = 0;
# define UPDATE_MAX_BLOBSIZE(P)
#endif
+#ifdef SQLITE_DEBUG
+/* This routine provides a convenient place to set a breakpoint during
+** tracing with PRAGMA vdbe_trace=on. The breakpoint fires right after
+** each opcode is printed. Variables "pc" (program counter) and pOp are
+** available to add conditionals to the breakpoint. GDB example:
+**
+** break test_trace_breakpoint if pc=22
+**
+** Other useful labels for breakpoints include:
+** test_addop_breakpoint(pc,pOp)
+** sqlite3CorruptError(lineno)
+** sqlite3MisuseError(lineno)
+** sqlite3CantopenError(lineno)
+*/
+static void test_trace_breakpoint(int pc, Op *pOp, Vdbe *v){
+ static int n = 0;
+ n++;
+}
+#endif
+
/*
** Invoke the VDBE coverage callback, if that callback is defined. This
** feature is used for test suite validation only and does not appear an
@@ -461,12 +481,9 @@ static u16 numericType(Mem *pMem){
** Write a nice string representation of the contents of cell pMem
** into buffer zBuf, length nBuf.
*/
-void sqlite3VdbeMemPrettyPrint(Mem *pMem, char *zBuf){
- char *zCsr = zBuf;
+void sqlite3VdbeMemPrettyPrint(Mem *pMem, StrAccum *pStr){
int f = pMem->flags;
-
static const char *const encnames[] = {"(X)", "(8)", "(16LE)", "(16BE)"};
-
if( f&MEM_Blob ){
int i;
char c;
@@ -482,57 +499,40 @@ void sqlite3VdbeMemPrettyPrint(Mem *pMem, char *zBuf){
}else{
c = 's';
}
- *(zCsr++) = c;
- *(zCsr++) = 'x';
- sqlite3_snprintf(100, zCsr, "%d[", pMem->n);
- zCsr += sqlite3Strlen30(zCsr);
+ sqlite3_str_appendf(pStr, "%cx[", c);
for(i=0; i<25 && in; i++){
- sqlite3_snprintf(100, zCsr, "%02X", ((int)pMem->z[i] & 0xFF));
- zCsr += sqlite3Strlen30(zCsr);
+ sqlite3_str_appendf(pStr, "%02X", ((int)pMem->z[i] & 0xFF));
}
- *zCsr++ = '|';
+ sqlite3_str_appendf(pStr, "|");
for(i=0; i<25 && in; i++){
char z = pMem->z[i];
- if( z<32 || z>126 ) *zCsr++ = '.';
- else *zCsr++ = z;
+ sqlite3_str_appendchar(pStr, 1, (z<32||z>126)?'.':z);
}
- *(zCsr++) = ']';
+ sqlite3_str_appendf(pStr,"]");
if( f & MEM_Zero ){
- sqlite3_snprintf(100, zCsr,"+%dz",pMem->u.nZero);
- zCsr += sqlite3Strlen30(zCsr);
+ sqlite3_str_appendf(pStr, "+%dz",pMem->u.nZero);
}
- *zCsr = '\0';
}else if( f & MEM_Str ){
- int j, k;
- zBuf[0] = ' ';
+ int j;
+ int c;
if( f & MEM_Dyn ){
- zBuf[1] = 'z';
+ c = 'z';
assert( (f & (MEM_Static|MEM_Ephem))==0 );
}else if( f & MEM_Static ){
- zBuf[1] = 't';
+ c = 't';
assert( (f & (MEM_Dyn|MEM_Ephem))==0 );
}else if( f & MEM_Ephem ){
- zBuf[1] = 'e';
+ c = 'e';
assert( (f & (MEM_Static|MEM_Dyn))==0 );
}else{
- zBuf[1] = 's';
+ c = 's';
}
- k = 2;
- sqlite3_snprintf(100, &zBuf[k], "%d", pMem->n);
- k += sqlite3Strlen30(&zBuf[k]);
- zBuf[k++] = '[';
+ sqlite3_str_appendf(pStr, " %c%d[", c, pMem->n);
for(j=0; j<25 && jn; j++){
u8 c = pMem->z[j];
- if( c>=0x20 && c<0x7f ){
- zBuf[k++] = c;
- }else{
- zBuf[k++] = '.';
- }
+ sqlite3_str_appendchar(pStr, 1, (c>=0x20&&c<=0x7f) ? c : '.');
}
- zBuf[k++] = ']';
- sqlite3_snprintf(100,&zBuf[k], encnames[pMem->enc]);
- k += sqlite3Strlen30(&zBuf[k]);
- zBuf[k++] = 0;
+ sqlite3_str_appendf(pStr, "]%s", encnames[pMem->enc]);
}
}
#endif
@@ -559,20 +559,37 @@ static void memTracePrint(Mem *p){
}else if( sqlite3VdbeMemIsRowSet(p) ){
printf(" (rowset)");
}else{
- char zBuf[200];
- sqlite3VdbeMemPrettyPrint(p, zBuf);
- printf(" %s", zBuf);
+ StrAccum acc;
+ char zBuf[1000];
+ sqlite3StrAccumInit(&acc, 0, zBuf, sizeof(zBuf), 0);
+ sqlite3VdbeMemPrettyPrint(p, &acc);
+ printf(" %s", sqlite3StrAccumFinish(&acc));
}
if( p->flags & MEM_Subtype ) printf(" subtype=0x%02x", p->eSubtype);
}
static void registerTrace(int iReg, Mem *p){
- printf("REG[%d] = ", iReg);
+ printf("R[%d] = ", iReg);
memTracePrint(p);
+ if( p->pScopyFrom ){
+ printf(" <== R[%d]", (int)(p->pScopyFrom - &p[-iReg]));
+ }
printf("\n");
sqlite3VdbeCheckMemInvariants(p);
}
#endif
+#ifdef SQLITE_DEBUG
+/*
+** Show the values of all registers in the virtual machine. Used for
+** interactive debugging.
+*/
+void sqlite3VdbeRegisterDump(Vdbe *v){
+ int i;
+ for(i=1; inMem; i++) registerTrace(i, v->aMem+i);
+}
+#endif /* SQLITE_DEBUG */
+
+
#ifdef SQLITE_DEBUG
# define REGISTER_TRACE(R,M) if(db->flags&SQLITE_VdbeTrace)registerTrace(R,M)
#else
@@ -738,6 +755,7 @@ int sqlite3VdbeExec(
#ifdef SQLITE_DEBUG
if( db->flags & SQLITE_VdbeTrace ){
sqlite3VdbePrintOp(stdout, (int)(pOp - aOp), pOp);
+ test_trace_breakpoint((int)(pOp - aOp),pOp,p);
}
#endif
@@ -845,6 +863,20 @@ int sqlite3VdbeExec(
** to the current line should be indented for EXPLAIN output.
*/
case OP_Goto: { /* jump */
+
+#ifdef SQLITE_DEBUG
+ /* In debuggging mode, when the p5 flags is set on an OP_Goto, that
+ ** means we should really jump back to the preceeding OP_ReleaseReg
+ ** instruction. */
+ if( pOp->p5 ){
+ assert( pOp->p2 < (int)(pOp - aOp) );
+ assert( pOp->p2 > 1 );
+ pOp = &aOp[pOp->p2 - 2];
+ assert( pOp[1].opcode==OP_ReleaseReg );
+ goto check_for_interrupt;
+ }
+#endif
+
jump_to_p2_and_check_for_interrupt:
pOp = &aOp[pOp->p2 - 1];
@@ -1321,8 +1353,13 @@ case OP_Move: {
memAboutToChange(p, pOut);
sqlite3VdbeMemMove(pOut, pIn1);
#ifdef SQLITE_DEBUG
- if( pOut->pScopyFrom>=&aMem[p1] && pOut->pScopyFrompScopyFrom += pOp->p2 - p1;
+ pIn1->pScopyFrom = 0;
+ { int i;
+ for(i=1; inMem; i++){
+ if( aMem[i].pScopyFrom==pIn1 ){
+ aMem[i].pScopyFrom = pOut;
+ }
+ }
}
#endif
Deephemeralize(pOut);
@@ -1463,6 +1500,14 @@ case OP_ResultRow: {
|| (pMem[i].flags & (MEM_Str|MEM_Blob))==0 );
sqlite3VdbeMemNulTerminate(&pMem[i]);
REGISTER_TRACE(pOp->p1+i, &pMem[i]);
+#ifdef SQLITE_DEBUG
+ /* The registers in the result will not be used again when the
+ ** prepared statement restarts. This is because sqlite3_column()
+ ** APIs might have caused type conversions of made other changes to
+ ** the register values. Therefore, we can go ahead and break any
+ ** OP_SCopy dependencies. */
+ pMem[i].pScopyFrom = 0;
+#endif
}
if( db->mallocFailed ) goto no_mem;
@@ -1470,6 +1515,7 @@ case OP_ResultRow: {
db->xTrace(SQLITE_TRACE_ROW, db->pTraceArg, p, 0);
}
+
/* Return SQLITE_ROW
*/
p->pc = (int)(pOp - aOp) + 1;
@@ -1866,9 +1912,11 @@ case OP_Cast: { /* in1 */
pIn1 = &aMem[pOp->p1];
memAboutToChange(p, pIn1);
rc = ExpandBlob(pIn1);
- sqlite3VdbeMemCast(pIn1, pOp->p2, encoding);
- UPDATE_MAX_BLOBSIZE(pIn1);
if( rc ) goto abort_due_to_error;
+ rc = sqlite3VdbeMemCast(pIn1, pOp->p2, encoding);
+ if( rc ) goto abort_due_to_error;
+ UPDATE_MAX_BLOBSIZE(pIn1);
+ REGISTER_TRACE(pOp->p1, pIn1);
break;
}
#endif /* SQLITE_OMIT_CAST */
@@ -2027,12 +2075,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 );
- ** this used to be possible with pIn1==pIn3, but not since
- ** the column cache was removed. The following assignment
- ** is essentially a no-op. But, it provides defense-in-depth
- ** in case our analysis is incorrect, so it is left in. */
+ testcase( flags3!=pIn3->flags );
flags3 = pIn3->flags;
}
if( (flags3 & (MEM_Int|MEM_IntReal|MEM_Real|MEM_Str))==MEM_Str ){
@@ -2055,7 +2098,7 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
sqlite3VdbeMemStringify(pIn1, encoding, 1);
testcase( (flags1&MEM_Dyn) != (pIn1->flags&MEM_Dyn) );
flags1 = (pIn1->flags & ~MEM_TypeMask) | (flags1 & MEM_TypeMask);
- assert( pIn1!=pIn3 );
+ if( pIn1==pIn3 ) flags3 = flags1 | MEM_Str;
}
if( (flags3 & MEM_Str)==0 && (flags3&(MEM_Int|MEM_Real|MEM_IntReal))!=0 ){
testcase( pIn3->flags & MEM_Int );
@@ -2090,10 +2133,10 @@ compare_op:
}
/* Undo any changes made by applyAffinity() to the input registers. */
- assert( (pIn1->flags & MEM_Dyn) == (flags1 & MEM_Dyn) );
- pIn1->flags = flags1;
assert( (pIn3->flags & MEM_Dyn) == (flags3 & MEM_Dyn) );
pIn3->flags = flags3;
+ assert( (pIn1->flags & MEM_Dyn) == (flags1 & MEM_Dyn) );
+ pIn1->flags = flags1;
if( pOp->p5 & SQLITE_STOREP2 ){
pOut = &aMem[pOp->p2];
@@ -2129,16 +2172,31 @@ compare_op:
/* Opcode: ElseNotEq * P2 * * *
**
-** This opcode must immediately follow an OP_Lt or OP_Gt comparison operator.
-** If result of an OP_Eq comparison on the same two operands
-** would have be NULL or false (0), then then jump to P2.
-** If the result of an OP_Eq comparison on the two previous operands
-** would have been true (1), then fall through.
+** This opcode must follow an OP_Lt or OP_Gt comparison operator. There
+** can be zero or more OP_ReleaseReg opcodes intervening, but no other
+** opcodes are allowed to occur between this instruction and the previous
+** OP_Lt or OP_Gt. Furthermore, the prior OP_Lt or OP_Gt must have the
+** SQLITE_STOREP2 bit set in the P5 field.
+**
+** If result of an OP_Eq comparison on the same two operands as the
+** prior OP_Lt or OP_Gt would have been NULL or false (0), then then
+** jump to P2. If the result of an OP_Eq comparison on the two previous
+** operands would have been true (1), then fall through.
*/
case OP_ElseNotEq: { /* same as TK_ESCAPE, jump */
- assert( pOp>aOp );
- assert( pOp[-1].opcode==OP_Lt || pOp[-1].opcode==OP_Gt );
- assert( pOp[-1].p5 & SQLITE_STOREP2 );
+
+#ifdef SQLITE_DEBUG
+ /* Verify the preconditions of this opcode - that it follows an OP_Lt or
+ ** OP_Gt with the SQLITE_STOREP2 flag set, with zero or more intervening
+ ** OP_ReleaseReg opcodes */
+ int iAddr;
+ for(iAddr = (int)(pOp - aOp) - 1; ALWAYS(iAddr>=0); iAddr--){
+ if( aOp[iAddr].opcode==OP_ReleaseReg ) continue;
+ assert( aOp[iAddr].opcode==OP_Lt || aOp[iAddr].opcode==OP_Gt );
+ assert( aOp[iAddr].p5 & SQLITE_STOREP2 );
+ break;
+ }
+#endif /* SQLITE_DEBUG */
VdbeBranchTaken(iCompare!=0, 2);
if( iCompare!=0 ) goto jump_to_p2;
break;
@@ -2549,7 +2607,9 @@ case OP_Column: {
u32 t; /* A type code from the record header */
Mem *pReg; /* PseudoTable input register */
+ assert( pOp->p1>=0 && pOp->p1nCursor );
pC = p->apCsr[pOp->p1];
+ assert( pC!=0 );
p2 = pOp->p2;
/* If the cursor cache is stale (meaning it is not currently point at
@@ -2561,7 +2621,6 @@ case OP_Column: {
assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) );
pDest = &aMem[pOp->p3];
memAboutToChange(p, pDest);
- assert( pOp->p1>=0 && pOp->p1nCursor );
assert( pC!=0 );
assert( p2nField );
aOffset = pC->aOffset;
@@ -2772,10 +2831,11 @@ case OP_Column: {
**
** Although sqlite3VdbeSerialGet() may read at most 8 bytes from the
** buffer passed to it, debugging function VdbeMemPrettyPrint() may
- ** read up to 16. So 16 bytes of bogus content is supplied.
+ ** read more. Use the global constant sqlite3CtypeMap[] as the array,
+ ** as that array is 256 bytes long (plenty for VdbeMemPrettyPrint())
+ ** and it begins with a bunch of zeros.
*/
- static u8 aZero[16]; /* This is the bogus content */
- sqlite3VdbeSerialGet(aZero, t, pDest);
+ sqlite3VdbeSerialGet((u8*)sqlite3CtypeMap, t, pDest);
}else{
rc = sqlite3VdbeMemFromBtree(pC->uc.pCursor, aOffset[p2], len, pDest);
if( rc!=SQLITE_OK ) goto abort_due_to_error;
@@ -2818,7 +2878,7 @@ case OP_Affinity: {
pIn1 = &aMem[pOp->p1];
while( 1 /*exit-by-break*/ ){
assert( pIn1 <= &p->aMem[(p->nMem+1 - p->nCursor)] );
- assert( memIsValid(pIn1) );
+ assert( zAffinity[0]==SQLITE_AFF_NONE || memIsValid(pIn1) );
applyAffinity(pIn1, zAffinity[0], encoding);
if( zAffinity[0]==SQLITE_AFF_REAL && (pIn1->flags & MEM_Int)!=0 ){
/* When applying REAL affinity, if the result is still an MEM_Int
@@ -3143,11 +3203,11 @@ case OP_Count: { /* out2 */
pCrsr = p->apCsr[pOp->p1]->uc.pCursor;
assert( pCrsr );
nEntry = 0; /* Not needed. Only used to silence a warning. */
- rc = sqlite3BtreeCount(pCrsr, &nEntry);
+ rc = sqlite3BtreeCount(db, pCrsr, &nEntry);
if( rc ) goto abort_due_to_error;
pOut = out2Prerelease(p, pOp);
pOut->u.i = nEntry;
- break;
+ goto check_for_interrupt;
}
#endif
@@ -3264,8 +3324,12 @@ case OP_Savepoint: {
p->rc = rc = SQLITE_BUSY;
goto vdbe_return;
}
- db->isTransactionSavepoint = 0;
rc = p->rc;
+ if( rc ){
+ db->autoCommit = 0;
+ }else{
+ db->isTransactionSavepoint = 0;
+ }
}else{
int isSchemaChange;
iSavepoint = db->nSavepoint - iSavepoint - 1;
@@ -3293,6 +3357,7 @@ case OP_Savepoint: {
db->mDbFlags |= DBFLAG_SchemaChange;
}
}
+ if( rc ) goto abort_due_to_error;
/* Regardless of whether this is a RELEASE or ROLLBACK, destroy all
** savepoints nested inside of the savepoint being operated on. */
@@ -3375,7 +3440,6 @@ case OP_AutoCommit: {
p->rc = rc = SQLITE_BUSY;
goto vdbe_return;
}
- assert( db->nStatement==0 );
sqlite3CloseSavepoints(db);
if( p->rc==SQLITE_OK ){
rc = SQLITE_DONE;
@@ -3456,7 +3520,8 @@ case OP_Transaction: {
goto abort_due_to_error;
}
- if( pOp->p2 && p->usesStmtJournal
+ if( p->usesStmtJournal
+ && pOp->p2
&& (db->autoCommit==0 || db->nVdbeRead>1)
){
assert( sqlite3BtreeIsInTrans(pBt) );
@@ -3788,6 +3853,7 @@ case OP_OpenDup: {
VdbeCursor *pCx; /* The new cursor */
pOrig = p->apCsr[pOp->p2];
+ assert( pOrig );
assert( pOrig->pBtx!=0 ); /* Only ephemeral cursors can be duplicated */
pCx = allocateCursor(p, pOp->p1, pOrig->nField, -1, CURTYPE_BTREE);
@@ -4291,7 +4357,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.
@@ -4306,6 +4372,20 @@ case OP_SeekHit: {
break;
}
+/* Opcode: IfNotOpen P1 P2 * * *
+** Synopsis: if( !csr[P1] ) goto P2
+**
+** If cursor P1 is not open, jump to instruction P2. Otherwise, fall through.
+*/
+case OP_IfNotOpen: { /* jump */
+ assert( pOp->p1>=0 && pOp->p1nCursor );
+ VdbeBranchTaken(p->apCsr[pOp->p1]==0, 2);
+ if( !p->apCsr[pOp->p1] ){
+ goto jump_to_p2_and_check_for_interrupt;
+ }
+ break;
+}
+
/* Opcode: Found P1 P2 P3 P4 *
** Synopsis: key=r[P3@P4]
**
@@ -4538,23 +4618,27 @@ case OP_SeekRowid: { /* jump, in3 */
pIn3 = &aMem[pOp->p3];
testcase( pIn3->flags & MEM_Int );
testcase( pIn3->flags & MEM_IntReal );
+ testcase( pIn3->flags & MEM_Real );
+ testcase( (pIn3->flags & (MEM_Str|MEM_Int))==MEM_Str );
if( (pIn3->flags & (MEM_Int|MEM_IntReal))==0 ){
- /* Make sure pIn3->u.i contains a valid integer representation of
- ** the key value, but do not change the datatype of the register, as
- ** other parts of the perpared statement might be depending on the
- ** current datatype. */
- u16 origFlags = pIn3->flags;
- int isNotInt;
- applyAffinity(pIn3, SQLITE_AFF_NUMERIC, encoding);
- isNotInt = (pIn3->flags & MEM_Int)==0;
- pIn3->flags = origFlags;
- if( isNotInt ) goto jump_to_p2;
+ /* If pIn3->u.i does not contain an integer, compute iKey as the
+ ** integer value of pIn3. Jump to P2 if pIn3 cannot be converted
+ ** into an integer without loss of information. Take care to avoid
+ ** changing the datatype of pIn3, however, as it is used by other
+ ** parts of the prepared statement. */
+ Mem x = pIn3[0];
+ applyAffinity(&x, SQLITE_AFF_NUMERIC, encoding);
+ if( (x.flags & MEM_Int)==0 ) goto jump_to_p2;
+ iKey = x.u.i;
+ goto notExistsWithKey;
}
/* Fall through into OP_NotExists */
case OP_NotExists: /* jump, in3 */
pIn3 = &aMem[pOp->p3];
assert( (pIn3->flags & MEM_Int)!=0 || pOp->opcode==OP_SeekRowid );
assert( pOp->p1>=0 && pOp->p1nCursor );
+ iKey = pIn3->u.i;
+notExistsWithKey:
pC = p->apCsr[pOp->p1];
assert( pC!=0 );
#ifdef SQLITE_DEBUG
@@ -4565,7 +4649,6 @@ case OP_NotExists: /* jump, in3 */
pCrsr = pC->uc.pCursor;
assert( pCrsr!=0 );
res = 0;
- iKey = pIn3->u.i;
rc = sqlite3BtreeMovetoUnpacked(pCrsr, 0, iKey, 0, &res);
assert( rc==SQLITE_OK || res==0 );
pC->movetoTarget = iKey; /* Used by OP_Delete */
@@ -4791,6 +4874,7 @@ case OP_Insert: {
pC = p->apCsr[pOp->p1];
assert( pC!=0 );
assert( pC->eCurType==CURTYPE_BTREE );
+ assert( pC->deferredMoveto==0 );
assert( pC->uc.pCursor!=0 );
assert( (pOp->p5 & OPFLAG_ISNOOP) || pC->isTable );
assert( pOp->p4type==P4_TABLE || pOp->p4type>=P4_STATIC );
@@ -4908,7 +4992,11 @@ case OP_Delete: {
sqlite3VdbeIncrWriteCounter(p, pC);
#ifdef SQLITE_DEBUG
- if( pOp->p4type==P4_TABLE && HasRowid(pOp->p4.pTab) && pOp->p5==0 ){
+ if( pOp->p4type==P4_TABLE
+ && HasRowid(pOp->p4.pTab)
+ && pOp->p5==0
+ && sqlite3BtreeCursorIsValidNN(pC->uc.pCursor)
+ ){
/* If p5 is zero, the seek operation that positioned the cursor prior to
** OP_Delete will have also set the pC->movetoTarget field to the rowid of
** the row that is being deleted */
@@ -5664,6 +5752,24 @@ case OP_IdxRowid: { /* out2 */
break;
}
+/* Opcode: FinishSeek P1 * * * *
+**
+** If cursor P1 was previously moved via OP_DeferredSeek, complete that
+** seek operation now, without further delay. If the cursor seek has
+** already occurred, this instruction is a no-op.
+*/
+case OP_FinishSeek: {
+ VdbeCursor *pC; /* The P1 index cursor */
+
+ assert( pOp->p1>=0 && pOp->p1nCursor );
+ pC = p->apCsr[pOp->p1];
+ if( pC->deferredMoveto ){
+ rc = sqlite3VdbeFinishMoveto(pC);
+ if( rc ) goto abort_due_to_error;
+ }
+ break;
+}
+
/* Opcode: IdxGE P1 P2 P3 P4 P5
** Synopsis: key=r[P3@P4]
**
@@ -6100,7 +6206,7 @@ case OP_IntegrityCk: {
pIn1 = &aMem[pOp->p1];
assert( pOp->p5nDb );
assert( DbMaskTest(p->btreeMask, pOp->p5) );
- z = sqlite3BtreeIntegrityCheck(db->aDb[pOp->p5].pBt, &aRoot[1], nRoot,
+ z = sqlite3BtreeIntegrityCheck(db, db->aDb[pOp->p5].pBt, &aRoot[1], nRoot,
(int)pnErr->u.i+1, &nErr);
sqlite3VdbeMemSetNull(pIn1);
if( nErr==0 ){
@@ -6113,7 +6219,7 @@ case OP_IntegrityCk: {
}
UPDATE_MAX_BLOBSIZE(pIn1);
sqlite3VdbeChangeEncoding(pIn1, encoding);
- break;
+ goto check_for_interrupt;
}
#endif /* SQLITE_OMIT_INTEGRITY_CHECK */
@@ -6982,6 +7088,36 @@ case OP_Expire: {
break;
}
+/* Opcode: CursorLock P1 * * * *
+**
+** Lock the btree to which cursor P1 is pointing so that the btree cannot be
+** written by an other cursor.
+*/
+case OP_CursorLock: {
+ VdbeCursor *pC;
+ assert( pOp->p1>=0 && pOp->p1nCursor );
+ pC = p->apCsr[pOp->p1];
+ assert( pC!=0 );
+ assert( pC->eCurType==CURTYPE_BTREE );
+ sqlite3BtreeCursorPin(pC->uc.pCursor);
+ break;
+}
+
+/* Opcode: CursorUnlock P1 * * * *
+**
+** Unlock the btree to which cursor P1 is pointing so that it can be
+** written by other cursors.
+*/
+case OP_CursorUnlock: {
+ VdbeCursor *pC;
+ assert( pOp->p1>=0 && pOp->p1nCursor );
+ pC = p->apCsr[pOp->p1];
+ assert( pC!=0 );
+ assert( pC->eCurType==CURTYPE_BTREE );
+ sqlite3BtreeCursorUnpin(pC->uc.pCursor);
+ break;
+}
+
#ifndef SQLITE_OMIT_SHARED_CACHE
/* Opcode: TableLock P1 P2 P3 P4 *
** Synopsis: iDb=P1 root=P2 write=P3
@@ -7226,7 +7362,7 @@ case OP_VColumn: {
assert( pModule->xColumn );
memset(&sContext, 0, sizeof(sContext));
sContext.pOut = pDest;
- testcase( (pOp->p5 & OPFLAG_NOCHNG)==0 && pOp->p5!=0 );
+ assert( pOp->p5==OPFLAG_NOCHNG || pOp->p5==0 );
if( pOp->p5 & OPFLAG_NOCHNG ){
sqlite3VdbeMemSetNull(pDest);
pDest->flags = MEM_Null|MEM_Zero;
@@ -7451,29 +7587,14 @@ case OP_MaxPgcnt: { /* out2 */
}
#endif
-/* Opcode: Function0 P1 P2 P3 P4 P5
-** Synopsis: r[P3]=func(r[P2@P5])
-**
-** Invoke a user function (P4 is a pointer to a FuncDef object that
-** defines the function) with P5 arguments taken from register P2 and
-** successors. The result of the function is stored in register P3.
-** Register P3 must not be one of the function inputs.
-**
-** P1 is a 32-bit bitmask indicating whether or not each argument to the
-** function was determined to be constant at compile time. If the first
-** argument was constant then bit 0 of P1 is set. This is used to determine
-** whether meta data associated with a user function argument using the
-** sqlite3_set_auxdata() API may be safely retained until the next
-** invocation of this opcode.
-**
-** See also: Function, AggStep, AggFinal
-*/
-/* Opcode: Function P1 P2 P3 P4 P5
+/* Opcode: Function P1 P2 P3 P4 *
** Synopsis: r[P3]=func(r[P2@P5])
**
** Invoke a user function (P4 is a pointer to an sqlite3_context object that
-** contains a pointer to the function to be run) with P5 arguments taken
-** from register P2 and successors. The result of the function is stored
+** contains a pointer to the function to be run) with arguments taken
+** from register P2 and successors. The number of arguments is in
+** the sqlite3_context object that P4 points to.
+** The result of the function is stored
** in register P3. Register P3 must not be one of the function inputs.
**
** P1 is a 32-bit bitmask indicating whether or not each argument to the
@@ -7483,40 +7604,35 @@ case OP_MaxPgcnt: { /* out2 */
** sqlite3_set_auxdata() API may be safely retained until the next
** invocation of this opcode.
**
-** SQL functions are initially coded as OP_Function0 with P4 pointing
-** to a FuncDef object. But on first evaluation, the P4 operand is
-** automatically converted into an sqlite3_context object and the operation
-** changed to this OP_Function opcode. In this way, the initialization of
-** the sqlite3_context object occurs only once, rather than once for each
-** evaluation of the function.
-**
-** See also: Function0, AggStep, AggFinal
+** See also: AggStep, AggFinal, PureFunc
+*/
+/* Opcode: PureFunc P1 P2 P3 P4 *
+** Synopsis: r[P3]=func(r[P2@P5])
+**
+** Invoke a user function (P4 is a pointer to an sqlite3_context object that
+** contains a pointer to the function to be run) with arguments taken
+** from register P2 and successors. The number of arguments is in
+** the sqlite3_context object that P4 points to.
+** The result of the function is stored
+** in register P3. Register P3 must not be one of the function inputs.
+**
+** P1 is a 32-bit bitmask indicating whether or not each argument to the
+** function was determined to be constant at compile time. If the first
+** argument was constant then bit 0 of P1 is set. This is used to determine
+** whether meta data associated with a user function argument using the
+** sqlite3_set_auxdata() API may be safely retained until the next
+** invocation of this opcode.
+**
+** This opcode works exactly like OP_Function. The only difference is in
+** its name. This opcode is used in places where the function must be
+** purely non-deterministic. Some built-in date/time functions can be
+** either determinitic of non-deterministic, depending on their arguments.
+** When those function are used in a non-deterministic way, they will check
+** to see if they were called using OP_PureFunc instead of OP_Function, and
+** if they were, they throw an error.
+**
+** See also: AggStep, AggFinal, Function
*/
-case OP_PureFunc0: /* group */
-case OP_Function0: { /* group */
- int n;
- sqlite3_context *pCtx;
-
- assert( pOp->p4type==P4_FUNCDEF );
- n = pOp->p5;
- assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) );
- assert( n==0 || (pOp->p2>0 && pOp->p2+n<=(p->nMem+1 - p->nCursor)+1) );
- assert( pOp->p3p2 || pOp->p3>=pOp->p2+n );
- pCtx = sqlite3DbMallocRawNN(db, sizeof(*pCtx) + (n-1)*sizeof(sqlite3_value*));
- if( pCtx==0 ) goto no_mem;
- pCtx->pOut = 0;
- pCtx->pFunc = pOp->p4.pFunc;
- pCtx->iOp = (int)(pOp - aOp);
- pCtx->pVdbe = p;
- pCtx->isError = 0;
- pCtx->argc = n;
- pOp->p4type = P4_FUNCCTX;
- pOp->p4.pCtx = pCtx;
- assert( OP_PureFunc == OP_PureFunc0+2 );
- assert( OP_Function == OP_Function0+2 );
- pOp->opcode += 2;
- /* Fall through into OP_Function */
-}
case OP_PureFunc: /* group */
case OP_Function: { /* group */
int i;
@@ -7531,9 +7647,11 @@ case OP_Function: { /* group */
** reinitializes the relavant parts of the sqlite3_context object */
pOut = &aMem[pOp->p3];
if( pCtx->pOut != pOut ){
+ pCtx->pVdbe = p;
pCtx->pOut = pOut;
for(i=pCtx->argc-1; i>=0; i--) pCtx->argv[i] = &aMem[pOp->p2+i];
}
+ assert( pCtx->pVdbe==p );
memAboutToChange(p, pOut);
#ifdef SQLITE_DEBUG
@@ -7705,6 +7823,55 @@ case OP_Abortable: {
}
#endif
+#ifdef SQLITE_DEBUG
+/* Opcode: ReleaseReg P1 P2 P3 * P5
+** Synopsis: release r[P1@P2] mask P3
+**
+** Release registers from service. Any content that was in the
+** the registers is unreliable after this opcode completes.
+**
+** The registers released will be the P2 registers starting at P1,
+** except if bit ii of P3 set, then do not release register P1+ii.
+** In other words, P3 is a mask of registers to preserve.
+**
+** Releasing a register clears the Mem.pScopyFrom pointer. That means
+** that if the content of the released register was set using OP_SCopy,
+** a change to the value of the source register for the OP_SCopy will no longer
+** generate an assertion fault in sqlite3VdbeMemAboutToChange().
+**
+** If P5 is set, then all released registers have their type set
+** to MEM_Undefined so that any subsequent attempt to read the released
+** register (before it is reinitialized) will generate an assertion fault.
+**
+** P5 ought to be set on every call to this opcode.
+** However, there are places in the code generator will release registers
+** before their are used, under the (valid) assumption that the registers
+** will not be reallocated for some other purpose before they are used and
+** hence are safe to release.
+**
+** This opcode is only available in testing and debugging builds. It is
+** not generated for release builds. The purpose of this opcode is to help
+** validate the generated bytecode. This opcode does not actually contribute
+** to computing an answer.
+*/
+case OP_ReleaseReg: {
+ Mem *pMem;
+ int i;
+ u32 constMask;
+ assert( pOp->p1>0 );
+ assert( pOp->p1+pOp->p2<=(p->nMem+1 - p->nCursor)+1 );
+ pMem = &aMem[pOp->p1];
+ constMask = pOp->p3;
+ for(i=0; ip2; i++, pMem++){
+ if( i>=32 || (constMask & MASKBIT32(i))==0 ){
+ pMem->pScopyFrom = 0;
+ if( i<32 && pOp->p5 ) MemSetTypeFlag(pMem, MEM_Undefined);
+ }
+ }
+ break;
+}
+#endif
+
/* Opcode: Noop * * * * *
**
** Do nothing. This instruction is often useful as a jump
@@ -7756,6 +7923,12 @@ default: { /* This is really OP_Noop, OP_Explain */
if( opProperty & OPFLG_OUT3 ){
registerTrace(pOrigOp->p3, &aMem[pOrigOp->p3]);
}
+ if( opProperty==0xff ){
+ /* Never happens. This code exists to avoid a harmless linkage
+ ** warning aboud sqlite3VdbeRegisterDump() being defined but not
+ ** used. */
+ sqlite3VdbeRegisterDump(p);
+ }
}
#endif /* SQLITE_DEBUG */
#endif /* NDEBUG */
diff --git a/src/vdbe.h b/src/vdbe.h
index e3aaaa1ce2..bfde25873f 100644
--- a/src/vdbe.h
+++ b/src/vdbe.h
@@ -179,6 +179,7 @@ typedef struct VdbeOpList VdbeOpList;
** for a description of what each of these routines does.
*/
Vdbe *sqlite3VdbeCreate(Parse*);
+Parse *sqlite3VdbeParser(Vdbe*);
int sqlite3VdbeAddOp0(Vdbe*,int);
int sqlite3VdbeAddOp1(Vdbe*,int,int);
int sqlite3VdbeAddOp2(Vdbe*,int,int,int);
@@ -189,6 +190,7 @@ int sqlite3VdbeAddOp3(Vdbe*,int,int,int,int);
int sqlite3VdbeAddOp4(Vdbe*,int,int,int,int,const char *zP4,int);
int sqlite3VdbeAddOp4Dup8(Vdbe*,int,int,int,int,const u8*,int);
int sqlite3VdbeAddOp4Int(Vdbe*,int,int,int,int,int);
+int sqlite3VdbeAddFunctionCall(Parse*,int,int,int,int,const FuncDef*,int);
void sqlite3VdbeEndCoroutine(Vdbe*,int);
#if defined(SQLITE_DEBUG) && !defined(SQLITE_TEST_REALLOC_STRESS)
void sqlite3VdbeVerifyNoMallocRequired(Vdbe *p, int N);
@@ -230,6 +232,11 @@ void sqlite3VdbeChangeP5(Vdbe*, u16 P5);
void sqlite3VdbeJumpHere(Vdbe*, int addr);
int sqlite3VdbeChangeToNoop(Vdbe*, int addr);
int sqlite3VdbeDeletePriorOpcode(Vdbe*, u8 op);
+#ifdef SQLITE_DEBUG
+ void sqlite3VdbeReleaseRegisters(Parse*,int addr, int n, u32 mask, int);
+#else
+# define sqlite3VdbeReleaseRegisters(P,A,N,M,F)
+#endif
void sqlite3VdbeChangeP4(Vdbe*, int addr, const char *zP4, int N);
void sqlite3VdbeAppendP4(Vdbe*, void *pP4, int p4type);
void sqlite3VdbeSetP4KeyInfo(Parse*, Index*);
@@ -278,9 +285,8 @@ UnpackedRecord *sqlite3VdbeAllocUnpackedRecord(KeyInfo*);
typedef int (*RecordCompare)(int,const void*,UnpackedRecord*);
RecordCompare sqlite3VdbeFindCompare(UnpackedRecord*);
-#ifndef SQLITE_OMIT_TRIGGER
void sqlite3VdbeLinkSubProgram(Vdbe *, SubProgram *);
-#endif
+int sqlite3VdbeHasSubProgram(Vdbe*);
int sqlite3NotPureFunc(sqlite3_context*);
diff --git a/src/vdbeInt.h b/src/vdbeInt.h
index bd035535ab..9311591fbc 100644
--- a/src/vdbeInt.h
+++ b/src/vdbeInt.h
@@ -286,7 +286,8 @@ struct sqlite3_value {
** True if Mem X is a NULL-nochng type.
*/
#define MemNullNochng(X) \
- ((X)->flags==(MEM_Null|MEM_Zero) && (X)->n==0 && (X)->u.nZero==0)
+ (((X)->flags&MEM_TypeMask)==(MEM_Null|MEM_Zero) \
+ && (X)->n==0 && (X)->u.nZero==0)
/*
** Return true if a memory cell is not marked as invalid. This macro
@@ -482,6 +483,7 @@ struct PreUpdate {
void sqlite3VdbeError(Vdbe*, const char *, ...);
void sqlite3VdbeFreeCursor(Vdbe *, VdbeCursor*);
void sqliteVdbePopStack(Vdbe*,int);
+int SQLITE_NOINLINE sqlite3VdbeFinishMoveto(VdbeCursor*);
int sqlite3VdbeCursorMoveto(VdbeCursor**, int*);
int sqlite3VdbeCursorRestore(VdbeCursor*);
u32 sqlite3VdbeSerialTypeLen(u32);
@@ -528,7 +530,7 @@ int sqlite3VdbeBooleanValue(Mem*, int ifNull);
void sqlite3VdbeIntegerAffinity(Mem*);
int sqlite3VdbeMemRealify(Mem*);
int sqlite3VdbeMemNumerify(Mem*);
-void sqlite3VdbeMemCast(Mem*,u8,u8);
+int sqlite3VdbeMemCast(Mem*,u8,u8);
int sqlite3VdbeMemFromBtree(BtCursor*,u32,u32,Mem*);
void sqlite3VdbeMemRelease(Mem *p);
int sqlite3VdbeMemFinalize(Mem*, FuncDef*);
@@ -594,7 +596,7 @@ int sqlite3VdbeCheckFk(Vdbe *, int);
#ifdef SQLITE_DEBUG
void sqlite3VdbePrintSql(Vdbe*);
- void sqlite3VdbeMemPrettyPrint(Mem *pMem, char *zBuf);
+ void sqlite3VdbeMemPrettyPrint(Mem *pMem, StrAccum *pStr);
#endif
#ifndef SQLITE_OMIT_UTF16
int sqlite3VdbeMemTranslate(Mem*, u8);
diff --git a/src/vdbeapi.c b/src/vdbeapi.c
index c7968ee60d..074d458815 100644
--- a/src/vdbeapi.c
+++ b/src/vdbeapi.c
@@ -1831,7 +1831,7 @@ int sqlite3_preupdate_old(sqlite3 *db, int iIdx, sqlite3_value **ppValue){
goto preupdate_old_out;
}
if( p->pPk ){
- iIdx = sqlite3ColumnOfIndex(p->pPk, iIdx);
+ iIdx = sqlite3TableColumnToIndex(p->pPk, iIdx);
}
if( iIdx>=p->pCsr->nField || iIdx<0 ){
rc = SQLITE_RANGE;
@@ -1921,7 +1921,7 @@ int sqlite3_preupdate_new(sqlite3 *db, int iIdx, sqlite3_value **ppValue){
goto preupdate_new_out;
}
if( p->pPk && p->op!=SQLITE_UPDATE ){
- iIdx = sqlite3ColumnOfIndex(p->pPk, iIdx);
+ iIdx = sqlite3TableColumnToIndex(p->pPk, iIdx);
}
if( iIdx>=p->pCsr->nField || iIdx<0 ){
rc = SQLITE_RANGE;
diff --git a/src/vdbeaux.c b/src/vdbeaux.c
index fb2dd9039a..fab8b705c8 100644
--- a/src/vdbeaux.c
+++ b/src/vdbeaux.c
@@ -15,6 +15,10 @@
#include "sqliteInt.h"
#include "vdbeInt.h"
+/* Forward references */
+static void freeEphemeralFunction(sqlite3 *db, FuncDef *pDef);
+static void vdbeFreeOpArray(sqlite3 *, Op *, int);
+
/*
** Create a new virtual database engine.
*/
@@ -42,6 +46,13 @@ Vdbe *sqlite3VdbeCreate(Parse *pParse){
return p;
}
+/*
+** Return the Parse object that owns a Vdbe object.
+*/
+Parse *sqlite3VdbeParser(Vdbe *p){
+ return p->pParse;
+}
+
/*
** Change the error string stored in Vdbe.zErrMsg
*/
@@ -122,7 +133,7 @@ void sqlite3VdbeSwap(Vdbe *pA, Vdbe *pB){
zTmp = pA->zSql;
pA->zSql = pB->zSql;
pB->zSql = zTmp;
-#if 0
+#ifdef SQLITE_ENABLE_NORMALIZE
zTmp = pA->zNormSql;
pA->zNormSql = pB->zNormSql;
pB->zNormSql = zTmp;
@@ -183,9 +194,16 @@ static int growOpArray(Vdbe *v, int nOp){
#ifdef SQLITE_DEBUG
/* This routine is just a convenient place to set a breakpoint that will
** fire after each opcode is inserted and displayed using
-** "PRAGMA vdbe_addoptrace=on".
+** "PRAGMA vdbe_addoptrace=on". Parameters "pc" (program counter) and
+** pOp are available to make the breakpoint conditional.
+**
+** Other useful labels for breakpoints include:
+** test_trace_breakpoint(pc,pOp)
+** sqlite3CorruptError(lineno)
+** sqlite3MisuseError(lineno)
+** sqlite3CantopenError(lineno)
*/
-static void test_addop_breakpoint(void){
+static void test_addop_breakpoint(int pc, Op *pOp){
static int n = 0;
n++;
}
@@ -238,7 +256,7 @@ int sqlite3VdbeAddOp3(Vdbe *p, int op, int p1, int p2, int p3){
#ifdef SQLITE_DEBUG
if( p->db->flags & SQLITE_VdbeAddopTrace ){
sqlite3VdbePrintOp(0, i, &p->aOp[i]);
- test_addop_breakpoint();
+ test_addop_breakpoint(i, &p->aOp[i]);
}
#endif
#ifdef VDBE_PROFILE
@@ -321,6 +339,49 @@ int sqlite3VdbeAddOp4(
return addr;
}
+/*
+** Add an OP_Function or OP_PureFunc opcode.
+**
+** The eCallCtx argument is information (typically taken from Expr.op2)
+** that describes the calling context of the function. 0 means a general
+** function call. NC_IsCheck means called by a check constraint,
+** NC_IdxExpr means called as part of an index expression. NC_PartIdx
+** means in the WHERE clause of a partial index. NC_GenCol means called
+** while computing a generated column value. 0 is the usual case.
+*/
+int sqlite3VdbeAddFunctionCall(
+ Parse *pParse, /* Parsing context */
+ int p1, /* Constant argument mask */
+ int p2, /* First argument register */
+ int p3, /* Register into which results are written */
+ int nArg, /* Number of argument */
+ const FuncDef *pFunc, /* The function to be invoked */
+ int eCallCtx /* Calling context */
+){
+ Vdbe *v = pParse->pVdbe;
+ int nByte;
+ int addr;
+ sqlite3_context *pCtx;
+ assert( v );
+ nByte = sizeof(*pCtx) + (nArg-1)*sizeof(sqlite3_value*);
+ pCtx = sqlite3DbMallocRawNN(pParse->db, nByte);
+ if( pCtx==0 ){
+ assert( pParse->db->mallocFailed );
+ freeEphemeralFunction(pParse->db, (FuncDef*)pFunc);
+ return 0;
+ }
+ pCtx->pOut = 0;
+ pCtx->pFunc = (FuncDef*)pFunc;
+ pCtx->pVdbe = 0;
+ pCtx->isError = 0;
+ pCtx->argc = nArg;
+ pCtx->iOp = sqlite3VdbeCurrentAddr(v);
+ addr = sqlite3VdbeAddOp4(v, eCallCtx ? OP_PureFunc : OP_Function,
+ p1, p2, p3, (char*)pCtx, P4_FUNCCTX);
+ sqlite3VdbeChangeP5(v, eCallCtx & NC_SelfRef);
+ return addr;
+}
+
/*
** Add an opcode that includes the p4 value with a P4_INT64 or
** P4_REAL type.
@@ -613,6 +674,7 @@ static Op *opIterNext(VdbeOpIter *p){
** * OP_HaltIfNull with P1=SQLITE_CONSTRAINT and P2=OE_Abort.
** * OP_Destroy
** * OP_VUpdate
+** * OP_VCreate
** * OP_VRename
** * OP_FkCounter with P2==0 (immediate foreign key constraint)
** * OP_CreateBtree/BTREE_INTKEY and OP_InitCoroutine
@@ -640,7 +702,8 @@ int sqlite3VdbeAssertMayAbort(Vdbe *v, int mayAbort){
int opcode = pOp->opcode;
if( opcode==OP_Destroy || opcode==OP_VUpdate || opcode==OP_VRename
|| opcode==OP_VDestroy
- || (opcode==OP_Function0 && pOp->p4.pFunc->funcFlags&SQLITE_FUNC_INTERNAL)
+ || opcode==OP_VCreate
+ || (opcode==OP_ParseSchema && pOp->p4.z==0)
|| ((opcode==OP_Halt || opcode==OP_HaltIfNull)
&& ((pOp->p1)!=SQLITE_OK && pOp->p2==OE_Abort))
){
@@ -1013,8 +1076,6 @@ static void freeEphemeralFunction(sqlite3 *db, FuncDef *pDef){
}
}
-static void vdbeFreeOpArray(sqlite3 *, Op *, int);
-
/*
** Delete a P4 value if necessary.
*/
@@ -1024,7 +1085,7 @@ static SQLITE_NOINLINE void freeP4Mem(sqlite3 *db, Mem *p){
}
static SQLITE_NOINLINE void freeP4FuncCtx(sqlite3 *db, sqlite3_context *p){
freeEphemeralFunction(db, p->pFunc);
- sqlite3DbFreeNN(db, p);
+ sqlite3DbFreeNN(db, p);
}
static void freeP4(sqlite3 *db, int p4type, void *p4){
assert( db );
@@ -1098,6 +1159,13 @@ void sqlite3VdbeLinkSubProgram(Vdbe *pVdbe, SubProgram *p){
pVdbe->pProgram = p;
}
+/*
+** Return true if the given Vdbe has any SubPrograms.
+*/
+int sqlite3VdbeHasSubProgram(Vdbe *pVdbe){
+ return pVdbe->pProgram!=0;
+}
+
/*
** Change the opcode at addr into OP_Noop
*/
@@ -1125,6 +1193,41 @@ int sqlite3VdbeDeletePriorOpcode(Vdbe *p, u8 op){
}
}
+#ifdef SQLITE_DEBUG
+/*
+** Generate an OP_ReleaseReg opcode to indicate that a range of
+** registers, except any identified by mask, are no longer in use.
+*/
+void sqlite3VdbeReleaseRegisters(
+ Parse *pParse, /* Parsing context */
+ int iFirst, /* Index of first register to be released */
+ int N, /* Number of registers to release */
+ u32 mask, /* Mask of registers to NOT release */
+ int bUndefine /* If true, mark registers as undefined */
+){
+ if( N==0 ) return;
+ assert( pParse->pVdbe );
+ assert( iFirst>=1 );
+ assert( iFirst+N-1<=pParse->nMem );
+ if( N<=31 && mask!=0 ){
+ while( N>0 && (mask&1)!=0 ){
+ mask >>= 1;
+ iFirst++;
+ N--;
+ }
+ while( N>0 && N<=32 && (mask & MASKBIT32(N-1))!=0 ){
+ mask &= ~MASKBIT32(N-1);
+ N--;
+ }
+ }
+ if( N>0 ){
+ sqlite3VdbeAddOp3(pParse->pVdbe, OP_ReleaseReg, iFirst, N, *(int*)&mask);
+ if( bUndefine ) sqlite3VdbeChangeP5(pParse->pVdbe, 1);
+ }
+}
+#endif /* SQLITE_DEBUG */
+
+
/*
** Change the value of the P4 operand for a specific instruction.
** This routine is useful when a large program is loaded from a
@@ -1242,7 +1345,8 @@ void sqlite3VdbeSetP4KeyInfo(Parse *pParse, Index *pIdx){
*/
static void vdbeVComment(Vdbe *p, const char *zFormat, va_list ap){
assert( p->nOp>0 || p->aOp==0 );
- assert( p->aOp==0 || p->aOp[p->nOp-1].zComment==0 || p->db->mallocFailed );
+ assert( p->aOp==0 || p->aOp[p->nOp-1].zComment==0 || p->db->mallocFailed
+ || p->pParse->nErr>0 );
if( p->nOp ){
assert( p->aOp );
sqlite3DbFree(p->db, p->aOp[p->nOp-1].zComment);
@@ -1523,13 +1627,11 @@ static char *displayP4(Op *pOp, char *zTemp, int nTemp){
sqlite3_str_appendf(&x, "%s(%d)", pDef->zName, pDef->nArg);
break;
}
-#if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE)
case P4_FUNCCTX: {
FuncDef *pDef = pOp->p4.pCtx->pFunc;
sqlite3_str_appendf(&x, "%s(%d)", pDef->zName, pDef->nArg);
break;
}
-#endif
case P4_INT64: {
sqlite3_str_appendf(&x, "%lld", *pOp->p4.pI64);
break;
@@ -2223,8 +2325,26 @@ void sqlite3VdbeMakeReady(
resolveP2Values(p, &nArg);
p->usesStmtJournal = (u8)(pParse->isMultiWrite && pParse->mayAbort);
- if( pParse->explain && nMem<10 ){
- nMem = 10;
+ if( pParse->explain ){
+ static const char * const azColName[] = {
+ "addr", "opcode", "p1", "p2", "p3", "p4", "p5", "comment",
+ "id", "parent", "notused", "detail"
+ };
+ int iFirst, mx, i;
+ if( nMem<10 ) nMem = 10;
+ if( pParse->explain==2 ){
+ sqlite3VdbeSetNumCols(p, 4);
+ iFirst = 8;
+ mx = 12;
+ }else{
+ sqlite3VdbeSetNumCols(p, 8);
+ iFirst = 0;
+ mx = 8;
+ }
+ for(i=iFirst; iexpired = 0;
@@ -2574,7 +2694,7 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
/* Select a master journal file name */
nMainFile = sqlite3Strlen30(zMainFile);
- zMaster = sqlite3MPrintf(db, "%s-mjXXXXXX9XXz", zMainFile);
+ zMaster = sqlite3MPrintf(db, "%s-mjXXXXXX9XXz%c%c", zMainFile, 0, 0);
if( zMaster==0 ) return SQLITE_NOMEM_BKPT;
do {
u32 iRandom;
@@ -3313,7 +3433,7 @@ void sqlite3VdbeDelete(Vdbe *p){
** carried out. Seek the cursor now. If an error occurs, return
** the appropriate error code.
*/
-static int SQLITE_NOINLINE handleDeferredMoveto(VdbeCursor *p){
+int SQLITE_NOINLINE sqlite3VdbeFinishMoveto(VdbeCursor *p){
int res, rc;
#ifdef SQLITE_TEST
extern int sqlite3_search_count;
@@ -3385,7 +3505,7 @@ int sqlite3VdbeCursorMoveto(VdbeCursor **pp, int *piCol){
*piCol = iMap - 1;
return SQLITE_OK;
}
- return handleDeferredMoveto(p);
+ return sqlite3VdbeFinishMoveto(p);
}
if( sqlite3BtreeCursorHasMoved(p->uc.pCursor) ){
return handleMovedCursor(p);
@@ -4925,13 +5045,25 @@ void sqlite3VdbeSetVarmask(Vdbe *v, int iVar){
** features such as 'now'.
*/
int sqlite3NotPureFunc(sqlite3_context *pCtx){
+ const VdbeOp *pOp;
#ifdef SQLITE_ENABLE_STAT4
if( pCtx->pVdbe==0 ) return 1;
#endif
- if( pCtx->pVdbe->aOp[pCtx->iOp].opcode==OP_PureFunc ){
- sqlite3_result_error(pCtx,
- "non-deterministic function in index expression or CHECK constraint",
- -1);
+ pOp = pCtx->pVdbe->aOp + pCtx->iOp;
+ if( pOp->opcode==OP_PureFunc ){
+ const char *zContext;
+ char *zMsg;
+ if( pOp->p5 & NC_IsCheck ){
+ zContext = "a CHECK constraint";
+ }else if( pOp->p5 & NC_GenCol ){
+ zContext = "a generated column";
+ }else{
+ zContext = "an index";
+ }
+ zMsg = sqlite3_mprintf("non-deterministic use of %s() in %s",
+ pCtx->pFunc->zName, zContext);
+ sqlite3_result_error(pCtx, zMsg, -1);
+ sqlite3_free(zMsg);
return 0;
}
return 1;
diff --git a/src/vdbemem.c b/src/vdbemem.c
index 820789fb8c..464e8ffdc5 100644
--- a/src/vdbemem.c
+++ b/src/vdbemem.c
@@ -460,15 +460,11 @@ int sqlite3VdbeMemFinalize(Mem *pMem, FuncDef *pFunc){
#ifndef SQLITE_OMIT_WINDOWFUNC
int sqlite3VdbeMemAggValue(Mem *pAccum, Mem *pOut, FuncDef *pFunc){
sqlite3_context ctx;
- Mem t;
assert( pFunc!=0 );
assert( pFunc->xValue!=0 );
assert( (pAccum->flags & MEM_Null)!=0 || pFunc==pAccum->u.pDef );
assert( pAccum->db==0 || sqlite3_mutex_held(pAccum->db->mutex) );
memset(&ctx, 0, sizeof(ctx));
- memset(&t, 0, sizeof(t));
- t.flags = MEM_Null;
- t.db = pAccum->db;
sqlite3VdbeMemSetNull(pOut);
ctx.pOut = pOut;
ctx.pMem = pAccum;
@@ -594,8 +590,7 @@ i64 sqlite3VdbeIntValue(Mem *pMem){
return pMem->u.i;
}else if( flags & MEM_Real ){
return doubleToInt64(pMem->u.r);
- }else if( flags & (MEM_Str|MEM_Blob) ){
- assert( pMem->z || pMem->n==0 );
+ }else if( (flags & (MEM_Str|MEM_Blob))!=0 && pMem->z!=0 ){
return memIntValue(pMem);
}else{
return 0;
@@ -752,8 +747,8 @@ int sqlite3VdbeMemNumerify(Mem *pMem){
** affinity even if that results in loss of data. This routine is
** used (for example) to implement the SQL "cast()" operator.
*/
-void sqlite3VdbeMemCast(Mem *pMem, u8 aff, u8 encoding){
- if( pMem->flags & MEM_Null ) return;
+int sqlite3VdbeMemCast(Mem *pMem, u8 aff, u8 encoding){
+ if( pMem->flags & MEM_Null ) return SQLITE_OK;
switch( aff ){
case SQLITE_AFF_BLOB: { /* Really a cast to BLOB */
if( (pMem->flags & MEM_Blob)==0 ){
@@ -784,9 +779,10 @@ void sqlite3VdbeMemCast(Mem *pMem, u8 aff, u8 encoding){
sqlite3ValueApplyAffinity(pMem, SQLITE_AFF_TEXT, encoding);
assert( pMem->flags & MEM_Str || pMem->db->mallocFailed );
pMem->flags &= ~(MEM_Int|MEM_Real|MEM_IntReal|MEM_Blob|MEM_Zero);
- break;
+ return sqlite3VdbeChangeEncoding(pMem, encoding);
}
}
+ return SQLITE_OK;
}
/*
@@ -952,23 +948,30 @@ int sqlite3VdbeMemTooBig(Mem *p){
** its link to a shallow copy and by marking any current shallow
** copies of this cell as invalid.
**
-** This is used for testing and debugging only - to make sure shallow
-** copies are not misused.
+** This is used for testing and debugging only - to help ensure that shallow
+** copies (created by OP_SCopy) are not misused.
*/
void sqlite3VdbeMemAboutToChange(Vdbe *pVdbe, Mem *pMem){
int i;
Mem *pX;
- for(i=0, pX=pVdbe->aMem; inMem; i++, pX++){
+ for(i=1, pX=pVdbe->aMem+1; inMem; i++, pX++){
if( pX->pScopyFrom==pMem ){
+ u16 mFlags;
+ if( pVdbe->db->flags & SQLITE_VdbeTrace ){
+ sqlite3DebugPrintf("Invalidate R[%d] due to change in R[%d]\n",
+ (int)(pX - pVdbe->aMem), (int)(pMem - pVdbe->aMem));
+ }
/* If pX is marked as a shallow copy of pMem, then verify that
** no significant changes have been made to pX since the OP_SCopy.
** A significant change would indicated a missed call to this
** function for pX. Minor changes, such as adding or removing a
** dual type, are allowed, as long as the underlying value is the
** same. */
- u16 mFlags = pMem->flags & pX->flags & pX->mScopyFlags;
+ mFlags = pMem->flags & pX->flags & pX->mScopyFlags;
assert( (mFlags&(MEM_Int|MEM_IntReal))==0 || pMem->u.i==pX->u.i );
- assert( (mFlags&MEM_Real)==0 || pMem->u.r==pX->u.r );
+ /* assert( (mFlags&MEM_Real)==0 || pMem->u.r==pX->u.r ); */
+ /* ^^ */
+ /* Cannot reliably compare doubles for equality */
assert( (mFlags&MEM_Str)==0 || (pMem->n==pX->n && pMem->z==pX->z) );
assert( (mFlags&MEM_Blob)==0 || sqlite3BlobCompare(pMem,pX)==0 );
@@ -982,7 +985,6 @@ void sqlite3VdbeMemAboutToChange(Vdbe *pVdbe, Mem *pMem){
}
#endif /* SQLITE_DEBUG */
-
/*
** Make an shallow copy of pFrom into pTo. Prior contents of
** pTo are freed. The pFrom->z field is not duplicated. If
@@ -1128,10 +1130,19 @@ int sqlite3VdbeMemSetStr(
pMem->n = nByte;
pMem->flags = flags;
- pMem->enc = (enc==0 ? SQLITE_UTF8 : enc);
+ if( enc ){
+ pMem->enc = enc;
+#ifdef SQLITE_ENABLE_SESSION
+ }else if( pMem->db==0 ){
+ pMem->enc = SQLITE_UTF8;
+#endif
+ }else{
+ assert( pMem->db!=0 );
+ pMem->enc = ENC(pMem->db);
+ }
#ifndef SQLITE_OMIT_UTF16
- if( pMem->enc!=SQLITE_UTF8 && sqlite3VdbeMemHandleBom(pMem) ){
+ if( enc>SQLITE_UTF8 && sqlite3VdbeMemHandleBom(pMem) ){
return SQLITE_NOMEM_BKPT;
}
#endif
diff --git a/src/vdbesort.c b/src/vdbesort.c
index 7d60ee5116..ad93489c90 100644
--- a/src/vdbesort.c
+++ b/src/vdbesort.c
@@ -1396,20 +1396,16 @@ static SorterCompare vdbeSorterGetCompare(VdbeSorter *p){
*/
static int vdbeSorterSort(SortSubtask *pTask, SorterList *pList){
int i;
- SorterRecord **aSlot;
SorterRecord *p;
int rc;
+ SorterRecord *aSlot[64];
rc = vdbeSortAllocUnpacked(pTask);
if( rc!=SQLITE_OK ) return rc;
p = pList->pList;
pTask->xCompare = vdbeSorterGetCompare(pTask->pSorter);
-
- aSlot = (SorterRecord **)sqlite3MallocZero(64 * sizeof(SorterRecord *));
- if( !aSlot ){
- return SQLITE_NOMEM_BKPT;
- }
+ memset(aSlot, 0, sizeof(aSlot));
while( p ){
SorterRecord *pNext;
@@ -1434,13 +1430,12 @@ static int vdbeSorterSort(SortSubtask *pTask, SorterList *pList){
}
p = 0;
- for(i=0; i<64; i++){
+ for(i=0; ipList = p;
- sqlite3_free(aSlot);
assert( pTask->pUnpacked->errCode==SQLITE_OK
|| pTask->pUnpacked->errCode==SQLITE_NOMEM
);
diff --git a/src/vtab.c b/src/vtab.c
index 085290914b..013511cfb4 100644
--- a/src/vtab.c
+++ b/src/vtab.c
@@ -305,12 +305,12 @@ void sqlite3VtabDisconnect(sqlite3 *db, Table *p){
*/
void sqlite3VtabUnlockList(sqlite3 *db){
VTable *p = db->pDisconnect;
- db->pDisconnect = 0;
assert( sqlite3BtreeHoldsAllMutexes(db) );
assert( sqlite3_mutex_held(db->mutex) );
if( p ){
+ db->pDisconnect = 0;
sqlite3ExpirePreparedStatements(db, 0);
do {
VTable *pNext = p->pNext;
@@ -457,6 +457,8 @@ void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){
int iReg;
Vdbe *v;
+ sqlite3MayAbort(pParse);
+
/* Compute the complete text of the CREATE VIRTUAL TABLE statement */
if( pEnd ){
pParse->sNameToken.n = (int)(pEnd->z - pParse->sNameToken.z) + pEnd->n;
@@ -482,13 +484,13 @@ void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){
zStmt,
pParse->regRowid
);
- sqlite3DbFree(db, zStmt);
v = sqlite3GetVdbe(pParse);
sqlite3ChangeCookie(pParse, iDb);
sqlite3VdbeAddOp0(v, OP_Expire);
- zWhere = sqlite3MPrintf(db, "name='%q' AND type='table'", pTab->zName);
+ zWhere = sqlite3MPrintf(db, "name=%Q AND sql=%Q", pTab->zName, zStmt);
sqlite3VdbeAddParseSchemaOp(v, iDb, zWhere);
+ sqlite3DbFree(db, zStmt);
iReg = ++pParse->nMem;
sqlite3VdbeLoadString(v, iReg, pTab->zName);
@@ -585,6 +587,7 @@ static int vtabCallConstructor(
}
pVTable->db = db;
pVTable->pMod = pMod;
+ pVTable->eVtabRisk = SQLITE_VTABRISK_Normal;
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
pTab->azModuleArg[1] = db->aDb[iDb].zDbSName;
@@ -624,7 +627,7 @@ static int vtabCallConstructor(
rc = SQLITE_ERROR;
}else{
int iCol;
- u8 oooHidden = 0;
+ u16 oooHidden = 0;
/* If everything went according to plan, link the new VTable structure
** into the linked list headed by pTab->pVTable. Then loop through the
** columns of the table to see if any of them contain the token "hidden".
@@ -890,7 +893,8 @@ int sqlite3VtabCallDestroy(sqlite3 *db, int iDb, const char *zTab){
}
p = vtabDisconnectAll(db, pTab);
xDestroy = p->pMod->pModule->xDestroy;
- assert( xDestroy!=0 ); /* Checked before the virtual table is created */
+ if( xDestroy==0 ) xDestroy = p->pMod->pModule->xDisconnect;
+ assert( xDestroy!=0 );
pTab->nTabRef++;
rc = xDestroy(p->pVtab);
/* Remove the sqlite3_vtab* from the aVTrans[] array, if applicable */
@@ -1273,28 +1277,38 @@ int sqlite3_vtab_on_conflict(sqlite3 *db){
int sqlite3_vtab_config(sqlite3 *db, int op, ...){
va_list ap;
int rc = SQLITE_OK;
+ VtabCtx *p;
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
#endif
sqlite3_mutex_enter(db->mutex);
- va_start(ap, op);
- switch( op ){
- case SQLITE_VTAB_CONSTRAINT_SUPPORT: {
- VtabCtx *p = db->pVtabCtx;
- if( !p ){
- rc = SQLITE_MISUSE_BKPT;
- }else{
- assert( p->pTab==0 || IsVirtual(p->pTab) );
+ p = db->pVtabCtx;
+ if( !p ){
+ rc = SQLITE_MISUSE_BKPT;
+ }else{
+ assert( p->pTab==0 || IsVirtual(p->pTab) );
+ va_start(ap, op);
+ switch( op ){
+ case SQLITE_VTAB_CONSTRAINT_SUPPORT: {
p->pVTable->bConstraint = (u8)va_arg(ap, int);
+ break;
+ }
+ case SQLITE_VTAB_INNOCUOUS: {
+ p->pVTable->eVtabRisk = SQLITE_VTABRISK_Low;
+ break;
+ }
+ case SQLITE_VTAB_DIRECTONLY: {
+ p->pVTable->eVtabRisk = SQLITE_VTABRISK_High;
+ break;
+ }
+ default: {
+ rc = SQLITE_MISUSE_BKPT;
+ break;
}
- break;
}
- default:
- rc = SQLITE_MISUSE_BKPT;
- break;
+ va_end(ap);
}
- va_end(ap);
if( rc!=SQLITE_OK ) sqlite3Error(db, rc);
sqlite3_mutex_leave(db->mutex);
diff --git a/src/wal.c b/src/wal.c
index afa84145f5..99d8e99933 100644
--- a/src/wal.c
+++ b/src/wal.c
@@ -2400,7 +2400,19 @@ static int walCheckpoint(
** 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. */
+ ** 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];
if( mxSafeFrame>y ){
assert( y<=pWal->hdr.mxFrame );
diff --git a/src/walker.c b/src/walker.c
index 67ecd8a809..5733210c47 100644
--- a/src/walker.c
+++ b/src/walker.c
@@ -73,8 +73,8 @@ static SQLITE_NOINLINE int walkExpr(Walker *pWalker, Expr *pExpr){
rc = pWalker->xExprCallback(pWalker, pExpr);
if( rc ) return rc & WRC_Abort;
if( !ExprHasProperty(pExpr,(EP_TokenOnly|EP_Leaf)) ){
+ assert( pExpr->x.pList==0 || pExpr->pRight==0 );
if( pExpr->pLeft && walkExpr(pWalker, pExpr->pLeft) ) return WRC_Abort;
- assert( pExpr->x.pList==0 || pExpr->pRight==0 );
if( pExpr->pRight ){
assert( !ExprHasProperty(pExpr, EP_WinFunc) );
pExpr = pExpr->pRight;
diff --git a/src/where.c b/src/where.c
index 1a43b8d19e..7fb27191a3 100644
--- a/src/where.c
+++ b/src/where.c
@@ -120,7 +120,7 @@ int sqlite3WhereBreakLabel(WhereInfo *pWInfo){
/*
** Return ONEPASS_OFF (0) if an UPDATE or DELETE statement is unable to
-** operate directly on the rowis returned by a WHERE clause. Return
+** operate directly on the rowids returned by a WHERE clause. Return
** ONEPASS_SINGLE (1) if the statement can operation directly because only
** a single row is to be changed. Return ONEPASS_MULTI (2) if the one-pass
** optimization can be used on multiple
@@ -147,6 +147,14 @@ int sqlite3WhereOkOnePass(WhereInfo *pWInfo, int *aiCur){
return pWInfo->eOnePass;
}
+/*
+** Return TRUE if the WHERE loop uses the OP_DeferredSeek opcode to move
+** the data cursor to the row selected by the index cursor.
+*/
+int sqlite3WhereUsesDeferredSeek(WhereInfo *pWInfo){
+ return pWInfo->bDeferredSeek;
+}
+
/*
** Move the content of pSrc into pDest
*/
@@ -279,8 +287,7 @@ static WhereTerm *whereScanNext(WhereScan *pScan){
continue;
}
assert(pX->pLeft);
- pColl = sqlite3BinaryCompareCollSeq(pParse,
- pX->pLeft, pX->pRight);
+ pColl = sqlite3ExprCompareCollSeq(pParse, pX);
if( pColl==0 ) pColl = pParse->db->pDfltColl;
if( sqlite3StrICmp(pColl->zName, pScan->zCollName) ){
continue;
@@ -606,7 +613,7 @@ static void translateColumnToCopy(
** are no-ops.
*/
#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(WHERETRACE_ENABLED)
-static void TRACE_IDX_INPUTS(sqlite3_index_info *p){
+static void whereTraceIndexInfoInputs(sqlite3_index_info *p){
int i;
if( !sqlite3WhereTrace ) return;
for(i=0; inConstraint; i++){
@@ -624,7 +631,7 @@ static void TRACE_IDX_INPUTS(sqlite3_index_info *p){
p->aOrderBy[i].desc);
}
}
-static void TRACE_IDX_OUTPUTS(sqlite3_index_info *p){
+static void whereTraceIndexInfoOutputs(sqlite3_index_info *p){
int i;
if( !sqlite3WhereTrace ) return;
for(i=0; inConstraint; i++){
@@ -640,8 +647,8 @@ static void TRACE_IDX_OUTPUTS(sqlite3_index_info *p){
sqlite3DebugPrintf(" estimatedRows=%lld\n", p->estimatedRows);
}
#else
-#define TRACE_IDX_INPUTS(A)
-#define TRACE_IDX_OUTPUTS(A)
+#define whereTraceIndexInfoInputs(A)
+#define whereTraceIndexInfoOutputs(A)
#endif
#ifndef SQLITE_OMIT_AUTOMATIC_INDEX
@@ -801,7 +808,8 @@ static void constructAutomaticIndex(
Expr *pX = pTerm->pExpr;
idxCols |= cMask;
pIdx->aiColumn[n] = pTerm->u.leftColumn;
- pColl = sqlite3BinaryCompareCollSeq(pParse, pX->pLeft, pX->pRight);
+ pColl = sqlite3ExprCompareCollSeq(pParse, pX);
+ assert( pColl!=0 || pParse->nErr>0 ); /* TH3 collate01.800 */
pIdx->azColl[n] = pColl ? pColl->zName : sqlite3StrBINARY;
n++;
}
@@ -870,8 +878,8 @@ static void constructAutomaticIndex(
pTabItem->fg.viaCoroutine = 0;
}else{
sqlite3VdbeAddOp2(v, OP_Next, pLevel->iTabCur, addrTop+1); VdbeCoverage(v);
+ sqlite3VdbeChangeP5(v, SQLITE_STMTSTATUS_AUTOINDEX);
}
- sqlite3VdbeChangeP5(v, SQLITE_STMTSTATUS_AUTOINDEX);
sqlite3VdbeJumpHere(v, addrTop);
sqlite3ReleaseTempReg(pParse, regRecord);
@@ -950,23 +958,14 @@ static sqlite3_index_info *allocateIndexInfo(
sqlite3ErrorMsg(pParse, "out of memory");
return 0;
}
-
- /* Initialize the structure. The sqlite3_index_info structure contains
- ** many fields that are declared "const" to prevent xBestIndex from
- ** changing them. We have to do some funky casting in order to
- ** initialize those fields.
- */
pHidden = (struct HiddenIndexInfo*)&pIdxInfo[1];
pIdxCons = (struct sqlite3_index_constraint*)&pHidden[1];
pIdxOrderBy = (struct sqlite3_index_orderby*)&pIdxCons[nTerm];
pUsage = (struct sqlite3_index_constraint_usage*)&pIdxOrderBy[nOrderBy];
- *(int*)&pIdxInfo->nConstraint = nTerm;
- *(int*)&pIdxInfo->nOrderBy = nOrderBy;
- *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint = pIdxCons;
- *(struct sqlite3_index_orderby**)&pIdxInfo->aOrderBy = pIdxOrderBy;
- *(struct sqlite3_index_constraint_usage**)&pIdxInfo->aConstraintUsage =
- pUsage;
-
+ pIdxInfo->nOrderBy = nOrderBy;
+ pIdxInfo->aConstraint = pIdxCons;
+ pIdxInfo->aOrderBy = pIdxOrderBy;
+ pIdxInfo->aConstraintUsage = pUsage;
pHidden->pWC = pWC;
pHidden->pParse = pParse;
for(i=j=0, pTerm=pWC->a; inTerm; i++, pTerm++){
@@ -980,18 +979,13 @@ static sqlite3_index_info *allocateIndexInfo(
testcase( pTerm->eOperator & WO_ALL );
if( (pTerm->eOperator & ~(WO_EQUIV))==0 ) continue;
if( pTerm->wtFlags & TERM_VNULL ) continue;
+
+ /* tag-20191211-002: WHERE-clause constraints are not useful to the
+ ** right-hand table of a LEFT JOIN. See tag-20191211-001 for the
+ ** equivalent restriction for ordinary tables. */
if( (pSrc->fg.jointype & JT_LEFT)!=0
&& !ExprHasProperty(pTerm->pExpr, EP_FromJoin)
- && (pTerm->eOperator & (WO_IS|WO_ISNULL))
){
- /* An "IS" term in the WHERE clause where the virtual table is the rhs
- ** of a LEFT JOIN. Do not pass this term to the virtual table
- ** implementation, as this can lead to incorrect results from SQL such
- ** as:
- **
- ** "LEFT JOIN vtab WHERE vtab.col IS NULL" */
- testcase( pTerm->eOperator & WO_ISNULL );
- testcase( pTerm->eOperator & WO_IS );
continue;
}
assert( pTerm->u.leftColumn>=(-1) );
@@ -1022,7 +1016,8 @@ static sqlite3_index_info *allocateIndexInfo(
if( op & (WO_LT|WO_LE|WO_GT|WO_GE)
&& sqlite3ExprIsVector(pTerm->pExpr->pRight)
){
- if( i<16 ) mNoOmit |= (1 << i);
+ testcase( j!=i );
+ if( j<16 ) mNoOmit |= (1 << j);
if( op==WO_LT ) pIdxCons[j].op = WO_LE;
if( op==WO_GT ) pIdxCons[j].op = WO_GE;
}
@@ -1030,6 +1025,7 @@ static sqlite3_index_info *allocateIndexInfo(
j++;
}
+ pIdxInfo->nConstraint = j;
for(i=0; ia[i].pExpr;
pIdxOrderBy[i].iColumn = pExpr->iColumn;
@@ -1060,9 +1056,9 @@ static int vtabBestIndex(Parse *pParse, Table *pTab, sqlite3_index_info *p){
sqlite3_vtab *pVtab = sqlite3GetVTable(pParse->db, pTab)->pVtab;
int rc;
- TRACE_IDX_INPUTS(p);
+ whereTraceIndexInfoInputs(p);
rc = pVtab->pModule->xBestIndex(pVtab, p);
- TRACE_IDX_OUTPUTS(p);
+ whereTraceIndexInfoOutputs(p);
if( rc!=SQLITE_OK && rc!=SQLITE_CONSTRAINT ){
if( rc==SQLITE_NOMEM ){
@@ -1743,16 +1739,17 @@ static int whereInScanEst(
/*
** Print the content of a WhereTerm object
*/
-static void whereTermPrint(WhereTerm *pTerm, int iTerm){
+void sqlite3WhereTermPrint(WhereTerm *pTerm, int iTerm){
if( pTerm==0 ){
sqlite3DebugPrintf("TERM-%-3d NULL\n", iTerm);
}else{
- char zType[4];
+ char zType[8];
char zLeft[50];
- memcpy(zType, "...", 4);
+ memcpy(zType, "....", 5);
if( pTerm->wtFlags & TERM_VIRTUAL ) zType[0] = 'V';
if( pTerm->eOperator & WO_EQUIV ) zType[1] = 'E';
if( ExprHasProperty(pTerm->pExpr, EP_FromJoin) ) zType[2] = 'L';
+ if( pTerm->wtFlags & TERM_CODED ) zType[3] = 'C';
if( pTerm->eOperator & WO_SINGLE ){
sqlite3_snprintf(sizeof(zLeft),zLeft,"left={%d:%d}",
pTerm->leftCursor, pTerm->u.leftColumn);
@@ -1763,14 +1760,21 @@ static void whereTermPrint(WhereTerm *pTerm, int iTerm){
sqlite3_snprintf(sizeof(zLeft),zLeft,"left=%d", pTerm->leftCursor);
}
sqlite3DebugPrintf(
- "TERM-%-3d %p %s %-12s prob=%-3d op=0x%03x wtFlags=0x%04x",
- iTerm, pTerm, zType, zLeft, pTerm->truthProb,
- pTerm->eOperator, pTerm->wtFlags);
- if( pTerm->iField ){
- sqlite3DebugPrintf(" iField=%d\n", pTerm->iField);
- }else{
- sqlite3DebugPrintf("\n");
+ "TERM-%-3d %p %s %-12s op=%03x wtFlags=%04x",
+ iTerm, pTerm, zType, zLeft, pTerm->eOperator, pTerm->wtFlags);
+ /* The 0x10000 .wheretrace flag causes extra information to be
+ ** shown about each Term */
+ if( sqlite3WhereTrace & 0x10000 ){
+ sqlite3DebugPrintf(" prob=%-3d prereq=%llx,%llx",
+ pTerm->truthProb, (u64)pTerm->prereqAll, (u64)pTerm->prereqRight);
}
+ if( pTerm->iField ){
+ sqlite3DebugPrintf(" iField=%d", pTerm->iField);
+ }
+ if( pTerm->iParent>=0 ){
+ sqlite3DebugPrintf(" iParent=%d", pTerm->iParent);
+ }
+ sqlite3DebugPrintf("\n");
sqlite3TreeViewExpr(0, pTerm->pExpr, 0);
}
}
@@ -1783,7 +1787,7 @@ static void whereTermPrint(WhereTerm *pTerm, int iTerm){
void sqlite3WhereClausePrint(WhereClause *pWC){
int i;
for(i=0; inTerm; i++){
- whereTermPrint(&pWC->a[i], i);
+ sqlite3WhereTermPrint(&pWC->a[i], i);
}
}
#endif
@@ -1792,7 +1796,7 @@ void sqlite3WhereClausePrint(WhereClause *pWC){
/*
** Print a WhereLoop object for debugging purposes
*/
-static void whereLoopPrint(WhereLoop *p, WhereClause *pWC){
+void sqlite3WhereLoopPrint(WhereLoop *p, WhereClause *pWC){
WhereInfo *pWInfo = pWC->pWInfo;
int nb = 1+(pWInfo->pTabList->nSrc+3)/4;
struct SrcList_item *pItem = pWInfo->pTabList->a + p->iTab;
@@ -1817,7 +1821,7 @@ static void whereLoopPrint(WhereLoop *p, WhereClause *pWC){
}else{
char *z;
if( p->u.vtab.idxStr ){
- z = sqlite3_mprintf("(%d,\"%s\",%x)",
+ z = sqlite3_mprintf("(%d,\"%s\",%#x)",
p->u.vtab.idxNum, p->u.vtab.idxStr, p->u.vtab.omitMask);
}else{
z = sqlite3_mprintf("(%d,%x)", p->u.vtab.idxNum, p->u.vtab.omitMask);
@@ -1834,7 +1838,7 @@ static void whereLoopPrint(WhereLoop *p, WhereClause *pWC){
if( p->nLTerm && (sqlite3WhereTrace & 0x100)!=0 ){
int i;
for(i=0; inLTerm; i++){
- whereTermPrint(p->aLTerm[i], i);
+ sqlite3WhereTermPrint(p->aLTerm[i], i);
}
}
}
@@ -1938,6 +1942,7 @@ static void whereInfoFree(sqlite3 *db, WhereInfo *pWInfo){
pWInfo->pLoops = p->pNextLoop;
whereLoopDelete(db, p);
}
+ assert( pWInfo->pExprMods==0 );
sqlite3DbFreeNN(db, pWInfo);
}
@@ -2139,6 +2144,8 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){
}
pBuilder->iPlanLimit--;
+ whereLoopAdjustCost(pWInfo->pLoops, pTemplate);
+
/* If pBuilder->pOrSet is defined, then only keep track of the costs
** and prereqs.
*/
@@ -2153,7 +2160,7 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){
#if WHERETRACE_ENABLED /* 0x8 */
if( sqlite3WhereTrace & 0x8 ){
sqlite3DebugPrintf(x?" or-%d: ":" or-X: ", n);
- whereLoopPrint(pTemplate, pBuilder->pWC);
+ sqlite3WhereLoopPrint(pTemplate, pBuilder->pWC);
}
#endif
}
@@ -2162,7 +2169,6 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){
/* Look for an existing WhereLoop to replace with pTemplate
*/
- whereLoopAdjustCost(pWInfo->pLoops, pTemplate);
ppPrev = whereLoopFindLesser(&pWInfo->pLoops, pTemplate);
if( ppPrev==0 ){
@@ -2171,7 +2177,7 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){
#if WHERETRACE_ENABLED /* 0x8 */
if( sqlite3WhereTrace & 0x8 ){
sqlite3DebugPrintf(" skip: ");
- whereLoopPrint(pTemplate, pBuilder->pWC);
+ sqlite3WhereLoopPrint(pTemplate, pBuilder->pWC);
}
#endif
return SQLITE_OK;
@@ -2187,12 +2193,12 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){
if( sqlite3WhereTrace & 0x8 ){
if( p!=0 ){
sqlite3DebugPrintf("replace: ");
- whereLoopPrint(p, pBuilder->pWC);
+ sqlite3WhereLoopPrint(p, pBuilder->pWC);
sqlite3DebugPrintf(" with: ");
}else{
sqlite3DebugPrintf(" add: ");
}
- whereLoopPrint(pTemplate, pBuilder->pWC);
+ sqlite3WhereLoopPrint(pTemplate, pBuilder->pWC);
}
#endif
if( p==0 ){
@@ -2216,7 +2222,7 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){
#if WHERETRACE_ENABLED /* 0x8 */
if( sqlite3WhereTrace & 0x8 ){
sqlite3DebugPrintf(" delete: ");
- whereLoopPrint(pToDel, pBuilder->pWC);
+ sqlite3WhereLoopPrint(pToDel, pBuilder->pWC);
}
#endif
whereLoopDelete(db, pToDel);
@@ -2425,8 +2431,9 @@ static int whereLoopAddBtreeIndex(
pNew = pBuilder->pNew;
if( db->mallocFailed ) return SQLITE_NOMEM_BKPT;
- WHERETRACE(0x800, ("BEGIN %s.addBtreeIdx(%s), nEq=%d\n",
- pProbe->pTable->zName,pProbe->zName, pNew->u.btree.nEq));
+ WHERETRACE(0x800, ("BEGIN %s.addBtreeIdx(%s), nEq=%d, nSkip=%d\n",
+ pProbe->pTable->zName,pProbe->zName,
+ pNew->u.btree.nEq, pNew->nSkip));
assert( (pNew->wsFlags & WHERE_VIRTUALTABLE)==0 );
assert( (pNew->wsFlags & WHERE_TOP_LIMIT)==0 );
@@ -2472,9 +2479,9 @@ static int whereLoopAddBtreeIndex(
** to mix with a lower range bound from some other source */
if( pTerm->wtFlags & TERM_LIKEOPT && pTerm->eOperator==WO_LT ) continue;
- /* Do not allow constraints from the WHERE clause to be used by the
- ** right table of a LEFT JOIN. Only constraints in the ON clause are
- ** allowed */
+ /* tag-20191211-001: Do not allow constraints from the WHERE clause to
+ ** be used by the right table of a LEFT JOIN. Only constraints in the
+ ** ON clause are allowed. See tag-20191211-002 for the vtab equivalent. */
if( (pSrc->fg.jointype & JT_LEFT)!=0
&& !ExprHasProperty(pTerm->pExpr, EP_FromJoin)
){
@@ -2723,6 +2730,7 @@ static int whereLoopAddBtreeIndex(
assert( 42==sqlite3LogEst(18) );
if( saved_nEq==saved_nSkip
&& saved_nEq+1nKeyCol
+ && saved_nEq==pNew->nLTerm
&& pProbe->noSkipScan==0
&& OptimizationEnabled(db, SQLITE_SkipScan)
&& pProbe->aiRowLogEst[saved_nEq+1]>=42 /* TUNING: Minimum for skip-scan */
@@ -2791,20 +2799,25 @@ static int indexMightHelpWithOrderBy(
/* Check to see if a partial index with pPartIndexWhere can be used
** in the current query. Return true if it can be and false if not.
*/
-static int whereUsablePartialIndex(int iTab, WhereClause *pWC, Expr *pWhere){
+static int whereUsablePartialIndex(
+ int iTab, /* The table for which we want an index */
+ int isLeft, /* True if iTab is the right table of a LEFT JOIN */
+ WhereClause *pWC, /* The WHERE clause of the query */
+ Expr *pWhere /* The WHERE clause from the partial index */
+){
int i;
WhereTerm *pTerm;
Parse *pParse = pWC->pWInfo->pParse;
while( pWhere->op==TK_AND ){
- if( !whereUsablePartialIndex(iTab,pWC,pWhere->pLeft) ) return 0;
+ if( !whereUsablePartialIndex(iTab,isLeft,pWC,pWhere->pLeft) ) return 0;
pWhere = pWhere->pRight;
}
if( pParse->db->flags & SQLITE_EnableQPSG ) pParse = 0;
for(i=0, pTerm=pWC->a; inTerm; i++, pTerm++){
Expr *pExpr;
- if( pTerm->wtFlags & TERM_NOPARTIDX ) continue;
pExpr = pTerm->pExpr;
if( (!ExprHasProperty(pExpr, EP_FromJoin) || pExpr->iRightJoinTable==iTab)
+ && (isLeft==0 || ExprHasProperty(pExpr, EP_FromJoin))
&& sqlite3ExprImpliesExpr(pParse, pExpr, pWhere, iTab)
){
return 1;
@@ -2967,8 +2980,11 @@ static int whereLoopAddBtree(
for(; rc==SQLITE_OK && pProbe;
pProbe=(pSrc->pIBIndex ? 0 : pProbe->pNext), iSortIdx++
){
+ int isLeft = (pSrc->fg.jointype & JT_OUTER)!=0;
if( pProbe->pPartIdxWhere!=0
- && !whereUsablePartialIndex(pSrc->iCursor, pWC, pProbe->pPartIdxWhere) ){
+ && !whereUsablePartialIndex(pSrc->iCursor, isLeft, pWC,
+ pProbe->pPartIdxWhere)
+ ){
testcase( pNew->iTab!=pSrc->iCursor ); /* See ticket [98d973b8f5] */
continue; /* Partial index inappropriate for this query */
}
@@ -3195,7 +3211,14 @@ static int whereLoopAddVirtualOne(
if( iTerm>mxTerm ) mxTerm = iTerm;
testcase( iTerm==15 );
testcase( iTerm==16 );
- if( iTerm<16 && pUsage[i].omit ) pNew->u.vtab.omitMask |= 1<u.vtab.omitMask |= 1<eOperator & WO_IN)!=0 ){
/* A virtual table that is constrained by an IN clause may not
** consume the ORDER BY clause because (1) the order of IN terms
@@ -3208,7 +3231,6 @@ static int whereLoopAddVirtualOne(
}
}
}
- pNew->u.vtab.omitMask &= ~mNoOmit;
pNew->nLTerm = mxTerm+1;
for(i=0; i<=mxTerm; i++){
@@ -3265,7 +3287,7 @@ const char *sqlite3_vtab_collation(sqlite3_index_info *pIdxInfo, int iCons){
int iTerm = pIdxInfo->aConstraint[iCons].iTermOffset;
Expr *pX = pHidden->pWC->a[iTerm].pExpr;
if( pX->pLeft ){
- pC = sqlite3BinaryCompareCollSeq(pHidden->pParse, pX->pLeft, pX->pRight);
+ pC = sqlite3ExprCompareCollSeq(pHidden->pParse, pX);
}
zRet = (pC ? pC->zName : sqlite3StrBINARY);
}
@@ -3490,7 +3512,8 @@ static int whereLoopAddOr(
if( rc==SQLITE_OK ){
rc = whereLoopAddOr(&sSubBuild, mPrereq, mUnusable);
}
- assert( rc==SQLITE_OK || sCur.n==0 );
+ assert( rc==SQLITE_OK || rc==SQLITE_DONE || sCur.n==0 );
+ testcase( rc==SQLITE_DONE );
if( sCur.n==0 ){
sSum.n = 0;
break;
@@ -3698,7 +3721,9 @@ static i8 wherePathSatisfiesOrderBy(
pLoop = pLast;
}
if( pLoop->wsFlags & WHERE_VIRTUALTABLE ){
- if( pLoop->u.vtab.isOrdered ) obSat = obDone;
+ if( pLoop->u.vtab.isOrdered && (wctrlFlags & WHERE_DISTINCTBY)==0 ){
+ obSat = obDone;
+ }
break;
}else if( wctrlFlags & WHERE_DISTINCTBY ){
pLoop->u.btree.nDistinctCol = 0;
@@ -4801,6 +4826,7 @@ WhereInfo *sqlite3WhereBegin(
}
}
if( sqlite3WhereTrace & 0x100 ){ /* Display all terms of the WHERE clause */
+ sqlite3DebugPrintf("---- WHERE clause at start of analysis:\n");
sqlite3WhereClausePrint(sWLB.pWC);
}
#endif
@@ -4817,7 +4843,7 @@ WhereInfo *sqlite3WhereBegin(
"ABCDEFGHIJKLMNOPQRSTUVWYXZ";
for(p=pWInfo->pLoops, i=0; p; p=p->pNextLoop, i++){
p->cId = zLabel[i%(sizeof(zLabel)-1)];
- whereLoopPrint(p, sWLB.pWC);
+ sqlite3WhereLoopPrint(p, sWLB.pWC);
}
}
#endif
@@ -4857,7 +4883,7 @@ WhereInfo *sqlite3WhereBegin(
}
sqlite3DebugPrintf("\n");
for(ii=0; iinLevel; ii++){
- whereLoopPrint(pWInfo->a[ii].pWLoop, sWLB.pWC);
+ sqlite3WhereLoopPrint(pWInfo->a[ii].pWLoop, sWLB.pWC);
}
}
#endif
@@ -4939,7 +4965,13 @@ WhereInfo *sqlite3WhereBegin(
nTabList--;
}
}
+#if defined(WHERETRACE_ENABLED)
+ if( sqlite3WhereTrace & 0x100 ){ /* Display all terms of the WHERE clause */
+ sqlite3DebugPrintf("---- WHERE clause at end of analysis:\n");
+ sqlite3WhereClausePrint(sWLB.pWC);
+ }
WHERETRACE(0xffff,("*** Optimizer Finished ***\n"));
+#endif
pWInfo->pParse->nQueryLoop += pWInfo->nRowOut;
/* If the caller is an UPDATE or DELETE statement that is requesting
@@ -5016,7 +5048,13 @@ WhereInfo *sqlite3WhereBegin(
assert( pTabItem->iCursor==pLevel->iTabCur );
testcase( pWInfo->eOnePass==ONEPASS_OFF && pTab->nCol==BMS-1 );
testcase( pWInfo->eOnePass==ONEPASS_OFF && pTab->nCol==BMS );
- if( pWInfo->eOnePass==ONEPASS_OFF && pTab->nColeOnePass==ONEPASS_OFF
+ && pTab->nColtabFlags & (TF_HasGenerated|TF_WithoutRowid))==0
+ ){
+ /* If we know that only a prefix of the record will be used,
+ ** it is advantageous to reduce the "column count" field in
+ ** the P4 operand of the OP_OpenRead/Write opcode. */
Bitmask b = pTabItem->colUsed;
int n = 0;
for(; b; b=b>>1, n++){}
@@ -5237,10 +5275,26 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
if( pIn->eEndLoopOp!=OP_Noop ){
if( pIn->nPrefix ){
assert( pLoop->wsFlags & WHERE_IN_EARLYOUT );
- sqlite3VdbeAddOp4Int(v, OP_IfNoHope, pLevel->iIdxCur,
- sqlite3VdbeCurrentAddr(v)+2,
- pIn->iBase, pIn->nPrefix);
- VdbeCoverage(v);
+ if( (pLoop->wsFlags & WHERE_VIRTUALTABLE)==0 ){
+ sqlite3VdbeAddOp4Int(v, OP_IfNoHope, pLevel->iIdxCur,
+ sqlite3VdbeCurrentAddr(v)+2+(pLevel->iLeftJoin!=0),
+ pIn->iBase, pIn->nPrefix);
+ VdbeCoverage(v);
+ }
+ if( pLevel->iLeftJoin ){
+ /* For LEFT JOIN queries, cursor pIn->iCur may not have been
+ ** opened yet. This occurs for WHERE clauses such as
+ ** "a = ? AND b IN (...)", where the index is on (a, b). If
+ ** the RHS of the (a=?) is NULL, then the "b IN (...)" may
+ ** never have been coded, but the body of the loop run to
+ ** return the null-row. So, if the cursor is not open yet,
+ ** jump over the OP_Next or OP_Prev instruction about to
+ ** be coded. */
+ sqlite3VdbeAddOp2(v, OP_IfNotOpen, pIn->iCur,
+ sqlite3VdbeCurrentAddr(v) + 2
+ );
+ VdbeCoverage(v);
+ }
}
sqlite3VdbeAddOp2(v, pIn->eEndLoopOp, pIn->iCur, pIn->addrInTop);
VdbeCoverage(v);
@@ -5378,8 +5432,11 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
Index *pPk = sqlite3PrimaryKeyIndex(pTab);
x = pPk->aiColumn[x];
assert( x>=0 );
+ }else{
+ testcase( x!=sqlite3StorageColumnToTable(pTab,x) );
+ x = sqlite3StorageColumnToTable(pTab,x);
}
- x = sqlite3ColumnOfIndex(pIdx, x);
+ x = sqlite3TableColumnToIndex(pIdx, x);
if( x>=0 ){
pOp->p2 = x;
pOp->p1 = pLevel->iIdxCur;
@@ -5402,6 +5459,14 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
}
}
+ /* Undo all Expr node modifications */
+ while( pWInfo->pExprMods ){
+ WhereExprMod *p = pWInfo->pExprMods;
+ pWInfo->pExprMods = p->pNext;
+ memcpy(p->pExpr, &p->orig, sizeof(p->orig));
+ sqlite3DbFree(db, p);
+ }
+
/* Final cleanup
*/
pParse->nQueryLoop = pWInfo->savedNQueryLoop;
diff --git a/src/whereInt.h b/src/whereInt.h
index 64978cf110..dbc6f1872a 100644
--- a/src/whereInt.h
+++ b/src/whereInt.h
@@ -291,7 +291,6 @@ struct WhereTerm {
#define TERM_LIKE 0x400 /* The original LIKE operator */
#define TERM_IS 0x800 /* Term.pExpr is an IS operator */
#define TERM_VARSELECT 0x1000 /* Term.pExpr contains a correlated sub-query */
-#define TERM_NOPARTIDX 0x2000 /* Not for use to enable a partial index */
/*
** An instance of the WhereScan object is used as an iterator for locating
@@ -434,6 +433,20 @@ struct WhereLoopBuilder {
# define SQLITE_QUERY_PLANNER_LIMIT_INCR 1000
#endif
+/*
+** Each instance of this object records a change to a single node
+** in an expression tree to cause that node to point to a column
+** of an index rather than an expression or a virtual column. All
+** such transformations need to be undone at the end of WHERE clause
+** processing.
+*/
+typedef struct WhereExprMod WhereExprMod;
+struct WhereExprMod {
+ WhereExprMod *pNext; /* Next translation on a list of them all */
+ Expr *pExpr; /* The Expr node that was transformed */
+ Expr orig; /* Original value of the Expr node */
+};
+
/*
** The WHERE clause processing routine has two halves. The
** first part does the start of the WHERE loop and the second
@@ -450,23 +463,25 @@ struct WhereInfo {
ExprList *pOrderBy; /* The ORDER BY clause or NULL */
ExprList *pResultSet; /* Result set of the query */
Expr *pWhere; /* The complete WHERE clause */
- LogEst iLimit; /* LIMIT if wctrlFlags has WHERE_USE_LIMIT */
int aiCurOnePass[2]; /* OP_OpenWrite cursors for the ONEPASS opt */
int iContinue; /* Jump here to continue with next record */
int iBreak; /* Jump here to break out of the loop */
int savedNQueryLoop; /* pParse->nQueryLoop outside the WHERE loop */
u16 wctrlFlags; /* Flags originally passed to sqlite3WhereBegin() */
+ LogEst iLimit; /* LIMIT if wctrlFlags has WHERE_USE_LIMIT */
u8 nLevel; /* Number of nested loop */
i8 nOBSat; /* Number of ORDER BY terms satisfied by indices */
- u8 sorted; /* True if really sorted (not just grouped) */
u8 eOnePass; /* ONEPASS_OFF, or _SINGLE, or _MULTI */
- u8 untestedTerms; /* Not all WHERE terms resolved by outer loop */
u8 eDistinct; /* One of the WHERE_DISTINCT_* values */
- u8 bOrderedInnerLoop; /* True if only the inner-most loop is ordered */
+ unsigned bDeferredSeek :1; /* Uses OP_DeferredSeek */
+ unsigned untestedTerms :1; /* Not all WHERE terms resolved by outer loop */
+ unsigned bOrderedInnerLoop:1;/* True if only the inner-most loop is ordered */
+ unsigned sorted :1; /* True if really sorted (not just grouped) */
+ LogEst nRowOut; /* Estimated number of output rows */
int iTop; /* The very beginning of the WHERE loop */
WhereLoop *pLoops; /* List of all WhereLoop objects */
+ WhereExprMod *pExprMods; /* Expression modifications */
Bitmask revMask; /* Mask of ORDER BY terms that need reversing */
- LogEst nRowOut; /* Estimated number of output rows */
WhereClause sWC; /* Decomposition of the WHERE clause */
WhereMaskSet sMaskSet; /* Map cursor numbers to bitmasks */
WhereLevel a[1]; /* Information about each nest loop in WHERE */
@@ -480,6 +495,8 @@ struct WhereInfo {
Bitmask sqlite3WhereGetMask(WhereMaskSet*,int);
#ifdef WHERETRACE_ENABLED
void sqlite3WhereClausePrint(WhereClause *pWC);
+void sqlite3WhereTermPrint(WhereTerm *pTerm, int iTerm);
+void sqlite3WhereLoopPrint(WhereLoop *p, WhereClause *pWC);
#endif
WhereTerm *sqlite3WhereFindTerm(
WhereClause *pWC, /* The WHERE clause to be searched */
diff --git a/src/wherecode.c b/src/wherecode.c
index 2fbcba17e9..0014a695d1 100644
--- a/src/wherecode.c
+++ b/src/wherecode.c
@@ -415,7 +415,8 @@ static Expr *removeUnindexableInClauseTerms(
Expr *pX /* The IN expression to be reduced */
){
sqlite3 *db = pParse->db;
- Expr *pNew = sqlite3ExprDup(db, pX, 0);
+ Expr *pNew;
+ pNew = sqlite3ExprDup(db, pX, 0);
if( db->mallocFailed==0 ){
ExprList *pOrigRhs = pNew->x.pSelect->pEList; /* Original unmodified RHS */
ExprList *pOrigLhs = pNew->pLeft->x.pList; /* Original unmodified LHS */
@@ -592,7 +593,7 @@ static int codeEqualityTerm(
if( i==iEq ){
pIn->iCur = iTab;
pIn->eEndLoopOp = bRev ? OP_Prev : OP_Next;
- if( iEq>0 && (pLoop->wsFlags & WHERE_VIRTUALTABLE)==0 ){
+ if( iEq>0 ){
pIn->iBase = iReg - i;
pIn->nPrefix = i;
pLoop->wsFlags |= WHERE_IN_EARLYOUT;
@@ -823,7 +824,7 @@ static int codeCursorHintCheckExpr(Walker *pWalker, Expr *pExpr){
assert( pHint->pIdx!=0 );
if( pExpr->op==TK_COLUMN
&& pExpr->iTable==pHint->iTabCur
- && sqlite3ColumnOfIndex(pHint->pIdx, pExpr->iColumn)<0
+ && sqlite3TableColumnToIndex(pHint->pIdx, pExpr->iColumn)<0
){
pWalker->eCode = 1;
}
@@ -891,7 +892,7 @@ static int codeCursorHintFixExpr(Walker *pWalker, Expr *pExpr){
pExpr->iTable = reg;
}else if( pHint->pIdx!=0 ){
pExpr->iTable = pHint->iIdxCur;
- pExpr->iColumn = sqlite3ColumnOfIndex(pHint->pIdx, pExpr->iColumn);
+ pExpr->iColumn = sqlite3TableColumnToIndex(pHint->pIdx, pExpr->iColumn);
assert( pExpr->iColumn>=0 );
}
}else if( pExpr->op==TK_AGG_FUNCTION ){
@@ -1044,6 +1045,7 @@ static void codeDeferredSeek(
assert( iIdxCur>0 );
assert( pIdx->aiColumn[pIdx->nColumn-1]==-1 );
+ pWInfo->bDeferredSeek = 1;
sqlite3VdbeAddOp3(v, OP_DeferredSeek, iIdxCur, 0, iCur);
if( (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)
&& DbMaskAllZero(sqlite3ParseToplevel(pParse)->writeMask)
@@ -1054,8 +1056,12 @@ static void codeDeferredSeek(
if( ai ){
ai[0] = pTab->nCol;
for(i=0; inColumn-1; i++){
+ int x1, x2;
assert( pIdx->aiColumn[i]nCol );
- if( pIdx->aiColumn[i]>=0 ) ai[pIdx->aiColumn[i]+1] = i+1;
+ x1 = pIdx->aiColumn[i];
+ x2 = sqlite3TableColumnToStorage(pTab, x1);
+ testcase( x1!=x2 );
+ if( x1>=0 ) ai[x2+1] = i+1;
}
sqlite3VdbeChangeP4(v, -1, (char*)ai, P4_INTARRAY);
}
@@ -1106,8 +1112,24 @@ typedef struct IdxExprTrans {
int iTabCur; /* The cursor of the corresponding table */
int iIdxCur; /* The cursor for the index */
int iIdxCol; /* The column for the index */
+ int iTabCol; /* The column for the table */
+ WhereInfo *pWInfo; /* Complete WHERE clause information */
+ sqlite3 *db; /* Database connection (for malloc()) */
} IdxExprTrans;
+/*
+** Preserve pExpr on the WhereETrans list of the WhereInfo.
+*/
+static void preserveExpr(IdxExprTrans *pTrans, Expr *pExpr){
+ WhereExprMod *pNew;
+ pNew = sqlite3DbMallocRaw(pTrans->db, sizeof(*pNew));
+ if( pNew==0 ) return;
+ pNew->pNext = pTrans->pWInfo->pExprMods;
+ pTrans->pWInfo->pExprMods = pNew;
+ pNew->pExpr = pExpr;
+ memcpy(&pNew->orig, pExpr, sizeof(*pExpr));
+}
+
/* The walker node callback used to transform matching expressions into
** a reference to an index column for an index on an expression.
**
@@ -1117,21 +1139,49 @@ typedef struct IdxExprTrans {
static int whereIndexExprTransNode(Walker *p, Expr *pExpr){
IdxExprTrans *pX = p->u.pIdxTrans;
if( sqlite3ExprCompare(0, pExpr, pX->pIdxExpr, pX->iTabCur)==0 ){
+ preserveExpr(pX, pExpr);
pExpr->affExpr = sqlite3ExprAffinity(pExpr);
pExpr->op = TK_COLUMN;
pExpr->iTable = pX->iIdxCur;
pExpr->iColumn = pX->iIdxCol;
pExpr->y.pTab = 0;
+ testcase( ExprHasProperty(pExpr, EP_Skip) );
+ testcase( ExprHasProperty(pExpr, EP_Unlikely) );
+ ExprClearProperty(pExpr, EP_Skip|EP_Unlikely);
return WRC_Prune;
}else{
return WRC_Continue;
}
}
+#ifndef SQLITE_OMIT_GENERATED_COLUMNS
+/* A walker node callback that translates a column reference to a table
+** into a corresponding column reference of an index.
+*/
+static int whereIndexExprTransColumn(Walker *p, Expr *pExpr){
+ if( pExpr->op==TK_COLUMN ){
+ IdxExprTrans *pX = p->u.pIdxTrans;
+ if( pExpr->iTable==pX->iTabCur && pExpr->iColumn==pX->iTabCol ){
+ assert( pExpr->y.pTab!=0 );
+ preserveExpr(pX, pExpr);
+ pExpr->affExpr = sqlite3TableColumnAffinity(pExpr->y.pTab,pExpr->iColumn);
+ pExpr->iTable = pX->iIdxCur;
+ pExpr->iColumn = pX->iIdxCol;
+ pExpr->y.pTab = 0;
+ }
+ }
+ return WRC_Continue;
+}
+#endif /* SQLITE_OMIT_GENERATED_COLUMNS */
+
/*
** For an indexes on expression X, locate every instance of expression X
** in pExpr and change that subexpression into a reference to the appropriate
** column of the index.
+**
+** 2019-10-24: Updated to also translate references to a VIRTUAL column in
+** the table into references to the corresponding (stored) column of the
+** index.
*/
static void whereIndexExprTrans(
Index *pIdx, /* The Index */
@@ -1141,20 +1191,48 @@ static void whereIndexExprTrans(
){
int iIdxCol; /* Column number of the index */
ExprList *aColExpr; /* Expressions that are indexed */
+ Table *pTab;
Walker w;
IdxExprTrans x;
aColExpr = pIdx->aColExpr;
- if( aColExpr==0 ) return; /* Not an index on expressions */
+ if( aColExpr==0 && !pIdx->bHasVCol ){
+ /* The index does not reference any expressions or virtual columns
+ ** so no translations are needed. */
+ return;
+ }
+ pTab = pIdx->pTable;
memset(&w, 0, sizeof(w));
- w.xExprCallback = whereIndexExprTransNode;
w.u.pIdxTrans = &x;
x.iTabCur = iTabCur;
x.iIdxCur = iIdxCur;
- for(iIdxCol=0; iIdxColnExpr; iIdxCol++){
- if( pIdx->aiColumn[iIdxCol]!=XN_EXPR ) continue;
- assert( aColExpr->a[iIdxCol].pExpr!=0 );
+ x.pWInfo = pWInfo;
+ x.db = pWInfo->pParse->db;
+ for(iIdxCol=0; iIdxColnColumn; iIdxCol++){
+ i16 iRef = pIdx->aiColumn[iIdxCol];
+ if( iRef==XN_EXPR ){
+ assert( aColExpr->a[iIdxCol].pExpr!=0 );
+ x.pIdxExpr = aColExpr->a[iIdxCol].pExpr;
+ if( sqlite3ExprIsConstant(x.pIdxExpr) ) continue;
+ w.xExprCallback = whereIndexExprTransNode;
+#ifndef SQLITE_OMIT_GENERATED_COLUMNS
+ }else if( iRef>=0
+ && (pTab->aCol[iRef].colFlags & COLFLAG_VIRTUAL)!=0
+ && (pTab->aCol[iRef].zColl==0
+ || sqlite3StrICmp(pTab->aCol[iRef].zColl, sqlite3StrBINARY)==0)
+ ){
+ /* Check to see if there are direct references to generated columns
+ ** that are contained in the index. Pulling the generated column
+ ** out of the index is an optimization only - the main table is always
+ ** available if the index cannot be used. To avoid unnecessary
+ ** complication, omit this optimization if the collating sequence for
+ ** the column is non-standard */
+ x.iTabCol = iRef;
+ w.xExprCallback = whereIndexExprTransColumn;
+#endif /* SQLITE_OMIT_GENERATED_COLUMNS */
+ }else{
+ continue;
+ }
x.iIdxCol = iIdxCol;
- x.pIdxExpr = aColExpr->a[iIdxCol].pExpr;
sqlite3WalkExpr(&w, pWInfo->pWhere);
sqlite3WalkExprList(&w, pWInfo->pOrderBy);
sqlite3WalkExprList(&w, pWInfo->pResultSet);
@@ -1226,6 +1304,21 @@ Bitmask sqlite3WhereCodeOneLoopStart(
pLevel->notReady = notReady & ~sqlite3WhereGetMask(&pWInfo->sMaskSet, iCur);
bRev = (pWInfo->revMask>>iLevel)&1;
VdbeModuleComment((v, "Begin WHERE-loop%d: %s",iLevel,pTabItem->pTab->zName));
+#if WHERETRACE_ENABLED /* 0x20800 */
+ if( sqlite3WhereTrace & 0x800 ){
+ sqlite3DebugPrintf("Coding level %d of %d: notReady=%llx iFrom=%d\n",
+ iLevel, pWInfo->nLevel, (u64)notReady, pLevel->iFrom);
+ sqlite3WhereLoopPrint(pLoop, pWC);
+ }
+ if( sqlite3WhereTrace & 0x20000 ){
+ if( iLevel==0 ){
+ sqlite3DebugPrintf("WHERE clause being coded:\n");
+ sqlite3TreeViewExpr(0, pWInfo->pWhere, 0);
+ }
+ sqlite3DebugPrintf("All WHERE-clause terms before coding:\n");
+ sqlite3WhereClausePrint(pWC);
+ }
+#endif
/* Create labels for the "break" and "continue" instructions
** for the current loop. Jump to addrBrk to break out of a loop.
@@ -1305,9 +1398,12 @@ Bitmask sqlite3WhereCodeOneLoopStart(
iIn = pLevel->u.in.nIn;
for(j=nConstraint-1; j>=0; j--){
pTerm = pLoop->aLTerm[j];
+ if( (pTerm->eOperator & WO_IN)!=0 ) iIn--;
if( j<16 && (pLoop->u.vtab.omitMask>>j)&1 ){
disableTerm(pLevel, pTerm);
- }else if( (pTerm->eOperator & WO_IN)!=0 ){
+ }else if( (pTerm->eOperator & WO_IN)!=0
+ && sqlite3ExprVectorSize(pTerm->pExpr->pLeft)==1
+ ){
Expr *pCompare; /* The comparison operator */
Expr *pRight; /* RHS of the comparison */
VdbeOp *pOp; /* Opcode to access the value of the IN constraint */
@@ -1318,8 +1414,8 @@ Bitmask sqlite3WhereCodeOneLoopStart(
** encoding of the value in the register, so it *must* be reloaded. */
assert( pLevel->u.in.aInLoop!=0 || db->mallocFailed );
if( !db->mallocFailed ){
- assert( iIn>0 );
- pOp = sqlite3VdbeGetOp(v, pLevel->u.in.aInLoop[--iIn].addrInTop);
+ assert( iIn>=0 && iInu.in.nIn );
+ pOp = sqlite3VdbeGetOp(v, pLevel->u.in.aInLoop[iIn].addrInTop);
assert( pOp->opcode==OP_Column || pOp->opcode==OP_Rowid );
assert( pOp->opcode!=OP_Column || pOp->p3==iReg+j+2 );
assert( pOp->opcode!=OP_Rowid || pOp->p2==iReg+j+2 );
@@ -1343,6 +1439,7 @@ Bitmask sqlite3WhereCodeOneLoopStart(
}
}
}
+ assert( iIn==0 || db->mallocFailed );
/* These registers need to be preserved in case there is an IN operator
** loop. So we could deallocate the registers here (and potentially
** reuse them later) if (pLoop->wsFlags & WHERE_IN_ABLE)==0. But it seems
@@ -1608,7 +1705,7 @@ Bitmask sqlite3WhereCodeOneLoopStart(
){
assert( bSeekPastNull==0 && nExtraReg==0 && nBtm==0 && nTop==0 );
assert( pRangeEnd==0 && pRangeStart==0 );
- assert( pLoop->nSkip==0 );
+ testcase( pLoop->nSkip>0 );
nExtraReg = 1;
bSeekPastNull = 1;
pLevel->regBignull = regBignull = ++pParse->nMem;
@@ -1807,10 +1904,10 @@ Bitmask sqlite3WhereCodeOneLoopStart(
if( omitTable ){
/* pIdx is a covering index. No need to access the main table. */
}else if( HasRowid(pIdx->pTable) ){
- if( (pWInfo->wctrlFlags & WHERE_SEEK_TABLE) || (
- (pWInfo->wctrlFlags & WHERE_SEEK_UNIQ_TABLE)
- && (pWInfo->eOnePass==ONEPASS_SINGLE)
- )){
+ if( (pWInfo->wctrlFlags & WHERE_SEEK_TABLE)
+ || ( (pWInfo->wctrlFlags & WHERE_SEEK_UNIQ_TABLE)!=0
+ && (pWInfo->eOnePass==ONEPASS_SINGLE || pLoop->nLTerm==0) )
+ ){
iRowidReg = ++pParse->nMem;
sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdxCur, iRowidReg);
sqlite3VdbeAddOp3(v, OP_NotExists, iCur, 0, iRowidReg);
@@ -1822,40 +1919,53 @@ Bitmask sqlite3WhereCodeOneLoopStart(
Index *pPk = sqlite3PrimaryKeyIndex(pIdx->pTable);
iRowidReg = sqlite3GetTempRange(pParse, pPk->nKeyCol);
for(j=0; jnKeyCol; j++){
- k = sqlite3ColumnOfIndex(pIdx, pPk->aiColumn[j]);
+ k = sqlite3TableColumnToIndex(pIdx, pPk->aiColumn[j]);
sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, k, iRowidReg+j);
}
sqlite3VdbeAddOp4Int(v, OP_NotFound, iCur, addrCont,
iRowidReg, pPk->nKeyCol); VdbeCoverage(v);
}
- /* If pIdx is an index on one or more expressions, then look through
- ** all the expressions in pWInfo and try to transform matching expressions
- ** into reference to index columns.
- **
- ** Do not do this for the RHS of a LEFT JOIN. This is because the
- ** expression may be evaluated after OP_NullRow has been executed on
- ** the cursor. In this case it is important to do the full evaluation,
- ** as the result of the expression may not be NULL, even if all table
- ** column values are. https://www.sqlite.org/src/info/7fa8049685b50b5a
- **
- ** Also, do not do this when processing one index an a multi-index
- ** OR clause, since the transformation will become invalid once we
- ** move forward to the next index.
- ** https://sqlite.org/src/info/4e8e4857d32d401f
- */
- if( pLevel->iLeftJoin==0 && (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)==0 ){
- whereIndexExprTrans(pIdx, iCur, iIdxCur, pWInfo);
+ if( pLevel->iLeftJoin==0 ){
+ /* If pIdx is an index on one or more expressions, then look through
+ ** all the expressions in pWInfo and try to transform matching expressions
+ ** into reference to index columns. Also attempt to translate references
+ ** to virtual columns in the table into references to (stored) columns
+ ** of the index.
+ **
+ ** Do not do this for the RHS of a LEFT JOIN. This is because the
+ ** expression may be evaluated after OP_NullRow has been executed on
+ ** the cursor. In this case it is important to do the full evaluation,
+ ** as the result of the expression may not be NULL, even if all table
+ ** column values are. https://www.sqlite.org/src/info/7fa8049685b50b5a
+ **
+ ** Also, do not do this when processing one index an a multi-index
+ ** OR clause, since the transformation will become invalid once we
+ ** move forward to the next index.
+ ** https://sqlite.org/src/info/4e8e4857d32d401f
+ */
+ if( (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)==0 ){
+ whereIndexExprTrans(pIdx, iCur, iIdxCur, pWInfo);
+ }
+
+ /* If a partial index is driving the loop, try to eliminate WHERE clause
+ ** terms from the query that must be true due to the WHERE clause of
+ ** the partial index.
+ **
+ ** 2019-11-02 ticket 623eff57e76d45f6: This optimization does not work
+ ** for a LEFT JOIN.
+ */
+ if( pIdx->pPartIdxWhere ){
+ whereApplyPartialIndexConstraints(pIdx->pPartIdxWhere, iCur, pWC);
+ }
+ }else{
+ testcase( pIdx->pPartIdxWhere );
+ /* The following assert() is not a requirement, merely an observation:
+ ** The OR-optimization doesn't work for the right hand table of
+ ** a LEFT JOIN: */
+ assert( (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)==0 );
}
-
- /* If a partial index is driving the loop, try to eliminate WHERE clause
- ** terms from the query that must be true due to the WHERE clause of
- ** the partial index
- */
- if( pIdx->pPartIdxWhere ){
- whereApplyPartialIndexConstraints(pIdx->pPartIdxWhere, iCur, pWC);
- }
-
+
/* Record the instruction used to terminate the loop. */
if( pLoop->wsFlags & WHERE_ONEROW ){
pLevel->op = OP_Noop;
@@ -2040,9 +2150,9 @@ Bitmask sqlite3WhereCodeOneLoopStart(
WhereInfo *pSubWInfo; /* Info for single OR-term scan */
Expr *pOrExpr = pOrTerm->pExpr; /* Current OR clause term */
int jmp1 = 0; /* Address of jump operation */
- assert( (pTabItem[0].fg.jointype & JT_LEFT)==0
- || ExprHasProperty(pOrExpr, EP_FromJoin)
- );
+ testcase( (pTabItem[0].fg.jointype & JT_LEFT)!=0
+ && !ExprHasProperty(pOrExpr, EP_FromJoin)
+ ); /* See TH3 vtab25.400 and ticket 614b25314c766238 */
if( pAndExpr ){
pAndExpr->pLeft = pOrExpr;
pOrExpr = pAndExpr;
@@ -2082,7 +2192,7 @@ Bitmask sqlite3WhereCodeOneLoopStart(
r = sqlite3GetTempRange(pParse, nPk);
for(iPk=0; iPkaiColumn[iPk];
- sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, iCol, r+iPk);
+ sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, iCol,r+iPk);
}
/* Check if the temp table already contains this key. If so,
@@ -2264,6 +2374,10 @@ Bitmask sqlite3WhereCodeOneLoopStart(
VdbeNoopComment((v, "WhereTerm[%d] (%p) priority=%d",
pWC->nTerm-j, pTerm, iLoop));
}
+ if( sqlite3WhereTrace & 0x800 ){
+ sqlite3DebugPrintf("Coding auxiliary constraint:\n");
+ sqlite3WhereTermPrint(pTerm, pWC->nTerm-j);
+ }
#endif
sqlite3ExprIfFalse(pParse, pE, addrCont, SQLITE_JUMPIFNULL);
if( skipLikeAddr ) sqlite3VdbeJumpHere(v, skipLikeAddr);
@@ -2287,8 +2401,14 @@ Bitmask sqlite3WhereCodeOneLoopStart(
if( (pTerm->eOperator & (WO_EQ|WO_IS))==0 ) continue;
if( (pTerm->eOperator & WO_EQUIV)==0 ) continue;
if( pTerm->leftCursor!=iCur ) continue;
- if( pLevel->iLeftJoin ) continue;
+ if( pTabItem->fg.jointype & JT_LEFT ) continue;
pE = pTerm->pExpr;
+#ifdef WHERETRACE_ENABLED /* 0x800 */
+ if( sqlite3WhereTrace & 0x800 ){
+ sqlite3DebugPrintf("Coding transitive constraint:\n");
+ sqlite3WhereTermPrint(pTerm, pWC->nTerm-j);
+ }
+#endif
assert( !ExprHasProperty(pE, EP_FromJoin) );
assert( (pTerm->prereqRight & pLevel->notReady)!=0 );
pAlt = sqlite3WhereFindTerm(pWC, iCur, pTerm->u.leftColumn, notReady,
@@ -2331,5 +2451,16 @@ Bitmask sqlite3WhereCodeOneLoopStart(
}
}
+#if WHERETRACE_ENABLED /* 0x20800 */
+ if( sqlite3WhereTrace & 0x20000 ){
+ sqlite3DebugPrintf("All WHERE-clause terms after coding level %d:\n",
+ iLevel);
+ sqlite3WhereClausePrint(pWC);
+ }
+ if( sqlite3WhereTrace & 0x800 ){
+ sqlite3DebugPrintf("End Coding level %d: notReady=%llx\n",
+ iLevel, (u64)pLevel->notReady);
+ }
+#endif
return pLevel->notReady;
}
diff --git a/src/whereexpr.c b/src/whereexpr.c
index a161310799..cec0aefd8b 100644
--- a/src/whereexpr.c
+++ b/src/whereexpr.c
@@ -109,39 +109,14 @@ static int allowedOp(int op){
/*
** Commute a comparison operator. Expressions of the form "X op Y"
** are converted into "Y op X".
-**
-** If left/right precedence rules come into play when determining the
-** collating sequence, then COLLATE operators are adjusted to ensure
-** that the collating sequence does not change. For example:
-** "Y collate NOCASE op X" becomes "X op Y" because any collation sequence on
-** the left hand side of a comparison overrides any collation sequence
-** attached to the right. For the same reason the EP_Collate flag
-** is not commuted.
-**
-** The return value is extra flags that are added to the WhereTerm object
-** after it is commuted. The only extra flag ever added is TERM_NOPARTIDX
-** which prevents the term from being used to enable a partial index if
-** COLLATE changes have been made.
*/
static u16 exprCommute(Parse *pParse, Expr *pExpr){
- u16 expRight = (pExpr->pRight->flags & EP_Collate);
- u16 expLeft = (pExpr->pLeft->flags & EP_Collate);
- u16 wtFlags = 0;
- assert( allowedOp(pExpr->op) && pExpr->op!=TK_IN );
- if( expRight==expLeft ){
- /* Either X and Y both have COLLATE operator or neither do */
- if( expRight ){
- /* Both X and Y have COLLATE operators. Make sure X is always
- ** used by clearing the EP_Collate flag from Y. */
- pExpr->pRight->flags &= ~EP_Collate;
- wtFlags |= TERM_NOPARTIDX;
- }else if( sqlite3ExprCollSeq(pParse, pExpr->pLeft)!=0 ){
- /* Neither X nor Y have COLLATE operators, but X has a non-default
- ** collating sequence. So add the EP_Collate marker on X to cause
- ** it to be searched first. */
- pExpr->pLeft->flags |= EP_Collate;
- wtFlags |= TERM_NOPARTIDX;
- }
+ if( pExpr->pLeft->op==TK_VECTOR
+ || pExpr->pRight->op==TK_VECTOR
+ || sqlite3BinaryCompareCollSeq(pParse, pExpr->pLeft, pExpr->pRight) !=
+ sqlite3BinaryCompareCollSeq(pParse, pExpr->pRight, pExpr->pLeft)
+ ){
+ pExpr->flags ^= EP_Commuted;
}
SWAP(Expr*,pExpr->pRight,pExpr->pLeft);
if( pExpr->op>=TK_GT ){
@@ -152,7 +127,7 @@ static u16 exprCommute(Parse *pParse, Expr *pExpr){
assert( pExpr->op>=TK_GT && pExpr->op<=TK_GE );
pExpr->op = ((pExpr->op-TK_GT)^2)+TK_GT;
}
- return wtFlags;
+ return 0;
}
/*
@@ -930,7 +905,7 @@ static int termIsEquivalence(Parse *pParse, Expr *pExpr){
){
return 0;
}
- pColl = sqlite3BinaryCompareCollSeq(pParse, pExpr->pLeft, pExpr->pRight);
+ pColl = sqlite3ExprCompareCollSeq(pParse, pExpr);
if( sqlite3IsBinary(pColl) ) return 1;
return sqlite3ExprCollSeqMatch(pParse, pExpr->pLeft, pExpr->pRight);
}
@@ -1323,6 +1298,7 @@ static void exprAnalyze(
0, sqlite3ExprDup(db, pRight, 0));
if( ExprHasProperty(pExpr, EP_FromJoin) && pNewExpr ){
ExprSetProperty(pNewExpr, EP_FromJoin);
+ pNewExpr->iRightJoinTable = pExpr->iRightJoinTable;
}
idxNew = whereClauseInsert(pWC, pNewExpr, TERM_VIRTUAL|TERM_DYNAMIC);
testcase( idxNew==0 );
@@ -1379,11 +1355,15 @@ static void exprAnalyze(
** expression). The WhereTerm.iField variable identifies the index within
** the vector on the LHS that the virtual term represents.
**
- ** This only works if the RHS is a simple SELECT, not a compound
+ ** This only works if the RHS is a simple SELECT (not a compound) that does
+ ** not use window functions.
*/
if( pWC->op==TK_AND && pExpr->op==TK_IN && pTerm->iField==0
&& pExpr->pLeft->op==TK_VECTOR
&& pExpr->x.pSelect->pPrior==0
+#ifndef SQLITE_OMIT_WINDOWFUNC
+ && pExpr->x.pSelect->pWin==0
+#endif
){
int i;
for(i=0; ipLeft); i++){
@@ -1541,9 +1521,10 @@ Bitmask sqlite3WhereExprUsageNN(WhereMaskSet *pMaskSet, Expr *p){
mask |= sqlite3WhereExprListUsage(pMaskSet, p->x.pList);
}
#ifndef SQLITE_OMIT_WINDOWFUNC
- if( p->op==TK_FUNCTION && p->y.pWin ){
+ if( (p->op==TK_FUNCTION || p->op==TK_AGG_FUNCTION) && p->y.pWin ){
mask |= sqlite3WhereExprListUsage(pMaskSet, p->y.pWin->pPartition);
mask |= sqlite3WhereExprListUsage(pMaskSet, p->y.pWin->pOrderBy);
+ mask |= sqlite3WhereExprUsage(pMaskSet, p->y.pWin->pFilter);
}
#endif
return mask;
@@ -1619,6 +1600,9 @@ void sqlite3WhereTabFuncArgs(
pRhs = sqlite3PExpr(pParse, TK_UPLUS,
sqlite3ExprDup(pParse->db, pArgs->a[j].pExpr, 0), 0);
pTerm = sqlite3PExpr(pParse, TK_EQ, pColRef, pRhs);
+ if( pItem->fg.jointype & JT_LEFT ){
+ sqlite3SetJoinExpr(pTerm, pItem->iCursor);
+ }
whereClauseInsert(pWC, pTerm, TERM_DYNAMIC);
}
}
diff --git a/src/window.c b/src/window.c
index e8dfa6c3ef..a72ec0d2db 100644
--- a/src/window.c
+++ b/src/window.c
@@ -787,8 +787,21 @@ static int selectWindowRewriteExprCb(Walker *pWalker, Expr *pExpr){
case TK_AGG_FUNCTION:
case TK_COLUMN: {
- Expr *pDup = sqlite3ExprDup(pParse->db, pExpr, 0);
- p->pSub = sqlite3ExprListAppend(pParse, p->pSub, pDup);
+ int iCol = -1;
+ if( p->pSub ){
+ int i;
+ for(i=0; ipSub->nExpr; i++){
+ if( 0==sqlite3ExprCompare(0, p->pSub->a[i].pExpr, pExpr, -1) ){
+ iCol = i;
+ break;
+ }
+ }
+ }
+ if( iCol<0 ){
+ Expr *pDup = sqlite3ExprDup(pParse->db, pExpr, 0);
+ if( pDup && pDup->op==TK_AGG_FUNCTION ) pDup->op = TK_FUNCTION;
+ p->pSub = sqlite3ExprListAppend(pParse, p->pSub, pDup);
+ }
if( p->pSub ){
assert( ExprHasProperty(pExpr, EP_Static)==0 );
ExprSetProperty(pExpr, EP_Static);
@@ -797,11 +810,11 @@ static int selectWindowRewriteExprCb(Walker *pWalker, Expr *pExpr){
memset(pExpr, 0, sizeof(Expr));
pExpr->op = TK_COLUMN;
- pExpr->iColumn = p->pSub->nExpr-1;
+ pExpr->iColumn = (iCol<0 ? p->pSub->nExpr-1: iCol);
pExpr->iTable = p->pWin->iEphCsr;
pExpr->y.pTab = p->pTab;
}
-
+ if( pParse->db->mallocFailed ) return WRC_Abort;
break;
}
@@ -882,10 +895,13 @@ static ExprList *exprListAppendList(
int i;
int nInit = pList ? pList->nExpr : 0;
for(i=0; inExpr; i++){
+ int iDummy;
Expr *pDup = sqlite3ExprDup(pParse->db, pAppend->a[i].pExpr, 0);
- if( bIntToNull && pDup && pDup->op==TK_INTEGER ){
+ 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;
}
pList = sqlite3ExprListAppend(pParse, pList, pDup);
if( pList ) pList->a[nInit+i].sortFlags = pAppend->a[i].sortFlags;
@@ -903,7 +919,7 @@ static ExprList *exprListAppendList(
*/
int sqlite3WindowRewrite(Parse *pParse, Select *p){
int rc = SQLITE_OK;
- if( p->pWin && p->pPrior==0 ){
+ if( p->pWin && p->pPrior==0 && (p->selFlags & SF_WinRewrite)==0 ){
Vdbe *v = sqlite3GetVdbe(pParse);
sqlite3 *db = pParse->db;
Select *pSub = 0; /* The subquery */
@@ -920,7 +936,7 @@ int sqlite3WindowRewrite(Parse *pParse, Select *p){
pTab = sqlite3DbMallocZero(db, sizeof(Table));
if( pTab==0 ){
- return SQLITE_NOMEM;
+ return sqlite3ErrorToParser(db, SQLITE_NOMEM);
}
p->pSrc = 0;
@@ -928,11 +944,12 @@ int sqlite3WindowRewrite(Parse *pParse, Select *p){
p->pGroupBy = 0;
p->pHaving = 0;
p->selFlags &= ~SF_Aggregate;
+ p->selFlags |= SF_WinRewrite;
/* Create the ORDER BY clause for the sub-select. This is the concatenation
** of the window PARTITION and ORDER BY clauses. Then, if this makes it
** redundant, remove the ORDER BY from the parent SELECT. */
- pSort = sqlite3ExprListDup(db, pMWin->pPartition, 0);
+ pSort = exprListAppendList(pParse, 0, pMWin->pPartition, 1);
pSort = exprListAppendList(pParse, pSort, pMWin->pOrderBy, 1);
if( pSort && p->pOrderBy && p->pOrderBy->nExpr<=pSort->nExpr ){
int nSave = pSort->nExpr;
@@ -1006,6 +1023,9 @@ int sqlite3WindowRewrite(Parse *pParse, Select *p){
pSub->selFlags |= SF_Expanded;
pTab2 = sqlite3ResultSetOfSelect(pParse, pSub, SQLITE_AFF_NONE);
if( pTab2==0 ){
+ /* Might actually be some other kind of error, but in that case
+ ** pParse->nErr will be set, so if SQLITE_NOMEM is set, we will get
+ ** the correct error message regardless. */
rc = SQLITE_NOMEM;
}else{
memcpy(pTab, pTab2, sizeof(Table));
@@ -1013,10 +1033,6 @@ int sqlite3WindowRewrite(Parse *pParse, Select *p){
p->pSrc->a[0].pTab = pTab;
pTab = pTab2;
}
- sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pMWin->iEphCsr, pSublist->nExpr);
- sqlite3VdbeAddOp2(v, OP_OpenDup, pMWin->iEphCsr+1, pMWin->iEphCsr);
- sqlite3VdbeAddOp2(v, OP_OpenDup, pMWin->iEphCsr+2, pMWin->iEphCsr);
- sqlite3VdbeAddOp2(v, OP_OpenDup, pMWin->iEphCsr+3, pMWin->iEphCsr);
}else{
sqlite3SelectDelete(db, pSub);
}
@@ -1024,6 +1040,13 @@ int sqlite3WindowRewrite(Parse *pParse, Select *p){
sqlite3DbFree(db, pTab);
}
+ if( rc ){
+ if( pParse->nErr==0 ){
+ assert( pParse->db->mallocFailed );
+ sqlite3ErrorToParser(pParse->db, SQLITE_NOMEM);
+ }
+ sqlite3SelectReset(pParse, p);
+ }
return rc;
}
@@ -1243,8 +1266,8 @@ void sqlite3WindowAttach(Parse *pParse, Expr *p, Window *pWin){
** SELECT, or (b) the windows already linked use a compatible window frame.
*/
void sqlite3WindowLink(Select *pSel, Window *pWin){
- if( 0==pSel->pWin
- || 0==sqlite3WindowCompare(0, pSel->pWin, pWin, 0)
+ if( pSel!=0
+ && (0==pSel->pWin || 0==sqlite3WindowCompare(0, pSel->pWin, pWin, 0))
){
pWin->pNextWin = pSel->pWin;
if( pSel->pWin ){
@@ -1256,20 +1279,29 @@ void sqlite3WindowLink(Select *pSel, Window *pWin){
}
/*
-** Return 0 if the two window objects are identical, or non-zero otherwise.
-** Identical window objects can be processed in a single scan.
+** Return 0 if the two window objects are identical, 1 if they are
+** different, or 2 if it cannot be determined if the objects are identical
+** or not. Identical window objects can be processed in a single scan.
*/
int sqlite3WindowCompare(Parse *pParse, Window *p1, Window *p2, int bFilter){
+ int res;
+ if( NEVER(p1==0) || NEVER(p2==0) ) return 1;
if( p1->eFrmType!=p2->eFrmType ) return 1;
if( p1->eStart!=p2->eStart ) return 1;
if( p1->eEnd!=p2->eEnd ) return 1;
if( p1->eExclude!=p2->eExclude ) return 1;
if( sqlite3ExprCompare(pParse, p1->pStart, p2->pStart, -1) ) return 1;
if( sqlite3ExprCompare(pParse, p1->pEnd, p2->pEnd, -1) ) return 1;
- if( sqlite3ExprListCompare(p1->pPartition, p2->pPartition, -1) ) return 1;
- if( sqlite3ExprListCompare(p1->pOrderBy, p2->pOrderBy, -1) ) return 1;
+ if( (res = sqlite3ExprListCompare(p1->pPartition, p2->pPartition, -1)) ){
+ return res;
+ }
+ if( (res = sqlite3ExprListCompare(p1->pOrderBy, p2->pOrderBy, -1)) ){
+ return res;
+ }
if( bFilter ){
- if( sqlite3ExprCompare(pParse, p1->pFilter, p2->pFilter, -1) ) return 1;
+ if( (res = sqlite3ExprCompare(pParse, p1->pFilter, p2->pFilter, -1)) ){
+ return res;
+ }
}
return 0;
}
@@ -1280,10 +1312,17 @@ int sqlite3WindowCompare(Parse *pParse, Window *p1, Window *p2, int bFilter){
** to begin iterating through the sub-query results. It is used to allocate
** and initialize registers and cursors used by sqlite3WindowCodeStep().
*/
-void sqlite3WindowCodeInit(Parse *pParse, Window *pMWin){
+void sqlite3WindowCodeInit(Parse *pParse, Select *pSelect){
+ int nEphExpr = pSelect->pSrc->a[0].pSelect->pEList->nExpr;
+ Window *pMWin = pSelect->pWin;
Window *pWin;
Vdbe *v = sqlite3GetVdbe(pParse);
+ sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pMWin->iEphCsr, nEphExpr);
+ sqlite3VdbeAddOp2(v, OP_OpenDup, pMWin->iEphCsr+1, pMWin->iEphCsr);
+ sqlite3VdbeAddOp2(v, OP_OpenDup, pMWin->iEphCsr+2, pMWin->iEphCsr);
+ sqlite3VdbeAddOp2(v, OP_OpenDup, pMWin->iEphCsr+3, pMWin->iEphCsr);
+
/* Allocate registers to use for PARTITION BY values, if any. Initialize
** said registers to NULL. */
if( pMWin->pPartition ){
@@ -1549,7 +1588,7 @@ static void windowAggStep(
/* All OVER clauses in the same window function aggregate step must
** be the same. */
- assert( pWin==pMWin || sqlite3WindowCompare(pParse,pWin,pMWin,0)==0 );
+ assert( pWin==pMWin || sqlite3WindowCompare(pParse,pWin,pMWin,0)!=1 );
for(i=0; izName!=nth_valueName ){
diff --git a/test/alter.test b/test/alter.test
index a82456d47b..0ec485ef81 100644
--- a/test/alter.test
+++ b/test/alter.test
@@ -684,7 +684,7 @@ do_test alter-8.2 {
# alter-9.X - Special test: Make sure the sqlite_rename_column() and
# rename_table() functions do not crash when handed bad input.
#
-sqlite3_test_control SQLITE_TESTCTRL_INTERNAL_FUNCTIONS 1
+sqlite3_test_control SQLITE_TESTCTRL_INTERNAL_FUNCTIONS db
do_test alter-9.1 {
execsql {SELECT SQLITE_RENAME_COLUMN(0,0,0,0,0,0,0,0,0)}
} {{}}
@@ -697,7 +697,7 @@ foreach {tn sql} {
catch { execsql $sql }
} 1
}
-sqlite3_test_control SQLITE_TESTCTRL_INTERNAL_FUNCTIONS 0
+sqlite3_test_control SQLITE_TESTCTRL_INTERNAL_FUNCTIONS db
# If the INTERNAL_FUNCTIONS test-control is disabled (which is the default),
# then the sqlite_rename_table() SQL function is not accessible to ordinary SQL.
diff --git a/test/alter3.test b/test/alter3.test
index 44b31c9833..b16a7f305b 100644
--- a/test/alter3.test
+++ b/test/alter3.test
@@ -54,8 +54,8 @@ proc get_file_format {{fname test.db}} {
}
do_test alter3-1.1 {
+ sqlite3_db_config db LEGACY_FILE_FORMAT 1
execsql {
- PRAGMA legacy_file_format=ON;
CREATE TABLE abc(a, b, c);
SELECT sql FROM sqlite_master;
}
@@ -198,8 +198,8 @@ do_test alter3-4.1 {
db close
forcedelete test.db
set ::DB [sqlite3 db test.db]
+ sqlite3_db_config db LEGACY_FILE_FORMAT 1
execsql {
- PRAGMA legacy_file_format=ON;
CREATE TABLE t1(a, b);
INSERT INTO t1 VALUES(1, 100);
INSERT INTO t1 VALUES(2, 300);
diff --git a/test/alter4.test b/test/alter4.test
index ca9175959b..92f33e7a36 100644
--- a/test/alter4.test
+++ b/test/alter4.test
@@ -383,8 +383,8 @@ do_execsql_test alter4-9.3 {
do_test alter4-10.1 {
db close
sqlite3 db :memory:
+ sqlite3_db_config db LEGACY_FILE_FORMAT 1
db eval {
- PRAGMA legacy_file_format=on;
CREATE TABLE t1(a,b,c);
CREATE INDEX t1a ON t1(a DESC);
INSERT INTO t1 VALUES(1,2,3);
diff --git a/test/altercol.test b/test/altercol.test
index d71a9b06e4..1479b3a7d3 100644
--- a/test/altercol.test
+++ b/test/altercol.test
@@ -618,7 +618,7 @@ foreach {tn trigger error} {
#-------------------------------------------------------------------------
# Passing invalid parameters directly to sqlite_rename_column().
#
-sqlite3_test_control SQLITE_TESTCTRL_INTERNAL_FUNCTIONS 1
+sqlite3_test_control SQLITE_TESTCTRL_INTERNAL_FUNCTIONS db
do_execsql_test 14.1 {
CREATE TABLE ddd(sql, type, object, db, tbl, icol, znew, bquote);
INSERT INTO ddd VALUES(
@@ -641,7 +641,7 @@ do_execsql_test 14.2 {
sqlite_rename_column(sql, type, object, db, tbl, icol, znew, bquote, 0)
FROM ddd;
} {{} {} {} {}}
-sqlite3_test_control SQLITE_TESTCTRL_INTERNAL_FUNCTIONS 0
+sqlite3_test_control SQLITE_TESTCTRL_INTERNAL_FUNCTIONS db
# If the INTERNAL_FUNCTIONS test-control is disabled (which is the default)
# then the sqlite_rename_table() SQL function is not accessible to
diff --git a/test/altertab.test b/test/altertab.test
index 2eed636e0d..7dcf8a5e0d 100644
--- a/test/altertab.test
+++ b/test/altertab.test
@@ -240,13 +240,13 @@ ifcapable vtab {
);
} {}
- sqlite3_test_control SQLITE_TESTCTRL_INTERNAL_FUNCTIONS 1
+ sqlite3_test_control SQLITE_TESTCTRL_INTERNAL_FUNCTIONS db
do_execsql_test 7.2 {
SELECT
sqlite_rename_table(db, 0, 0, sql, zOld, zNew, bTemp)
FROM ddd;
} {{} {} {}}
- sqlite3_test_control SQLITE_TESTCTRL_INTERNAL_FUNCTIONS 0
+ sqlite3_test_control SQLITE_TESTCTRL_INTERNAL_FUNCTIONS db
}
#-------------------------------------------------------------------------
@@ -542,19 +542,39 @@ ifcapable fts3 {
CREATE VIRTUAL TABLE y1 USING fts3;
}
- do_catchsql_test 16.1 {
+ do_catchsql_test 16.10 {
INSERT INTO y1_segments VALUES(1, X'1234567890');
} {1 {table y1_segments may not be modified}}
- do_catchsql_test 16.2 {
+ do_catchsql_test 16.20 {
+ DROP TABLE y1_segments;
+ } {1 {table y1_segments may not be dropped}}
+
+ do_catchsql_test 16.20 {
ALTER TABLE y1_segments RENAME TO abc;
} {1 {table y1_segments may not be altered}}
+ sqlite3_db_config db DEFENSIVE 0
+ do_catchsql_test 16.22 {
+ ALTER TABLE y1_segments RENAME TO abc;
+ } {0 {}}
+ sqlite3_db_config db DEFENSIVE 1
+ do_catchsql_test 16.23 {
+ CREATE TABLE y1_segments AS SELECT * FROM abc;
+ } {1 {object name reserved for internal use: y1_segments}}
+ do_catchsql_test 16.24 {
+ CREATE VIEW y1_segments AS SELECT * FROM abc;
+ } {1 {object name reserved for internal use: y1_segments}}
+ sqlite3_db_config db DEFENSIVE 0
+ do_catchsql_test 16.25 {
+ ALTER TABLE abc RENAME TO y1_segments;
+ } {0 {}}
+ sqlite3_db_config db DEFENSIVE 1
- do_execsql_test 16.3 {
+ do_execsql_test 16.30 {
ALTER TABLE y1 RENAME TO z1;
}
- do_execsql_test 16.4 {
+ do_execsql_test 16.40 {
SELECT * FROM z1_segments;
}
}
diff --git a/test/altertab2.test b/test/altertab2.test
index f14dc13ff1..9c1ad58134 100644
--- a/test/altertab2.test
+++ b/test/altertab2.test
@@ -343,22 +343,21 @@ do_execsql_test 8.4 {
CREATE VIEW v4 AS SELECT * FROM t4 WHERE (a=1 AND 0) OR b=2;
}
-# Do not rename branches of an expression tree that is optimized out by
-# the AND optimization.
+# Branches of an expression tree that are optimized out by the AND
+# optimization are renamed.
#
do_execsql_test 8.5 {
ALTER TABLE t4 RENAME a TO c;
SELECT sql FROM sqlite_master WHERE name = 'v4'
-} {{CREATE VIEW v4 AS SELECT * FROM t4 WHERE (a=1 AND 0) OR b=2}}
-# "a" is not renamed to "c" ---^
+} {{CREATE VIEW v4 AS SELECT * FROM t4 WHERE (c=1 AND 0) OR b=2}}
# 2019-06-10 https://www.sqlite.org/src/info/533010b8cacebe82
reset_db
-do_execsql_test 8.6 {
+do_catchsql_test 8.6 {
CREATE TABLE t0(c0);
CREATE INDEX i0 ON t0(LIKELIHOOD(1,2) AND 0);
ALTER TABLE t0 RENAME TO t1;
SELECT sql FROM sqlite_master WHERE name='i0';
-} {{CREATE INDEX i0 ON "t1"(LIKELIHOOD(1,2) AND 0)}}
+} {1 {error in index i0: second argument to likelihood() must be a constant between 0.0 and 1.0}}
finish_test
diff --git a/test/altertab3.test b/test/altertab3.test
index 948a351e70..b39065589c 100644
--- a/test/altertab3.test
+++ b/test/altertab3.test
@@ -20,7 +20,6 @@ ifcapable !altertable {
return
}
-
ifcapable windowfunc {
do_execsql_test 1.0 {
CREATE TABLE t1(a, b);
@@ -381,5 +380,211 @@ do_execsql_test 17.2 {
END}
}
+#-------------------------------------------------------------------------
+reset_db
+do_execsql_test 18.1 {
+ CREATE TABLE t1(a,b);
+ CREATE TRIGGER r1 AFTER INSERT ON t1 BEGIN
+ SELECT a, b FROM t1
+ INTERSECT SELECT b,a FROM t1
+ ORDER BY b IN (
+ SELECT a UNION SELECT b
+ FROM t1
+ ORDER BY b COLLATE nocase
+ )
+ ;
+ END;
+}
+
+do_catchsql_test 18.2 {
+ SELECT a, b FROM t1
+ INTERSECT
+ SELECT b,a FROM t1
+ ORDER BY b IN (
+ SELECT a UNION SELECT b
+ FROM t1
+ ORDER BY b COLLATE nocase
+ );
+} {1 {1st ORDER BY term does not match any column in the result set}}
+
+do_catchsql_test 18.3 {
+ ALTER TABLE t1 RENAME TO t1x;
+} {1 {error in trigger r1: 1st ORDER BY term does not match any column in the result set}}
+
+#-------------------------------------------------------------------------
+reset_db
+do_execsql_test 19.0 {
+ CREATE TABLE a(a,h CONSTRAINT a UNIQUE ON CONFLICT FAIL,CONSTRAINT a);
+}
+
+foreach {tn v res} {
+ 1 {
+ CREATE VIEW q AS SELECT 123
+
+ WINDOW x AS (
+ RANGE BETWEEN UNBOUNDED PRECEDING AND INDEXED() OVER(
+ PARTITION BY ( WITH x AS(VALUES(col1)) VALUES(453) )
+ )
+ FOLLOWING
+ )
+ } {1 {error in view q: no such column: col1}}
+
+ 2 {
+ CREATE VIEW q AS SELECT
+ CAST(CAST(CAST(CAST(CAST(CAST(CAST(CAST(CAST(CAST(CAST(RIGHT
+ AS)AS)AS)AS)AS)AS)AS)AS)AS)AS)AS)WINDOW x AS(RANGE BETWEEN UNBOUNDED
+ PRECEDING AND INDEXED(*)OVER(PARTITION BY
+ CROSS,CROSS,NATURAL,sqlite_master(*)OVER a,(WITH a AS(VALUES(LEFT)UNION
+ VALUES(LEFT)UNION VALUES(LEFT)UNION VALUES(LEFT)UNION VALUES(LEFT)UNION
+ VALUES(LEFT)UNION VALUES(LEFT))VALUES(LEFT))IN
+ STORED,LEFT,LEFT,LEFT,LEFT,LEFT,LEFT)*LEFT FOLLOWING)ORDER BY
+ LEFT,LEFT,LEFT,LEFT,LEFT,LEFT,LEFT,LEFT,LEFT,LEFT,LEFT LIMIT
+ LEFT,INDEXED(*)OVER(PARTITION BY
+ CROSS,CROSS,CROSS,LEFT,INDEXED(*)OVER(PARTITION BY
+ CROSS,CROSS,CROSS),INDEXED(*)OVER(PARTITION BY
+ LEFT,LEFT,LEFT,LEFT,LEFT,LEFT,LEFT,LEFT,LEFT,LEFT,LEFT),
+ LEFT,LEFT,INNER,CROSS,CROSS,CROSS,INNER,NATURAL ORDER BY
+ OUTER,NATURAL,NATURAL,NATURAL,NATURAL,NATURAL,NATURAL,NATURAL,INNER,
+ INNER,INNER NULLS LAST GROUPS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED
+ FOLLOWING);
+ } {1 {error in view q: no such column: LEFT}}
+
+ 3 {
+ CREATE VIEW q AS SELECT 99 WINDOW x AS (RANGE BETWEEN UNBOUNDED PRECEDING
+ AND count(*)OVER(PARTITION BY (WITH a AS(VALUES(2),(x3))VALUES(0)))
+ FOLLOWING)ORDER BY x2,sum(1)OVER(PARTITION BY avg(5)OVER(PARTITION BY x1));
+ } {1 {error in view q: no such column: x3}}
+} {
+ do_execsql_test 19.$tn.1 "
+ DROP VIEW IF EXISTS q;
+ $v
+ " {}
+
+ do_catchsql_test 19.$tn.2 {
+ ALTER TABLE a RENAME TO g;
+ } $res
+}
+
+# Verify that the "if( pParse->nErr ) return WRC_Abort" at the top of the
+# renameUnmapSelectCb() routine in alter.c (2019-12-04) is really required.
+#
+sqlite3 db :memory:
+do_catchsql_test 20.10 {
+ CREATE TABLE s(a, b, c);
+ CREATE INDEX k ON s( (WITH s AS( SELECT * ) VALUES(2) ) IN () );
+ ALTER TABLE s RENAME a TO a2;
+} {1 {error in index k: no tables specified}}
+
+#------------------------------------------------------------------------
+#
+reset_db
+do_execsql_test 21.1 {
+ CREATE TABLE s(col);
+ CREATE VIEW v AS SELECT (
+ WITH x(a) AS(SELECT * FROM s) VALUES(RIGHT)
+ ) IN() ;
+ CREATE TABLE a(a);
+ ALTER TABLE a RENAME a TO b;
+}
+
+#------------------------------------------------------------------------
+#
+reset_db
+do_execsql_test 22.1 {
+ CREATE TABLE t1(a);
+ CREATE VIEW v2(b) AS SELECT * FROM v2;
+}
+
+do_catchsql_test 22.2 {
+ ALTER TABLE t1 RENAME TO t4;
+} {1 {error in view v2: view v2 is circularly defined}}
+
+do_execsql_test 22.3 {
+ DROP VIEW v2;
+ CREATE VIEW v2(b) AS WITH t3 AS (SELECT b FROM v2) SELECT * FROM t3;
+}
+
+do_catchsql_test 22.4 {
+ ALTER TABLE t1 RENAME TO t4;
+} {1 {error in view v2: view v2 is circularly defined}}
+
+do_execsql_test 22.5 {
+ DROP VIEW v2;
+ CREATE VIEW v2(b) AS WITH t3 AS (SELECT b FROM v2) VALUES(1);
+}
+
+do_catchsql_test 22.6 {
+ ALTER TABLE t1 RENAME TO t4;
+} {0 {}}
+
+#------------------------------------------------------------------------
+#
+reset_db
+do_execsql_test 23.1 {
+ CREATE TABLE t1(x);
+ CREATE TRIGGER r1 AFTER INSERT ON t1 BEGIN
+ UPDATE t1 SET (c,d)=((SELECT 1 FROM t1 JOIN t2 ON b=x),1);
+ END;
+}
+
+do_catchsql_test 23.2 {
+ ALTER TABLE t1 RENAME TO t1x;
+} {1 {error in trigger r1: no such table: main.t2}}
+
+#------------------------------------------------------------------------
+#
+reset_db
+do_execsql_test 23.1 {
+ CREATE TABLE v0 (a);
+ CREATE VIEW v2 (v3) AS
+ WITH x1 AS (SELECT * FROM v2)
+ SELECT v3 AS x, v3 AS y FROM v2;
+}
+
+do_catchsql_test 23.2 {
+ SELECT * FROM v2
+} {1 {view v2 is circularly defined}}
+
+db close
+sqlite3 db test.db
+
+do_catchsql_test 23.3 {
+ ALTER TABLE v0 RENAME TO t3 ;
+} {1 {error in view v2: view v2 is circularly defined}}
+
+#------------------------------------------------------------------------
+#
+reset_db
+do_execsql_test 24.1 {
+ CREATE TABLE v0 (v1);
+ CREATE TABLE v2 (v3 INTEGER UNIQUE ON CONFLICT ABORT);
+ CREATE TRIGGER x AFTER INSERT ON v2 WHEN (
+ ( SELECT v1 AS PROMO_REVENUE FROM v2 JOIN v0 USING ( VALUE ) ) AND 0 )
+ BEGIN
+ DELETE FROM v2;
+ END;
+}
+do_catchsql_test 24.2 {
+ ALTER TABLE v0 RENAME TO x ;
+} {1 {error in trigger x: cannot join using column VALUE - column not present in both tables}}
+
+do_execsql_test 24.3 {
+ DROP TRIGGER x;
+ CREATE TRIGGER x AFTER INSERT ON v2 WHEN (
+ 0 AND (SELECT rowid FROM v0)
+ ) BEGIN
+ DELETE FROM v2;
+ END;
+}
+
+do_execsql_test 24.4 {
+ ALTER TABLE v0 RENAME TO xyz;
+ SELECT sql FROM sqlite_master WHERE type='trigger'
+} {{CREATE TRIGGER x AFTER INSERT ON v2 WHEN (
+ 0 AND (SELECT rowid FROM "xyz")
+ ) BEGIN
+ DELETE FROM v2;
+ END}}
finish_test
+
diff --git a/test/atof1.test b/test/atof1.test
index 55f5e44d96..34e69c12f8 100644
--- a/test/atof1.test
+++ b/test/atof1.test
@@ -56,5 +56,29 @@ for {set i 1} {$i<20000} {incr i} {
} {1}
}
+# 2020-01-08 ticket 9eda2697f5cc1aba
+# When running sqlite3AtoF() on a blob with an odd number of bytes using
+# UTF16, ignore the last byte so that the string has an integer number of
+# UTF16 code points.
+#
+reset_db
+do_execsql_test atof1-2.10 {
+ PRAGMA encoding = 'UTF16be';
+ CREATE TABLE t1(a, b);
+ INSERT INTO t1(rowid,a) VALUES (1,x'00'),(2,3);
+ SELECT substr(a,',') is true FROM t1 ORDER BY rowid;
+} {0 1}
+do_execsql_test atof1-2.20 {
+ SELECT substr(a,',') is true FROM t1 ORDER BY rowid DESC;
+} {1 0}
+do_execsql_test atof1-2.30 {
+ CREATE INDEX i1 ON t1(a);
+ SELECT count(*) FROM t1 WHERE substr(a,',');
+} {1}
+
+
+
+
+
finish_test
diff --git a/test/attach4.test b/test/attach4.test
index 77dd7e4115..87911814a0 100644
--- a/test/attach4.test
+++ b/test/attach4.test
@@ -115,4 +115,24 @@ do_test 1.8 {
db close
foreach {name f} $files { forcedelete $f }
+#-------------------------------------------------------------------------
+reset_db
+do_execsql_test 2.0 {
+ ATTACH DATABASE '' AS aux;
+ CREATE TABLE IF NOT EXISTS aux.t1(a, b);
+ CREATE TEMPORARY TRIGGER tr1 DELETE ON t1 BEGIN
+ DELETE FROM t1;
+ END;
+ CREATE TABLE temp.t1(a, b);
+}
+
+do_execsql_test 2.1 {
+ DETACH DATABASE aux;
+}
+
+do_execsql_test 2.2 {
+ DROP TRIGGER tr1;
+}
+
finish_test
+
diff --git a/test/cast.test b/test/cast.test
index e6795ce456..d2eaffcbb5 100644
--- a/test/cast.test
+++ b/test/cast.test
@@ -461,6 +461,18 @@ do_execsql_test cast-7.43 {
SELECT CAST('-1.0' AS numeric);
} -1
+ifcapable utf16 {
+ reset_db
+ execsql { PRAGMA encoding='utf16' }
+
+ do_execsql_test cast-8.1 {
+ SELECT quote(X'310032003300')==quote(substr(X'310032003300', 1))
+ } 1
+ do_execsql_test cast-8.2 {
+ SELECT CAST(X'310032003300' AS TEXT)
+ ==CAST(substr(X'310032003300', 1) AS TEXT)
+ } 1
+}
finish_test
diff --git a/test/check.test b/test/check.test
index e23043eb04..3e16b9dcf5 100644
--- a/test/check.test
+++ b/test/check.test
@@ -11,7 +11,6 @@
# This file implements regression tests for SQLite library. The
# focus of this file is testing CHECK constraints
#
-# $Id: check.test,v 1.13 2009/06/05 17:09:12 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
@@ -442,7 +441,7 @@ do_test check-6.15 {
#
reset_db
proc myfunc {x} {expr $x < 10}
-db func myfunc myfunc
+db func myfunc -deterministic myfunc
do_execsql_test 7.1 { CREATE TABLE t6(a CHECK (myfunc(a))) }
do_execsql_test 7.2 { INSERT INTO t6 VALUES(9) }
@@ -536,7 +535,71 @@ do_execsql_test 11.6 {
INSERT INTO t2(b, a) VALUES(2, 'abc');
}
-finish_test
-
+# 2019-12-24 ticket b383b90278186263
+#
+reset_db
+do_execsql_test 12.10 {
+ CREATE TABLE t1(a TEXT, CHECK(a=+a));
+ INSERT INTO t1(a) VALUES(NULL),('xyz'),(5),(x'303132'),(4.75);
+ SELECT quote(a) FROM t1 ORDER BY rowid;
+} {NULL 'xyz' '5' X'303132' '4.75'}
+do_execsql_test 12.20 {
+ DROP TABLE t1;
+ CREATE TABLE t1(a TEXT, CHECK(a<>+a));
+ INSERT INTO t1(a) VALUES(NULL);
+} {}
+do_catchsql_test 12.21 {
+ INSERT INTO t1(a) VALUES('xyz');
+} {1 {CHECK constraint failed: t1}}
+do_catchsql_test 12.22 {
+ INSERT INTO t1(a) VALUES(123);
+} {1 {CHECK constraint failed: t1}}
+do_execsql_test 12.30 {
+ DROP TABLE t1;
+ CREATE TABLE t1(a TEXT, CHECK(NOT(a=+a)));
+ INSERT INTO t1(a) VALUES(NULL);
+} {}
+do_catchsql_test 12.31 {
+ INSERT INTO t1(a) VALUES('xyz');
+} {1 {CHECK constraint failed: t1}}
+do_catchsql_test 12.32 {
+ INSERT INTO t1(a) VALUES(123);
+} {1 {CHECK constraint failed: t1}}
+do_execsql_test 12.40 {
+ DROP TABLE t1;
+ CREATE TABLE t1(a TEXT, CHECK(NOT(a<>+a)));
+ INSERT INTO t1(a) VALUES(NULL),('xyz'),(5),(x'303132'),(4.75);
+ SELECT quote(a) FROM t1 ORDER BY rowid;
+} {NULL 'xyz' '5' X'303132' '4.75'}
+do_execsql_test 12.50 {
+ DROP TABLE t1;
+ CREATE TABLE t1(a TEXT, CHECK(a BETWEEN 0 AND +a));
+ INSERT INTO t1(a) VALUES(NULL),('xyz'),(5),(x'303132'),(4.75);
+ SELECT quote(a) FROM t1 ORDER BY rowid;
+} {NULL 'xyz' '5' X'303132' '4.75'}
+do_execsql_test 12.60 {
+ DROP TABLE t1;
+ CREATE TABLE t1(a TEXT, CHECK(a NOT BETWEEN 0 AND +a));
+ INSERT INTO t1(a) VALUES(NULL);
+ SELECT quote(a) FROM t1 ORDER BY rowid;
+} {NULL}
+do_catchsql_test 12.61 {
+ INSERT INTO t1(a) VALUES(456);
+} {1 {CHECK constraint failed: t1}}
+do_execsql_test 12.70 {
+ DROP TABLE t1;
+ CREATE TABLE t1(a TEXT, CHECK(a BETWEEN +a AND 999999));
+ INSERT INTO t1(a) VALUES(NULL),(5);
+ SELECT quote(a) FROM t1 ORDER BY rowid;
+} {NULL '5'}
+do_execsql_test 12.80 {
+ DROP TABLE t1;
+ CREATE TABLE t1(a TEXT, CHECK(a NOT BETWEEN +a AND 999999));
+ INSERT INTO t1(a) VALUES(NULL);
+ SELECT quote(a) FROM t1 ORDER BY rowid;
+} {NULL}
+do_catchsql_test 12.81 {
+ INSERT INTO t1(a) VALUES(456);
+} {1 {CHECK constraint failed: t1}}
finish_test
diff --git a/test/collate1.test b/test/collate1.test
index a1623f07e6..007dd7c370 100644
--- a/test/collate1.test
+++ b/test/collate1.test
@@ -417,4 +417,35 @@ do_execsql_test 8.2 {
SELECT * FROM t0 WHERE c1 = 1;
} {{ } 1}
+# 2019-10-09
+# ALWAYS() macro fails following OOM
+# Problem detected by dbsqlfuzz.
+#
+do_execsql_test 9.0 {
+ CREATE TABLE t1(a, b);
+ CREATE TABLE t2(c, d);
+}
+
+do_faultsim_test 9.1 -faults oom* -body {
+ execsql {
+ SELECT * FROM (
+ SELECT b COLLATE nocase IN (SELECT c FROM t2) FROM t1
+ );
+ }
+} -test {
+ faultsim_test_result {0 {}}
+}
+
+# 2020-01-03 dbsqlfuzz find
+#
+reset_db
+do_catchsql_test 10.0 {
+ CREATE TABLE t1(a INTEGER PRIMARY KEY,b);
+ INSERT INTO t1 VALUES(0,NULL);
+ CREATE TABLE t2(x UNIQUE);
+ CREATE VIEW v1a(z,y) AS SELECT x COLLATE x FROM t2;
+ SELECT a,b,z,y,'' FROM t1 JOIN v1a ON b IS NOT FALSE;
+} {1 {no such collation sequence: x}}
+
+
finish_test
diff --git a/test/conflict.test b/test/conflict.test
index 136bc3fec6..b86f86022b 100644
--- a/test/conflict.test
+++ b/test/conflict.test
@@ -834,5 +834,27 @@ do_catchsql_test conflict-14.1 {
REPLACE INTO t1 DEFAULT VALUES;
} {1 {NOT NULL constraint failed: t1.x}}
+# 2019-12-15 gramfuzz1 find
+# Three UNIQUE constraints, where the third would is a duplicate except
+# that it adds ON CONFLICT REPLACE. Verify that the indexes end up
+# sorted in the correct order (REPLACE last) so that constraint processing
+# works correctly.
+#
+reset_db
+do_execsql_test conflict-15.10 {
+ CREATE TABLE t1(
+ x PRIMARY KEY,
+ UNIQUE(x,x),
+ UNIQUE(x,x) ON CONFLICT REPLACE
+ );
+ INSERT INTO t1(x) VALUES(1);
+ SELECT * FROM t1;
+} {1}
+do_catchsql_test conflict-15.20 {
+ INSERT INTO t1(x) VALUES(1);
+} {1 {UNIQUE constraint failed: t1.x}}
+do_execsql_test conflict-15.30 {
+ SELECT * FROM t1;
+} {1}
finish_test
diff --git a/test/conflict3.test b/test/conflict3.test
index 413e8241fe..8eb4c1b0f7 100644
--- a/test/conflict3.test
+++ b/test/conflict3.test
@@ -380,15 +380,15 @@ ifcapable trigger {
INSERT INTO t0 VALUES(0, NULL);
}
- do_execsql_test 13.1.1 {
+ do_catchsql_test 13.1.1 {
UPDATE OR REPLACE t0 SET c1 = 1;
- }
+ } {1 {constraint failed}}
integrity_check 13.1.2
do_execsql_test 13.1.3 {
SELECT * FROM t0
- } {}
+ } {1 {} 0 {}}
do_execsql_test 13.2.0 {
CREATE TABLE t2 (a PRIMARY KEY, b UNIQUE, c UNIQUE) WITHOUT ROWID;
@@ -400,15 +400,15 @@ ifcapable trigger {
INSERT INTO t2 VALUES(2, 2, 2);
}
- do_execsql_test 13.2.1 {
+ do_catchsql_test 13.2.1 {
UPDATE OR REPLACE t2 SET c = 0;
- }
+ } {1 {constraint failed}}
integrity_check 13.2.2
do_execsql_test 13.2.3 {
SELECT * FROM t2
- } {}
+ } {1 1 1 2 2 2}
do_execsql_test 13.3.0 {
CREATE TABLE t1(a, b);
@@ -435,4 +435,3 @@ ifcapable trigger {
}
finish_test
-
diff --git a/test/corruptC.test b/test/corruptC.test
index d151a27304..a56abeec72 100644
--- a/test/corruptC.test
+++ b/test/corruptC.test
@@ -34,9 +34,9 @@ database_may_be_corrupt
# Construct a compact, dense database for testing.
#
do_test corruptC-1.1 {
+ sqlite3_db_config db LEGACY_FILE_FORMAT 1
execsql {
PRAGMA auto_vacuum = 0;
- PRAGMA legacy_file_format=1;
BEGIN;
CREATE TABLE t1(x,y);
INSERT INTO t1 VALUES(1,1);
diff --git a/test/corruptE.test b/test/corruptE.test
index 54aa420f43..8c55623ea4 100644
--- a/test/corruptE.test
+++ b/test/corruptE.test
@@ -36,9 +36,9 @@ ifcapable oversize_cell_check {
# Construct a compact, dense database for testing.
#
do_test corruptE-1.1 {
+ sqlite3_db_config db LEGACY_FILE_FORMAT 1
execsql {
PRAGMA auto_vacuum = 0;
- PRAGMA legacy_file_format=1;
BEGIN;
CREATE TABLE t1(x,y);
INSERT INTO t1 VALUES(1,1);
diff --git a/test/corruptL.test b/test/corruptL.test
index b0ad66db44..72aedd9aa0 100644
--- a/test/corruptL.test
+++ b/test/corruptL.test
@@ -1071,4 +1071,72 @@ do_catchsql_test 11.1 {
DELETE FROM t3 WHERE x IN (SELECT x FROM t4);
} {1 {database disk image is malformed}}
+#-------------------------------------------------------------------------
+reset_db
+do_test 12.0 {
+ sqlite3 db {}
+ db deserialize [decode_hexdb {
+| size 12288 pagesize 4096 filename crash-e6d070858a3a85.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 00 00 00 02 0f 8f 00 0f bf 0f 8f ................
+| 3968: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 2e ................
+| 3984: 02 06 17 15 11 01 45 69 6e 64 65 78 74 31 63 62 ......Eindext1cb
+| 4000: 74 31 03 43 52 45 41 54 45 20 49 4e 44 45 58 20 t1.CREATE INDEX
+| 4016: 74 31 63 62 20 4f 4e 20 74 31 28 63 2c 62 29 3f t1cb ON t1(c,b)?
+| 4032: 01 06 17 11 11 01 6b 74 61 62 6c 65 74 31 74 31 ......ktablet1t1
+| 4048: 02 43 52 45 41 54 45 20 54 41 42 4c 45 20 74 31 .CREATE TABLE t1
+| 4064: 28 61 20 49 4e 54 2c 20 62 20 49 4e 54 2c 20 43 (a INT, b INT, C
+| 4080: 20 49 4e 54 20 44 45 46 41 55 4c 54 20 31 36 29 INT DEFAULT 16)
+| page 2 offset 4096
+| 0: 0d 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+| 4000: 00 00 00 00 00 00 00 00 07 0b 04 01 01 01 63 63 ..............cc
+| 4016: 11 05 0a 04 00 00 01 11 05 09 04 08 08 01 0f 05 ................
+| 4032: 08 04 00 00 01 01 56 07 04 01 08 01 07 10 07 06 ......V.........
+| 4048: 14 01 01 01 06 08 10 06 05 04 f5 00 01 05 10 07 ................
+| 4064: 04 04 01 01 01 04 03 10 06 03 04 01 09 01 03 10 ................
+| 4080: 06 02 04 01 00 01 02 10 06 01 04 09 01 01 02 10 ................
+| page 3 offset 8192
+| 0: 0a 00 00 00 0b 0f b0 00 0f f9 0f f2 0f eb 0f e4 ................
+| 16: 0f dd 0f d6 0f 9f 0f c7 0f be 00 00 00 00 00 00 ................
+| 4016: 07 04 01 01 01 11 e2 0b 06 04 91 00 01 11 0a 07 ................
+| 4032: 04 01 01 01 10 08 06 07 04 01 01 01 10 04 04 06 ................
+| 4048: 04 01 01 09 10 02 06 04 01 0a 01 10 00 00 00 00 ................
+| end crash-e6d070858a3a85.db
+}]} {}
+
+do_catchsql_test 12.1 {
+ SELECT CAST((SELECT b FROM t1 WHERE 16=c) AS int) FROM t1 WHERE 16=c;
+} {1 {database disk image is malformed}}
+
+#-------------------------------------------------------------------------
+reset_db
+do_test 13.0 {
+ sqlite3 db {}
+ db deserialize [decode_hexdb {
+| size 8192 pagesize 4096 filename crash-81dd2952aef34f.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 02 .....@ ........
+| 32: 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 04 ................
+| 48: 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 ................
+| 96: 00 00 00 00 0d 00 00 00 01 0f c4 00 0f c4 00 00 ................
+| 4032: 00 00 00 00 3a 11 06 17 11 11 01 61 74 61 62 6c ....:......atabl
+| 4048: 65 74 31 74 31 02 43 52 45 41 54 45 20 54 41 42 et1t1.CREATE TAB
+| 4064: 4c 45 20 74 31 28 61 20 49 4e 54 45 47 45 52 20 LE t1(a INTEGER
+| 4080: 50 52 49 4d 41 52 59 20 4b 45 59 2c 62 2c 63 29 PRIMARY KEY,b,c)
+| page 2 offset 4096
+| 0: 0d 07 70 00 02 0f eb 00 0f fa 00 00 00 00 00 00 ..p.............
+| 4064: 00 00 00 00 00 00 00 00 00 00 00 05 bf ff ff ff ................
+| 4080: ff ff ff ff ff 04 00 01 00 02 04 01 00 00 00 00 ................
+| end crash-81dd2952aef34f.db
+}]} {}
+
+do_catchsql_test 13.1 {
+ WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x-2019 FROM c WHERE x<2)
+ INSERT INTO t1(b,c) SELECT last_insert_rowid(), x FROM c;
+} {1 {database disk image is malformed}}
+
+
finish_test
diff --git a/test/date2.test b/test/date2.test
index 2815df5ec7..820420ccf5 100644
--- a/test/date2.test
+++ b/test/date2.test
@@ -30,7 +30,7 @@ do_execsql_test date2-100 {
} {}
do_catchsql_test date2-110 {
INSERT INTO t1(x,y) VALUES('now','two');
-} {1 {non-deterministic function in index expression or CHECK constraint}}
+} {1 {non-deterministic use of date() in a CHECK constraint}}
do_execsql_test date2-120 {
SELECT * FROM t1;
} {2017-07-20 one}
@@ -45,7 +45,7 @@ do_execsql_test date2-200 {
}
do_catchsql_test date2-210 {
INSERT INTO t2(x,y) VALUES(3, 'now');
-} {1 {non-deterministic function in index expression or CHECK constraint}}
+} {1 {non-deterministic use of date() in an index}}
do_execsql_test date2-220 {
SELECT x, y FROM t2 ORDER BY x;
} {1 2017-07-20 2 xyzzy}
@@ -58,7 +58,7 @@ do_execsql_test date2-300 {
}
do_catchsql_test date2-310 {
CREATE INDEX t3b1 ON t3(datetime(b));
-} {1 {non-deterministic function in index expression or CHECK constraint}}
+} {1 {non-deterministic use of datetime() in an index}}
do_catchsql_test date2-320 {
CREATE INDEX t3b1 ON t3(datetime(b)) WHERE typeof(b)='real';
} {0 {}}
@@ -84,7 +84,7 @@ do_execsql_test date2-400 {
do_catchsql_test date2-410 {
CREATE INDEX t4b1 ON t4(b)
WHERE date(b) BETWEEN '2017-06-01' AND '2017-08-31';
-} {1 {non-deterministic function in index expression or CHECK constraint}}
+} {1 {non-deterministic use of date() in an index}}
do_execsql_test date2-420 {
DELETE FROM t4 WHERE a=500;
CREATE INDEX t4b1 ON t4(b)
@@ -92,7 +92,7 @@ do_execsql_test date2-420 {
}
do_catchsql_test date2-430 {
INSERT INTO t4(a,b) VALUES(9999,'now');
-} {1 {non-deterministic function in index expression or CHECK constraint}}
+} {1 {non-deterministic use of date() in an index}}
do_execsql_test date2-500 {
CREATE TABLE mods(x);
@@ -121,14 +121,49 @@ do_execsql_test date2-500 {
}
do_catchsql_test date2-510 {
INSERT INTO t5(y,m) VALUES('2017-07-20','localtime');
-} {1 {non-deterministic function in index expression or CHECK constraint}}
+} {1 {non-deterministic use of datetime() in an index}}
do_catchsql_test date2-520 {
INSERT INTO t5(y,m) VALUES('2017-07-20','utc');
-} {1 {non-deterministic function in index expression or CHECK constraint}}
+} {1 {non-deterministic use of datetime() in an index}}
+
+# 2019-10-30 Ticket 830277d9db6c3ba1
+#
+do_catchsql_test date2-600 {
+ CREATE TABLE t600(a REAL CHECK( a(b=3 AND 0),a)
+ FROM dual LEFT JOIN t1;
+} {0}
+do_execsql_test expr-16.101 {
+ SELECT implies_nonnull_row( (b=1 AND 0)>(b=3 AND a=4),a)
+ FROM dual LEFT JOIN t1;
+} {1}
+do_execsql_test expr-16.102 {
+ SELECT implies_nonnull_row( (b=1 AND a=2)>(b=3 AND a=4),a)
+ FROM dual LEFT JOIN t1;
+} {1}
+
finish_test
diff --git a/test/filter1.test b/test/filter1.test
index 85e43a68bb..ee17099d99 100644
--- a/test/filter1.test
+++ b/test/filter1.test
@@ -164,5 +164,44 @@ do_execsql_test 4.4 {
SELECT a, avg(c) FILTER (WHERE b!=1) FROM t1 GROUP BY a ORDER BY 2
} {c 2.0 b 5.0 a 10.0}
-finish_test
+#-------------------------------------------------------------------------
+reset_db
+do_execsql_test 5.0 {
+ CREATE TABLE t1(a, b);
+ INSERT INTO t1 VALUES(1, 2);
+ INSERT INTO t1 VALUES(1, 3);
+}
+do_execsql_test 5.1 {
+ SELECT count(*) FILTER (WHERE b>2) FROM (SELECT * FROM t1)
+} {1}
+
+do_execsql_test 5.2 {
+ SELECT count(*) FILTER (WHERE b>2) OVER () FROM (SELECT * FROM t1)
+} {1 1}
+
+do_execsql_test 5.3 {
+ SELECT count(*) FILTER (WHERE b>2) OVER (ORDER BY b) FROM (SELECT * FROM t1)
+} {0 1}
+
+#-------------------------------------------------------------------------
+reset_db
+do_execsql_test 6.0 {
+ CREATE TABLE t1(a,b);
+ INSERT INTO t1 VALUES(1,1);
+ INSERT INTO t1 VALUES(2,2);
+ CREATE TABLE t2(x,y);
+ INSERT INTO t2 VALUES(1,1);
+}
+
+do_execsql_test 6.1 {
+ SELECT (SELECT COUNT(a) FILTER(WHERE x) FROM t2) FROM t1;
+} {1 1}
+do_execsql_test 6.2 {
+ SELECT (SELECT COUNT(a+x) FROM t2) FROM t1;
+} {1 1}
+do_execsql_test 6.3 {
+ SELECT (SELECT COUNT(a) FROM t2) FROM t1;
+} {2}
+
+finish_test
diff --git a/test/fkey2.test b/test/fkey2.test
index 86316f2936..e7fa7b6457 100644
--- a/test/fkey2.test
+++ b/test/fkey2.test
@@ -987,7 +987,7 @@ ifcapable altertable {
'main', 'table', 't1', $zCreate, $zOld, $zNew, 0
)}
}
- sqlite3_test_control SQLITE_TESTCTRL_INTERNAL_FUNCTIONS 1
+ sqlite3_test_control SQLITE_TESTCTRL_INTERNAL_FUNCTIONS db
do_test fkey2-14.2.1.1 {
test_rename_parent {CREATE TABLE t1(a REFERENCES t2)} t2 t3
} {{CREATE TABLE t1(a REFERENCES "t3")}}
@@ -997,7 +997,7 @@ ifcapable altertable {
do_test fkey2-14.2.1.3 {
test_rename_parent {CREATE TABLE t1(a REFERENCES "t2")} t2 t3
} {{CREATE TABLE t1(a REFERENCES "t3")}}
- sqlite3_test_control SQLITE_TESTCTRL_INTERNAL_FUNCTIONS 0
+ sqlite3_test_control SQLITE_TESTCTRL_INTERNAL_FUNCTIONS db
# Test ALTER TABLE RENAME TABLE a bit.
#
@@ -1070,7 +1070,7 @@ ifcapable altertable {
}
} {{CREATE TABLE t2(a, b, c REFERENCES t1, d DEFAULT NULL REFERENCES t1, e REFERENCES t1 DEFAULT NULL, h DEFAULT 'text' REFERENCES t1)}}
- sqlite3_test_control SQLITE_TESTCTRL_INTERNAL_FUNCTIONS 1
+ sqlite3_test_control SQLITE_TESTCTRL_INTERNAL_FUNCTIONS db
do_test fkey2-14.2tmp.1.1 {
test_rename_parent {CREATE TABLE t1(a REFERENCES t2)} t2 t3
} {{CREATE TABLE t1(a REFERENCES "t3")}}
@@ -1080,7 +1080,7 @@ ifcapable altertable {
do_test fkey2-14.2tmp.1.3 {
test_rename_parent {CREATE TABLE t1(a REFERENCES "t2")} t2 t3
} {{CREATE TABLE t1(a REFERENCES "t3")}}
- sqlite3_test_control SQLITE_TESTCTRL_INTERNAL_FUNCTIONS 0
+ sqlite3_test_control SQLITE_TESTCTRL_INTERNAL_FUNCTIONS db
# Test ALTER TABLE RENAME TABLE a bit.
#
@@ -1154,7 +1154,7 @@ ifcapable altertable {
}
} {{CREATE TABLE t2(a, b, c REFERENCES t1, d DEFAULT NULL REFERENCES t1, e REFERENCES t1 DEFAULT NULL, h DEFAULT 'text' REFERENCES t1)}}
- sqlite3_test_control SQLITE_TESTCTRL_INTERNAL_FUNCTIONS 1
+ sqlite3_test_control SQLITE_TESTCTRL_INTERNAL_FUNCTIONS db
do_test fkey2-14.2aux.1.1 {
test_rename_parent {CREATE TABLE t1(a REFERENCES t2)} t2 t3
} {{CREATE TABLE t1(a REFERENCES "t3")}}
@@ -1164,7 +1164,7 @@ ifcapable altertable {
do_test fkey2-14.2aux.1.3 {
test_rename_parent {CREATE TABLE t1(a REFERENCES "t2")} t2 t3
} {{CREATE TABLE t1(a REFERENCES "t3")}}
- sqlite3_test_control SQLITE_TESTCTRL_INTERNAL_FUNCTIONS 0
+ sqlite3_test_control SQLITE_TESTCTRL_INTERNAL_FUNCTIONS db
# Test ALTER TABLE RENAME TABLE a bit.
#
diff --git a/test/format4.test b/test/format4.test
index 14d794709b..a850ce2e42 100644
--- a/test/format4.test
+++ b/test/format4.test
@@ -17,7 +17,8 @@
set testdir [file dirname $argv0]
source $testdir/tester.tcl
-db eval {PRAGMA legacy_file_format=OFF}
+#db eval {PRAGMA legacy_file_format=OFF}
+sqlite3_db_config db LEGACY_FILE_FORMAT 0
# The size of the database depends on whether or not autovacuum
# is enabled.
diff --git a/test/fts3atoken.test b/test/fts3atoken.test
index 1dccf41266..4981480b5e 100644
--- a/test/fts3atoken.test
+++ b/test/fts3atoken.test
@@ -129,6 +129,29 @@ do_test fts3atoken-1.9 {
}
} {1 blob blob blob blob}
+# 2019-12-31: The fts3_tokenizer() function can never be invoked from
+# within a trigger or view.
+#
+do_catchsql_test fts3atoken-1.10 {
+ CREATE VIEW v110(x) AS
+ SELECT fts3_tokenizer('tok110', fts3_tokenizer('simple')) IS NULL;
+} {0 {}}
+do_catchsql_test fts3atoken-1.11 {
+ SELECT * FROM v110;
+} {1 {unsafe use of fts3_tokenizer()}}
+do_catchsql_test fts3atoken-1.12 {
+ CREATE TABLE t110(a,b);
+ CREATE TRIGGER r110 AFTER INSERT ON t110 BEGIN
+ SELECT fts3_tokenizer('tok110', fts3_tokenizer('simple')) IS NULL;
+ END;
+} {0 {}}
+do_catchsql_test fts3atoken-1.13 {
+ INSERT INTO t110(a,b) VALUES(1,2);
+} {1 {unsafe use of fts3_tokenizer()}}
+do_catchsql_test fts3atoken-1.14 {
+ SELECT * FROM t110;
+} {0 {}}
+
#--------------------------------------------------------------------------
# Test cases fts3atoken-2.* test error cases in the scalar function based
# API for getting and setting tokenizers.
diff --git a/test/fts3auto.test b/test/fts3auto.test
index 4abf06ff98..c2887cbf08 100644
--- a/test/fts3auto.test
+++ b/test/fts3auto.test
@@ -570,6 +570,11 @@ foreach {tn create} {
do_fts3query_test 4.$tn.4.3 -deferred fi* t1 {on* NEAR/1 fi*}
do_fts3query_test 4.$tn.4.4 -deferred fi* t1 {on* NEAR/2 fi*}
do_fts3query_test 4.$tn.4.5 -deferred fi* t1 {on* NEAR/3 fi*}
+
+ db eval {UPDATE t1_stat SET value=x'' WHERE id=0}
+ do_catchsql_test 4.$tn.4.6 {
+ SELECT docid FROM t1 WHERE t1 MATCH 'on* NEAR/3 fi*'
+ } {1 {database disk image is malformed}}
}
#--------------------------------------------------------------------------
diff --git a/test/fts3corrupt.test b/test/fts3corrupt.test
index 664b1393b8..4019509a0e 100644
--- a/test/fts3corrupt.test
+++ b/test/fts3corrupt.test
@@ -165,5 +165,20 @@ do_catchsql_test 5.3 {
} {1 {database disk image is malformed}}
do_test 5.3.1 { sqlite3_extended_errcode db } SQLITE_CORRUPT_VTAB
+# 2019-11-18 https://bugs.chromium.org/p/chromium/issues/detail?id=1025467
+# bug1
+db close
+sqlite3 db :memory:
+do_catchsql_test 6.10 {
+ CREATE VIRTUAL TABLE f using fts3(a,b);
+ CREATE TABLE f_stat(id INTEGER PRIMARY KEY, value BLOB);
+ INSERT INTO f_segdir VALUES (2000, 0,0,0, '16', '');
+ INSERT INTO f_segdir VALUES (1999, 0,0,0, '0 18',
+ x'000131030102000103323334050101010200');
+ INSERT INTO f_segments (blockid) values (16);
+ INSERT INTO f_segments values (0, x'');
+ INSERT INTO f_stat VALUES (1,x'cf0f01');
+ INSERT INTO f(f) VALUES ("merge=1");
+} {1 {database disk image is malformed}}
finish_test
diff --git a/test/fts3corrupt4.test b/test/fts3corrupt4.test
index 3aecc2963b..7404ddeb2c 100644
--- a/test/fts3corrupt4.test
+++ b/test/fts3corrupt4.test
@@ -4139,7 +4139,7 @@ do_catchsql_test 24.1 {
PRAGMA writable_schema = 1;
WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT '4hE'+x FROM c WHERE x<72)
INSERT INTO t1(a) SELECT randomblob(2829) FROM c;
-} {0 {}}
+} {1 {database disk image is malformed}}
do_catchsql_test 24.2 {
UPDATE t1 SET b=quote((true) ) WHERE t1 MATCH 'h';
@@ -4148,7 +4148,7 @@ do_catchsql_test 24.2 {
do_catchsql_test 24.3 {
WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT 3+x FROM c WHERE x<72)
INSERT INTO t1(a) SELECT randomblob(2829) FROM c;
-} {0 {}}
+} {1 {database disk image is malformed}}
do_catchsql_test 24.4 {
WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT null<.$..
+| 80: 0b 48 00 00 00 00 00 00 00 00 00 00 00 00 00 00 .H..............
+| 2880: 00 00 00 00 00 00 00 00 81 3f 25 06 00 82 7f 00 .........?%.....
+| 2896: 00 43 4f 4d 50 49 4c 45 52 3d 67 63 63 2d 35 2e .COMPILER=gcc-5.
+| 2912: 34 2e 30 20 32 30 31 36 30 36 30 39 20 44 45 42 4.0 20160609 DEB
+| 2928: 55 47 20 45 4e 41 42 4c 45 20 44 42 53 54 7e 54 UG ENABLE DBST~T
+| 2944: 20 56 54 41 42 20 45 4e 41 42 4c 45 20 46 54 53 VTAB ENABLE FTS
+| 2960: 44 20 45 4e 41 42 4c 45 20 46 54 53 35 20 45 4e D 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 4c 45 20 4a 53 4f 4e 31 20 45 4e 41 42 4c 45 BLE 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 54 41 46 45 3d 30 58 42 49 .THREADTAFE=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 bd 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 4e IT LOAD EXTENSIN
+| 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 44 20 45 58 54 45 4e 53 OMIT LOAD EXTENS
+| 3248: 49 4f 4e 58 52 54 52 49 4d 1f 1e 05 00 33 0f 19 IONXRTRIM....3..
+| 3264: 4d 41 58 1f 4d 45 4d 4f 52 59 3d 35 30 30 30 30 MAX.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 44 4d 4f 52 59 3d 35 30 30 ..MAX MDMORY=500
+| 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 55 20 52 54 52 45 45 58 4e 4f 43 41 53 45 17 LU RTREEXNOCASE.
+| 3408: 19 05 00 25 0f 17 45 4e 41 42 4c 45 20 52 54 52 ...%..ENABLE 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 4c NARY....)..ENABL
+| 3472: 45 20 4d 45 4d 53 59 53 35 58 4e 3f 43 41 53 45 E MEMSYS5XN?CASE
+| 3488: 19 16 05 00 29 0f 17 45 4e a1 42 4c 45 20 4d 45 ....)..EN.BLE 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 1a 12 05 00 29 0f 19 45 N1XRTRIM....)..E
+| 3600: 4e 41 42 4c 45 20 47 45 4f 50 5f 4c 59 58 42 49 NABLE GEOP_LYXBI
+| 3616: 4e 41 52 59 1a 11 05 00 29 0f 19 45 4e 41 42 4c NARY....)..ENABL
+| 3632: 45 20 47 45 4f 50 4f 4c 59 58 4b bf 43 41 53 45 E GEOPOLYXK.CASE
+| 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 55 20 46 54 53 35 58 42 49 ..ENABLU FTS5XBI
+| 3696: 4e 4b a2 59 17 0e 05 00 23 0f 19 45 4e 41 42 4c NK.Y....#..ENABL
+| 3712: 45 20 46 54 52 35 58 4e 4f 43 41 53 45 16 0d 05 E FTR5XNOCASE...
+| 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 0b 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 17 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 07 e1 0f 19 45 4e 41 42 4c 45 20 44 42 53 ......ENABLE DBS
+| 3840: 54 41 54 20 56 54 41 42 58 42 49 4e 41 52 59 1e TAT VTABXBINARY.
+| 3856: 18 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 41 18 4e 4f 43 41 53 45 1d TAT VTAA.NOCASE.
+| 3888: 07 05 00 31 0f 17 45 4e 41 42 4c 45 20 44 32 53 ...1..ENABLE D2S
+| 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 00 00 00 00 00 00 Y.......DE......
+| page 5 offset 16384
+| 0: 0d 00 00 00 02 0b a0 00 0c ad 0b a0 01 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 30 36 ..0.%.....201606
+| 3008: 30 38 03 25 07 00 00 01 34 03 25 05 00 00 01 35 08.%....4.%....5
+| 3024: 03 25 13 00 01 07 30 30 30 30 30 30 30 03 25 1a .%....0000000.%.
+| 3040: 00 00 08 63 6f 6d 70 69 6c 65 72 03 25 02 00 00 ...compiler.%...
+| 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 6e 73 69 6f .........xtensio
+| 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 6f 6c 79 03 25 11 00 00 05 6a 73 6f .eopoly.%....jso
+| 3152: 6e 31 03 25 13 00 00 04 6c 6f 61 64 03 25 1c 00 n1.%....load.%..
+| 3168: 00 03 6d 62 78 03 25 18 00 01 05 65 6d 6f 72 79 ..mbx.%....emory
+| 3184: 03 25 19 00 03 04 73 c8 73 35 03 25 15 00 00 04 .%....s.s5.%....
+| 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 02 04 ......5.........
+| 3328: 00 01 07 30 2f 30 30 30 30 30 09 1c 04 00 01 04 ...0/00000......
+| 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 02 00 03 01 02 02 00 03 01 02 02 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 61 6c 2c 65 3f 07 02 00 01 02 00 01 02 .enal,e?........
+| 3488: 00 01 02 00 01 02 00 01 02 00 01 02 00 01 02 00 ................
+| 3504: 01 02 00 01 02 00 01 02 00 01 01 ff f1 02 00 01 ................
+| 3520: 02 00 01 02 00 01 02 00 f1 02 00 01 02 00 01 4f ...............O
+| 3536: 00 01 02 00 01 02 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 00 f3 00 03 01 35 09 0d 4............5..
+| 3584: 03 00 01 04 00 01 03 00 00 03 67 63 63 09 01 03 ..........gcc...
+| 3600: 00 01 03 00 01 03 00 01 06 65 6f 70 6f 6c 79 09 .........eopoly.
+| 3616: 10 03 00 01 03 00 01 03 00 00 05 6a 73 6f 6e 31 ...........json1
+| 3632: 09 13 03 00 01 02 ff 01 03 00 00 04 6c 6f 61 63 ............loac
+| 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 64 6d 6f 72 79 ...........dmory
+| 3680: 09 1c 03 00 01 03 00 01 03 00 03 04 73 79 73 35 ............sys5
+| 3696: 09 16 02 f0 01 03 00 01 03 00 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 4b 01 02 02 00 ...........K....
+| 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 72 65 65 09 19 03 00 01 03 00 01 03 00 .rtree..........
+| 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 02 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 01 02 00 00 04 76 74 61 62 09 07 04 .........vtab...
+| 3904: 00 01 04 00 01 04 00 00 01 78 b4 01 01 01 01 02 .........x......
+| 3920: 00 01 f4 01 02 00 01 02 01 02 00 01 01 01 02 ff ................
+| 3936: 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 01 ................
+| 3952: 01 01 02 ae 01 01 01 02 00 01 01 01 02 00 01 01 ................
+| 3968: 01 12 00 01 01 01 02 00 01 01 01 02 00 01 01 01 ................
+| 3984: 12 00 01 01 01 02 01 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 02 00 01 01 01 02 00 01 01 ................
+| 4048: 01 02 00 01 01 01 02 00 01 76 01 02 00 01 01 01 .........v......
+| 4064: 02 00 01 01 01 02 01 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 00 00 00 00 ................
+| 4080: 00 00 00 00 00 05 04 08 09 01 02 04 04 08 08 09 ................
+| end crash-74fdbc96edbc04.db
+}]} {}
+
+do_catchsql_test 32.1 {
+ UPDATE t1 SET b=quote(zeroblob(6.51158946e+5)) WHERE a MATCH '*t*';
+} {1 {database disk image is malformed}}
+
+#do_catchsql_test 32.2 {
+# UPDATE t1 SET b=((- '' )) WHERE a MATCH '0*t';
+#} {1 {database disk image is malformed}}
+
+#-------------------------------------------------------------------------
+#
+ifcapable icu {
+ reset_db
+ do_catchsql_test 33.0 {
+ CREATE VIRTUAL TABLE f USING fts3(a,b,tokenize=icu);
+ CREATE TABLE 'f_docsize'(docid INTEGER PRIMARY KEY, size BLOB);
+ CREATE TABLE 'f_stat'(id INTEGER PRIMARY KEY, value BLOB);
+ INSERT INTO f VALUES (1, '1234');
+ INSERT INTO f_stat VALUES (1,x'0000000165656565db6569746565c5c52bc5c5c53e3a003bc502ffffffffc5c5c53e3a003bc502fffffffffb8b2afbfb6565f0740100650000000165656565db6569746565c5c52bc5c5c53e3a003bc502ffffffffc5c5c53e3a003b8b00c5c5c5c5c5bfc5');
+ INSERT INTO f(f) VALUES ('merge=198,49');
+ } {1 {database disk image is malformed}}
+}
+
+#-------------------------------------------------------------------------
+#
+reset_db
+do_execsql_test 34.0 {
+ CREATE VIRTUAL TABLE f USING fts3(a,b);
+ INSERT INTO f VALUES (1, '1234');
+ INSERT INTO f_segdir VALUES (1,255,0,0,'1 255',x'00');
+ UPDATE f_segdir SET level = 0 WHERE level IN (
+ SELECT level FROM f_segdir LIMIT 1 OFFSET 1
+ );
+ INSERT INTO f_segdir VALUES (255,249,0,121,'0 0',x'00');
+ INSERT INTO f_content VALUES (255,0,x'ff');
+ INSERT INTO f_segdir VALUES (1,255,16,0,'1 255',x'00');
+}
+
+do_catchsql_test 34.1 {
+ UPDATE f SET b = x'00' WHERE b IN (SELECT b FROM f LIMIT 1 OFFSET 0);
+} {1 {database disk image is malformed}}
+
+#-------------------------------------------------------------------------
+#
+reset_db
+do_execsql_test 35.0 {
+ CREATE VIRTUAL TABLE f USING fts3(a,b);
+ INSERT INTO f_segdir VALUES (1,255,0,0,'1 255',x'0001ff000001ff000001ff000001ff000001ff00c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5bec5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5');
+}
+
+do_catchsql_test 35.1 {
+ INSERT INTO f(f) VALUES ('integrity-check');
+} {1 {database disk image is malformed}}
+
+reset_db
+do_catchsql_test 36.0 {
+ CREATE VIRTUAL TABLE f USING fts3(a,tokenize=porter);
+ CREATE TABLE 'f_stat'(id INTEGER PRIMARY KEY, value BLOB);
+ INSERT INTO f VALUES (1);
+ INSERT INTO f_stat VALUES (1,x'00000000000101010119013d00ffff0400fa83717b71a69297979701f63d010101010101010101010101190000000000000000fa83717b71a601f63d01010101010101010101010119013d00ffffff0400fa83717b71a69297979701f63d010101010101010101010101190000000000000000fa83717b71a69201f63d010101f63d01010101010101010101010119013d00ffffff0400fa83717b71a6929797010101010101010101010119013d00ffff01f63d01010101010101010101010119013d00ffffff0400fa83717b71a69297979701f63d00fa03ffffffa69297979701f63d010101000000000101010101197e9797976567656565ffa63535354e');
+ INSERT INTO f(f) VALUES ('merge=53,216');
+} {0 {}}
+
finish_test
diff --git a/test/fts3cov.test b/test/fts3cov.test
index 95269a6b0b..5d83836576 100644
--- a/test/fts3cov.test
+++ b/test/fts3cov.test
@@ -97,7 +97,7 @@ do_test fts3cov-2.2 {
} {}
do_error_test fts3cov-2.3 {
SELECT * FROM t1 WHERE t1 MATCH 'c*'
-} {SQL logic error}
+} {database disk image is malformed}
# Test the "replaced with NULL" case:
do_test fts3cov-2.4 {
@@ -105,7 +105,7 @@ do_test fts3cov-2.4 {
} {}
do_error_test fts3cov-2.5 {
SELECT * FROM t1 WHERE t1 MATCH 'cloud'
-} {SQL logic error}
+} {database disk image is malformed}
#--------------------------------------------------------------------------
# The following tests are to test the effects of OOM errors while storing
diff --git a/test/fts3misc.test b/test/fts3misc.test
index 60126dd6b4..92b93d033d 100644
--- a/test/fts3misc.test
+++ b/test/fts3misc.test
@@ -226,5 +226,81 @@ do_execsql_test 6.1 {
SELECT rowid FROM t6 WHERE t6 MATCH 'b OR "x a"'
} {50001 50002 50003 50004}
+#-------------------------------------------------------------------------
+#
+reset_db
+do_execsql_test 7.0 {
+ CREATE VIRTUAL TABLE vt0 USING fts3(c0);
+ INSERT INTO vt0 VALUES (x'00');
+}
+do_execsql_test 7.1 {
+ INSERT INTO vt0(vt0) VALUES('integrity-check');
+}
+
+#-------------------------------------------------------------------------
+# Ticket [8a6fa2bb].
+#
+reset_db
+do_execsql_test 7.0.1 {
+ CREATE VIRTUAL TABLE vt0 USING fts4(c0, order=DESC);
+ INSERT INTO vt0(c0) VALUES (0), (0);
+}
+do_execsql_test 7.0.2 {
+ INSERT INTO vt0(vt0) VALUES('integrity-check');
+}
+reset_db
+do_execsql_test 7.1.1 {
+ CREATE VIRTUAL TABLE vt0 USING fts4(c0, order=ASC);
+ INSERT INTO vt0(c0) VALUES (0), (0);
+}
+do_execsql_test 7.1.2 {
+ INSERT INTO vt0(vt0) VALUES('integrity-check');
+}
+do_execsql_test 7.2.1 {
+ CREATE VIRTUAL TABLE ft USING fts4(c0, c1, order=DESC, prefix=1);
+ INSERT INTO ft VALUES('a b c d', 'hello world');
+ INSERT INTO ft VALUES('negative', 'positive');
+ INSERT INTO ft VALUES('hello world', 'a b c d');
+}
+do_execsql_test 7.2.2 {
+ INSERT INTO vt0(vt0) VALUES('integrity-check');
+}
+
+#-------------------------------------------------------------------------
+# Ticket [745f1abc].
+#
+reset_db
+do_execsql_test 8.1 {
+ CREATE VIRTUAL TABLE vt0 USING fts4(c0, prefix=1);
+}
+do_execsql_test 8.2 {
+ BEGIN;
+ INSERT INTO vt0 VALUES (0);
+ INSERT INTO vt0(vt0) VALUES('optimize');
+ COMMIT;
+}
+do_execsql_test 8.3 {
+ INSERT INTO vt0(vt0) VALUES('integrity-check');
+}
+
+#-------------------------------------------------------------------------
+#
+reset_db
+do_execsql_test 9.0 {
+ CREATE VIRTUAL TABLE t1 using fts4(mailcontent);
+ insert into t1(rowid, mailcontent) values
+ (-4764623217061966105, 'we are going to upgrade'),
+ (8324454597464624651, 'we are going to upgrade');
+}
+
+do_execsql_test 9.1 {
+ INSERT INTO t1(t1) VALUES('integrity-check');
+}
+
+do_execsql_test 9.2 {
+ SELECT rowid FROM t1 WHERE t1 MATCH 'upgrade';
+} {
+ -4764623217061966105 8324454597464624651
+}
finish_test
diff --git a/test/fts3snippet.test b/test/fts3snippet.test
index 976c8c8492..749aa4e0b8 100644
--- a/test/fts3snippet.test
+++ b/test/fts3snippet.test
@@ -561,6 +561,7 @@ do_test 4.3 {
}]
} {64}
+
#-------------------------------------------------------------------------
# Request a snippet from a query with more than 64 phrases.
#
@@ -587,5 +588,18 @@ 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/fts4aa.test b/test/fts4aa.test
index e6c7f9336e..7349841dd9 100644
--- a/test/fts4aa.test
+++ b/test/fts4aa.test
@@ -191,4 +191,61 @@ foreach {q r} [array get fts4aa_res] {
} $r
}
+# 2019-11-16 https://bugs.chromium.org/p/chromium/issues/detail?id=1025472
+#
+db close
+sqlite3 db :memory:
+do_execsql_test fts4aa-5.10 {
+ CREATE VIRTUAL TABLE t1 USING fts4(a, b, c, d, e,f,g,h,i,j,k,l,m,n,o,p,q,r);
+ INSERT INTO t1 VALUES('X Y', '2', '3', '4', '5', '6', '7', '8', '9', '0',
+ 'a','b','c','d','e','f','g','h');
+ UPDATE t1_docsize SET size=x'88' WHERE docid=1;
+} {}
+do_catchsql_test fts4aa-5.20 {
+ SELECT quote(matchinfo(t1, 'l')) FROM t1 WHERE t1 MATCH 'X Y';
+} {1 {database disk image is malformed}}
+do_execsql_test fts4aa-5.30 {
+ DROP TABLE t1;
+ CREATE VIRTUAL TABLE t1 USING fts4(a,b,c,d);
+ INSERT INTO t1 VALUES('one two','three four','five six','seven eight');
+} {}
+do_catchsql_test fts4aa-5.40 {
+ UPDATE t1_stat SET value=x'01010101' WHERE id=0;
+ SELECT quote(matchinfo(t1,'a')) FROM t1 WHERE t1 MATCH 'one two';
+} {1 {database disk image is malformed}}
+do_catchsql_test fts4aa-5.50 {
+ UPDATE t1_stat SET value=x'010101' WHERE id=0;
+ SELECT quote(matchinfo(t1,'a')) FROM t1 WHERE t1 MATCH 'one two';
+} {1 {database disk image is malformed}}
+do_catchsql_test fts4aa-5.60 {
+ UPDATE t1_stat SET value=x'01' WHERE id=0;
+ SELECT quote(matchinfo(t1,'a')) FROM t1 WHERE t1 MATCH 'one two';
+} {1 {database disk image is malformed}}
+do_catchsql_test fts4aa-5.70 {
+ UPDATE t1_stat SET value=x'' WHERE id=0;
+ SELECT quote(matchinfo(t1,'a')) FROM t1 WHERE t1 MATCH 'one two';
+} {1 {database disk image is malformed}}
+
+# 2019-11-18 https://bugs.chromium.org/p/chromium/issues/detail?id=1025467
+db close
+sqlite3 db :memory:
+do_execsql_test fts4aa-6.10 {
+ CREATE VIRTUAL TABLE f USING fts4();
+ INSERT INTO f_segdir VALUES (77,91,0,0,'255 77',x'0001308000004d5c4ddddddd4d4d7b4d4d4d614d8019ff4d05000001204d4d2e4d6e4d4d4d4b4d6c4d004d4d4d4d4d4d3d000000004d5d4d4d645d4d004d4d4d4d4d4d4d4d4d454d6910004d05ffff054d646c4d004d5d4d4d4d4d3d000000004d4d4d4d4d4d4d4d4d4d4d69624d4d4d04004d4d4d4d4d604d4ce1404d554d45');
+ INSERT INTO f_segdir VALUES (77,108,0,0,'255 77',x'0001310000fa64004d4d4d3c5d4d654d4d4d614d8000ff4d05000001204d4d2e4d6e4d4d4dff4d4d4d4d4d4d00104d4d4d4d000000004d4d4d0400311d4d4d4d4d4d4d4d4d4d684d6910004d05ffff054d4d6c4d004d4d4d4d4d4d3d000000004d4d4d4d644d4d4d4d4d4d69624d4d4d03ed4d4d4d4d4d604d4ce1404d550080');
+ INSERT INTO f_stat VALUES (0,x'80808080100000000064004d4d4d3c4d4d654d4d4d614d8000ff4df6ff1a00204d4d2e4d6e4d4d4d104d4d4d4d4d4d00104d4d4d4d4d4d69574d4d4d000031044d4d4d3e4d4d4c4d05004d6910');
+ SELECT quote(matchinfo(f,'pnax')) from f where f match '0 1';
+} {X'0200000000000000000000000E0000000E00000001000000010000000100000001000000'}
+
+# 2019-11-18 Detect infinite loop in fts3SelectLeaf()
+db close
+sqlite3 db :memory:
+do_catchsql_test fts4aa-7.10 {
+ CREATE VIRTUAL TABLE f USING fts4();
+ INSERT INTO f_segdir VALUES (63,60,60,60,'60 60',x'3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c483c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c20003c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c283c3c3c3c3c3c3c3c3c3c3c223c3c3c3c3c3c3c3c3c');
+ INSERT INTO f_segments VALUES (60,x'3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c5a3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c2a3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c5e3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c803c3c3c3c3c3c233c3c3c3c1c3c3c3c3c3c3c3c3c3c3c3c1b3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c273c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c1a3c3c3c3c3c3c000200003c3c3c3c3c3c3c3c3c3c3c3c3c383c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d898d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d3c3c3c3c3c3c3c3c3c3cba3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c1c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c00023c3c3c3c3c3c383c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3cbc3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c2c3c3c3c403c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c16161616161616163c3c3c3c3c3c3c3c3c3c3c3c3c583c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c2b3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c1c013c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c20003c3c3c3c3c3c3c3c3c3c3c800000003c3c3c3c3c3c3c2c3c3c3c3c3c3c353c08080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808f4080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808083c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c323c3c3c3c3c3c3c3c3c3c3c4f3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3cfcfcfcfcfcfcfcfcfcfcfc10fcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfd02fcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfc03e8fcfcfcfc3c3c3c3c3c3c8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c553c3c3c3c3c3c3c3c3c3c3c3c3c573c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c000000803c3c4dd5d5a6d52cf3d5d5d5d5d5d5d5d5d5d5d5d5d5d53c3c3c3c3f3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c2d3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c013c3c3c3c00643c3c3c3ce93c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c263c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c363c3c3c3c3c3c3c3c3c3c3c3c3c3c543c3c3c3c3c3c3c3c3c3c273c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c330000003c3c3c3c3c3c3c3c3c3c3c3c3c3c4d3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c000010003c3c3c3c3c3c413c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c1c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c403c3c3c3c3c3c3c3c3c3c3c3cec0000fa3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c2d3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c4c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c5e3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c1b3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c593c3c3c3c3c3c243c3c373c3c3c3c3cff3c3c3c3c3c3c3c3c3c3c3c3c3c000080003c3c3c3c3c3c3c3c3c3c353c3c3c3c3c3d3c3c3c3c3c3c3c3c3c3c3c3c4d3c3c3c3c3c3c3c3c3c3c3c3c3c40003c3c3c3c3c293c3c3c3c3c3c3c3c3c3d3c3c3c3c3c3c3c3c353c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c4f3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3f3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3cff7f3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c2d3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3ca43c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3cbf3c3c3c3c3c3c3c3c3c008000003c3c3c3c3c3c3c3c343c3c373c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c593c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c');
+ SELECT * from f where f match '0';
+} {1 {database disk image is malformed}}
+
+
finish_test
diff --git a/test/fts4content.test b/test/fts4content.test
index 2da51d1516..980586ea3a 100644
--- a/test/fts4content.test
+++ b/test/fts4content.test
@@ -634,5 +634,41 @@ do_catchsql_test 11.1 {
CREATE VIRTUAL TABLE x1 USING fts4(content=x1);
} {1 {vtable constructor called recursively: x1}}
+#---------------------------------------------------------------------------
+# Check that an fts4 table cannot be its own content table.
+#
+reset_db
+breakpoint
+do_execsql_test 12.1.1 {
+ CREATE VIRTUAL TABLE t1 USING fts4(a, content=t1 );
+ INSERT INTO t1(rowid, a) VALUES(1, 'abc');
+}
+do_catchsql_test 12.1.2 {
+ SELECT * FROM t1;
+} {1 {SQL logic error}}
+do_catchsql_test 12.1.3 {
+ SELECT * FROM t1('abc');
+} {1 {SQL logic error}}
+do_catchsql_test 12.1.4 {
+ SELECT count(*) FROM t1;
+} {1 {SQL logic error}}
+
+reset_db
+do_execsql_test 12.2.1 {
+ CREATE VIRTUAL TABLE t1 USING fts4(a, content=t2 );
+ CREATE VIRTUAL TABLE t2 USING fts4(a, content=t1 );
+ INSERT INTO t1(rowid, a) VALUES(1, 'abc');
+}
+do_catchsql_test 12.2.2 {
+ SELECT * FROM t1;
+} {1 {SQL logic error}}
+do_catchsql_test 12.2.3 {
+ SELECT * FROM t1('abc');
+} {1 {SQL logic error}}
+do_catchsql_test 12.2.4 {
+ SELECT count(*) FROM t1;
+} {1 {SQL logic error}}
+
+
finish_test
diff --git a/test/fts4langid.test b/test/fts4langid.test
index 9fffe95219..45e851f940 100644
--- a/test/fts4langid.test
+++ b/test/fts4langid.test
@@ -489,4 +489,19 @@ foreach lid [list 4 [expr 1<<30]] {
SELECT count(*) FROM t6_segments;
} {1 2}
}
+
+reset_db
+do_execsql_test 6.0 {
+ CREATE VIRTUAL TABLE vt0 USING fts4(c0, languageid="lid");
+ INSERT INTO vt0 VALUES ('a'), ('b');
+ BEGIN;
+ UPDATE vt0 SET lid = 1 WHERE lid=0;
+}
+do_execsql_test 6.1 {
+ INSERT INTO vt0(vt0) VALUES('integrity-check');
+}
+do_execsql_test 6.2 {
+ COMMIT;
+ INSERT INTO vt0(vt0) VALUES('integrity-check');
+}
finish_test
diff --git a/test/fts4merge.test b/test/fts4merge.test
index 48661afd71..3cd693209d 100644
--- a/test/fts4merge.test
+++ b/test/fts4merge.test
@@ -326,7 +326,22 @@ foreach mod {fts3 fts4} {
execsql { INSERT INTO t1(t1) VALUES('merge=200,10') }
expr { ([db total_changes] - $x)>1 }
} {0}
+}
+#-------------------------------------------------------------------------
+# Test cases 8.* - ticket [bf1aab89].
+#
+set testprefix fts4merge
+reset_db
+do_execsql_test 8.0 {
+ CREATE VIRTUAL TABLE t1 USING fts4(a, order=DESC);
+ INSERT INTO t1(a) VALUES (0);
+ INSERT INTO t1(a) VALUES (0);
+ UPDATE t1 SET a = NULL;
+}
+
+do_execsql_test 8.1 {
+ INSERT INTO t1(t1) VALUES('merge=1,4');
}
finish_test
diff --git a/test/func.test b/test/func.test
index 7315af322a..34a6f18bcf 100644
--- a/test/func.test
+++ b/test/func.test
@@ -315,9 +315,9 @@ ifcapable floatingpoint {
do_test func-4.38 {
execsql {SELECT round(9999999999999.556,2);}
} {9999999999999.56}
- do_execsql_test func-4.39 {
- SELECT round(1e500), round(-1e500);
- } {Inf -Inf}
+ do_test func-4.39 {
+ string tolower [db eval {SELECT round(1e500), round(-1e500);}]
+ } {inf -inf}
}
# Test the upper() and lower() functions
@@ -1430,7 +1430,7 @@ do_test func-33.1 {
do_catchsql_test func-33.2 {
CREATE VIEW v33(y) AS SELECT testdirectonly(15);
SELECT * FROM v33;
-} {1 {testdirectonly() prohibited in triggers and views}}
+} {1 {unsafe use of testdirectonly()}}
do_execsql_test func-33.3 {
SELECT * FROM (SELECT testdirectonly(15)) AS v33;
} {30}
@@ -1441,7 +1441,7 @@ do_execsql_test func-33.4 {
do_catchsql_test func-33.5 {
WITH c(x) AS (SELECT * FROM v33)
SELECT * FROM c;
-} {1 {testdirectonly() prohibited in triggers and views}}
+} {1 {unsafe use of testdirectonly()}}
do_execsql_test func-33.10 {
CREATE TABLE t33a(a,b);
CREATE TABLE t33b(x,y);
@@ -1451,7 +1451,7 @@ do_execsql_test func-33.10 {
} {}
do_catchsql_test func-33.11 {
INSERT INTO t33a VALUES(1,2);
-} {1 {testdirectonly() prohibited in triggers and views}}
+} {1 {unsafe use of testdirectonly()}}
do_execsql_test func-33.20 {
ALTER TABLE t33a RENAME COLUMN a TO aaa;
SELECT sql FROM sqlite_master WHERE name='r1';
@@ -1459,5 +1459,22 @@ do_execsql_test func-33.20 {
INSERT INTO t33b(x,y) VALUES(testdirectonly(new.aaa),new.b);
END}}
+# 2020-01-09 Yongheng fuzzer find
+# The bug is in the register-validity debug logic, not in the SQLite core
+# and as such it only impacts debug builds. Release builds work fine.
+#
+reset_db
+do_execsql_test func-34.10 {
+ CREATE TABLE t1(a INT CHECK(
+ datetime( 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10,11,12,13,14,15,16,17,18,19,
+ 20,21,22,23,24,25,26,27,28,29,
+ 30,31,32,33,34,35,36,37,38,39,
+ 40,41,42,43,44,45,46,47,48,a)
+ )
+ );
+ INSERT INTO t1(a) VALUES(1),(2);
+ SELECT * FROM t1;
+} {1 2}
finish_test
diff --git a/test/fuzzcheck.c b/test/fuzzcheck.c
index 4d52aedea9..4f3321f0a1 100644
--- a/test/fuzzcheck.c
+++ b/test/fuzzcheck.c
@@ -134,6 +134,7 @@ struct Blob {
*/
static struct GlobalVars {
const char *zArgv0; /* Name of program */
+ const char *zDbFile; /* Name of database file */
VFile aFile[MX_FILE]; /* The virtual filesystem */
int nDb; /* Number of template databases */
Blob *pFirstDb; /* Content of first template database */
@@ -148,11 +149,10 @@ static struct GlobalVars {
*/
static void fatalError(const char *zFormat, ...){
va_list ap;
- if( g.zTestName[0] ){
- fprintf(stderr, "%s (%s): ", g.zArgv0, g.zTestName);
- }else{
- fprintf(stderr, "%s: ", g.zArgv0);
- }
+ fprintf(stderr, "%s", g.zArgv0);
+ if( g.zDbFile ) fprintf(stderr, " %s", g.zDbFile);
+ if( g.zTestName[0] ) fprintf(stderr, " (%s)", g.zTestName);
+ fprintf(stderr, ": ");
va_start(ap, zFormat);
vfprintf(stderr, zFormat, ap);
va_end(ap);
@@ -161,12 +161,21 @@ static void fatalError(const char *zFormat, ...){
}
/*
-** Timeout handler
+** signal handler
*/
#ifdef __unix__
-static void timeoutHandler(int NotUsed){
- (void)NotUsed;
- fatalError("timeout\n");
+static void signalHandler(int signum){
+ const char *zSig;
+ if( signum==SIGABRT ){
+ zSig = "abort";
+ }else if( signum==SIGALRM ){
+ zSig = "timeout";
+ }else if( signum==SIGSEGV ){
+ zSig = "segfault";
+ }else{
+ zSig = "signal";
+ }
+ fatalError(zSig);
}
#endif
@@ -453,6 +462,9 @@ static unsigned int mxProgressCb = 2000;
/* Maximum string length in SQLite */
static int lengthLimit = 1000000;
+/* Limit on the amount of heap memory that can be used */
+static sqlite3_int64 heapLimit = 1000000000;
+
/* Maximum byte-code program length in SQLite */
static int vdbeOpLimit = 25000;
@@ -777,6 +789,7 @@ int runCombinedDbSqlInput(const uint8_t *aData, size_t nByte){
if( lengthLimit>0 ){
sqlite3_limit(cx.db, SQLITE_LIMIT_LENGTH, lengthLimit);
}
+ sqlite3_hard_heap_limit64(heapLimit);
if( nDb>=20 && aDb[18]==2 && aDb[19]==2 ){
aDb[18] = aDb[19] = 1;
@@ -1307,6 +1320,7 @@ static void showHelp(void){
" --sqlid N Use only SQL where sqlid=N\n"
" --timeout N Abort if any single test needs more than N seconds\n"
" -v|--verbose Increased output. Repeat for more output.\n"
+" --vdbe-debug Activate VDBE debugging.\n"
);
}
@@ -1341,7 +1355,7 @@ int main(int argc, char **argv){
int cellSzCkFlag = 0; /* --cell-size-check */
int sqlFuzz = 0; /* True for SQL fuzz. False for DB fuzz */
int iTimeout = 120; /* Default 120-second timeout */
- int nMem = 0; /* Memory limit */
+ int nMem = 0; /* Memory limit override */
int nMemThisDb = 0; /* Memory limit set by the CONFIG table */
char *zExpDb = 0; /* Write Databases to files in this directory */
char *zExpSql = 0; /* Write SQL to files in this directory */
@@ -1356,7 +1370,9 @@ int main(int argc, char **argv){
sqlite3_initialize();
iBegin = timeOfDay();
#ifdef __unix__
- signal(SIGALRM, timeoutHandler);
+ signal(SIGALRM, signalHandler);
+ signal(SIGSEGV, signalHandler);
+ signal(SIGABRT, signalHandler);
#endif
g.zArgv0 = argv[0];
openFlags4Data = SQLITE_OPEN_READONLY;
@@ -1391,13 +1407,8 @@ int main(int argc, char **argv){
infoFlag = 1;
}else
if( strcmp(z,"limit-mem")==0 ){
-#if !defined(SQLITE_ENABLE_MEMSYS3) && !defined(SQLITE_ENABLE_MEMSYS5)
- fatalError("the %s option requires -DSQLITE_ENABLE_MEMSYS5 or _MEMSYS3",
- argv[i]);
-#else
if( i>=argc-1 ) fatalError("missing arguments on %s", argv[i]);
nMem = integerValue(argv[++i]);
-#endif
}else
if( strcmp(z,"limit-vdbe")==0 ){
vdbeLimitFlag = 1;
@@ -1465,6 +1476,9 @@ int main(int argc, char **argv){
fatalError("timeout is not available on non-unix systems");
#endif
}else
+ if( strcmp(z,"vdbe-debug")==0 ){
+ bVdbeDebug = 1;
+ }else
if( strcmp(z,"verbose")==0 ){
quietFlag = 0;
verboseFlag++;
@@ -1507,6 +1521,7 @@ int main(int argc, char **argv){
/* Process each source database separately */
for(iSrcDb=0; iSrcDbzName);
if( rc ){
@@ -1586,14 +1601,9 @@ int main(int argc, char **argv){
ossFuzzThisDb = sqlite3_column_int(pStmt,1);
if( verboseFlag ) printf("Config: oss-fuzz=%d\n", ossFuzzThisDb);
}
- if( strcmp(zName, "limit-mem")==0 && !nativeMalloc ){
-#if !defined(SQLITE_ENABLE_MEMSYS3) && !defined(SQLITE_ENABLE_MEMSYS5)
- fatalError("the limit-mem option requires -DSQLITE_ENABLE_MEMSYS5"
- " or _MEMSYS3");
-#else
+ if( strcmp(zName, "limit-mem")==0 ){
nMemThisDb = sqlite3_column_int(pStmt,1);
if( verboseFlag ) printf("Config: limit-mem=%d\n", nMemThisDb);
-#endif
}
}
sqlite3_finalize(pStmt);
@@ -1720,12 +1730,18 @@ int main(int argc, char **argv){
/* Limit available memory, if requested */
sqlite3_shutdown();
- if( nMemThisDb>0 && !nativeMalloc ){
- pHeap = realloc(pHeap, nMemThisDb);
- if( pHeap==0 ){
- fatalError("failed to allocate %d bytes of heap memory", nMem);
+ if( nMemThisDb>0 && nMem==0 ){
+ if( !nativeMalloc ){
+ pHeap = realloc(pHeap, nMemThisDb);
+ if( pHeap==0 ){
+ fatalError("failed to allocate %d bytes of heap memory", nMem);
+ }
+ sqlite3_config(SQLITE_CONFIG_HEAP, pHeap, nMemThisDb, 128);
+ }else{
+ sqlite3_hard_heap_limit64((sqlite3_int64)nMemThisDb);
}
- sqlite3_config(SQLITE_CONFIG_HEAP, pHeap, nMemThisDb, 128);
+ }else{
+ sqlite3_hard_heap_limit64(0);
}
/* Disable lookaside with the --native-malloc option */
@@ -1809,6 +1825,9 @@ int main(int argc, char **argv){
#ifdef SQLITE_TESTCTRL_PRNG_SEED
sqlite3_test_control(SQLITE_TESTCTRL_PRNG_SEED, 1, db);
#endif
+ if( bVdbeDebug ){
+ sqlite3_exec(db, "PRAGMA vdbe_debug=ON", 0, 0, 0);
+ }
do{
runSql(db, (char*)pSql->a, runFlags);
}while( timeoutTest );
diff --git a/test/fuzzdata1.db b/test/fuzzdata1.db
index 4b4a6b574b..091a645298 100644
Binary files a/test/fuzzdata1.db and b/test/fuzzdata1.db differ
diff --git a/test/fuzzdata8.db b/test/fuzzdata8.db
index 80c1ad0079..5f6d7467da 100644
Binary files a/test/fuzzdata8.db and b/test/fuzzdata8.db differ
diff --git a/test/gencol1.test b/test/gencol1.test
new file mode 100644
index 0000000000..5276d9694d
--- /dev/null
+++ b/test/gencol1.test
@@ -0,0 +1,563 @@
+# 2019-10-31
+#
+# The author disclaims copyright to this source code. In place of
+# a legal notice, here is a blessing:
+#
+# May you do good and not evil.
+# May you find forgiveness for yourself and forgive others.
+# May you share freely, never taking more than you give.
+#
+#***********************************************************************
+#
+# Test cases for generated columns.
+#
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+
+# ticket 830277d9db6c3ba1 on 2019-10-31
+do_execsql_test gencol1-100 {
+ CREATE TABLE t0(c0 AS(TYPEOF(c1)), c1);
+ INSERT INTO t0(c1) VALUES(0);
+ CREATE TABLE t1(x AS (typeof(y)), y);
+ INSERT INTO t1 SELECT * FROM t0;
+ SELECT * FROM t1;
+} {integer 0}
+
+foreach {tn schema} {
+1 {
+ CREATE TABLE t1(
+ a INT,
+ b TEXT,
+ c ANY,
+ w INT GENERATED ALWAYS AS (a*10),
+ x TEXT AS (typeof(c)),
+ y TEXT AS (substr(b,a,a+2))
+ );
+ }
+2 {
+ CREATE TABLE t1(
+ w INT GENERATED ALWAYS AS (a*10),
+ x TEXT AS (typeof(c)),
+ y TEXT AS (substr(b,a,a+2)),
+ a INT,
+ b TEXT,
+ c ANY
+ );
+ }
+3 {
+ CREATE TABLE t1(
+ w INT GENERATED ALWAYS AS (a*10),
+ a INT,
+ x TEXT AS (typeof(c)) STORED,
+ b TEXT,
+ y TEXT AS (substr(b,a,a+2)),
+ c ANY
+ );
+ }
+4 {
+ CREATE TABLE t1(
+ a INTEGER PRIMARY KEY,
+ w INT GENERATED ALWAYS AS (a*10),
+ b TEXT,
+ x TEXT AS (typeof(c)),
+ y TEXT AS (substr(b,a,a+2)) STORED,
+ c ANY
+ );
+ }
+5 {
+ CREATE TABLE t1(
+ w INT GENERATED ALWAYS AS (a*10),
+ a INT,
+ x TEXT AS (typeof(c)),
+ b TEXT,
+ y TEXT AS (substr(b,a,a+2)) STORED,
+ c ANY,
+ PRIMARY KEY(a,b)
+ ) WITHOUT ROWID;
+ }
+6 {
+ CREATE TABLE t1(
+ w INT GENERATED ALWAYS AS (m*5),
+ m INT AS (a*2) STORED,
+ a INT,
+ x TEXT AS (typeof(c)),
+ b TEXT,
+ y TEXT AS (substr(b,m/2,m/2+2)) STORED,
+ c ANY,
+ PRIMARY KEY(a,b)
+ );
+ }
+7 {
+ CREATE TABLE t1(
+ w INT GENERATED ALWAYS AS (m*5),
+ m INT AS (a*2) NOT NULL,
+ a INT,
+ x TEXT AS (typeof(c)) CHECK (x<>'blank'),
+ b TEXT,
+ y TEXT AS (substr(b,m/2,m/2+2)) STORED,
+ c ANY,
+ PRIMARY KEY(b,a)
+ ) WITHOUT ROWID;
+ }
+} {
+ catch {db close}
+ sqlite3 db :memory:
+ db eval $schema
+ do_execsql_test gencol1-2.$tn.100 {
+ INSERT INTO t1(a,b,c) VALUES(1,'abcdef',5.5),(3,'cantaloupe',NULL);
+ SELECT w, x, y, '|' FROM t1 ORDER BY a;
+ } {10 real abc | 30 null ntalo |}
+ do_execsql_test gencol1-2.$tn.101 {
+ SELECT w, x, y, '|' FROM t1 ORDER BY w;
+ } {10 real abc | 30 null ntalo |}
+ do_execsql_test gencol1-2.$tn.102 {
+ SELECT a FROM t1 WHERE w=30;
+ } {3}
+ do_execsql_test gencol1-2.$tn.103 {
+ SELECT a FROM t1 WHERE x='real';
+ } {1}
+ do_execsql_test gencol1-2.$tn.104 {
+ SELECT a FROM t1 WHERE y LIKE '%tal%' OR x='real' ORDER BY b;
+ } {1 3}
+ do_execsql_test gencol1-2.$tn.110 {
+ CREATE INDEX t1w ON t1(w);
+ SELECT a FROM t1 WHERE w=10;
+ } {1}
+ do_execsql_test gencol1-2.$tn.120 {
+ CREATE INDEX t1x ON t1(x) WHERE w BETWEEN 20 AND 40;
+ SELECT a FROM t1 WHERE x='null' AND w BETWEEN 20 AND 40;
+ } {3}
+ do_execsql_test gencol1-2.$tn.121 {
+ SELECT a FROM t1 WHERE x='real';
+ } {1}
+ do_execsql_test gencol1-2.$tn.130 {
+ VACUUM;
+ PRAGMA integrity_check;
+ } {ok}
+ do_execsql_test gencol1-2.$tn.140 {
+ UPDATE t1 SET a=a+100 WHERE w<20;
+ SELECT a, w, '|' FROM t1 ORDER BY w;
+ } {3 30 | 101 1010 |}
+ do_execsql_test gencol1-2.$tn.150 {
+ INSERT INTO t1 VALUES(4,'jambalaya','Chef John'),(15,87719874135,0);
+ SELECT w, x, y, '|' FROM t1 ORDER BY w;
+ } {30 null ntalo | 40 text balaya | 150 integer {} | 1010 real {} |}
+}
+
+# 2019-10-31 ticket b9befa4b83a660cc
+db close
+sqlite3 db :memory:
+do_execsql_test gencol1-3.100 {
+ PRAGMA foreign_keys = true;
+ CREATE TABLE t0(c0 PRIMARY KEY, c1, c2 AS (c0+c1-c3) REFERENCES t0, c3);
+ INSERT INTO t0 VALUES (0, 0, 0), (11, 5, 5);
+ UPDATE t0 SET c1 = c0, c3 = c0;
+ SELECT *, '|' FROM t0 ORDER BY +c0;
+} {0 0 0 0 | 11 11 11 11 |}
+do_catchsql_test gencol1-3.110 {
+ UPDATE t0 SET c1 = c0, c3 = c0+1;
+} {1 {FOREIGN KEY constraint failed}}
+
+# 2019-11-01 ticket c28a01da72f8957c
+db close
+sqlite3 db :memory:
+do_execsql_test gencol1-4.100 {
+ CREATE TABLE t0 (
+ c0,
+ c1 a UNIQUE AS (1),
+ c2,
+ c3 REFERENCES t0(c1)
+ );
+ PRAGMA foreign_keys = true;
+ INSERT INTO t0(c0,c2,c3) VALUES(0,0,1);
+} {}
+do_catchsql_test gencol1-4.110 {
+ REPLACE INTO t0(c0,c2,c3) VALUES(0,0,0),(0,0,0);
+} {1 {FOREIGN KEY constraint failed}}
+
+# 2019-11-01 Problem found while adding new foreign key test cases in TH3.
+db close
+sqlite3 db :memory:
+do_execsql_test gencol1-5.100 {
+ PRAGMA foreign_keys=ON;
+ CREATE TABLE t1(
+ gcb AS (b*1),
+ a INTEGER PRIMARY KEY,
+ gcc AS (c+0),
+ b UNIQUE,
+ gca AS (1*a+0),
+ c UNIQUE
+ ) WITHOUT ROWID;
+ INSERT INTO t1 VALUES(1,2,3);
+ INSERT INTO t1 VALUES(4,5,6);
+ INSERT INTO t1 VALUES(7,8,9);
+ CREATE TABLE t1a(
+ gcx AS (x+0) REFERENCES t1(a) ON DELETE CASCADE,
+ id,
+ x,
+ gcid AS (1*id)
+ );
+ INSERT INTO t1a VALUES(1, 1);
+ INSERT INTO t1a VALUES(2, 4);
+ INSERT INTO t1a VALUES(3, 7);
+ DELETE FROM t1 WHERE b=5;
+ SELECT id,x,'|' FROM t1a ORDER BY id;
+} {1 1 | 3 7 |}
+
+do_catchsql_test gencol1-6.10 {
+ DROP TABLE IF EXISTS t0;
+ CREATE TABLE t0(c0 NOT NULL AS(c1), c1);
+ REPLACE INTO t0(c1) VALUES(NULL);
+} {1 {NOT NULL constraint failed: t0.c0}}
+
+# 2019-11-06 ticket https://www.sqlite.org/src/info/2399f5986134f79c
+# 2019-12-27 ticket https://www.sqlite.org/src/info/5fbc159eeb092130
+# 2019-12-27 ticket https://www.sqlite.org/src/info/37823501c68a09f9
+#
+# All of the above tickets deal with NOT NULL ON CONFLICT REPLACE
+# constraints on tables that have generated columns.
+#
+reset_db
+do_execsql_test gencol1-7.10 {
+ CREATE TABLE t0 (c0 GENERATED ALWAYS AS (1), c1 UNIQUE, c2 UNIQUE);
+ INSERT INTO t0(c1) VALUES (1);
+ SELECT quote(0 = t0.c2 OR t0.c1 BETWEEN t0.c2 AND 1) FROM t0;
+} {NULL}
+do_execsql_test gencol1-7.11 {
+ DROP TABLE t0;
+ CREATE TABLE t0(c0 NOT NULL DEFAULT 'xyz', c1 AS(c0) NOT NULL);
+ REPLACE INTO t0(c0) VALUES(NULL);
+ SELECT * FROM t0;
+} {xyz xyz}
+do_execsql_test gencol1-7.12 {
+ DROP TABLE t0;
+ CREATE TABLE t0(c0 NOT NULL DEFAULT 'xyz', c1 AS(c0) STORED NOT NULL);
+ REPLACE INTO t0(c0) VALUES(NULL);
+ SELECT * FROM t0;
+} {xyz xyz}
+do_execsql_test gencol1-7.20 {
+ CREATE TABLE t1(
+ a NOT NULL DEFAULT 'aaa',
+ b AS(c) NOT NULL,
+ c NOT NULL DEFAULT 'ccc');
+ REPLACE INTO t1(a,c) VALUES(NULL,NULL);
+ SELECT * FROM t1;
+} {aaa ccc ccc}
+do_execsql_test gencol1-7.21 {
+ DROP TABLE t1;
+ CREATE TABLE t1(
+ a NOT NULL DEFAULT 'aaa',
+ b AS(c) STORED NOT NULL,
+ c NOT NULL DEFAULT 'ccc');
+ REPLACE INTO t1(a,c) VALUES(NULL,NULL);
+ SELECT * FROM t1;
+} {aaa ccc ccc}
+do_execsql_test gencol1-7.30 {
+ CREATE TABLE t2(
+ a NOT NULL DEFAULT 'aaa',
+ b AS(a) NOT NULL,
+ c NOT NULL DEFAULT 'ccc');
+ REPLACE INTO t2(a,c) VALUES(NULL,NULL);
+ SELECT * FROM t2;
+} {aaa aaa ccc}
+do_execsql_test gencol1-7.31 {
+ DROP TABLE t2;
+ CREATE TABLE t2(
+ a NOT NULL DEFAULT 'aaa',
+ b AS(a) STORED NOT NULL,
+ c NOT NULL DEFAULT 'ccc');
+ REPLACE INTO t2(a,c) VALUES(NULL,NULL);
+ SELECT * FROM t2;
+} {aaa aaa ccc}
+do_execsql_test gencol1-7.40 {
+ CREATE TABLE t3(a NOT NULL DEFAULT 123, b AS(a) UNIQUE);
+ REPLACE INTO t3 VALUES(NULL);
+ SELECT * FROM t3;
+} {123 123}
+do_execsql_test gencol1-7.41 {
+ SELECT * FROM t3 WHERE b=123;
+} {123 123}
+do_execsql_test gencol1-7.50 {
+ CREATE TABLE t4(a NOT NULL DEFAULT 123, b AS(a*10+4) STORED UNIQUE);
+ REPLACE INTO t4 VALUES(NULL);
+ SELECT * FROM t4;
+} {123 1234}
+do_execsql_test gencol1-7.51 {
+ SELECT * FROM t4 WHERE b=1234;
+} {123 1234}
+
+# 2019-11-06 ticket 4fc08501f4e56692
+do_execsql_test gencol1-8.10 {
+ DROP TABLE IF EXISTS t0;
+ CREATE TABLE t0(
+ c0 AS (('a', 9) < ('b', c1)),
+ c1 AS (1),
+ c2 CHECK (1 = c1)
+ );
+ INSERT INTO t0 VALUES (0),(99);
+ SELECT * FROM t0;
+} {1 1 0 1 1 99}
+do_catchsql_test gencol1-8.20 {
+ DROP TABLE IF EXISTS t0;
+ CREATE TABLE t0(
+ c0,
+ c1 AS(c0 + c2),
+ c2 AS(c1) CHECK(c2)
+ );
+ UPDATE t0 SET c0 = NULL;
+} {1 {generated column loop on "c2"}}
+
+# 2019-11-21 Problems in the new generated column logic
+# reported by Yongheng Chen and Rui Zhong
+reset_db
+do_execsql_test gencol1-9.10 {
+ PRAGMA foreign_keys=OFF;
+ CREATE TABLE t1(aa , bb AS (17) UNIQUE);
+ INSERT INTO t1 VALUES(17);
+ CREATE TABLE t2(cc);
+ INSERT INTO t2 VALUES(41);
+ SELECT * FROM t2 JOIN t1 WHERE t1.bb=t1.aa AND t1.bb=17;
+} {41 17 17}
+do_execsql_test gencol1-9.20 {
+ CREATE TABLE t3(aa INT PRIMARY KEY, bb UNIQUE AS(aa));
+ INSERT INTO t3 VALUES(1);
+ SELECT 100, * FROM t3;
+ DELETE FROM t3 WHERE (SELECT bb FROM t3);
+ SELECT 200, * FROM t3;
+} {100 1 1}
+
+# 2019-12-04 Generated column in a CREATE TABLE IF NOT EXISTS that
+# does already exist.
+#
+sqlite3 db :memory:
+do_execsql_test gencol1-10.10 {
+ CREATE TABLE t1(aa,bb);
+ CREATE TABLE IF NOT EXISTS t1(aa, bb AS (aa+1));
+ PRAGMA integrity_check;
+} {ok}
+
+# 2019-12-06 Found by mrigger
+#
+sqlite3 db :memory:
+do_execsql_test gencol1-11.10 {
+ PRAGMA foreign_keys = true;
+ CREATE TABLE t0(
+ c0,
+ c1 INTEGER PRIMARY KEY,
+ c2 BLOB UNIQUE DEFAULT x'00',
+ c3 BLOB GENERATED ALWAYS AS (1),
+ FOREIGN KEY(c1) REFERENCES t0(c2)
+ );
+}
+do_catchsql_test gencol1-11.20 {
+ INSERT OR REPLACE INTO t0(c0, c1) VALUES (2, 1), (1, 0)
+} {1 {FOREIGN KEY constraint failed}}
+do_execsql_test gencol1-11.30 {
+ DROP TABLE t0;
+ CREATE TABLE t0(
+ c0,
+ c1 INTEGER PRIMARY KEY,
+ c3 BLOB GENERATED ALWAYS AS (1),
+ c2 BLOB UNIQUE DEFAULT x'00',
+ FOREIGN KEY(c1) REFERENCES t0(c2)
+ );
+}
+do_catchsql_test gencol1-11.40 {
+ INSERT OR REPLACE INTO t0(c0, c1) VALUES (2, 1), (1, 0)
+} {1 {FOREIGN KEY constraint failed}}
+do_execsql_test gencol1-11.50 {
+ DROP TABLE t0;
+ CREATE TABLE t0(
+ c0,
+ c3 BLOB GENERATED ALWAYS AS (1),
+ c1 INTEGER PRIMARY KEY,
+ c2 BLOB UNIQUE DEFAULT x'00',
+ FOREIGN KEY(c1) REFERENCES t0(c2)
+ );
+}
+do_catchsql_test gencol1-11.60 {
+ INSERT OR REPLACE INTO t0(c0, c1) VALUES (2, 1), (1, 0)
+} {1 {FOREIGN KEY constraint failed}}
+do_execsql_test gencol1-11.70 {
+ DROP TABLE t0;
+ CREATE TABLE t0(
+ c3 BLOB GENERATED ALWAYS AS (1),
+ c0,
+ c1 INTEGER PRIMARY KEY,
+ c2 BLOB UNIQUE DEFAULT x'00',
+ FOREIGN KEY(c1) REFERENCES t0(c2)
+ );
+}
+do_catchsql_test gencol1-11.80 {
+ INSERT OR REPLACE INTO t0(c0, c1) VALUES (2, 1), (1, 0)
+} {1 {FOREIGN KEY constraint failed}}
+
+# 2019-12-09 ticket bd8c280671ba44a7
+# With generated columns, the sqlite3ExprGetColumnOfTable() routine might
+# generate a code sequence that does not end with OP_Column. So check to
+# make sure that the last instruction generated is an OP_column prior to
+# applying the OPFLAG_TYPEOFARG optimization to NOT NULL checks in the
+# PRAGMA integrity_check code.
+#
+sqlite3 db :memory:
+do_execsql_test gencol1-12.10 {
+ CREATE TABLE t0 (c0, c1 NOT NULL AS (c0==0));
+ INSERT INTO t0(c0) VALUES (0);
+ PRAGMA integrity_check;
+} {ok}
+
+# 2019-12-09 bug report from Yongheng Chen
+# Ensure that the SrcList_item.colUsed field is set correctly when a
+# generated column appears in the USING clause of a join.
+#
+do_execsql_test gencol1-13.10 {
+ CREATE TABLE t1(x, y AS(x+1));
+ INSERT INTO t1 VALUES(10);
+ SELECT y FROM t1 JOIN t1 USING (y,y);
+} {11}
+do_execsql_test gencol1-13.11 {
+ SELECT 123 FROM t1 JOIN t1 USING (x);
+} {123}
+do_execsql_test gencol1-13.11 {
+ SELECT 456 FROM t1 JOIN t1 USING (x,x);
+} {456}
+do_execsql_test gencol1-13.20 {
+ CREATE INDEX t1y ON t1(y);
+ SELECT y FROM t1 JOIN t1 USING (y,y);
+} {11}
+do_execsql_test gencol1-13.21 {
+ CREATE INDEX t1x ON t1(x);
+ SELECT 123 FROM t1 JOIN t1 USING (x);
+} {123}
+do_execsql_test gencol1-13.22 {
+ SELECT 456 FROM t1 JOIN t1 USING (x,x);
+} {456}
+
+# 2019-12-14 ticket b439bfcfb7deedc6
+#
+sqlite3 db :memory:
+do_execsql_test gencol1-14.10 {
+ CREATE TABLE t0(c0 AS(1 >= 1), c1 UNIQUE AS(TYPEOF(c0)), c2);
+ INSERT INTO t0 VALUES(0);
+ REINDEX;
+ SELECT * FROM t0;
+} {1 integer 0}
+do_catchsql_test gencol1-14.10 {
+ INSERT INTO t0 VALUES(2);
+} {1 {UNIQUE constraint failed: t0.c1}}
+
+# 2019-12-14 gramfuzz1 find
+# The schema is malformed in that it has a subquery on a generated
+# column expression. This will be loaded if writable_schema=ON. SQLite
+# must not use such an expression during code generation as the code generator
+# will add bits of content to the expression tree that might be allocated
+# from lookaside. But the schema is not tied to a particular database
+# connection, so the use of lookaside memory is prohibited. The fix
+# is to change the generated column expression to NULL before adding it
+# to the schema.
+#
+reset_db
+do_test gencol1-15.10 {
+ sqlite3 db {}
+ db deserialize [decode_hexdb {
+| size 8192 pagesize 4096 filename c27.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 01 00 00 00 02 .....@ ........
+| 32: 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 04 ................
+| 48: 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 ................
+| 80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 ................
+| 96: 00 2e 3f d8 0d 00 00 00 01 0f ba 00 0f ba 00 00 ..?.............
+| 4016: 00 00 00 00 00 00 00 00 00 00 44 01 06 17 11 11 ..........D.....
+| 4032: 01 75 74 61 62 6c 65 74 31 74 31 02 43 52 45 41 .utablet1t1.CREA
+| 4048: 54 45 20 54 41 42 4c 45 20 74 31 28 61 20 49 4e TE TABLE t1(a IN
+| 4064: 54 2c 20 62 20 41 53 28 28 56 41 4c 55 45 53 28 T, b AS((VALUES(
+| 4080: 31 29 29 20 49 53 20 75 6e 6b 6e 6f 77 6e 29 29 1)) IS unknown))
+| page 2 offset 4096
+| 0: 0d 00 00 00 00 10 00 00 00 00 00 00 00 00 00 00 ................
+| end c27.db
+}]} {}
+do_execsql_test gencol1-15.20 {
+ PRAGMA writable_schema=ON;
+ REPLACE INTO t1 VALUES(9);
+ SELECT a, quote(b) FROM t1
+} {9 NULL}
+
+# 2019-12-16 ticket 3b84b42943644d6f
+# When a table is the right table of a LEFT JOIN and the ON clause is
+# false, make sure any generated columns evaluate to NULL.
+reset_db
+do_execsql_test gencol1-16.10 {
+ CREATE TABLE t0(c0);
+ CREATE TABLE t1(c1, c2 AS(1));
+ INSERT INTO t0 VALUES(0);
+ SELECT c0, c1, c2 FROM t0 LEFT JOIN t1;
+} {0 {} {}}
+do_execsql_test gencol1-16.20 {
+ DROP TABLE t1;
+ CREATE TABLE t1(c1, c2 AS (c1 ISNULL));
+ SELECT c0, c1, c2 FROM t0 LEFT JOIN t1;
+} {0 {} {}}
+do_execsql_test gencol1-16.30 {
+ INSERT INTO t1(c1) VALUES(1),(NULL);
+ SELECT * FROM t1;
+} {1 0 {} 1}
+do_execsql_test gencol1-16.40 {
+ SELECT c0, c1, c2 FROM t0 LEFT JOIN t1 ON c0=c1;
+} {0 {} {}}
+
+# 2019-12-20 ticket e0a8120553f4b082
+# Generated columns with REAL affinity need to have an OP_RealAffinity
+# opcode applied, even when the column value is extracted from an index.
+#
+reset_db
+do_execsql_test gencol1-17.10 {
+ CREATE TABLE t0(c0 REAL AS(1) UNIQUE, c1 INT);
+ INSERT INTO t0 VALUES('');
+ SELECT quote(c0), quote(c1) from t0;
+} {1.0 ''}
+do_execsql_test gencol1-17.20 {
+ SELECT *, (1 BETWEEN CAST(t0.c0 AS TEXT) AND t0.c0) FROM t0;
+} {1.0 {} 0}
+do_execsql_test gencol1-17.30 {
+ SELECT * FROM t0 WHERE (1 BETWEEN CAST(t0.c0 AS TEXT) AND t0.c0);
+} {}
+do_execsql_test gencol1-17.40 {
+ CREATE TABLE t1(a TEXT AS(b) COLLATE nocase, b TEXT, c INT, d DEFAULT 1);
+ INSERT INTO t1(b,c) VALUES('abc',11),('DEF',22),('ghi',33);
+ SELECT a FROM t1 WHERE b='DEF' AND a='def';
+} {DEF}
+do_execsql_test gencol1-17.50 {
+ CREATE INDEX t1bca ON t1(b,c,a);
+ SELECT a FROM t1 WHERE b='DEF' AND a='def';
+} {DEF}
+
+# 2019-12-26 ticket ec8abb025e78f40c
+# An index on a virtual column with a constant value (why would anybody
+# ever do such a thing?) can cause problems for a one-pass DELETE.
+#
+reset_db
+do_execsql_test gencol1-18.10 {
+ CREATE TABLE t0(c0 UNIQUE AS(0), c1, c2);
+ INSERT INTO t0(c1) VALUES(0);
+ SELECT * FROM t0;
+} {0 0 {}}
+do_execsql_test gencol1-18.20 {
+ UPDATE t0 SET c1=0, c2=0 WHERE c0>=0;
+ SELECT * FROM t0;
+} {0 0 0}
+
+# 2019-12-27 ticket de4b04149b9fdeae
+#
+reset_db
+do_catchsql_test gencol1-19.10 {
+ CREATE TABLE t0(
+ c0 INT AS(2) UNIQUE,
+ c1 TEXT UNIQUE,
+ FOREIGN KEY(c0) REFERENCES t0(c1)
+ );
+ INSERT INTO t0(c1) VALUES(0.16334143182538696), (0);
+} {1 {UNIQUE constraint failed: t0.c0}}
+
+finish_test
diff --git a/test/in4.test b/test/in4.test
index 787b9ea36c..37eafdebec 100644
--- a/test/in4.test
+++ b/test/in4.test
@@ -13,6 +13,7 @@
set testdir [file dirname $argv0]
source $testdir/tester.tcl
+set testprefix in4
do_test in4-1.1 {
execsql {
@@ -338,5 +339,30 @@ do_execsql_test in4-6.2-eqp {
SELECT * FROM t6a, t6b WHERE a=3 AND c IN (b);
} {~/SCAN/}
+reset_db
+do_execsql_test 7.0 {
+ CREATE TABLE t1(a, b, c);
+ CREATE TABLE t2(d, e);
+ CREATE INDEX t1bc ON t1(c, b);
+ INSERT INTO t2(e) VALUES(1);
+ INSERT INTO t1 VALUES(NULL, NULL, NULL);
+}
+
+do_execsql_test 7.1 {
+ SELECT * FROM t2 LEFT JOIN t1 ON c = d AND b IN (10,10,10);
+} {{} 1 {} {} {}}
+
+ifcapable rtree {
+ reset_db
+ do_execsql_test 7.2 {
+ CREATE VIRTUAL TABLE t1 USING rtree(a, b, c);
+ CREATE TABLE t2(d INTEGER, e INT);
+ INSERT INTO t2(e) VALUES(1);
+ }
+
+ do_execsql_test 7.3 {
+ SELECT * FROM t2 LEFT JOIN t1 ON c IN (d) AND b IN (10,10,10);
+ } {{} 1 {} {} {}}
+}
finish_test
diff --git a/test/index6.test b/test/index6.test
index 976c49fb86..d385692584 100644
--- a/test/index6.test
+++ b/test/index6.test
@@ -478,7 +478,24 @@ do_execsql_test index6-16.3 {
SELECT 3 FROM t0 WHERE c1 <= c0;
} {3}
-
-
+# 2019-11-02
+# Ticket https://sqlite.org/src/tktview/a9efb42811fa41ee286e8
+db close
+sqlite3 db :memory:
+do_execsql_test index6-17.1 {
+ CREATE TABLE t0(c0);
+ CREATE INDEX i0 ON t0(0) WHERE c0 GLOB c0;
+ INSERT INTO t0 VALUES (0);
+ CREATE UNIQUE INDEX i1 ON t0(0);
+ PRAGMA integrity_check;
+} {ok}
+do_execsql_test index6-17.2 {
+ CREATE UNIQUE INDEX i2 ON t0(0);
+ REPLACE INTO t0 VALUES(0);
+ PRAGMA integrity_check;
+} {ok}
+do_execsql_test index6-17.3 {
+ SELECT COUNT(*) FROM t0 WHERE t0.c0 GLOB t0.c0;
+} {1}
finish_test
diff --git a/test/indexexpr1.test b/test/indexexpr1.test
index 6b134dbd3f..19c2573509 100644
--- a/test/indexexpr1.test
+++ b/test/indexexpr1.test
@@ -186,7 +186,7 @@ do_catchsql_test indexexpr1-300 {
} {1 {non-deterministic functions prohibited in index expressions}}
do_catchsql_test indexexpr1-301 {
CREATE INDEX t2x1 ON t2(julianday('now',a));
-} {1 {non-deterministic function in index expression or CHECK constraint}}
+} {1 {non-deterministic use of julianday() in an index}}
do_catchsql_test indexexpr1-310 {
CREATE INDEX t2x2 ON t2(a,b+(SELECT 15));
} {1 {subqueries prohibited in index expressions}}
diff --git a/test/indexexpr2.test b/test/indexexpr2.test
index 5d387c7523..35caef3c24 100644
--- a/test/indexexpr2.test
+++ b/test/indexexpr2.test
@@ -373,4 +373,3 @@ foreach {tn expr} {
}
finish_test
-
diff --git a/test/insert.test b/test/insert.test
index 397a0e6ff9..51e62268db 100644
--- a/test/insert.test
+++ b/test/insert.test
@@ -1,4 +1,4 @@
-# 2001 September 15
+# 2001-09-15
#
# The author disclaims copyright to this source code. In place of
# a legal notice, here is a blessing:
@@ -11,7 +11,6 @@
# This file implements regression tests for SQLite library. The
# focus of this file is testing the INSERT statement.
#
-# $Id: insert.test,v 1.31 2007/04/05 11:25:59 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
@@ -458,7 +457,7 @@ do_execsql_test insert-14.1 {
SELECT x FROM t14;
} {1}
-integrity_check insert-99.0
+integrity_check insert-14.2
# 2019-08-12.
#
@@ -475,5 +474,130 @@ do_execsql_test insert-15.1 {
SELECT a, length(b) FROM t1;
} {4 33000}
+# 2019-10-16
+# ticket https://www.sqlite.org/src/info/a8a4847a2d96f5de
+# On a REPLACE INTO, if an AFTER trigger adds back the conflicting
+# row, you can end up with the wrong number of rows in an index.
+#
+db close
+sqlite3 db :memory:
+do_catchsql_test insert-16.1 {
+ PRAGMA recursive_triggers = true;
+ CREATE TABLE t0(c0,c1);
+ CREATE UNIQUE INDEX i0 ON t0(c0);
+ INSERT INTO t0(c0,c1) VALUES(123,1);
+ CREATE TRIGGER tr0 AFTER DELETE ON t0
+ BEGIN
+ INSERT INTO t0 VALUES(123,2);
+ END;
+ REPLACE INTO t0(c0,c1) VALUES(123,3);
+} {1 {UNIQUE constraint failed: t0.c0}}
+do_execsql_test insert-16.2 {
+ SELECT * FROM t0;
+} {123 1}
+integrity_check insert-16.3
+do_catchsql_test insert-16.4 {
+ CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
+ CREATE INDEX t1b ON t1(b);
+ INSERT INTO t1 VALUES(1, 'one');
+ CREATE TRIGGER tr3 AFTER DELETE ON t1 BEGIN
+ INSERT INTO t1 VALUES(1, 'three');
+ END;
+ REPLACE INTO t1 VALUES(1, 'two');
+} {1 {UNIQUE constraint failed: t1.a}}
+integrity_check insert-16.5
+do_catchsql_test insert-16.6 {
+ PRAGMA foreign_keys = 1;
+ CREATE TABLE p1(a, b UNIQUE);
+ CREATE TABLE c1(c, d REFERENCES p1(b) ON DELETE CASCADE);
+ CREATE TRIGGER tr6 AFTER DELETE ON c1 BEGIN
+ INSERT INTO p1 VALUES(4, 1);
+ END;
+ INSERT INTO p1 VALUES(1, 1);
+ INSERT INTO c1 VALUES(2, 1);
+ REPLACE INTO p1 VALUES(3, 1);2
+} {1 {UNIQUE constraint failed: p1.b}}
+integrity_check insert-16.7
+
+# 2019-10-25 ticket c1e19e12046d23fe
+do_catchsql_test insert-17.1 {
+ PRAGMA temp.recursive_triggers = true;
+ DROP TABLE IF EXISTS t0;
+ CREATE TABLE t0(aa, bb);
+ CREATE UNIQUE INDEX t0bb ON t0(bb);
+ CREATE TRIGGER "r17.1" BEFORE DELETE ON t0
+ BEGIN INSERT INTO t0(aa,bb) VALUES(99,1);
+ END;
+ INSERT INTO t0(aa,bb) VALUES(10,20);
+ REPLACE INTO t0(aa,bb) VALUES(30,20);
+} {1 {UNIQUE constraint failed: t0.rowid}}
+integrity_check insert-17.2
+do_catchsql_test insert-17.3 {
+ DROP TABLE IF EXISTS t1;
+ CREATE TABLE t1(a, b UNIQUE, c UNIQUE);
+ INSERT INTO t1(a,b,c) VALUES(1,1,1),(2,2,2),(3,3,3),(4,4,4);
+ CREATE TRIGGER "r17.3" AFTER DELETE ON t1 WHEN OLD.c<>3 BEGIN
+ INSERT INTO t1(rowid,a,b,c) VALUES(100,100,100,3);
+ END;
+ REPLACE INTO t1(rowid,a,b,c) VALUES(200,1,2,3);
+} {1 {UNIQUE constraint failed: t1.c}}
+integrity_check insert-17.4
+do_execsql_test insert-17.5 {
+ CREATE TABLE t2(a INTEGER PRIMARY KEY, b);
+ CREATE UNIQUE INDEX t2b ON t2(b);
+ INSERT INTO t2(a,b) VALUES(1,1),(2,2),(3,3),(4,4);
+ CREATE TABLE fire(x);
+ CREATE TRIGGER t2r1 AFTER DELETE ON t2 BEGIN
+ INSERT INTO fire VALUES(old.a);
+ END;
+ UPDATE OR REPLACE t2 SET a=4, b=3 WHERE a=1;
+ SELECT *, 'x' FROM t2 ORDER BY a;
+} {2 2 x 4 3 x}
+do_execsql_test insert-17.6 {
+ SELECT x FROM fire ORDER BY x;
+} {3 4}
+do_execsql_test insert-17.7 {
+ DELETE FROM t2;
+ DELETE FROM fire;
+ INSERT INTO t2(a,b) VALUES(1,1),(2,2),(3,3),(4,4);
+ UPDATE OR REPLACE t2 SET a=1, b=3 WHERE a=1;
+ SELECT *, 'x' FROM t2 ORDER BY a;
+} {1 3 x 2 2 x 4 4 x}
+do_execsql_test insert-17.8 {
+ SELECT x FROM fire ORDER BY x;
+} {3}
+do_execsql_test insert-17.10 {
+ CREATE TABLE t3(a INTEGER PRIMARY KEY, b INT, c INT, d INT);
+ CREATE UNIQUE INDEX t3bpi ON t3(b) WHERE c<=d;
+ CREATE UNIQUE INDEX t3d ON t3(d);
+ INSERT INTO t3(a,b,c,d) VALUES(1,1,1,1),(2,1,3,2),(3,4,5,6);
+ CREATE TRIGGER t3r1 AFTER DELETE ON t3 BEGIN
+ SELECT 'hi';
+ END;
+ REPLACE INTO t3(a,b,c,d) VALUES(4,4,8,9);
+} {}
+do_execsql_test insert-17.11 {
+ SELECT *, 'x' FROM t3 ORDER BY a;
+} {1 1 1 1 x 2 1 3 2 x 4 4 8 9 x}
+do_execsql_test insert-17.12 {
+ REPLACE INTO t3(a,b,c,d) VALUES(5,1,11,2);
+ SELECT *, 'x' FROM t3 ORDER BY a;
+} {1 1 1 1 x 4 4 8 9 x 5 1 11 2 x}
+
+do_execsql_test insert-17.13 {
+ DELETE FROM t3;
+ INSERT INTO t3(a,b,c,d) VALUES(1,1,1,1),(2,1,3,2),(3,4,5,6);
+ DROP TRIGGER t3r1;
+ CREATE TRIGGER t3r1 AFTER DELETE ON t3 BEGIN
+ INSERT INTO t3(b,c,d) VALUES(old.b,old.c,old.d);
+ END;
+} {}
+do_catchsql_test insert-17.14 {
+ REPLACE INTO t3(a,b,c,d) VALUES(4,4,8,9);
+} {1 {UNIQUE constraint failed: t3.b}}
+do_catchsql_test insert-17.15 {
+ REPLACE INTO t3(a,b,c,d) VALUES(5,1,11,2);
+} {1 {UNIQUE constraint failed: t3.d}}
+
finish_test
diff --git a/test/insert4.test b/test/insert4.test
index c819b80832..4c6a6d4a6c 100644
--- a/test/insert4.test
+++ b/test/insert4.test
@@ -34,8 +34,8 @@ proc xferopt_test {testname N} {
# Create tables used for testing.
#
+sqlite3_db_config db LEGACY_FILE_FORMAT 0
execsql {
- PRAGMA legacy_file_format = 0;
CREATE TABLE t1(a int, b int, check(b>a));
CREATE TABLE t2(x int, y int);
CREATE VIEW v2 AS SELECT y, x FROM t2;
diff --git a/test/join.test b/test/join.test
index f53a90c84a..391e0681ce 100644
--- a/test/join.test
+++ b/test/join.test
@@ -884,4 +884,144 @@ do_execsql_test join-17.110 {
WHERE NOT(y='a');
} {1 3 1 3}
+#-------------------------------------------------------------------------
+reset_db
+do_execsql_test join-18.1 {
+ CREATE TABLE t0(a);
+ CREATE TABLE t1(b);
+ CREATE VIEW v0 AS SELECT a FROM t1 LEFT JOIN t0;
+ INSERT INTO t1 VALUES (1);
+} {}
+
+do_execsql_test join-18.2 {
+ SELECT * FROM v0 WHERE NOT(v0.a IS FALSE);
+} {{}}
+
+do_execsql_test join-18.3 {
+ SELECT * FROM t1 LEFT JOIN t0 WHERE NOT(a IS FALSE);
+} {1 {}}
+
+do_execsql_test join-18.4 {
+ SELECT NOT(v0.a IS FALSE) FROM v0
+} {1}
+
+#-------------------------------------------------------------------------
+reset_db
+do_execsql_test join-19.0 {
+ CREATE TABLE t1(a);
+ CREATE TABLE t2(b);
+ INSERT INTO t1(a) VALUES(0);
+ CREATE VIEW v0(c) AS SELECT t2.b FROM t1 LEFT JOIN t2;
+}
+
+do_execsql_test join-19.1 {
+ SELECT * FROM v0 WHERE v0.c NOTNULL NOTNULL;
+} {{}}
+
+do_execsql_test join-19.2 {
+ SELECT * FROM t1 LEFT JOIN t2
+} {0 {}}
+
+do_execsql_test join-19.3 {
+ SELECT * FROM t1 LEFT JOIN t2 WHERE (b IS NOT NULL) IS NOT NULL;
+} {0 {}}
+
+do_execsql_test join-19.4 {
+ SELECT (b IS NOT NULL) IS NOT NULL FROM t1 LEFT JOIN t2
+} {1}
+
+do_execsql_test join-19.5 {
+ SELECT * FROM t1 LEFT JOIN t2 WHERE
+ (b IS NOT NULL AND b IS NOT NULL) IS NOT NULL;
+} {0 {}}
+
+# 2019-11-02 ticket 623eff57e76d45f6
+# The optimization of exclusing the WHERE expression of a partial index
+# from the WHERE clause of the query if the index is used does not work
+# of the table of the index is the right-hand table of a LEFT JOIN.
+#
+db close
+sqlite3 db :memory:
+do_execsql_test join-20.1 {
+ CREATE TABLE t1(c1);
+ CREATE TABLE t0(c0);
+ INSERT INTO t0(c0) VALUES (0);
+ SELECT * FROM t0 LEFT JOIN t1 WHERE NULL IN (c1);
+} {}
+do_execsql_test join-20.2 {
+ CREATE INDEX t1x ON t1(0) WHERE NULL IN (c1);
+ SELECT * FROM t0 LEFT JOIN t1 WHERE NULL IN (c1);
+} {}
+
+# 2019-11-30 ticket 7f39060a24b47353
+# Do not allow a WHERE clause term to qualify a partial index on the
+# right table of a LEFT JOIN.
+#
+do_execsql_test join-21.10 {
+ DROP TABLE t0;
+ DROP TABLE t1;
+ CREATE TABLE t0(aa);
+ CREATE TABLE t1(bb);
+ INSERT INTO t0(aa) VALUES (1);
+ INSERT INTO t1(bb) VALUES (1);
+ SELECT 11, * FROM t1 LEFT JOIN t0 WHERE aa ISNULL;
+ SELECT 12, * FROM t1 LEFT JOIN t0 WHERE +aa ISNULL;
+ SELECT 13, * FROM t1 LEFT JOIN t0 ON aa ISNULL;
+ SELECT 14, * FROM t1 LEFT JOIN t0 ON +aa ISNULL;
+ CREATE INDEX i0 ON t0(aa) WHERE aa ISNULL;
+ SELECT 21, * FROM t1 LEFT JOIN t0 WHERE aa ISNULL;
+ SELECT 22, * FROM t1 LEFT JOIN t0 WHERE +aa ISNULL;
+ SELECT 23, * FROM t1 LEFT JOIN t0 ON aa ISNULL;
+ SELECT 24, * FROM t1 LEFT JOIN t0 ON +aa ISNULL;
+} {13 1 {} 14 1 {} 23 1 {} 24 1 {}}
+
+# 2019-12-18 problem with a LEFT JOIN where the RHS is a view.
+# Detected by Yongheng and Rui.
+# Follows from the optimization attempt of check-in 41c27bc0ff1d3135
+# on 2017-04-18
+#
+reset_db
+do_execsql_test join-22.10 {
+ CREATE TABLE t0(a, b);
+ CREATE INDEX t0a ON t0(a);
+ INSERT INTO t0 VALUES(10,10),(10,11),(10,12);
+ SELECT DISTINCT c FROM t0 LEFT JOIN (SELECT a+1 AS c FROM t0) ORDER BY c ;
+} {11}
+
+# 2019-12-22 ticket 7929c1efb2d67e98
+#
+reset_db
+do_execsql_test join-23.10 {
+ CREATE TABLE t0(c0);
+ INSERT INTO t0(c0) VALUES(123);
+ CREATE VIEW v0(c0) AS SELECT 0 GROUP BY 1;
+ SELECT t0.c0, v0.c0, vt0.name
+ FROM v0, t0 LEFT JOIN pragma_table_info('t0') AS vt0
+ ON vt0.name LIKE 'c0'
+ WHERE v0.c0 == 0;
+} {123 0 c0}
+
+#-------------------------------------------------------------------------
+reset_db
+do_execsql_test join-24.1 {
+ CREATE TABLE t1(a PRIMARY KEY, x);
+ CREATE TABLE t2(b INT);
+ CREATE INDEX t1aa ON t1(a, a);
+
+ INSERT INTO t1 VALUES('abc', 'def');
+ INSERT INTO t2 VALUES(1);
+}
+
+do_execsql_test join-24.2 {
+ SELECT * FROM t2 JOIN t1 WHERE a='abc' AND x='def';
+} {1 abc def}
+do_execsql_test join-24.3 {
+ SELECT * FROM t2 JOIN t1 WHERE a='abc' AND x='abc';
+} {}
+
+do_execsql_test join-24.2 {
+ SELECT * FROM t2 LEFT JOIN t1 ON a=0 WHERE (x='x' OR x IS NULL);
+} {1 {} {}}
+
finish_test
+
diff --git a/test/join2.test b/test/join2.test
index 5a70573e0e..bfcecda29b 100644
--- a/test/join2.test
+++ b/test/join2.test
@@ -279,5 +279,19 @@ do_execsql_test 7.0 {
SELECT * FROM test;
} {3 4 {} {} {} x 5 6 {} {} {} x}
+#-------------------------------------------------------------------------
+# Ticket [dfd66334].
+#
+reset_db
+do_execsql_test 8.0 {
+ CREATE TABLE t0(c0);
+ CREATE TABLE t1(c0);
+}
+
+do_execsql_test 8.1 {
+ SELECT * FROM t0 LEFT JOIN t1
+ WHERE (t1.c0 BETWEEN 0 AND 0) > ('' AND t0.c0);
+}
+
finish_test
diff --git a/test/journal3.test b/test/journal3.test
index 9dc7aa25f8..c3e3d12db6 100644
--- a/test/journal3.test
+++ b/test/journal3.test
@@ -38,6 +38,7 @@ if {$::tcl_platform(platform) == "unix"
} {
db close
#set effective [format %.5o [expr $permissions & ~$umask]]
+ set res "/[regsub {^00} $permissions {0.}]/"
if {$tcl_version>=8.7} {
regsub {^00} $permissions {0o} permissions
}
@@ -46,7 +47,7 @@ if {$::tcl_platform(platform) == "unix"
catch { forcedelete test.db-journal }
file attributes test.db -permissions $permissions
file attributes test.db -permissions
- } $permissions
+ } $res
do_test journal3-1.2.$tn.2 { file exists test.db-journal } {0}
do_test journal3-1.2.$tn.3 {
sqlite3 db test.db
@@ -58,7 +59,7 @@ if {$::tcl_platform(platform) == "unix"
} {1}
do_test journal3-1.2.$tn.4 {
file attr test.db-journal -perm
- } $effective
+ } $res
do_execsql_test journal3-1.2.$tn.5 { ROLLBACK } {}
}
diff --git a/test/json101.test b/test/json101.test
index 534478df93..0d59f2e83d 100644
--- a/test/json101.test
+++ b/test/json101.test
@@ -832,4 +832,19 @@ do_execsql_test json-15.130 {
SELECT xyz.* FROM (JSON_EACH('{"a":1, "b":2}')) AS xyz;
} {a 1 integer 1 2 {} {$.a} {$} b 2 integer 2 4 {} {$.b} {$}}
+# 2019-11-10
+# Mailing list bug report on the handling of surrogate pairs
+# in JSON.
+#
+do_execsql_test json-16.10 {
+ SELECT length(json_extract('"abc\uD834\uDD1Exyz"','$'));
+} {7}
+do_execsql_test json-16.20 {
+ SELECT length(json_extract('"\uD834\uDD1E"','$'));
+} {1}
+do_execsql_test json-16.30 {
+ SELECT unicode(json_extract('"\uD834\uDD1E"','$'));
+} {119070}
+
+
finish_test
diff --git a/test/json105.test b/test/json105.test
new file mode 100644
index 0000000000..46d36774f7
--- /dev/null
+++ b/test/json105.test
@@ -0,0 +1,118 @@
+# 2019-11-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.
+#
+#***********************************************************************
+# This file implements tests for "[#]" extension to json-path
+#
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+set testprefix json104
+
+ifcapable !json1 {
+ finish_test
+ return
+}
+
+# This is the example from pages 2 and 3 of RFC-7396
+db eval {
+ CREATE TABLE t1(j);
+ INSERT INTO t1(j) VALUES('{"a":1,"b":[1,[2,3],4],"c":99}');
+}
+proc json_extract_test {testnum path result} {
+ do_execsql_test json105-1.$testnum "SELECT quote(json_extract(j,$path)) FROM t1" $result
+}
+json_extract_test 10 {'$.b[#]'} NULL
+json_extract_test 20 {'$.b[#-1]'} 4
+json_extract_test 30 {'$.b[#-2]'} {'[2,3]'}
+json_extract_test 31 {'$.b[#-02]'} {'[2,3]'}
+json_extract_test 40 {'$.b[#-3]'} 1
+json_extract_test 50 {'$.b[#-4]'} NULL
+json_extract_test 60 {'$.b[#-2][#-1]'} 3
+json_extract_test 70 {'$.b[0]','$.b[#-1]'} {'[1,4]'}
+
+json_extract_test 100 {'$.a[#-1]'} NULL
+json_extract_test 110 {'$.b[#-000001]'} 4
+
+proc json_remove_test {testnum path result} {
+ do_execsql_test json105-2.$testnum "SELECT quote(json_remove(j,$path)) FROM t1" $result
+}
+json_remove_test 10 {'$.b[#]'} {'{"a":1,"b":[1,[2,3],4],"c":99}'}
+json_remove_test 20 {'$.b[#-0]'} {'{"a":1,"b":[1,[2,3],4],"c":99}'}
+json_remove_test 30 {'$.b[#-1]'} {'{"a":1,"b":[1,[2,3]],"c":99}'}
+json_remove_test 40 {'$.b[#-2]'} {'{"a":1,"b":[1,4],"c":99}'}
+json_remove_test 50 {'$.b[#-3]'} {'{"a":1,"b":[[2,3],4],"c":99}'}
+json_remove_test 60 {'$.b[#-4]'} {'{"a":1,"b":[1,[2,3],4],"c":99}'}
+json_remove_test 70 {'$.b[#-2][#-1]'} {'{"a":1,"b":[1,[2],4],"c":99}'}
+
+json_remove_test 100 {'$.b[0]','$.b[#-1]'} {'{"a":1,"b":[[2,3]],"c":99}'}
+json_remove_test 110 {'$.b[#-1]','$.b[0]'} {'{"a":1,"b":[[2,3]],"c":99}'}
+json_remove_test 120 {'$.b[#-1]','$.b[#-2]'} {'{"a":1,"b":[[2,3]],"c":99}'}
+json_remove_test 130 {'$.b[#-1]','$.b[#-1]'} {'{"a":1,"b":[1],"c":99}'}
+json_remove_test 140 {'$.b[#-2]','$.b[#-1]'} {'{"a":1,"b":[1],"c":99}'}
+
+proc json_insert_test {testnum x result} {
+ do_execsql_test json105-3.$testnum "SELECT quote(json_insert(j,$x)) FROM t1" $result
+}
+json_insert_test 10 {'$.b[#]','AAA'} {'{"a":1,"b":[1,[2,3],4,"AAA"],"c":99}'}
+json_insert_test 20 {'$.b[1][#]','AAA'} {'{"a":1,"b":[1,[2,3,"AAA"],4],"c":99}'}
+json_insert_test 30 {'$.b[1][#]','AAA','$.b[#]','BBB'} \
+ {'{"a":1,"b":[1,[2,3,"AAA"],4,"BBB"],"c":99}'}
+json_insert_test 40 {'$.b[#]','AAA','$.b[#]','BBB'} \
+ {'{"a":1,"b":[1,[2,3],4,"AAA","BBB"],"c":99}'}
+
+proc json_set_test {testnum x result} {
+ do_execsql_test json105-4.$testnum "SELECT quote(json_set(j,$x)) FROM t1" $result
+}
+json_set_test 10 {'$.b[#]','AAA'} {'{"a":1,"b":[1,[2,3],4,"AAA"],"c":99}'}
+json_set_test 20 {'$.b[1][#]','AAA'} {'{"a":1,"b":[1,[2,3,"AAA"],4],"c":99}'}
+json_set_test 30 {'$.b[1][#]','AAA','$.b[#]','BBB'} \
+ {'{"a":1,"b":[1,[2,3,"AAA"],4,"BBB"],"c":99}'}
+json_set_test 40 {'$.b[#]','AAA','$.b[#]','BBB'} \
+ {'{"a":1,"b":[1,[2,3],4,"AAA","BBB"],"c":99}'}
+json_set_test 50 {'$.b[#-1]','AAA'} {'{"a":1,"b":[1,[2,3],"AAA"],"c":99}'}
+json_set_test 60 {'$.b[1][#-1]','AAA'} {'{"a":1,"b":[1,[2,"AAA"],4],"c":99}'}
+json_set_test 70 {'$.b[1][#-1]','AAA','$.b[#-1]','BBB'} \
+ {'{"a":1,"b":[1,[2,"AAA"],"BBB"],"c":99}'}
+json_set_test 80 {'$.b[#-1]','AAA','$.b[#-1]','BBB'} \
+ {'{"a":1,"b":[1,[2,3],"BBB"],"c":99}'}
+
+proc json_replace_test {testnum x result} {
+ do_execsql_test json105-5.$testnum "SELECT quote(json_replace(j,$x)) FROM t1" $result
+}
+json_replace_test 10 {'$.b[#]','AAA'} {'{"a":1,"b":[1,[2,3],4],"c":99}'}
+json_replace_test 20 {'$.b[1][#]','AAA'} {'{"a":1,"b":[1,[2,3],4],"c":99}'}
+json_replace_test 30 {'$.b[1][#]','AAA','$.b[#]','BBB'} \
+ {'{"a":1,"b":[1,[2,3],4],"c":99}'}
+json_replace_test 40 {'$.b[#]','AAA','$.b[#]','BBB'} \
+ {'{"a":1,"b":[1,[2,3],4],"c":99}'}
+json_replace_test 50 {'$.b[#-1]','AAA'} {'{"a":1,"b":[1,[2,3],"AAA"],"c":99}'}
+json_replace_test 60 {'$.b[1][#-1]','AAA'} {'{"a":1,"b":[1,[2,"AAA"],4],"c":99}'}
+json_replace_test 70 {'$.b[1][#-1]','AAA','$.b[#-1]','BBB'} \
+ {'{"a":1,"b":[1,[2,"AAA"],"BBB"],"c":99}'}
+json_replace_test 80 {'$.b[#-1]','AAA','$.b[#-1]','BBB'} \
+ {'{"a":1,"b":[1,[2,3],"BBB"],"c":99}'}
+
+do_catchsql_test json105-6.10 {
+ SELECT json_extract(j, '$.b[#-]') FROM t1;
+} {1 {JSON path error near '[#-]'}}
+do_catchsql_test json105-6.20 {
+ SELECT json_extract(j, '$.b[#9]') FROM t1;
+} {1 {JSON path error near '[#9]'}}
+do_catchsql_test json105-6.30 {
+ SELECT json_extract(j, '$.b[#+2]') FROM t1;
+} {1 {JSON path error near '[#+2]'}}
+do_catchsql_test json105-6.40 {
+ SELECT json_extract(j, '$.b[#-1') FROM t1;
+} {1 {JSON path error near '[#-1'}}
+do_catchsql_test json105-6.50 {
+ SELECT json_extract(j, '$.b[#-1x]') FROM t1;
+} {1 {JSON path error near '[#-1x]'}}
+
+finish_test
diff --git a/test/minmax2.test b/test/minmax2.test
index b6114f2e51..5129146259 100644
--- a/test/minmax2.test
+++ b/test/minmax2.test
@@ -21,8 +21,8 @@ set testdir [file dirname $argv0]
source $testdir/tester.tcl
do_test minmax2-1.0 {
+ sqlite3_db_config db LEGACY_FILE_FORMAT 0
execsql {
- PRAGMA legacy_file_format=0;
BEGIN;
CREATE TABLE t1(x, y);
INSERT INTO t1 VALUES(1,1);
diff --git a/test/normalize.test b/test/normalize.test
index 8b0c7ed8db..29a5aabb26 100644
--- a/test/normalize.test
+++ b/test/normalize.test
@@ -347,6 +347,36 @@ foreach {tnum sql flags norm} {
{SELECT x FROM t1 WHERE x IN ([x] IS NOT NULL, NULL, 1, 'a', "b", x'00');}
0x2
{0 {SELECT x FROM t1 WHERE x IN(x IS NOT NULL,?,?,?,b,?);}}
+
+ 800
+ {ATTACH "normalize800.db" AS somefile;}
+ 0x2
+ {0 {ATTACH"normalize800.db"AS somefile;}}
+
+ 810
+ {ATTACH DATABASE "normalize810.db" AS somefile;}
+ 0x2
+ {0 {ATTACH DATABASE"normalize810.db"AS somefile;}}
+
+ 900
+ {INSERT INTO t1 (x) VALUES("sl1"), (1), ("sl2"), ('i');}
+ 0x2
+ {0 {INSERT INTO t1(x)VALUES(?),(?),(?),(?);}}
+
+ 910
+ {UPDATE t1 SET x = "sl1" WHERE x IN (1, "sl2", 'i');}
+ 0x2
+ {0 {UPDATE t1 SET x=?WHERE x IN(?,?,?);}}
+
+ 920
+ {UPDATE t1 SET x = "y" WHERE x IN (1, "sl1", 'i');}
+ 0x2
+ {0 {UPDATE t1 SET x=y WHERE x IN(?,?,?);}}
+
+ 930
+ {DELETE FROM t1 WHERE x IN (1, "sl1", 'i');}
+ 0x2
+ {0 {DELETE FROM t1 WHERE x IN(?,?,?);}}
} {
do_test $tnum {
set code [catch {
diff --git a/test/nulls1.test b/test/nulls1.test
index 98fc6ab37d..9f4402f916 100644
--- a/test/nulls1.test
+++ b/test/nulls1.test
@@ -248,6 +248,54 @@ do_execsql_test 7.0 {
SELECT * FROM t71 ORDER BY a DESC NULLS FIRST;
}
+# 2019-12-18 gramfuzz1 find
+# NULLS LAST not allows on an INTEGER PRIMARY KEY.
+#
+do_catchsql_test 8.0 {
+ CREATE TABLE t80(a, b INTEGER, PRIMARY KEY(b NULLS LAST)) WITHOUT ROWID;
+} {1 {unsupported use of NULLS LAST}}
+
+#-------------------------------------------------------------------------
+reset_db
+do_execsql_test 9.0 {
+ CREATE TABLE v0 (c1, c2, c3);
+ CREATE INDEX v3 ON v0 (c1, c2, c3);
+}
+do_execsql_test 9.1 {
+ ANALYZE sqlite_master;
+ INSERT INTO sqlite_stat1 VALUES('v0','v3','648 324 81');
+ ANALYZE sqlite_master;
+}
+
+do_execsql_test 9.2 {
+ INSERT INTO v0 VALUES
+ (1, 10, 'b'),
+ (1, 10, 'd'),
+ (1, 10, NULL),
+ (2, 10, 'a'),
+ (2, 10, NULL),
+ (1, 10, 'c'),
+ (2, 10, 'b'),
+ (1, 10, 'a'),
+ (1, 10, NULL),
+ (2, 10, NULL),
+ (2, 10, 'd'),
+ (2, 10, 'c');
+}
+
+do_execsql_test 9.3 {
+ SELECT c1, c2, ifnull(c3, 'NULL') FROM v0
+ WHERE c2=10 ORDER BY c1, c3 NULLS LAST
+} {
+ 1 10 a 1 10 b 1 10 c 1 10 d 1 10 NULL 1 10 NULL
+ 2 10 a 2 10 b 2 10 c 2 10 d 2 10 NULL 2 10 NULL
+}
+
+do_eqp_test 9.4 {
+ SELECT c1, c2, ifnull(c3, 'NULL') FROM v0
+ WHERE c2=10 ORDER BY c1, c3 NULLS LAST
+} {SEARCH TABLE v0 USING COVERING INDEX v3 (ANY(c1) AND c2=?)}
+
+
+
finish_test
-
-
diff --git a/test/orderby1.test b/test/orderby1.test
index 836ca4b83b..5152ffaf89 100644
--- a/test/orderby1.test
+++ b/test/orderby1.test
@@ -558,5 +558,9 @@ do_execsql_test 10.0 {
SELECT b, rowid, '^' FROM t10 ORDER BY b, a LIMIT 4;
} {2 1 ^ 4 3 ^ 4 4 ^ 7 5 ^}
+do_catchsql_test 11.0 {
+ VALUES(2) EXCEPT SELECT '' ORDER BY abc
+} {1 {1st ORDER BY term does not match any column in the result set}}
+
finish_test
diff --git a/test/ossfuzz.c b/test/ossfuzz.c
index 3b1017f726..b0156a640e 100644
--- a/test/ossfuzz.c
+++ b/test/ossfuzz.c
@@ -155,6 +155,9 @@ int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
/* Set a limit on the maximum size of a prepared statement */
sqlite3_limit(cx.db, SQLITE_LIMIT_VDBE_OP, 25000);
+ /* Limit total memory available to SQLite to 20MB */
+ sqlite3_hard_heap_limit64(20000000);
+
/* Set a limit on the maximum length of a string or BLOB. Without this
** limit, fuzzers will invoke randomblob(N) for a large N, and the process
** will timeout trying to generate the huge blob */
diff --git a/test/pragma3.test b/test/pragma3.test
index eebbcbb9c6..c4794c743c 100644
--- a/test/pragma3.test
+++ b/test/pragma3.test
@@ -255,4 +255,33 @@ if {[permutation]!="inmemory_journal"} {
}
}
+#-------------------------------------------------------------------------
+# Check that empty write transactions do not cause the return of "PRAGMA
+# data_version" to be decremented with journal_mode=PERSIST and
+# locking_mode=EXCLUSIVE
+#
+foreach {tn sql} {
+ A {
+ }
+ B {
+ PRAGMA journal_mode = PERSIST;
+ PRAGMA locking_mode = EXCLUSIVE;
+ }
+} {
+ reset_db
+ execsql $sql
+
+ do_execsql_test pragma3-510$tn {
+ CREATE TABLE t1(x, y);
+ INSERT INTO t1 VALUES(1, 2);
+ PRAGMA data_version;
+ } {1}
+
+ do_execsql_test pragma3-520$tn {
+ BEGIN EXCLUSIVE;
+ COMMIT;
+ PRAGMA data_version;
+ } {1}
+}
+
finish_test
diff --git a/test/pragma4.test b/test/pragma4.test
index bceb4b84f4..2eef060b6c 100644
--- a/test/pragma4.test
+++ b/test/pragma4.test
@@ -44,7 +44,6 @@ foreach {tn sql} {
14 "PRAGMA full_column_names = 1"
15 "PRAGMA fullfsync = 1"
16 "PRAGMA ignore_check_constraints = 1"
- 17 "PRAGMA legacy_file_format = 1"
18 "PRAGMA page_size = 511"
19 "PRAGMA page_size = 512"
20 "PRAGMA query_only = false"
diff --git a/test/pragma5.test b/test/pragma5.test
index f16e4627ba..6d9b5bbcdc 100644
--- a/test/pragma5.test
+++ b/test/pragma5.test
@@ -32,12 +32,18 @@ do_execsql_test 1.0 {
} {
0 name {} 0 {} 0
1 builtin {} 0 {} 0
+ 2 type {} 0 {} 0
+ 3 enc {} 0 {} 0
+ 4 narg {} 0 {} 0
+ 5 flags {} 0 {} 0
}
do_execsql_test 1.1 {
- SELECT * FROM pragma_function_list WHERE name='upper' AND builtin
+ SELECT DISTINCT name, builtin
+ FROM pragma_function_list WHERE name='upper' AND builtin
} {upper 1}
do_execsql_test 1.2 {
- SELECT * FROM pragma_function_list WHERE name LIKE 'exter%';
+ SELECT DISTINCT name, builtin
+ FROM pragma_function_list WHERE name LIKE 'exter%';
} {external 0}
ifcapable fts5 {
diff --git a/test/rowvalue.test b/test/rowvalue.test
index e859024711..e3b66a1096 100644
--- a/test/rowvalue.test
+++ b/test/rowvalue.test
@@ -570,4 +570,78 @@ do_execsql_test 22.100 {
SELECT (SELECT 5,6 UNION SELECT 3,4 ORDER BY 1 DESC) IN (SELECT 5,6);
} {1 0 1 0 0 1 0 1}
+# 2019-10-21 Ticket b47e3627ecaadbde
+#
+do_execsql_test 23.100 {
+ DROP TABLE IF EXISTS t0;
+ CREATE TABLE t0(aa COLLATE NOCASE, bb);
+ INSERT INTO t0 VALUES('a', 'A');
+ SELECT (+bb,1) >= (aa, 1), (aa,1)<=(+bb,1) FROM t0;
+ SELECT 2 FROM t0 WHERE (+bb,1) >= (aa,1);
+ SELECT 3 FROM t0 WHERE (aa,1) <= (+bb,1);
+} {0 1 3}
+do_execsql_test 23.110 {
+ SELECT (SELECT +bb,1) >= (aa, 1), (aa,1)<=(SELECT +bb,1) FROM t0;
+ SELECT 2 FROM t0 WHERE (SELECT +bb,1) >= (aa,1);
+ SELECT 3 FROM t0 WHERE (aa,1) <= (SELECT +bb,1);
+} {0 1 3}
+
+# 2019-10-22 Ticket 6ef984af8972c2eb
+do_execsql_test 24.100 {
+ DROP TABLE t0;
+ CREATE TABLE t0(c0 TEXT PRIMARY KEY);
+ INSERT INTO t0(c0) VALUES ('');
+ SELECT (t0.c0, TRUE) > (CAST(0 AS REAL), FALSE) FROM t0;
+ SELECT 2 FROM t0 WHERE (t0.c0, TRUE) > (CAST('' AS REAL), FALSE);
+} {1 2}
+
+# 2019-10-23 Ticket 135c9da7513e5a97
+do_execsql_test 25.10 {
+ DROP TABLE t0;
+ CREATE TABLE t0(c0 UNIQUE);
+ INSERT INTO t0(c0) VALUES('a');
+ SELECT (t0.c0, 0) < ('B' COLLATE NOCASE, 0) FROM t0;
+ SELECT 2 FROM t0 WHERE (t0.c0, 0) < ('B' COLLATE NOCASE, 0);
+} {1 2}
+do_execsql_test 25.20 {
+ SELECT ('B' COLLATE NOCASE, 0)> (t0.c0, 0) FROM t0;
+ SELECT 2 FROM t0 WHERE ('B' COLLATE NOCASE, 0)> (t0.c0, 0);
+} {1 2}
+do_execsql_test 25.30 {
+ SELECT ('B', 0)> (t0.c0 COLLATE nocase, 0) FROM t0;
+ SELECT 2 FROM t0 WHERE ('B', 0)> (t0.c0 COLLATE nocase, 0);
+} {1 2}
+do_execsql_test 25.40 {
+ SELECT (t0.c0 COLLATE nocase, 0) < ('B', 0) FROM t0;
+ SELECT 2 FROM t0 WHERE (t0.c0 COLLATE nocase, 0) < ('B', 0);
+} {1 2}
+
+# 2019-11-04 Ticket 02aa2bd02f97d0f2
+# The TK_VECTOR operator messes up sqlite3ExprImpliesNonNull() which
+# causes incorrect LEFT JOIN strength reduction. TK_VECTOR should be
+# treated the same as TK_OR.
+#
+db close
+sqlite3 db :memory:
+do_execsql_test 26.10 {
+ CREATE TABLE t0(c0);
+ CREATE TABLE t1(c1);
+ INSERT INTO t1(c1) VALUES (0);
+ SELECT (c0, x'') != (NULL, 0) FROM t1 LEFT JOIN t0;
+} {1}
+do_execsql_test 26.20 {
+ SELECT 2 FROM t1 LEFT JOIN t0 ON (c0, x'') != (NULL, 0);
+} {2}
+do_execsql_test 26.30 {
+ SELECT 3 FROM t1 LEFT JOIN t0 WHERE (c0, x'') != (NULL, 0);
+} {3}
+
+# 2019-12-30 ticket 892575cdba4e1e36
+#
+reset_db
+do_catchsql_test 27.10 {
+ CREATE TABLE t0(c0 CHECK(((0, 0) > (0, c0))));
+ INSERT INTO t0(c0) VALUES(0) ON CONFLICT(c0) DO UPDATE SET c0 = 3;
+} {1 {ON CONFLICT clause does not match any PRIMARY KEY or UNIQUE constraint}}
+
finish_test
diff --git a/test/rowvaluevtab.test b/test/rowvaluevtab.test
new file mode 100644
index 0000000000..aa834657b8
--- /dev/null
+++ b/test/rowvaluevtab.test
@@ -0,0 +1,90 @@
+# 2018 October 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.
+#
+#***********************************************************************
+#
+
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+set ::testprefix rowvaluevtab
+
+register_echo_module db
+
+do_execsql_test 1.0 {
+ CREATE TABLE t1(a, b, c);
+ CREATE INDEX t1b ON t1(b);
+ INSERT INTO t1 VALUES('one', 1, 1);
+ INSERT INTO t1 VALUES('two', 1, 2);
+ INSERT INTO t1 VALUES('three', 1, 3);
+ INSERT INTO t1 VALUES('four', 2, 1);
+ INSERT INTO t1 VALUES('five', 2, 2);
+ INSERT INTO t1 VALUES('six', 2, 3);
+ INSERT INTO t1 VALUES('seven', 3, 1);
+ INSERT INTO t1 VALUES('eight', 3, 2);
+ INSERT INTO t1 VALUES('nine', 3, 3);
+
+ WITH s(i) AS (
+ SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<10000
+ ) INSERT INTO t1 SELECT NULL, NULL, NULL FROM s;
+ CREATE VIRTUAL TABLE e1 USING echo(t1);
+}
+
+proc do_vfilter4_test {tn sql expected} {
+ set res [list]
+ db eval "explain $sql" {
+ if {$opcode=="VFilter"} {
+ lappend res $p4
+ }
+ }
+ uplevel [list do_test $tn [list set {} $res] [list {*}$expected]]
+}
+
+do_execsql_test 1.1 {
+ SELECT a FROM e1 WHERE (b, c) = (2, 2)
+} {five}
+do_vfilter4_test 1.1f {
+ SELECT a FROM e1 WHERE (b, c) = (?, ?)
+} {{SELECT rowid, a, b, c FROM 't1' WHERE b = ?}}
+
+do_execsql_test 1.2 {
+ SELECT a FROM e1 WHERE (b, c) > (2, 2)
+} {six seven eight nine}
+do_vfilter4_test 1.2f {
+ SELECT a FROM e1 WHERE (b, c) > (2, 2)
+} {
+ {SELECT rowid, a, b, c FROM 't1' WHERE b >= ?}
+}
+
+do_execsql_test 1.3 {
+ SELECT a FROM e1 WHERE (b, c) >= (2, 2)
+} {five six seven eight nine}
+do_vfilter4_test 1.3f {
+ SELECT a FROM e1 WHERE (b, c) >= (2, 2)
+} {
+ {SELECT rowid, a, b, c FROM 't1' WHERE b >= ?}
+}
+
+do_execsql_test 1.3 {
+ SELECT a FROM e1 WHERE (b, c) BETWEEN (1, 2) AND (2, 3)
+} {two three four five six}
+do_vfilter4_test 1.3f {
+ SELECT a FROM e1 WHERE (b, c) BETWEEN (1, 2) AND (2, 3)
+} {
+ {SELECT rowid, a, b, c FROM 't1' WHERE b >= ? AND b <= ?}
+}
+
+do_execsql_test 1.4 {
+ SELECT a FROM e1 WHERE (b, c) IN ( VALUES(2, 2) )
+} {five}
+do_vfilter4_test 1.4f {
+ SELECT a FROM e1 WHERE (b, c) IN ( VALUES(2, 2) )
+} {{SELECT rowid, a, b, c FROM 't1' WHERE b = ?}}
+
+finish_test
diff --git a/test/select1.test b/test/select1.test
index 27191caf67..b9414d3857 100644
--- a/test/select1.test
+++ b/test/select1.test
@@ -1165,4 +1165,40 @@ do_execsql_test select1-18.4 {
);
} {1}
+# 2019-12-17 gramfuzz find
+#
+do_execsql_test select-19.10 {
+ DROP TABLE IF EXISTS t1;
+ CREATE TABLE t1(x);
+} {}
+do_catchsql_test select-19.20 {
+ INSERT INTO t1
+ SELECT 1,2,3,4,5,6,7
+ UNION ALL SELECT 1,2,3,4,5,6,7
+ ORDER BY 1;
+} {1 {table t1 has 1 columns but 7 values were supplied}}
+do_catchsql_test select-19.21 {
+ INSERT INTO t1
+ SELECT 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
+ UNION ALL SELECT 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
+ ORDER BY 1;
+} {1 {table t1 has 1 columns but 15 values were supplied}}
+
+# 2020-01-01 Found by Yongheng's fuzzer
+#
+reset_db
+do_execsql_test select-20.10 {
+ CREATE TABLE t1 (
+ a INTEGER PRIMARY KEY,
+ b AS('Y') UNIQUE
+ );
+ INSERT INTO t1(a) VALUES (10);
+ SELECT * FROM t1 JOIN t1 USING(a,b)
+ WHERE ((SELECT t1.a FROM t1 AS x GROUP BY b) AND b=0)
+ OR a = 10;
+} {10 Y}
+do_execsql_test select-20.20 {
+ SELECT ifnull(a, max((SELECT 123))), count(a) FROM t1 ;
+} {10 1}
+
finish_test
diff --git a/test/skipscan1.test b/test/skipscan1.test
index da9df8fe5e..367cd2a108 100644
--- a/test/skipscan1.test
+++ b/test/skipscan1.test
@@ -398,4 +398,25 @@ do_eqp_test skipscan1-3.2 {
`--USE TEMP B-TREE FOR DISTINCT
}
+# 2020-01-06 ticket 304017f5f04a0035
+#
+reset_db
+do_execsql_test skipscan1-4.10 {
+ CREATE TABLE t1(a,b INT);
+ INSERT INTO t1(a,b) VALUES(1,2),(3,3),(4,5);
+ CREATE UNIQUE INDEX i1 ON t1(b,b,a,a,a,a,a,b,a);
+ ANALYZE;
+ DROP TABLE IF EXISTS sqlite_stat4;
+ INSERT INTO sqlite_stat1 VALUES('t1','i1','30 30 30 2 2 2 2 2 2 2');
+ ANALYZE sqlite_master;
+
+ SELECT DISTINCT a
+ FROM t1
+ WHERE a = b
+ AND a = 3
+ AND b IN (1,3,2,4)
+ AND b >= 0
+ AND a <= 10;
+} {3}
+
finish_test
diff --git a/test/stat.test b/test/stat.test
index 66ca5e2f2b..105169df1d 100644
--- a/test/stat.test
+++ b/test/stat.test
@@ -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';
+ FROM stat WHERE name != 'sqlite_master' 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 \
@@ -134,6 +134,14 @@ do_execsql_test stat-2.1 {
t3 /00f/ 23 leaf 2 738 268 370 \
]
+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 \
+ t3 {} 17 {} 47 11188 5815 370 {} 17408 \
+]
+
# With every index entry overflowing, make sure no pages are missed
# (other than the locking page which is 64 in this test build.)
#
@@ -150,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';
+ FROM stat WHERE name != 'sqlite_master' ORDER BY name;
} [list \
i4 / 3 leaf 1 103 905 7782 \
i4 /000+000000 4 overflow 0 1020 0 0 \
@@ -171,6 +179,15 @@ do_execsql_test stat-3.1 {
t4 /000+000006 18 overflow 0 1020 0 0 \
]
+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 | \
+ t4 {} 8 {} 1 7780 367 7780 {} 8192 | \
+]
+
+
do_execsql_test stat-4.1 {
CREATE TABLE t5(x);
CREATE INDEX i5 ON t5(x);
@@ -201,6 +218,16 @@ do_execsql_test stat-5.1 {
t1 /001+000000 4 overflow 0 1020 0 0 \
]
+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 |}
+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 |}
+
+
do_catchsql_test stat-6.1 {
CREATE VIRTUAL TABLE temp.s2 USING dbstat(mainx);
} {1 {no such database: mainx}}
@@ -271,4 +298,21 @@ do_catchsql_test 7.2.4 {
SELECT * FROM x3;
} {1 {unrecognized token: "123corp"}}
+
+do_execsql_test 8.1 {
+ CREATE VIRTUAL TABLE st4 USING dbstat;
+}
+do_execsql_test 8.2 {
+ SELECT * FROM st4 WHERE st4.aggregate = NULL;
+}
+do_execsql_test 8.3 {
+ SELECT aggregate=1 FROM st4 WHERE aggregate = 5
+}
+do_execsql_test 8.4 {
+ SELECT * FROM st4 WHERE name = NULL;
+} {}
+do_execsql_test 8.5 {
+ SELECT * FROM st4 WHERE schema = NULL;
+} {}
+
finish_test
diff --git a/test/symlink.test b/test/symlink.test
index 4695b29fa0..98b2a32c0e 100644
--- a/test/symlink.test
+++ b/test/symlink.test
@@ -37,11 +37,30 @@ do_test 1.1 {
sqlite3_db_filename db2 main
} [file join [pwd] test.db]
+# But not with the -nofollow flag
+#
+do_test 1.1.2 {
+ db2 close
+ set rc [catch {sqlite3 db2 test.db2 -nofollow 1} msg]
+ lappend rc $msg
+} {1 {unable to open database file}}
+
+# If the main database is successfully opened with -nofollow, then -nofollow
+# is also used for ATTACH.
+#
+do_test 1.1.3 {
+ catch {db2 close}
+ sqlite3 db2 test.db -nofollow 1
+} {}
+do_test 1.1.4 {
+ catchsql {ATTACH 'test.db2' AS aux1;} db2
+} {1 {unable to open database: test.db2}}
+
# Test that if the symlink points to a file that does not exists, it is
# created when it is opened.
#
do_test 1.2.1 {
- db2 close
+ catch {db2 close}
db close
forcedelete test.db
file exists test.db
diff --git a/test/symlink2.test b/test/symlink2.test
new file mode 100644
index 0000000000..4123092deb
--- /dev/null
+++ b/test/symlink2.test
@@ -0,0 +1,116 @@
+# 2019 November 18
+#
+# The author disclaims copyright to this source code. In place of
+# a legal notice, here is a blessing:
+#
+# May you do good and not evil.
+# May you find forgiveness for yourself and forgive others.
+# May you share freely, never taking more than you give.
+#
+#***********************************************************************
+# This file implements regression tests for SQLite library. The
+# focus of this file is testing that SQLite can follow symbolic links.
+#
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+set testprefix symlink2
+
+# This only runs on Windows.
+if {$::tcl_platform(platform)!="windows"} {
+ finish_test
+ return
+}
+
+proc createWin32Symlink { link target } {
+ exec -- $::env(ComSpec) /c mklink \
+ [file nativename $link] [file nativename $target]
+ return ""
+}
+
+proc deleteWin32Symlink { link } {
+ exec -- $::env(ComSpec) /c del [file nativename $link]
+ return ""
+}
+
+proc canCreateWin32Symlink {} {
+ set link [file join $::testdir lnk[pid].sym]
+ if {[file exists $link]} { return 0 }
+ set target [info nameofexecutable]
+ if {[catch {createWin32Symlink $link $target}] == 0} {
+ deleteWin32Symlink $link
+ return 1
+ }
+ return 0
+}
+
+# Creating symlinks may require administrator privileges on Windows.
+if {![canCreateWin32Symlink]} {
+ finish_test
+ return
+}
+
+# Ensure that test.db has been created.
+#
+do_execsql_test 1.0 {
+ CREATE TABLE t1(x, y);
+ INSERT INTO t1 VALUES(1,9999);
+}
+
+do_test 2.0 {
+ createWin32Symlink link.db test.db
+} {}
+
+do_test 2.1 {
+ file exists test.db
+} {1}
+
+do_test 2.2 {
+ file exists link.db
+} {1}
+
+do_test 3.1 {
+ execsql { SELECT x, y FROM t1; } db
+} {1 9999}
+
+do_test 3.2 {
+ sqlite3 db2 link.db
+ execsql { SELECT x, y FROM t1; } db2
+} {1 9999}
+
+do_test 3.3 {
+ sqlite3 db3 test.db -nofollow true
+ execsql { SELECT x, y FROM t1; } db3
+} {1 9999}
+
+do_test 3.4 {
+ db3 close
+} {}
+
+do_test 3.5 {
+ list [catch {
+ sqlite3 db4 link.db -nofollow true
+ execsql { SELECT x, y FROM t1; } db4
+ } res] $res
+} {1 {unable to open database file}}
+
+catch {db4 close}
+
+do_test 4.0 {
+ db2 close
+ deleteWin32Symlink link.db
+} {}
+
+do_test 4.1 {
+ file exists test.db
+} {1}
+
+do_test 4.2 {
+ file exists link.db
+} {0}
+
+do_test 5.1 {
+ execsql { SELECT x, y FROM t1; } db
+} {1 9999}
+
+finish_test
diff --git a/test/tabfunc01.test b/test/tabfunc01.test
index 49f0df889e..04bc6f42ad 100644
--- a/test/tabfunc01.test
+++ b/test/tabfunc01.test
@@ -218,6 +218,15 @@ do_test tabfunc01-750 {
}
} {5.0 x5 | 7.0 x7 | 13.0 x13 | 17.0 x17 | 23.0 x23 |}
+# ticket https://www.sqlite.org/src/info/2ae0c599b735d59e
+do_test tabfunc01-751 {
+ db eval {
+ SELECT aa.value, bb.value, '|'
+ FROM carray(inttoptr($PTR4),5,'double') AS aa
+ LEFT JOIN carray(inttoptr($PTR5),5,'char*') AS bb ON aa.rowid=bb.rowid;
+ }
+} {5.0 x5 | 7.0 x7 | 13.0 x13 | 17.0 x17 | 23.0 x23 |}
+
# Free up memory allocations
intarray_addr
int64array_addr
diff --git a/test/tclsqlite.test b/test/tclsqlite.test
index 92425aeffb..b01da0ec23 100644
--- a/test/tclsqlite.test
+++ b/test/tclsqlite.test
@@ -25,7 +25,7 @@ set testprefix tcl
# Check the error messages generated by tclsqlite
#
-set r "sqlite_orig HANDLE ?FILENAME? ?-vfs VFSNAME? ?-readonly BOOLEAN? ?-create BOOLEAN? ?-nomutex BOOLEAN? ?-fullmutex BOOLEAN? ?-uri BOOLEAN?"
+set r "sqlite_orig HANDLE ?FILENAME? ?-vfs VFSNAME? ?-readonly BOOLEAN? ?-create BOOLEAN? ?-nofollow BOOLEAN? ?-nomutex BOOLEAN? ?-fullmutex BOOLEAN? ?-uri BOOLEAN?"
if {[sqlite3 -has-codec]} {
append r " ?-key CODECKEY?"
}
@@ -789,7 +789,7 @@ do_test 17.6.2 {
do_test 17.6.3 {
list [catch { db function xyz -n object ret } msg] $msg
-} {1 {bad option "-n": must be -argcount, -deterministic, -directonly, or -returntype}}
+} {1 {bad option "-n": must be -argcount, -deterministic, -directonly, -innocuous, or -returntype}}
# 2019-02-28: The "bind_fallback" command.
#
diff --git a/test/tester.tcl b/test/tester.tcl
index dadf91b20a..d26ec3056b 100644
--- a/test/tester.tcl
+++ b/test/tester.tcl
@@ -388,6 +388,7 @@ proc print_help_and_quit {} {
puts {Options:
--pause Wait for user input before continuing
--soft-heap-limit=N Set the soft-heap-limit to N
+ --hard-heap-limit=N Set the hard-heap-limit to N
--maxerror=N Quit after N errors
--verbose=(0|1) Control the amount of output. Default '1'
--output=FILE set --verbose=2 and output to FILE. Implies -q
@@ -408,6 +409,7 @@ if {[info exists cmdlinearg]==0} {
#
# --pause
# --soft-heap-limit=NN
+ # --hard-heap-limit=NN
# --maxerror=NN
# --malloctrace=N
# --backtrace=N
@@ -424,6 +426,7 @@ if {[info exists cmdlinearg]==0} {
# --help
#
set cmdlinearg(soft-heap-limit) 0
+ set cmdlinearg(hard-heap-limit) 0
set cmdlinearg(maxerror) 1000
set cmdlinearg(malloctrace) 0
set cmdlinearg(backtrace) 10
@@ -450,6 +453,9 @@ if {[info exists cmdlinearg]==0} {
{^-+soft-heap-limit=.+$} {
foreach {dummy cmdlinearg(soft-heap-limit)} [split $a =] break
}
+ {^-+hard-heap-limit=.+$} {
+ foreach {dummy cmdlinearg(hard-heap-limit)} [split $a =] break
+ }
{^-+maxerror=.+$} {
foreach {dummy cmdlinearg(maxerror)} [split $a =] break
}
@@ -586,7 +592,8 @@ if {[info exists cmdlinearg]==0} {
# way if an individual test file changes the soft-heap-limit, it
# will be reset at the start of the next test file.
#
-sqlite3_soft_heap_limit $cmdlinearg(soft-heap-limit)
+sqlite3_soft_heap_limit64 $cmdlinearg(soft-heap-limit)
+sqlite3_hard_heap_limit64 $cmdlinearg(hard-heap-limit)
# Create a test database
#
@@ -1208,7 +1215,8 @@ proc finalize_testing {} {
db close
sqlite3_reset_auto_extension
- sqlite3_soft_heap_limit 0
+ sqlite3_soft_heap_limit64 0
+ sqlite3_hard_heap_limit64 0
set nTest [incr_ntest]
set nErr [set_test_counter errors]
diff --git a/test/tkt-18458b1a.test b/test/tkt-18458b1a.test
index 996ca88451..4a61274859 100644
--- a/test/tkt-18458b1a.test
+++ b/test/tkt-18458b1a.test
@@ -50,4 +50,3 @@ foreach tn {1 2} {
}
finish_test
-
diff --git a/test/tkt-a7debbe0.test b/test/tkt-a7debbe0.test
index 974f6d66b0..cc72eb7b5e 100644
--- a/test/tkt-a7debbe0.test
+++ b/test/tkt-a7debbe0.test
@@ -100,4 +100,3 @@ foreach tn {1 2} {
}
finish_test
-
diff --git a/test/tkt3292.test b/test/tkt3292.test
index 0f95244643..717a29c9a0 100644
--- a/test/tkt3292.test
+++ b/test/tkt3292.test
@@ -20,8 +20,8 @@ set testdir [file dirname $argv0]
source $testdir/tester.tcl
do_test tkt3292-1.1 {
+ sqlite3_db_config db LEGACY_FILE_FORMAT 0
execsql {
- PRAGMA legacy_file_format=OFF;
CREATE TABLE t1(a INTEGER PRIMARY KEY, b INT);
INSERT INTO t1 VALUES(0, 1);
INSERT INTO t1 VALUES(1, 1);
diff --git a/test/trigger1.test b/test/trigger1.test
index ddb40e3adb..456e983381 100644
--- a/test/trigger1.test
+++ b/test/trigger1.test
@@ -782,4 +782,49 @@ do_execsql_test trigger1-20.1 {
DROP TRIGGER r20_3;
} {}
+# 2019-10-24 ticket 50c09fc2cf0d91ce
+#
+db close
+sqlite3 db :memory:
+do_execsql_test trigger1-21.1 {
+ PRAGMA recursive_triggers = true;
+ CREATE TABLE t0(a, b, c UNIQUE);
+ CREATE UNIQUE INDEX i0 ON t0(b) WHERE a;
+ CREATE TRIGGER tr0 AFTER DELETE ON t0 BEGIN
+ DELETE FROM t0;
+ END;
+ INSERT INTO t0(a,b,c) VALUES(0,0,9),(1,1,1);
+ REPLACE INTO t0(a,b,c) VALUES(2,0,9);
+ SELECT * FROM t0;
+} {2 0 9}
+
+# 2020-01-04 From Yongheng
+# The test case below caused problems for the register validity
+# tracking logic. There was no bug in the release build. The
+# only problem was a false-positive in the register validity
+# tracking.
+#
+reset_db
+do_execsql_test trigger1-22.10 {
+ CREATE TABLE t1(
+ a INTEGER PRIMARY KEY,
+ b DOUBLE
+ );
+ CREATE TRIGGER x AFTER UPDATE ON t1 BEGIN
+ SELECT sum(b)OVER(ORDER BY (SELECT b FROM t1 AS x
+ WHERE b IN (t1.a,127,t1.b)
+ GROUP BY b))
+ FROM t1
+ GROUP BY a;
+ END;
+ CREATE TEMP TRIGGER x BEFORE INSERT ON t1 BEGIN
+ UPDATE t1
+ SET b=randomblob(10)
+ WHERE b >= 'E'
+ AND a < (SELECT a FROM t1 WHERE a<22 GROUP BY b);
+ END;
+ INSERT INTO t1(b) VALUES('Y'),('X'),('Z');
+ SELECT a, CASE WHEN typeof(b)='text' THEN quote(b) ELSE '' END, '|' FROM t1;
+} {1 | 2 'X' | 3 'Z' |}
+
finish_test
diff --git a/test/trigger2.test b/test/trigger2.test
index 7b939bdab7..1be72131f7 100644
--- a/test/trigger2.test
+++ b/test/trigger2.test
@@ -752,8 +752,23 @@ do_test trigger2-9.1 {
}
} {}
+integrity_check trigger2-9.99
+
+# 2019-11-02 Problem found by TH3, related to generated column support.
+db close
+sqlite3 db :memory:
+do_execsql_test trigger2-10.1 {
+ CREATE TABLE t1(a,b,c,d);
+ CREATE VIEW v2(a,b,c,d) AS SELECT * FROM t1;
+ CREATE TRIGGER v2ins INSTEAD OF INSERT ON v2 BEGIN
+ INSERT INTO t1(a,b,c,d) VALUES(new.a, new.b, new.c, new.d);
+ END;
+ INSERT INTO v2(a,d) VALUES(11,14);
+ SELECT * FROM t1;
+} {11 {} {} 14}
+
} ;# ifcapable view
-integrity_check trigger2-9.9
+integrity_check trigger2-999
finish_test
diff --git a/test/trustschema1.test b/test/trustschema1.test
new file mode 100644
index 0000000000..dba954f146
--- /dev/null
+++ b/test/trustschema1.test
@@ -0,0 +1,251 @@
+# 2020-01-08
+#
+# The author disclaims copyright to this source code. In place of
+# a legal notice, here is a blessing:
+#
+# May you do good and not evil.
+# May you find forgiveness for yourself and forgive others.
+# May you share freely, never taking more than you give.
+#
+#***********************************************************************
+#
+# Test cases for managing execution of code snippets found in untrusted
+# schemas.
+#
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+set testprefix trustschema1
+
+# edgy functions used in generated columns
+#
+proc f1 {x} {return $x}
+do_test 1.100 {
+ db function f1 -innocuous -deterministic f1
+ db function f2 -deterministic f1
+ db function f3 -directonly -deterministic f1
+ db eval {
+ CREATE TABLE t1(a, b AS (f1(a+1)), c AS (f2(a+2)));
+ INSERT INTO t1 VALUES(100),(200);
+ }
+} {}
+do_catchsql_test 1.110 {
+ SELECT a, b, c FROM t1;
+} {0 {100 101 102 200 201 202}}
+do_execsql_test 1.120 {
+ PRAGMA trusted_schema=OFF;
+} {}
+do_catchsql_test 1.130 {
+ SELECT a, b FROM t1;
+} {0 {100 101 200 201}}
+do_catchsql_test 1.140 {
+ SELECT a, b, c FROM t1;
+} {1 {unsafe use of f2()}}
+do_catchsql_test 1.150 {
+ PRAGMA trusted_schema=ON;
+ DROP TABLE t1;
+ CREATE TABLE t1(a, b AS (f3(a+1)));
+} {1 {unsafe use of f3()}}
+do_execsql_test 1.160 {
+ PRAGMA trusted_schema=OFF;
+ CREATE TEMP TABLE temp1(a,b AS (f3(a+1)));
+ INSERT INTO temp1(a) VALUES(100),(900);
+ SELECT * FROM temp1;
+} {100 101 900 901}
+
+# edgy functions used in CHECK constraints
+#
+do_catchsql_test 1.200 {
+ PRAGMA trusted_schema=ON;
+ CREATE TABLE t2(a,b,c,CHECK(f3(c)==c));
+} {1 {unsafe use of f3()}}
+do_catchsql_test 1.210 {
+ PRAGMA trusted_schema=Off;
+ CREATE TABLE t2(a,b,c,CHECK(f2(c)==c));
+} {1 {unsafe use of f2()}}
+do_catchsql_test 1.211 {
+ PRAGMA trusted_schema=On;
+ CREATE TABLE t2(a,b,c,CHECK(f2(c)==c));
+} {0 {}}
+do_catchsql_test 1.220 {
+ INSERT INTO t2 VALUES(1,2,3);
+ SELECT * FROM t2;
+} {0 {1 2 3}}
+do_catchsql_test 1.230 {
+ PRAGMA trusted_schema=off;
+ INSERT INTO t2 VALUES(4,5,6);
+} {1 {unsafe use of f2()}}
+do_execsql_test 1.231 {
+ SELECT * FROM t2;
+} {1 2 3}
+# Ok to put as many edgy functions as you want in a
+# TEMP table.
+do_execsql_test 1.240 {
+ PRAGMA trusted_schema=OFF;
+ CREATE TEMP TABLE temp2(a, b, CHECK(f3(b)==b));
+ INSERT INTO temp2(a,b) VALUES(1,2),('x','y');
+ SELECT * FROM temp2;
+} {1 2 x y}
+
+# edgy functions used in DEFAULT constraints
+#
+do_catchsql_test 1.300 {
+ CREATE TABLE t3(a,b DEFAULT(f2(25)));
+} {0 {}}
+do_catchsql_test 1.310 {
+ PRAGMA trusted_schema=Off;
+ INSERT INTO t3(a) VALUES(1);
+} {1 {unsafe use of f2()}}
+do_catchsql_test 1.311 {
+ INSERT INTO t3(a,b) VALUES(1,2);
+} {0 {}}
+do_execsql_test 1.320 {
+ CREATE TEMP TABLE temp3(a, b DEFAULT(f3(31)));
+ INSERT INTO temp3(a) VALUES(22);
+ SELECT * FROM temp3;
+} {22 31}
+
+# edgy functions used in partial indexes.
+#
+do_execsql_test 1.400 {
+ CREATE TABLE t4(a,b,c);
+ INSERT INTO t4 VALUES(1,2,3),('a','b','c'),(4,'d',0);
+ SELECT * FROM t4;
+ CREATE TEMP TABLE temp4(a,b,c);
+ INSERT INTO temp4 SELECT * FROM t4;
+} {1 2 3 a b c 4 d 0}
+do_catchsql_test 1.410 {
+ CREATE INDEX t4a ON t4(a) WHERE f3(c);
+} {1 {unsafe use of f3()}}
+do_catchsql_test 1.420 {
+ PRAGMA trusted_schema=OFF;
+ CREATE INDEX t4a ON t4(a) WHERE f2(c);
+} {1 {unsafe use of f2()}}
+do_execsql_test 1.421 {
+ CREATE INDEX t4a ON t4(a) WHERE f1(c);
+ SELECT a FROM t4 WHERE f1(c) ORDER BY a;
+} {1}
+do_execsql_test 1.430 {
+ PRAGMA trusted_schema=ON;
+ CREATE INDEX t4b ON t4(b) WHERE f2(c);
+ SELECT b FROM t4 WHERE f2(c) ORDER BY b;
+} {2}
+do_execsql_test 1.440 {
+ PRAGMA trusted_schema=OFF;
+ CREATE INDEX temp4a ON temp4(a) WHERE f3(c);
+ SELECT a FROM temp4 WHERE f2(c) ORDER BY a;
+} {1}
+
+# edgy functions used in index expressions
+#
+do_execsql_test 1.500 {
+ CREATE TABLE t5(a,b,c);
+ INSERT INTO t5 VALUES(1,2,3),(4,5,6),(7,0,-3);
+ SELECT * FROM t5;
+ CREATE TEMP TABLE temp5(a,b,c);
+ INSERT INTO temp5 SELECT * FROM t5;
+} {1 2 3 4 5 6 7 0 -3}
+do_catchsql_test 1.510 {
+ CREATE INDEX t5x1 ON t5(a+f3(b));
+} {1 {unsafe use of f3()}}
+do_catchsql_test 1.520 {
+ PRAGMA trusted_schema=OFF;
+ CREATE INDEX t5x1 ON t5(a+f2(b));
+} {1 {unsafe use of f2()}}
+do_execsql_test 1.521 {
+ CREATE INDEX t5x1 ON t5(a+f1(b));
+ SELECT * FROM t5 INDEXED BY t5x1 WHERE a+f1(b)=3;
+} {1 2 3}
+do_execsql_test 1.530 {
+ PRAGMA trusted_schema=ON;
+ CREATE INDEX t5x2 ON t5(b+f2(c));
+ SELECT * FROM t5 INDEXED BY t5x2 WHERE b+f2(c)=11;
+} {4 5 6}
+do_execsql_test 1.540 {
+ PRAGMA trusted_schema=OFF;
+ CREATE INDEX temp5x1 ON temp5(a+f3(b));
+ SELECT * FROM temp5 INDEXED BY temp5x1 WHERE a+f3(b)=7;
+} {7 0 -3}
+
+# edgy functions in VIEWs
+#
+reset_db
+db function f1 -innocuous -deterministic f1
+db function f2 -deterministic f1
+db function f3 -directonly -deterministic f1
+do_execsql_test 2.100 {
+ CREATE TABLE t1(a,b,c);
+ INSERT INTO t1 VALUES(1,2,3),(100,50,75),(-11,22,-33);
+ CREATE VIEW v1a AS SELECT f3(a+b) FROM t1;
+ SELECT f3(a+b) FROM t1;
+} {3 150 11}
+do_catchsql_test 2.110 {
+ PRAGMA trusted_schema=ON;
+ SELECT * FROM v1a;
+} {1 {unsafe use of f3()}}
+do_catchsql_test 2.111 {
+ PRAGMA trusted_schema=OFF;
+ SELECT * FROM v1a;
+} {1 {unsafe use of f3()}}
+do_execsql_test 2.120 {
+ DROP VIEW v1a;
+ CREATE TEMP VIEW v1a AS SELECT f3(a+b) FROM t1;
+ SELECT * FROM v1a;
+} {3 150 11}
+do_execsql_test 2.130 {
+ CREATE VIEW v1b AS SELECT f2(b+c) FROM t1;
+ SELECT f2(b+c) FROM t1;
+} {5 125 -11}
+do_catchsql_test 2.140 {
+ PRAGMA trusted_schema=ON;
+ SELECT * FROM v1b;
+} {0 {5 125 -11}}
+do_catchsql_test 2.141 {
+ PRAGMA trusted_schema=OFF;
+ SELECT * FROM v1b;
+} {1 {unsafe use of f2()}}
+do_execsql_test 2.150 {
+ DROP VIEW v1b;
+ CREATE TEMP VIEW v1b AS SELECT f2(b+c) FROM t1;
+ SELECT * FROM v1b;
+} {5 125 -11}
+
+# edgy functions inside of triggers
+#
+do_execsql_test 3.100 {
+ DELETE FROM t1;
+ CREATE TABLE t2(x);
+ CREATE TRIGGER r1 AFTER INSERT ON t1 BEGIN
+ INSERT INTO t2(x) SELECT f3(new.a);
+ END;
+} {}
+do_catchsql_test 3.110 {
+ INSERT INTO t1 VALUES(7,6,5);
+} {1 {unsafe use of f3()}}
+do_execsql_test 3.111 {
+ SELECT * FROM t1;
+ SELECT * FROM t2;
+} {}
+
+do_execsql_test 3.120 {
+ DROP TRIGGER r1;
+ CREATE TRIGGER r1 AFTER INSERT ON t1 BEGIN
+ INSERT INTO t2(x) SELECT f2(new.a)+100;
+ END;
+ PRAGMA trusted_schema=ON;
+ INSERT INTO t1 VALUES(7,6,5);
+ SELECT * FROM t1, t2;
+} {7 6 5 107}
+do_catchsql_test 3.130 {
+ DELETE FROM t1;
+ DELETE FROM t2;
+ PRAGMA trusted_schema=OFF;
+ INSERT INTO t1 VALUES(7,6,5);
+} {1 {unsafe use of f2()}}
+do_execsql_test 3.131 {
+ SELECT * FROM t1;
+ SELECT * FROM t2;
+} {}
+
+
+finish_test
diff --git a/test/update.test b/test/update.test
index 99fff45818..dd96124b4d 100644
--- a/test/update.test
+++ b/test/update.test
@@ -641,4 +641,93 @@ do_execsql_test update-16.1 {
SELECT * FROM t16 ORDER BY +a;
} {1 2 3 4 5 6}
+# 2019-12-09 gramfuzz find
+# If a partial index that does not reference any column of its table (which is you
+# must admit is a very strange index, but one that is allowed) is used by an UPDATE
+# statement, void the use of OP_DeferredSeek on the main loop, as the seek will not
+# be resolved prior to the OP_Delete.
+#
+do_execsql_test update-17.10 {
+ DROP TABLE IF EXISTS t1;
+ CREATE TABLE t1(x,y);
+ INSERT INTO t1(x) VALUES(1);
+ CREATE INDEX t1x1 ON t1(1) WHERE 3;
+ UPDATE t1 SET x=2, y=3 WHERE 3;
+ SELECT * FROM t1;
+} {2 3}
+
+# 2019-12-22 ticket 5ad2aa6921faa1ee
+# Make a hard-copy of values that need to be run through OP_RealAffinity
+# rather than a soft-copy. This is not strictly necessary, but it avoids
+# a memory-accounting assert().
+#
+reset_db
+do_execsql_test update-18.10 {
+ PRAGMA encoding = 'UTF16';
+ CREATE TABLE t0(c0 REAL, c1);
+ INSERT INTO t0(c0,c1) VALUES('xyz',11),('uvw',22);
+ CREATE INDEX i0 ON t0(c1) WHERE c0 GLOB 3;
+ CREATE INDEX i1 ON t0(c0,c1) WHERE typeof(c0)='text' AND typeof(c1)='integer';
+ UPDATE t0 SET c1=345;
+ SELECT * FROM t0;
+} {xyz 345 uvw 345}
+
+# 2019-12-22 ticket c62c5e58524b204d
+# This is really the same underlying problem as 5ad2aa6921faa1ee
+#
+reset_db
+do_execsql_test update-18.20 {
+ PRAGMA encoding = 'utf16';
+ CREATE TABLE t0(c0 TEXT);
+ CREATE INDEX i0 ON t0(0 LIKE COALESCE(c0, 0));
+ INSERT INTO t0(c0) VALUES (0), (0);
+ SELECT * FROM t0;
+} {0 0}
+
+# 2019-12-28 assertion fault reported by Yongheng
+# Similar to ticket ec8abb025e78f40c
+# An UPDATE was reaching the OP_Delete after running OP_DeferredSeek
+# without ever hitting an OP_Column. The enhanced solution is to
+# fix OP_Delete so that it can do the seek itself.
+#
+reset_db
+do_execsql_test update-19.10 {
+ CREATE TABLE t1(
+ a TEXT,
+ b INTEGER PRIMARY KEY UNIQUE
+ );
+ INSERT INTO t1 VALUES(1,2);
+ UPDATE t1 SET a = quote(b) WHERE b>=2;
+ SELECT * FROM t1;
+} {2 2}
+
+# 2019-12-29 ticket https://www.sqlite.org/src/info/314cc133e5ada126
+# REPLACE conflict resolution during an UPDATE causes a DELETE trigger
+# to fire. If that DELETE trigger subsequently modifies the row
+# being updated, bad things can happen. Prevent this by prohibiting
+# triggers from making changes to the table being updated while doing
+# REPLACE conflict resolution on the UPDATE.
+#
+# See also tickets:
+# https://www.sqlite.org/src/info/c1e19e12046d23fe 2019-10-25
+# https://www.sqlite.org/src/info/a8a4847a2d96f5de 2019-10-16
+#
+reset_db
+do_execsql_test update-20.10 {
+ PRAGMA recursive_triggers = true;
+ CREATE TABLE t1(a UNIQUE ON CONFLICT REPLACE, b);
+ INSERT INTO t1(a,b) VALUES(4,12),(9,13);
+ CREATE INDEX i0 ON t1(b);
+ CREATE TRIGGER tr0 DELETE ON t1 BEGIN
+ UPDATE t1 SET b = a;
+ END;
+ PRAGMA integrity_check;
+} {ok}
+do_catchsql_test update-20.20 {
+ UPDATE t1 SET a=0;
+} {1 {constraint failed}}
+do_execsql_test update-20.30 {
+ PRAGMA integrity_check;
+} {ok}
+
finish_test
diff --git a/test/upsert1.test b/test/upsert1.test
index 006af438dc..5250a5d2f5 100644
--- a/test/upsert1.test
+++ b/test/upsert1.test
@@ -221,4 +221,24 @@ do_execsql_test upsert1-800 {
REINDEX;
} {ok}
+# 2019-12-06 gramfuzz find
+sqlite3 db :memory:
+do_execsql_test upsert1-900 {
+ CREATE VIEW t1(a) AS SELECT 1;
+ CREATE TRIGGER t1r1 INSTEAD OF INSERT ON t1 BEGIN
+ SELECT 2;
+ END;
+}
+do_catchsql_test upsert1-910 {
+ INSERT INTO t1 VALUES(3) ON CONFLICT(x) DO NOTHING;
+} {1 {cannot UPSERT a view}}
+
+# 2019-12-26 ticket 7c13db5c3bf74001
+reset_db
+do_catchsql_test upsert1-1000 {
+ CREATE TABLE t0(c0 PRIMARY KEY, c1, c2 UNIQUE) WITHOUT ROWID;
+ INSERT OR FAIL INTO t0(c2) VALUES (0), (NULL)
+ ON CONFLICT(c2) DO UPDATE SET c1 = c0;
+} {1 {NOT NULL constraint failed: t0.c0}}
+
finish_test
diff --git a/test/walvfs.test b/test/walvfs.test
index 8ffc6f9ba2..da0f43c3b1 100644
--- a/test/walvfs.test
+++ b/test/walvfs.test
@@ -387,6 +387,7 @@ do_execsql_test 8.3 {
PRAGMA wal_checkpoint;
SELECT count(*) FROM t1
} {0 5 5 21}
+db close
tvfs2 delete
#-------------------------------------------------------------------------
diff --git a/test/whereG.test b/test/whereG.test
index 595de116aa..9d4cde7b4d 100644
--- a/test/whereG.test
+++ b/test/whereG.test
@@ -306,7 +306,15 @@ do_execsql_test 8.10 {
SELECT * FROM t0 WHERE likelihood(t0.rowid <= '0', 0.5);
} {}
-
-
+# 2019-12-31: assertion fault discovered by Yongheng's fuzzer.
+# Harmless memIsValid() due to the code generators failure to
+# release the registers used by OP_ResultRow.
+#
+do_execsql_test 9.10 {
+ DROP TABLE IF EXISTS t1;
+ CREATE TABLE t1(a, b FLOAT);
+ INSERT INTO t1(a) VALUES(''),(NULL),('X'),(NULL);
+ SELECT coalesce(max(quote(a)),10) FROM t1 GROUP BY a;
+} {NULL '' 'X'}
finish_test
diff --git a/test/whereL.test b/test/whereL.test
index d0e5f0b604..bd2f561607 100644
--- a/test/whereL.test
+++ b/test/whereL.test
@@ -122,4 +122,27 @@ do_execsql_test 400 {
SELECT x.a FROM x JOIN y ON x.c = y.a WHERE x.b = 1 AND x.b = 1;
} {}
+# 2020-01-07: ticket 82ac75ba0093e5dc
+# Incorrect join result due to mishandling of affinity in constant
+# propagation.
+#
+reset_db
+do_execsql_test 500 {
+ PRAGMA automatic_index=OFF;
+ CREATE TABLE t0(c0);
+ INSERT INTO t0 VALUES('0');
+ CREATE VIEW v0(c0) AS SELECT CAST(0 AS INT) FROM t0;
+ SELECT 200, * FROM t0, v0 WHERE 0 = t0.c0 AND t0.c0 = v0.c0;
+} {}
+do_execsql_test 510 {
+ SELECT 200, * FROM t0, v0 WHERE t0.c0 = 0 AND t0.c0 = v0.c0;
+} {}
+do_execsql_test 520 {
+ SELECT 200, * FROM t0, v0 WHERE 0 = t0.c0 AND v0.c0 = t0.c0;
+} {}
+do_execsql_test 530 {
+ SELECT 200, * FROM t0, v0 WHERE t0.c0 = 0 AND v0.c0 = t0.c0;
+} {}
+
+
finish_test
diff --git a/test/window1.test b/test/window1.test
index 778bd861ba..833e211fbd 100644
--- a/test/window1.test
+++ b/test/window1.test
@@ -1190,4 +1190,408 @@ do_execsql_test 30.0 {
win3 AS (win2 RANGE BETWEEN 5.2 PRECEDING AND true PRECEDING );
} {1 1}
+#-------------------------------------------------------------------------
+reset_db
+do_execsql_test 31.1 {
+ CREATE TABLE t1(a, b);
+ CREATE TABLE t2(c, d);
+ CREATE TABLE t3(e, f);
+
+ INSERT INTO t1 VALUES(1, 1);
+ INSERT INTO t2 VALUES(1, 1);
+ INSERT INTO t3 VALUES(1, 1);
+}
+
+do_execsql_test 31.2 {
+ SELECT d IN (SELECT sum(c) OVER (ORDER BY e+c) FROM t3) FROM (
+ SELECT * FROM t2
+ );
+} {1}
+
+do_execsql_test 31.3 {
+ SELECT d IN (SELECT sum(c) OVER (PARTITION BY d ORDER BY e+c) FROM t3) FROM (
+ SELECT * FROM t2
+ );
+} {1}
+
+do_catchsql_test 31.3 {
+ SELECT d IN (
+ SELECT sum(c) OVER ( ROWS BETWEEN d FOLLOWING AND UNBOUNDED FOLLOWING)
+ FROM t3
+ )
+ FROM (
+ SELECT * FROM t2
+ );
+} {1 {frame starting offset must be a non-negative integer}}
+
+do_catchsql_test 31.3 {
+ SELECT d IN (
+ SELECT sum(c) OVER ( ROWS BETWEEN CURRENT ROW AND c FOLLOWING)
+ FROM t3
+ )
+ FROM (
+ SELECT * FROM t2
+ );
+} {1 {frame ending offset must be a non-negative integer}}
+
+# 2019-11-16 chromium issue 1025467
+db close
+sqlite3 db :memory:
+do_catchsql_test 32.10 {
+ CREATE VIEW a AS SELECT NULL INTERSECT SELECT NULL ORDER BY s() OVER R;
+ CREATE TABLE a0 AS SELECT 0;
+ ALTER TABLE a0 RENAME TO S;
+} {1 {error in view a: 1st ORDER BY term does not match any column in the result set}}
+
+reset_db
+do_execsql_test 33.1 {
+ CREATE TABLE t1(aa, bb);
+ INSERT INTO t1 VALUES(1, 2);
+ INSERT INTO t1 VALUES(5, 6);
+ CREATE TABLE t2(x);
+ INSERT INTO t2 VALUES(1);
+}
+do_execsql_test 33.2 {
+ SELECT (SELECT DISTINCT sum(aa) OVER() FROM t1 ORDER BY 1), x FROM t2
+ ORDER BY 1;
+} {6 1}
+
+reset_db
+do_execsql_test 34.1 {
+ CREATE TABLE t1(a,b,c);
+}
+do_execsql_test 34.2 {
+ SELECT avg(a) OVER (
+ ORDER BY (SELECT sum(b) OVER ()
+ FROM t1 ORDER BY (
+ SELECT total(d) OVER (ORDER BY c)
+ FROM (SELECT 1 AS d) ORDER BY 1
+ )
+ )
+ )
+ FROM t1;
+}
+
+#-------------------------------------------------------------------------
+reset_db
+do_catchsql_test 35.0 {
+ SELECT * WINDOW f AS () ORDER BY name COLLATE nocase;
+} {1 {no tables specified}}
+
+do_catchsql_test 35.1 {
+ VALUES(1) INTERSECT SELECT * WINDOW f AS () ORDER BY x COLLATE nocase;
+} {1 {no tables specified}}
+
+do_execsql_test 35.2 {
+ CREATE TABLE t1(x);
+ INSERT INTO t1 VALUES(1), (2), (3);
+ VALUES(1) INTERSECT
+ SELECT sum(x) OVER f FROM t1 WINDOW f AS (ORDER BY x) ORDER BY 1;
+} {1}
+
+do_execsql_test 35.3 {
+ VALUES(8) EXCEPT
+ SELECT sum(x) OVER f FROM t1 WINDOW f AS (ORDER BY x) ORDER BY 1;
+} {8}
+
+do_execsql_test 35.4 {
+ VALUES(1) UNION
+ SELECT sum(x) OVER f FROM t1 WINDOW f AS (ORDER BY x) ORDER BY 1;
+} {1 3 6}
+
+# 2019-12-07 gramfuzz find
+#
+do_execsql_test 36.10 {
+ VALUES(count(*)OVER());
+} {1}
+do_execsql_test 36.20 {
+ VALUES(count(*)OVER()),(2);
+} {1 2}
+do_execsql_test 36.30 {
+ VALUES(2),(count(*)OVER());
+} {2 1}
+do_execsql_test 36.40 {
+ VALUES(2),(3),(count(*)OVER()),(4),(5);
+} {2 3 1 4 5}
+
+# 2019-12-17 crash test case found by Yongheng and Rui
+# See check-in 1ca0bd982ab1183b
+#
+reset_db
+do_execsql_test 37.10 {
+ CREATE TABLE t0(a UNIQUE, b PRIMARY KEY);
+ CREATE VIEW v0(c) AS SELECT max((SELECT count(a)OVER(ORDER BY 1))) FROM t0;
+ SELECT c FROM v0 WHERE c BETWEEN 10 AND 20;
+} {}
+do_execsql_test 37.20 {
+ DROP VIEW v0;
+ CREATE VIEW v0(c) AS SELECT max((SELECT count(a)OVER(ORDER BY 1234))) FROM t0;
+ SELECT c FROM v0 WHERE c BETWEEN -10 AND 20;
+} {}
+
+# 2019-12-20 mrigger reported problem with a FILTER clause on an aggregate
+# in a join.
+#
+reset_db
+do_catchsql_test 38.10 {
+ CREATE TABLE t0(c0);
+ CREATE TABLE t1(c0, c1 UNIQUE);
+ INSERT INTO t0(c0) VALUES(1);
+ INSERT INTO t1(c0,c1) VALUES(2,3);
+ SELECT COUNT(*) FROM t0, t1 WHERE (SELECT AVG(0) FILTER(WHERE t1.c1));
+} {1 {misuse of aggregate: AVG()}}
+do_execsql_test 38.20 {
+ SELECT COUNT(*), AVG(1) FILTER(WHERE t1.c1) FROM t0, t1;
+} {1 1.0}
+do_catchsql_test 38.30 {
+ SELECT COUNT(*) FROM t0, t1 WHERE (SELECT AVG(1) FILTER(WHERE t1.c1));
+} {1 {misuse of aggregate: AVG()}}
+
+reset_db
+do_execsql_test 39.1 {
+ CREATE TABLE t0(c0 UNIQUE);
+}
+do_execsql_test 39.2 {
+ SELECT FIRST_VALUE(0) OVER();
+} {0}
+do_execsql_test 39.3 {
+ SELECT * FROM t0 WHERE(c0, 0) IN(SELECT FIRST_VALUE(0) OVER(), 0);
+}
+do_execsql_test 39.4 {
+ SELECT * FROM t0 WHERE (t0.c0, 1) IN(SELECT NTILE(1) OVER(), 0 FROM t0);
+}
+
+ifcapable rtree {
+ # 2019-12-25 ticket d87336c81c7d0873
+ #
+ reset_db
+ do_catchsql_test 40.1 {
+ CREATE VIRTUAL TABLE t0 USING rtree(c0, c1, c2);
+ SELECT * FROM t0
+ WHERE ((0,0) IN (SELECT COUNT(*),LAG(5)OVER(PARTITION BY 0) FROM t0),0)<=(c1,0);
+ } {0 {}}
+}
+
+#-------------------------------------------------------------------------
+reset_db
+do_execsql_test 41.1 {
+ CREATE TABLE t1(a, b, c);
+ INSERT INTO t1 VALUES(NULL,'bb',355);
+ INSERT INTO t1 VALUES('CC','aa',158);
+ INSERT INTO t1 VALUES('GG','bb',929);
+ INSERT INTO t1 VALUES('FF','Rb',574);
+}
+
+do_execsql_test 41.2 {
+ SELECT min(c) OVER (
+ ORDER BY a RANGE BETWEEN 5.2 PRECEDING AND 0.1 PRECEDING
+ ) FROM t1
+} {355 158 574 929}
+
+do_execsql_test 41.2 {
+ SELECT min(c) OVER (
+ ORDER BY a RANGE BETWEEN 5.2 PRECEDING AND 0.1 PRECEDING
+ ) << 100 FROM t1
+} {0 0 0 0}
+
+do_execsql_test 41.3 {
+ SELECT
+ min(c) OVER win3 << first_value(c) OVER win3,
+ min(c) OVER win3 << first_value(c) OVER win3
+ FROM t1
+ WINDOW win3 AS (
+ PARTITION BY 6 ORDER BY a RANGE BETWEEN 5.2 PRECEDING AND 0.1 PRECEDING
+ );
+} {0 0 0 0 0 0 0 0}
+
+#-------------------------------------------------------------------------
+reset_db
+do_execsql_test 42.1 {
+ CREATE TABLE t1(a, b, c);
+ INSERT INTO t1 VALUES(1, 1, 1);
+ INSERT INTO t1 VALUES(2, 2, 2);
+}
+do_execsql_test 42.2 {
+ SELECT * FROM t1 WHERE (0, 0) IN ( SELECT count(*), 0 FROM t1 )
+} {}
+do_execsql_test 42.3 {
+ SELECT * FROM t1 WHERE (2, 0) IN ( SELECT count(*), 0 FROM t1 )
+} {1 1 1 2 2 2}
+
+do_execsql_test 42.3 {
+ SELECT count(*), max(a) OVER () FROM t1 GROUP BY c;
+} {1 2 1 2}
+
+do_execsql_test 42.4 {
+ SELECT sum(a), max(b) OVER () FROM t1;
+} {3 1}
+
+do_execsql_test 42.5 {
+ CREATE TABLE t2(a, b);
+ INSERT INTO t2 VALUES('a', 1);
+ INSERT INTO t2 VALUES('a', 2);
+ INSERT INTO t2 VALUES('a', 3);
+ INSERT INTO t2 VALUES('b', 4);
+ INSERT INTO t2 VALUES('b', 5);
+ INSERT INTO t2 VALUES('b', 6);
+}
+
+do_execsql_test 42.6 {
+ SELECT a, sum(b), sum( sum(b) ) OVER (ORDER BY a) FROM t2 GROUP BY a;
+} {a 6 6 b 15 21}
+
+do_execsql_test 42.7 {
+ SELECT sum(b), sum( sum(b) ) OVER (ORDER BY a) FROM t2;
+} {21 21}
+
+#-------------------------------------------------------------------------
+reset_db
+do_execsql_test 43.1.1 {
+ CREATE TABLE t1(x INTEGER PRIMARY KEY);
+ INSERT INTO t1 VALUES (10);
+}
+do_catchsql_test 43.1.2 {
+ SELECT count() OVER() AS m FROM t1 ORDER BY (SELECT m);
+} {1 {misuse of aliased window function m}}
+
+reset_db
+do_execsql_test 43.2.1 {
+ CREATE TABLE t1(a INTEGER PRIMARY KEY, b INTEGER);
+ INSERT INTO t1(a, b) VALUES(1, 10); -- 10
+ INSERT INTO t1(a, b) VALUES(2, 15); -- 25
+ INSERT INTO t1(a, b) VALUES(3, -5); -- 20
+ INSERT INTO t1(a, b) VALUES(4, -5); -- 15
+ INSERT INTO t1(a, b) VALUES(5, 20); -- 35
+ INSERT INTO t1(a, b) VALUES(6, -11); -- 24
+}
+
+do_execsql_test 43.2.2 {
+ SELECT a, sum(b) OVER (ORDER BY a) AS abc FROM t1 ORDER BY 2
+} {
+ 1 10 4 15 3 20 6 24 2 25 5 35
+}
+
+do_execsql_test 43.2.3 {
+ SELECT a, sum(b) OVER (ORDER BY a) AS abc FROM t1 ORDER BY abc
+} {
+ 1 10 4 15 3 20 6 24 2 25 5 35
+}
+
+do_execsql_test 43.2.4 {
+ SELECT a, sum(b) OVER (ORDER BY a) AS abc FROM t1 ORDER BY abc+5
+} {
+ 1 10 4 15 3 20 6 24 2 25 5 35
+}
+
+do_catchsql_test 43.2.5 {
+ SELECT a, sum(b) OVER (ORDER BY a) AS abc FROM t1 ORDER BY (SELECT abc)
+} {1 {misuse of aliased window function abc}}
+
+do_catchsql_test 43.2.6 {
+ SELECT a, 1+sum(b) OVER (ORDER BY a) AS abc FROM t1 ORDER BY (SELECT abc)
+} {1 {misuse of aliased window function abc}}
+
+#-------------------------------------------------------------------------
+reset_db
+do_execsql_test 44.1 {
+ CREATE TABLE t0(c0);
+}
+
+do_catchsql_test 44.2.1 {
+ SELECT ntile(0) OVER ();
+} {1 {argument of ntile must be a positive integer}}
+do_catchsql_test 44.2.2 {
+ SELECT (0, 0) IN(SELECT MIN(c0), NTILE(0) OVER()) FROM t0;
+} {1 {argument of ntile must be a positive integer}}
+
+do_execsql_test 44.3.1 {
+ SELECT ntile(1) OVER ();
+} {1}
+do_execsql_test 44.3.2 {
+ SELECT (0, 0) IN(SELECT MIN(c0), NTILE(1) OVER()) FROM t0;
+} {0}
+
+do_execsql_test 44.4.2 {
+ INSERT INTO t0 VALUES(2), (1), (0);
+ SELECT (0, 1) IN(SELECT MIN(c0), NTILE(1) OVER()) FROM t0;
+} {1}
+
+#-------------------------------------------------------------------------
+reset_db
+do_execsql_test 45.1 {
+ CREATE TABLE t0(x);
+ CREATE TABLE t1(a);
+ INSERT INTO t1 VALUES(1000);
+ INSERT INTO t1 VALUES(1000);
+ INSERT INTO t0 VALUES(10000);
+}
+do_execsql_test 45.2 {
+ SELECT * FROM (
+ SELECT sum (a) OVER() FROM t1 UNION ALL SELECT x FROM t0
+ );
+} {2000 2000 10000}
+
+#-------------------------------------------------------------------------
+reset_db
+do_execsql_test 46.1 {
+ CREATE TABLE t1 (a);
+ CREATE INDEX i1 ON t1(a);
+
+ INSERT INTO t1 VALUES (10);
+}
+
+do_execsql_test 46.2 {
+ SELECT (SELECT sum(a) OVER(ORDER BY a)) FROM t1
+} 10
+
+do_execsql_test 46.3 {
+ SELECT * FROM t1 WHERE (SELECT sum(a) OVER(ORDER BY a));
+} 10
+
+do_execsql_test 46.4 {
+ SELECT * FROM t1 NATURAL JOIN t1
+ WHERE a=1
+ OR ((SELECT sum(a)OVER(ORDER BY a)) AND a<=10)
+} 10
+
+#-------------------------------------------------------------------------
+reset_db
+do_execsql_test 47.0 {
+ CREATE TABLE t1(
+ a,
+ e,
+ f,
+ g UNIQUE,
+ h UNIQUE
+ );
+}
+
+do_execsql_test 47.1 {
+ CREATE VIEW t2(k) AS
+ SELECT e FROM t1 WHERE g = 'abc' OR h BETWEEN 10 AND f;
+}
+
+do_catchsql_test 47.2 {
+ SELECT 234 FROM t2
+ WHERE k=1
+ OR (SELECT k FROM t2 WHERE (SELECT sum(a) OVER() FROM t1 GROUP BY 1));
+} {1 {misuse of window function sum()}}
+
+#-------------------------------------------------------------------------
+reset_db
+do_execsql_test 48.0 {
+ CREATE TABLE t1(a);
+ INSERT INTO t1 VALUES(1);
+ INSERT INTO t1 VALUES(2);
+ INSERT INTO t1 VALUES(3);
+ SELECT (SELECT max(x)OVER(ORDER BY x) + min(x)OVER(ORDER BY x))
+ FROM (SELECT (SELECT sum(a) FROM t1) AS x FROM t1);
+} {12 12 12}
+
+do_execsql_test 48.1 {
+ SELECT (SELECT max(x)OVER(ORDER BY x) + min(x)OVER(ORDER BY x))
+ FROM (SELECT (SELECT sum(a) FROM t1 GROUP BY a) AS x FROM t1);
+} {2 2 2}
+
+
finish_test
diff --git a/test/window2.tcl b/test/window2.tcl
index 5edc536808..4c18b7970d 100644
--- a/test/window2.tcl
+++ b/test/window2.tcl
@@ -448,6 +448,47 @@ execsql_float_test 5.1 {
SELECT avg(x) OVER (ORDER BY y) AS z FROM t1 ORDER BY z;
}
+==========
+
+execsql_test 6.0 {
+ DROP TABLE IF EXISTS t0;
+ CREATE TABLE t0(c0 INTEGER UNIQUE);
+ INSERT INTO t0 VALUES(0);
+}
+execsql_test 6.1 {
+ SELECT DENSE_RANK() OVER(), LAG(0) OVER() FROM t0;
+}
+execsql_test 6.2 {
+ SELECT * FROM t0 WHERE
+ (0, t0.c0) IN (SELECT DENSE_RANK() OVER(), LAG(0) OVER() FROM t0);
+}
+
+==========
+
+execsql_test 7.0 {
+ DROP TABLE IF EXISTS t1;
+ CREATE TABLE t1(a INTEGER, b INTEGER, c INTEGER);
+ INSERT INTO t1 VALUES(1, 1, 1);
+ INSERT INTO t1 VALUES(1, 2, 2);
+ INSERT INTO t1 VALUES(3, 3, 3);
+ INSERT INTO t1 VALUES(3, 4, 4);
+}
+
+execsql_test 7.1 {
+ SELECT c, sum(c) OVER win1 FROM t1
+ WINDOW win1 AS (ORDER BY b)
+}
+
+execsql_test 7.2 {
+ SELECT c, sum(c) OVER win1 FROM t1
+ WINDOW win1 AS (PARTITION BY 1 ORDER BY b)
+}
+
+execsql_test 7.3 {
+ SELECT c, sum(c) OVER win1 FROM t1
+ WINDOW win1 AS (ORDER BY 1)
+}
+
finish_test
diff --git a/test/window2.test b/test/window2.test
index 5f028eb72d..e241d59644 100644
--- a/test/window2.test
+++ b/test/window2.test
@@ -930,4 +930,47 @@ do_test 5.1 {
set {} {}
} {}
+#==========================================================================
+
+do_execsql_test 6.0 {
+ DROP TABLE IF EXISTS t0;
+ CREATE TABLE t0(c0 INTEGER UNIQUE);
+ INSERT INTO t0 VALUES(0);
+} {}
+
+do_execsql_test 6.1 {
+ SELECT DENSE_RANK() OVER(), LAG(0) OVER() FROM t0;
+} {1 {}}
+
+do_execsql_test 6.2 {
+ SELECT * FROM t0 WHERE
+ (0, t0.c0) IN (SELECT DENSE_RANK() OVER(), LAG(0) OVER() FROM t0);
+} {}
+
+#==========================================================================
+
+do_execsql_test 7.0 {
+ DROP TABLE IF EXISTS t1;
+ CREATE TABLE t1(a INTEGER, b INTEGER, c INTEGER);
+ INSERT INTO t1 VALUES(1, 1, 1);
+ INSERT INTO t1 VALUES(1, 2, 2);
+ INSERT INTO t1 VALUES(3, 3, 3);
+ INSERT INTO t1 VALUES(3, 4, 4);
+} {}
+
+do_execsql_test 7.1 {
+ SELECT c, sum(c) OVER win1 FROM t1
+ WINDOW win1 AS (ORDER BY b)
+} {1 1 2 3 3 6 4 10}
+
+do_execsql_test 7.2 {
+ SELECT c, sum(c) OVER win1 FROM t1
+ WINDOW win1 AS (PARTITION BY 1 ORDER BY b)
+} {1 1 2 3 3 6 4 10}
+
+do_execsql_test 7.3 {
+ SELECT c, sum(c) OVER win1 FROM t1
+ WINDOW win1 AS (ORDER BY 1)
+} {1 10 2 10 3 10 4 10}
+
finish_test
diff --git a/test/window9.test b/test/window9.test
index 6f2f2d9526..adfeaba356 100644
--- a/test/window9.test
+++ b/test/window9.test
@@ -233,4 +233,3 @@ do_execsql_test 7.4 {
}
finish_test
-
diff --git a/test/windowfault.test b/test/windowfault.test
index e037c467b0..e97544f4c8 100644
--- a/test/windowfault.test
+++ b/test/windowfault.test
@@ -230,7 +230,7 @@ do_execsql_test 10.0 {
CREATE TABLE t2(a, b, c, d);
}
-do_faultsim_test 1 -faults oom* -prep {
+do_faultsim_test 10 -faults oom* -prep {
} -body {
execsql {
SELECT row_number() OVER win
@@ -246,4 +246,21 @@ do_faultsim_test 1 -faults oom* -prep {
faultsim_test_result {0 {}}
}
+reset_db
+do_execsql_test 11.0 {
+ DROP TABLE IF EXISTS t0;
+ CREATE TABLE t0(c0 INTEGER UNIQUE);
+ INSERT INTO t0 VALUES(0);
+} {}
+
+do_faultsim_test 11 -faults oom* -prep {
+} -body {
+ execsql {
+ SELECT * FROM t0 WHERE
+ (0, t0.c0) IN (SELECT DENSE_RANK() OVER(), LAG(0) OVER() FROM t0);
+ }
+} -test {
+ faultsim_test_result {0 {}}
+}
+
finish_test
diff --git a/test/with1.test b/test/with1.test
index 5631bfb69d..f798dd2111 100644
--- a/test/with1.test
+++ b/test/with1.test
@@ -1140,4 +1140,28 @@ do_execsql_test 24.2 {
3 1 1 3
}
+# 2020-01-02 chromium ticket 1033461
+# Do not allow the generated name of a CTE be "true" or "false" as
+# such a label might be later confused for the boolean literals of
+# the same name, causing inconsistencies in the abstract syntax
+# tree. This problem first arose in version 3.23.0 when SQLite
+# began recognizing "true" and "false" as boolean literals, but also
+# had to continue to recognize "true" and "false" as identifiers for
+# backwards compatibility.
+#
+reset_db
+do_execsql_test 25.1 {
+ CREATE TABLE dual(dummy);
+ INSERT INTO dual(dummy) VALUES('X');
+ WITH cte1 AS (
+ SELECT TRUE, (
+ WITH cte2 AS (SELECT avg(DISTINCT TRUE) FROM dual)
+ SELECT 2571 FROM cte2
+ ) AS subquery1
+ FROM dual
+ GROUP BY 1
+ )
+ SELECT (SELECT 1324 FROM cte1) FROM cte1;
+} {1324}
+
finish_test
diff --git a/test/with3.test b/test/with3.test
index 360d37f9b9..eebb9d6546 100644
--- a/test/with3.test
+++ b/test/with3.test
@@ -30,7 +30,15 @@ do_catchsql_test 1.0 {
SELECT 5 FROM t0 UNION SELECT 8 FROM m
)
SELECT * FROM i;
-} {1 {no such table: m}}
+} {1 {no such table: t0}}
+
+# 2019-11-09 dbfuzzcheck find
+do_catchsql_test 1.1 {
+ CREATE VIEW v1(x,y) AS
+ WITH t1(a,b) AS (VALUES(1,2))
+ SELECT * FROM nosuchtable JOIN t1;
+ SELECT * FROM v1;
+} {1 {no such table: main.nosuchtable}}
# Additional test cases that came out of the work to
# fix for Kostya's problem.
diff --git a/test/without_rowid1.test b/test/without_rowid1.test
index 23fae118e4..3497ca0ccc 100644
--- a/test/without_rowid1.test
+++ b/test/without_rowid1.test
@@ -430,5 +430,27 @@ do_execsql_test 12.1 {
PRAGMA integrity_check;
} {ok}
+# 2019-11-07 ticket https://www.sqlite.org/src/info/302027baf1374498
+# The xferCompatibleIndex() function confuses a PRIMARY KEY index
+# with a UNIQUE index.
+#
+do_execsql_test 13.10 {
+ DROP TABLE IF EXISTS t0;
+ DROP TABLE IF EXISTS t1;
+ CREATE TABLE t0(
+ c0,
+ c1 UNIQUE,
+ PRIMARY KEY(c1, c1)
+ ) WITHOUT ROWID;
+ INSERT INTO t0(c0,c1) VALUES('abc','xyz');
+ CREATE TABLE t1(
+ c0,
+ c1 UNIQUE,
+ PRIMARY KEY(c1, c1)
+ ) WITHOUT ROWID;
+ INSERT INTO t1 SELECT * FROM t0;
+ PRAGMA integrity_check;
+ SELECT * FROM t0, t1;
+} {ok abc xyz abc xyz}
finish_test
diff --git a/test/without_rowid3.test b/test/without_rowid3.test
index b895f06cf3..24ef2304de 100644
--- a/test/without_rowid3.test
+++ b/test/without_rowid3.test
@@ -953,7 +953,7 @@ ifcapable altertable {
'main', 'table', 't1', $zCreate, $zOld, $zNew, 0
)}
}
- sqlite3_test_control SQLITE_TESTCTRL_INTERNAL_FUNCTIONS 1
+ sqlite3_test_control SQLITE_TESTCTRL_INTERNAL_FUNCTIONS db
do_test without_rowid3-14.2.1.1 {
test_rename_parent {CREATE TABLE t1(a REFERENCES t2)} t2 t3
} {{CREATE TABLE t1(a REFERENCES "t3")}}
@@ -963,7 +963,7 @@ ifcapable altertable {
do_test without_rowid3-14.2.1.3 {
test_rename_parent {CREATE TABLE t1(a REFERENCES "t2")} t2 t3
} {{CREATE TABLE t1(a REFERENCES "t3")}}
- sqlite3_test_control SQLITE_TESTCTRL_INTERNAL_FUNCTIONS 0
+ sqlite3_test_control SQLITE_TESTCTRL_INTERNAL_FUNCTIONS db
# Test ALTER TABLE RENAME TABLE a bit.
#
@@ -1039,7 +1039,7 @@ ifcapable altertable {
}
} {{CREATE TABLE t2(a, b, c REFERENCES t1, d DEFAULT NULL REFERENCES t1, e REFERENCES t1 DEFAULT NULL, h DEFAULT 'text' REFERENCES t1)}}
- sqlite3_test_control SQLITE_TESTCTRL_INTERNAL_FUNCTIONS 1
+ sqlite3_test_control SQLITE_TESTCTRL_INTERNAL_FUNCTIONS db
do_test without_rowid3-14.2tmp.1.1 {
test_rename_parent {CREATE TABLE t1(a REFERENCES t2)} t2 t3
} {{CREATE TABLE t1(a REFERENCES "t3")}}
@@ -1049,7 +1049,7 @@ ifcapable altertable {
do_test without_rowid3-14.2tmp.1.3 {
test_rename_parent {CREATE TABLE t1(a REFERENCES "t2")} t2 t3
} {{CREATE TABLE t1(a REFERENCES "t3")}}
- sqlite3_test_control SQLITE_TESTCTRL_INTERNAL_FUNCTIONS 0
+ sqlite3_test_control SQLITE_TESTCTRL_INTERNAL_FUNCTIONS db
# Test ALTER TABLE RENAME TABLE a bit.
#
@@ -1126,7 +1126,7 @@ ifcapable altertable {
}
} {{CREATE TABLE t2(a, b, c REFERENCES t1, d DEFAULT NULL REFERENCES t1, e REFERENCES t1 DEFAULT NULL, h DEFAULT 'text' REFERENCES t1)}}
- sqlite3_test_control SQLITE_TESTCTRL_INTERNAL_FUNCTIONS 1
+ sqlite3_test_control SQLITE_TESTCTRL_INTERNAL_FUNCTIONS db
do_test without_rowid3-14.2aux.1.1 {
test_rename_parent {CREATE TABLE t1(a REFERENCES t2)} t2 t3
} {{CREATE TABLE t1(a REFERENCES "t3")}}
@@ -1136,7 +1136,7 @@ ifcapable altertable {
do_test without_rowid3-14.2aux.1.3 {
test_rename_parent {CREATE TABLE t1(a REFERENCES "t2")} t2 t3
} {{CREATE TABLE t1(a REFERENCES "t3")}}
- sqlite3_test_control SQLITE_TESTCTRL_INTERNAL_FUNCTIONS 0
+ sqlite3_test_control SQLITE_TESTCTRL_INTERNAL_FUNCTIONS db
# Test ALTER TABLE RENAME TABLE a bit.
#
diff --git a/test/zipfile.test b/test/zipfile.test
index 2bab066df0..79298a0506 100644
--- a/test/zipfile.test
+++ b/test/zipfile.test
@@ -795,4 +795,52 @@ if {$tcl_platform(platform)!="windows"} {
} {. ./x1.txt ./x2.txt}
}
+# 2019-12-18 Yongheng and Rui fuzzer
+#
+do_execsql_test 13.10 {
+ DROP TABLE IF EXISTS t0;
+ DROP TABLE IF EXISTS t1;
+ CREATE TABLE t0(a,b,c,d,e,f,g);
+ REPLACE INTO t0(c,b,f) VALUES(10,10,10);
+ CREATE VIRTUAL TABLE t1 USING zipfile('h.zip');
+ REPLACE INTO t1 SELECT * FROM t0;
+ SELECT quote(name),quote(mode),quote(mtime),quote(sz),quote(rawdata),
+ quote(data),quote(method) FROM t1;
+} {'' 10 10 2 X'3130' X'3130' 0}
+
+# 2019-12-23 Yongheng and Rui fuzzer
+# Run using valgrind to see the problem.
+#
+do_execsql_test 14.10 {
+ DROP TABLE t1;
+ CREATE TABLE t1(x char);
+ INSERT INTO t1(x) VALUES('1');
+ INSERT INTO t1(x) SELECT zipfile(x, 'xyz') FROM t1;
+ INSERT INTO t1(x) SELECT zipfile(x, 'uvw') FROM t1;
+ SELECT count(*) FROM t1;
+ PRAGMA integrity_check;
+} {3 ok}
+
+# 2019-12-26 More problems in zipfile from the Yongheng and Rui fuzzer
+#
+do_execsql_test 15.10 {
+ DROP TABLE IF EXISTS t1;
+ CREATE VIRTUAL TABLE t1 USING zipfile(null);
+ REPLACE INTO t1 VALUES(null,null,0,null,null,null,null);
+} {}
+do_execsql_test 15.20 {
+ DROP TABLE IF EXISTS t2;
+ CREATE VIRTUAL TABLE t2 USING zipfile(null);
+ REPLACE INTO t2 values(null,null,null,null,null,10,null);
+} {}
+
+# 2020-01-02 Yongheng fuzzer discovery
+#
+do_catchsql_test 16.10 {
+ DELETE FROM zipfile;
+} {1 {zipfile: missing filename}}
+do_catchsql_test 16.20 {
+ REPLACE INTO zipfile VALUES(null,null,null,null,null,123,null);
+} {1 {zipfile: missing filename}}
+
finish_test
diff --git a/tool/GetFile.cs b/tool/GetFile.cs
index 56601f3e85..1784a79263 100644
--- a/tool/GetFile.cs
+++ b/tool/GetFile.cs
@@ -167,7 +167,8 @@ namespace GetFile
string fileName = Path.GetFileName(
Process.GetCurrentProcess().MainModule.FileName);
- Console.WriteLine(String.Format("usage: {0} ", fileName));
+ Console.WriteLine(String.Format(
+ "usage: {0} [fileName]", fileName));
}
///////////////////////////////////////////////////////////////////////
@@ -336,7 +337,7 @@ namespace GetFile
return (int)ExitCode.MissingArgs;
}
- if (args.Length != 1)
+ if ((args.Length < 1) || (args.Length > 2))
{
Error(null, true);
return (int)ExitCode.WrongNumArgs;
@@ -355,15 +356,26 @@ namespace GetFile
}
//
- // NOTE: Attempt to extract the file name portion of the URI we
- // just created.
+ // NOTE: If a file name was specified on the command line, try to
+ // use it (without its directory name); otherwise, fallback
+ // to using the file name portion of the URI.
//
- string fileName = GetFileName(uri);
+ string fileName = (args.Length == 2) ?
+ Path.GetFileName(args[1]) : null;
- if (fileName == null)
+ if (String.IsNullOrEmpty(fileName))
{
- Error("Could not extract the file name from the URI.", false);
- return (int)ExitCode.BadFileName;
+ //
+ // NOTE: Attempt to extract the file name portion of the URI
+ // we just created.
+ //
+ fileName = GetFileName(uri);
+
+ if (fileName == null)
+ {
+ Error("Could not extract file name from URI.", false);
+ return (int)ExitCode.BadFileName;
+ }
}
//
@@ -381,6 +393,15 @@ namespace GetFile
try
{
+ //
+ // HACK: For use of the TLS 1.2 security protocol because some
+ // web servers fail without it. In order to support the
+ // .NET Framework 2.0+ at compilation time, must use its
+ // integer constant here.
+ //
+ ServicePointManager.SecurityProtocol =
+ (SecurityProtocolType)0xC00;
+
using (WebClient webClient = new WebClient())
{
//
diff --git a/tool/dbhash.c b/tool/dbhash.c
index b1c72b3e36..7696ddbde6 100644
--- a/tool/dbhash.c
+++ b/tool/dbhash.c
@@ -62,24 +62,9 @@ struct GlobalVars {
*
* blk0le() for little-endian and blk0be() for big-endian.
*/
-#if __GNUC__ && (defined(__i386__) || defined(__x86_64__))
-/*
- * GCC by itself only generates left rotates. Use right rotates if
- * possible to be kinder to dinky implementations with iterative rotate
- * instructions.
- */
-#define SHA_ROT(op, x, k) \
- ({ unsigned int y; asm(op " %1,%0" : "=r" (y) : "I" (k), "0" (x)); y; })
-#define rol(x,k) SHA_ROT("roll", x, k)
-#define ror(x,k) SHA_ROT("rorl", x, k)
-
-#else
-/* Generic C equivalent */
#define SHA_ROT(x,l,r) ((x) << (l) | (x) >> (r))
#define rol(x,k) SHA_ROT(x,k,32-(k))
#define ror(x,k) SHA_ROT(x,32-(k),k)
-#endif
-
#define blk0le(i) (block[i] = (ror(block[i],8)&0xFF00FF00) \
|(rol(block[i],8)&0x00FF00FF))
diff --git a/tool/lemon.c b/tool/lemon.c
index 6efc6af301..8dcf65179f 100644
--- a/tool/lemon.c
+++ b/tool/lemon.c
@@ -218,7 +218,7 @@ void Plink_delete(struct plink *);
/********** From the file "report.h" *************************************/
void Reprint(struct lemon *);
void ReportOutput(struct lemon *);
-void ReportTable(struct lemon *, int);
+void ReportTable(struct lemon *, int, int);
void ReportHeader(struct lemon *);
void CompressTables(struct lemon *);
void ResortStates(struct lemon *);
@@ -292,13 +292,15 @@ struct rule {
const char *code; /* The code executed when this rule is reduced */
const char *codePrefix; /* Setup code before code[] above */
const char *codeSuffix; /* Breakdown code after code[] above */
- int noCode; /* True if this rule has no associated C code */
- int codeEmitted; /* True if the code has been emitted already */
struct symbol *precsym; /* Precedence symbol for this rule */
int index; /* An index number for this rule */
int iRule; /* Rule number as used in the generated tables */
+ Boolean noCode; /* True if this rule has no associated C code */
+ Boolean codeEmitted; /* True if the code has been emitted already */
Boolean canReduce; /* True if this rule is ever reduced */
Boolean doesReduce; /* Reduce actions occur after optimization */
+ Boolean neverReduce; /* Reduce is theoretically possible, but prevented
+ ** by actions or other outside implementation */
struct rule *nextlhs; /* Next rule with the same LHS */
struct rule *next; /* Next rule in the global list */
};
@@ -385,6 +387,7 @@ struct lemon {
int nstate; /* Number of states */
int nxstate; /* nstate with tail degenerate states removed */
int nrule; /* Number of rules */
+ int nruleWithAction; /* Number of rules with actions */
int nsymbol; /* Number of terminal and nonterminal symbols */
int nterminal; /* Number of terminal symbols */
int minShiftReduce; /* Minimum shift-reduce action value */
@@ -907,9 +910,9 @@ void FindStates(struct lemon *lemp)
sp = Symbol_find(lemp->start);
if( sp==0 ){
ErrorMsg(lemp->filename,0,
-"The specified start symbol \"%s\" is not \
-in a nonterminal of the grammar. \"%s\" will be used as the start \
-symbol instead.",lemp->start,lemp->startRule->lhs->name);
+ "The specified start symbol \"%s\" is not "
+ "in a nonterminal of the grammar. \"%s\" will be used as the start "
+ "symbol instead.",lemp->start,lemp->startRule->lhs->name);
lemp->errorcnt++;
sp = lemp->startRule->lhs;
}
@@ -925,9 +928,9 @@ symbol instead.",lemp->start,lemp->startRule->lhs->name);
for(i=0; inrhs; i++){
if( rp->rhs[i]==sp ){ /* FIX ME: Deal with multiterminals */
ErrorMsg(lemp->filename,0,
-"The start symbol \"%s\" occurs on the \
-right-hand side of a rule. This will result in a parser which \
-does not work properly.",sp->name);
+ "The start symbol \"%s\" occurs on the "
+ "right-hand side of a rule. This will result in a parser which "
+ "does not work properly.",sp->name);
lemp->errorcnt++;
}
}
@@ -1632,6 +1635,7 @@ int main(int argc, char **argv)
static int mhflag = 0;
static int nolinenosflag = 0;
static int noResort = 0;
+ static int sqlFlag = 0;
static struct s_options options[] = {
{OPT_FLAG, "b", (char*)&basisflag, "Print only the basis in report."},
@@ -1650,6 +1654,8 @@ int main(int argc, char **argv)
{OPT_FLAG, "r", (char*)&noResort, "Do not sort or renumber states"},
{OPT_FLAG, "s", (char*)&statistics,
"Print parser stats to standard output."},
+ {OPT_FLAG, "S", (char*)&sqlFlag,
+ "Generate the *.sql file describing the parser tables."},
{OPT_FLAG, "x", (char*)&version, "Print the version number."},
{OPT_FSTR, "T", (char*)handle_T_option, "Specify a template file."},
{OPT_FSTR, "W", 0, "Ignored. (Placeholder for '-W' compiler options.)"},
@@ -1711,6 +1717,7 @@ int main(int argc, char **argv)
for(i=0, rp=lem.rule; rp; rp=rp->next){
rp->iRule = rp->code ? i++ : -1;
}
+ lem.nruleWithAction = i;
for(rp=lem.rule; rp; rp=rp->next){
if( rp->iRule<0 ) rp->iRule = i++;
}
@@ -1758,7 +1765,7 @@ int main(int argc, char **argv)
if( !quiet ) ReportOutput(&lem);
/* Generate the source code for the parser */
- ReportTable(&lem, mhflag);
+ ReportTable(&lem, mhflag, sqlFlag);
/* Produce a header file for use by the scanner. (This step is
** omitted if the "-m" option is used because makeheaders will
@@ -2267,14 +2274,16 @@ static void parseonetoken(struct pstate *psp)
}else if( x[0]=='{' ){
if( psp->prevrule==0 ){
ErrorMsg(psp->filename,psp->tokenlineno,
-"There is no prior rule upon which to attach the code \
-fragment which begins on this line.");
+ "There is no prior rule upon which to attach the code "
+ "fragment which begins on this line.");
psp->errorcnt++;
}else if( psp->prevrule->code!=0 ){
ErrorMsg(psp->filename,psp->tokenlineno,
-"Code fragment beginning on this line is not the first \
-to follow the previous rule.");
+ "Code fragment beginning on this line is not the first "
+ "to follow the previous rule.");
psp->errorcnt++;
+ }else if( strcmp(x, "{NEVER-REDUCE")==0 ){
+ psp->prevrule->neverReduce = 1;
}else{
psp->prevrule->line = psp->tokenlineno;
psp->prevrule->code = &x[1];
@@ -2300,8 +2309,8 @@ to follow the previous rule.");
psp->errorcnt++;
}else if( psp->prevrule->precsym!=0 ){
ErrorMsg(psp->filename,psp->tokenlineno,
-"Precedence mark on this line is not the first \
-to follow the previous rule.");
+ "Precedence mark on this line is not the first "
+ "to follow the previous rule.");
psp->errorcnt++;
}else{
psp->prevrule->precsym = Symbol_new(x);
@@ -2904,7 +2913,8 @@ void Parse(struct lemon *gp)
}
if( c==0 ){
ErrorMsg(ps.filename,startline,
-"String starting on this line is not terminated before the end of the file.");
+ "String starting on this line is not terminated before "
+ "the end of the file.");
ps.errorcnt++;
nextcp = cp;
}else{
@@ -2943,7 +2953,8 @@ void Parse(struct lemon *gp)
}
if( c==0 ){
ErrorMsg(ps.filename,ps.tokenlineno,
-"C code starting on this line is not terminated before the end of the file.");
+ "C code starting on this line is not terminated before "
+ "the end of the file.");
ps.errorcnt++;
nextcp = cp;
}else{
@@ -4143,9 +4154,10 @@ static void writeRuleText(FILE *out, struct rule *rp){
/* Generate C source code for the parser */
void ReportTable(
struct lemon *lemp,
- int mhflag /* Output in makeheaders format if true */
+ int mhflag, /* Output in makeheaders format if true */
+ int sqlFlag /* Generate the *.sql file too */
){
- FILE *out, *in;
+ FILE *out, *in, *sql;
char line[LINESIZE];
int lineno;
struct state *stp;
@@ -4175,6 +4187,78 @@ void ReportTable(
fclose(in);
return;
}
+ if( sqlFlag==0 ){
+ sql = 0;
+ }else{
+ sql = file_open(lemp, ".sql", "wb");
+ if( sql==0 ){
+ fclose(in);
+ fclose(out);
+ return;
+ }
+ fprintf(sql,
+ "BEGIN;\n"
+ "CREATE TABLE symbol(\n"
+ " id INTEGER PRIMARY KEY,\n"
+ " name TEXT NOT NULL,\n"
+ " isTerminal BOOLEAN NOT NULL,\n"
+ " fallback INTEGER REFERENCES symbol"
+ " DEFERRABLE INITIALLY DEFERRED\n"
+ ");\n"
+ );
+ for(i=0; insymbol; i++){
+ fprintf(sql,
+ "INSERT INTO symbol(id,name,isTerminal,fallback)"
+ "VALUES(%d,'%s',%s",
+ i, lemp->symbols[i]->name,
+ interminal ? "TRUE" : "FALSE"
+ );
+ if( lemp->symbols[i]->fallback ){
+ fprintf(sql, ",%d);\n", lemp->symbols[i]->fallback->index);
+ }else{
+ fprintf(sql, ",NULL);\n");
+ }
+ }
+ fprintf(sql,
+ "CREATE TABLE rule(\n"
+ " ruleid INTEGER PRIMARY KEY,\n"
+ " lhs INTEGER REFERENCES symbol(id),\n"
+ " txt TEXT\n"
+ ");\n"
+ "CREATE TABLE rulerhs(\n"
+ " ruleid INTEGER REFERENCES rule(ruleid),\n"
+ " pos INTEGER,\n"
+ " sym INTEGER REFERENCES symbol(id)\n"
+ ");\n"
+ );
+ for(i=0, rp=lemp->rule; rp; rp=rp->next, i++){
+ assert( i==rp->iRule );
+ fprintf(sql,
+ "INSERT INTO rule(ruleid,lhs,txt)VALUES(%d,%d,'",
+ rp->iRule, rp->lhs->index
+ );
+ writeRuleText(sql, rp);
+ fprintf(sql,"');\n");
+ for(j=0; jnrhs; j++){
+ struct symbol *sp = rp->rhs[j];
+ if( sp->type!=MULTITERMINAL ){
+ fprintf(sql,
+ "INSERT INTO rulerhs(ruleid,pos,sym)VALUES(%d,%d,%d);\n",
+ i,j,sp->index
+ );
+ }else{
+ int k;
+ for(k=0; knsubsym; k++){
+ fprintf(sql,
+ "INSERT INTO rulerhs(ruleid,pos,sym)VALUES(%d,%d,%d);\n",
+ i,j,sp->subsym[k]->index
+ );
+ }
+ }
+ }
+ }
+ fprintf(sql, "COMMIT;\n");
+ }
lineno = 1;
tplt_xfer(lemp->name,in,out,&lineno);
@@ -4350,6 +4434,8 @@ void ReportTable(
** been computed */
fprintf(out,"#define YYNSTATE %d\n",lemp->nxstate); lineno++;
fprintf(out,"#define YYNRULE %d\n",lemp->nrule); lineno++;
+ fprintf(out,"#define YYNRULE_WITH_ACTION %d\n",lemp->nruleWithAction);
+ lineno++;
fprintf(out,"#define YYNTOKEN %d\n",lemp->nterminal); lineno++;
fprintf(out,"#define YY_MAX_SHIFT %d\n",lemp->nxstate-1); lineno++;
i = lemp->minShiftReduce;
@@ -4669,7 +4755,10 @@ void ReportTable(
assert( rp->noCode );
fprintf(out," /* (%d) ", rp->iRule);
writeRuleText(out, rp);
- if( rp->doesReduce ){
+ if( rp->neverReduce ){
+ fprintf(out, " (NEVER REDUCES) */ assert(yyruleno!=%d);\n",
+ rp->iRule); lineno++;
+ }else if( rp->doesReduce ){
fprintf(out, " */ yytestcase(yyruleno==%d);\n", rp->iRule); lineno++;
}else{
fprintf(out, " (OPTIMIZED OUT) */ assert(yyruleno!=%d);\n",
@@ -4697,6 +4786,7 @@ void ReportTable(
acttab_free(pActtab);
fclose(in);
fclose(out);
+ if( sql ) fclose(sql);
return;
}
diff --git a/tool/lempar.c b/tool/lempar.c
index f75ad51c39..c82e33298a 100644
--- a/tool/lempar.c
+++ b/tool/lempar.c
@@ -725,12 +725,15 @@ static YYACTIONTYPE yy_reduce(
if( yyTraceFILE && yyruleno<(int)(sizeof(yyRuleName)/sizeof(yyRuleName[0])) ){
yysize = yyRuleInfoNRhs[yyruleno];
if( yysize ){
- fprintf(yyTraceFILE, "%sReduce %d [%s], go to state %d.\n",
+ fprintf(yyTraceFILE, "%sReduce %d [%s]%s, pop back to state %d.\n",
yyTracePrompt,
- yyruleno, yyRuleName[yyruleno], yymsp[yysize].stateno);
+ yyruleno, yyRuleName[yyruleno],
+ yyruleno= aKeywordTable[j].priority ) return;
+ aKeywordTable[i].iNext = aKeywordTable[j].iNext;
+ aKeywordTable[j].iNext = i+1;
+ *pFrom = j+1;
+ reorder(&aKeywordTable[i].iNext);
+}
+
/*
** This routine does the work. The generated code is printed on standard
** output.
@@ -489,6 +515,7 @@ int main(int argc, char **argv){
h = aKeywordTable[i].hash % bestSize;
aKeywordTable[i].iNext = aKWHash[h];
aKWHash[h] = i+1;
+ reorder(&aKWHash[h]);
}
/* Begin generating code */
@@ -603,6 +630,17 @@ int main(int argc, char **argv){
}
}
printf("%s};\n", j==0 ? "" : "\n");
+ printf("/* Hash table decoded:\n");
+ for(i=0; i sqlite3.def
dumpbin /all $(LIBOBJ) \\
- | .\Replace.exe "^\s+/EXPORT:_?(sqlite3(?:session|changeset|changegroup|rebaser)?_[^@,]*)(?:@\d+|,DATA)?$$" $$1 true \\
+ | .\Replace.exe "^\s+/EXPORT:_?(sqlite3(?:session|changeset|changegroup|rebaser|rbu)?_[^@,]*)(?:@\d+|,DATA)?$$" $$1 true \\
| sort >> sqlite3.def
}]]
diff --git a/tool/mkpragmatab.tcl b/tool/mkpragmatab.tcl
index 832153916e..9ce5bd40fe 100644
--- a/tool/mkpragmatab.tcl
+++ b/tool/mkpragmatab.tcl
@@ -41,11 +41,6 @@ set pragma_def {
ARG: SQLITE_NullCallback
IF: !defined(SQLITE_OMIT_FLAG_PRAGMAS)
- NAME: legacy_file_format
- TYPE: FLAG
- ARG: SQLITE_LegacyFileFmt
- IF: !defined(SQLITE_OMIT_FLAG_PRAGMAS)
-
NAME: fullfsync
TYPE: FLAG
ARG: SQLITE_FullFSync
@@ -133,6 +128,11 @@ set pragma_def {
ARG: SQLITE_RecTriggers
IF: !defined(SQLITE_OMIT_FLAG_PRAGMAS)
+ NAME: trusted_schema
+ TYPE: FLAG
+ ARG: SQLITE_TrustedSchema
+ IF: !defined(SQLITE_OMIT_FLAG_PRAGMAS)
+
NAME: foreign_keys
TYPE: FLAG
ARG: SQLITE_ForeignKeys
@@ -262,7 +262,7 @@ set pragma_def {
NAME: function_list
FLAG: Result0
- COLS: name builtin
+ COLS: name builtin type enc narg flags
IF: !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
IF: !defined(SQLITE_OMIT_INTROSPECTION_PRAGMAS)
@@ -406,6 +406,9 @@ set pragma_def {
NAME: soft_heap_limit
FLAG: Result0
+ NAME: hard_heap_limit
+ FLAG: Result0
+
NAME: threads
FLAG: Result0
diff --git a/tool/mksourceid.c b/tool/mksourceid.c
index 282f5c4414..dd153997df 100644
--- a/tool/mksourceid.c
+++ b/tool/mksourceid.c
@@ -540,27 +540,9 @@ struct SHA1Context {
*
* blk0le() for little-endian and blk0be() for big-endian.
*/
-#if __GNUC__ && (defined(__i386__) || defined(__x86_64__))
-/*
- * GCC by itself only generates left rotates. Use right rotates if
- * possible to be kinder to dinky implementations with iterative rotate
- * instructions.
- */
-#define SHA_ROT(op, x, k) \
- ({ unsigned int y; asm(op " %1,%0" : "=r" (y) : "I" (k), "0" (x)); y; })
-#define rol(x,k) SHA_ROT("roll", x, k)
-#define ror(x,k) SHA_ROT("rorl", x, k)
-
-#else
-/* Generic C equivalent */
#define SHA_ROT(x,l,r) ((x) << (l) | (x) >> (r))
#define rol(x,k) SHA_ROT(x,k,32-(k))
#define ror(x,k) SHA_ROT(x,32-(k),k)
-#endif
-
-
-
-
#define blk0le(i) (block[i] = (ror(block[i],8)&0xFF00FF00) \
|(rol(block[i],8)&0x00FF00FF))
diff --git a/tool/showdb.c b/tool/showdb.c
index a28656b3ea..fe4e9aca01 100644
--- a/tool/showdb.c
+++ b/tool/showdb.c
@@ -956,7 +956,7 @@ static void page_usage_freelist(int pgno){
** Determine pages used as PTRMAP pages
*/
static void page_usage_ptrmap(unsigned char *a){
- if( a[55] ){
+ if( decodeInt32(a+52) ){
int usable = g.pagesize - a[20];
int pgno = 2;
int perPage = usable/5;