diff --git a/Makefile.in b/Makefile.in
index 5bab165cd6..992d0f0d9e 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -180,7 +180,7 @@ LIBOBJS0 = alter.lo analyze.lo attach.lo auth.lo \
fts3_unicode.lo fts3_unicode2.lo fts3_write.lo \
fts5.lo \
func.lo global.lo hash.lo \
- icu.lo insert.lo json1.lo legacy.lo loadext.lo \
+ icu.lo insert.lo json.lo legacy.lo loadext.lo \
main.lo malloc.lo mem0.lo mem1.lo mem2.lo mem3.lo mem5.lo \
memdb.lo memjournal.lo \
mutex.lo mutex_noop.lo mutex_unix.lo mutex_w32.lo \
@@ -234,6 +234,7 @@ SRC = \
$(TOP)/src/hash.h \
$(TOP)/src/hwtime.h \
$(TOP)/src/insert.c \
+ $(TOP)/src/json.c \
$(TOP)/src/legacy.c \
$(TOP)/src/loadext.c \
$(TOP)/src/main.c \
@@ -366,7 +367,6 @@ SRC += \
$(TOP)/ext/rbu/sqlite3rbu.h \
$(TOP)/ext/rbu/sqlite3rbu.c
SRC += \
- $(TOP)/ext/misc/json1.c \
$(TOP)/ext/misc/stmt.c
# Generated source code files
@@ -875,6 +875,9 @@ hash.lo: $(TOP)/src/hash.c $(HDR)
insert.lo: $(TOP)/src/insert.c $(HDR)
$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/insert.c
+json.lo: $(TOP)/src/json.c
+ $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/json.c
+
legacy.lo: $(TOP)/src/legacy.c $(HDR)
$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/legacy.c
@@ -1178,9 +1181,6 @@ userauth.lo: $(TOP)/ext/userauth/userauth.c $(HDR) $(EXTHDR)
sqlite3session.lo: $(TOP)/ext/session/sqlite3session.c $(HDR) $(EXTHDR)
$(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/session/sqlite3session.c
-json1.lo: $(TOP)/ext/misc/json1.c
- $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/misc/json1.c
-
stmt.lo: $(TOP)/ext/misc/stmt.c
$(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/misc/stmt.c
diff --git a/Makefile.msc b/Makefile.msc
index e4115f28dc..a16e76f7c7 100644
--- a/Makefile.msc
+++ b/Makefile.msc
@@ -580,17 +580,17 @@ RCC = $(RC) -DSQLITE_OS_WIN=1 -I. -I$(TOP) -I$(TOP)\src $(RCOPTS) $(RCCOPTS)
#
!IF $(USE_STDCALL)!=0 || $(FOR_WIN10)!=0
!IF "$(PLATFORM)"=="x86"
-CORE_CCONV_OPTS = -Gz -DSQLITE_CDECL=__cdecl -DSQLITE_APICALL=__stdcall -DSQLITE_CALLBACK=__stdcall -DSQLITE_SYSAPI=__stdcall
-SHELL_CCONV_OPTS = -Gz -DSQLITE_CDECL=__cdecl -DSQLITE_APICALL=__stdcall -DSQLITE_CALLBACK=__stdcall -DSQLITE_SYSAPI=__stdcall
+CORE_CCONV_OPTS = -Gz -guard:cf -DSQLITE_CDECL=__cdecl -DSQLITE_APICALL=__stdcall -DSQLITE_CALLBACK=__stdcall -DSQLITE_SYSAPI=__stdcall
+SHELL_CCONV_OPTS = -Gz -guard:cf -DSQLITE_CDECL=__cdecl -DSQLITE_APICALL=__stdcall -DSQLITE_CALLBACK=__stdcall -DSQLITE_SYSAPI=__stdcall
# <>
-TEST_CCONV_OPTS = -Gz -DSQLITE_CDECL=__cdecl -DSQLITE_APICALL=__stdcall -DSQLITE_CALLBACK=__stdcall -DSQLITE_SYSAPI=__stdcall -DINCLUDE_SQLITE_TCL_H=1 -DSQLITE_TCLAPI=__cdecl
+TEST_CCONV_OPTS = -Gz -guard:cf -DSQLITE_CDECL=__cdecl -DSQLITE_APICALL=__stdcall -DSQLITE_CALLBACK=__stdcall -DSQLITE_SYSAPI=__stdcall -DINCLUDE_SQLITE_TCL_H=1 -DSQLITE_TCLAPI=__cdecl
# <>
!ELSE
!IFNDEF PLATFORM
-CORE_CCONV_OPTS = -Gz -DSQLITE_CDECL=__cdecl -DSQLITE_APICALL=__stdcall -DSQLITE_CALLBACK=__stdcall -DSQLITE_SYSAPI=__stdcall
-SHELL_CCONV_OPTS = -Gz -DSQLITE_CDECL=__cdecl -DSQLITE_APICALL=__stdcall -DSQLITE_CALLBACK=__stdcall -DSQLITE_SYSAPI=__stdcall
+CORE_CCONV_OPTS = -Gz -guard:cf -DSQLITE_CDECL=__cdecl -DSQLITE_APICALL=__stdcall -DSQLITE_CALLBACK=__stdcall -DSQLITE_SYSAPI=__stdcall
+SHELL_CCONV_OPTS = -Gz -guard:cf -DSQLITE_CDECL=__cdecl -DSQLITE_APICALL=__stdcall -DSQLITE_CALLBACK=__stdcall -DSQLITE_SYSAPI=__stdcall
# <>
-TEST_CCONV_OPTS = -Gz -DSQLITE_CDECL=__cdecl -DSQLITE_APICALL=__stdcall -DSQLITE_CALLBACK=__stdcall -DSQLITE_SYSAPI=__stdcall -DINCLUDE_SQLITE_TCL_H=1 -DSQLITE_TCLAPI=__cdecl
+TEST_CCONV_OPTS = -Gz -guard:cf -DSQLITE_CDECL=__cdecl -DSQLITE_APICALL=__stdcall -DSQLITE_CALLBACK=__stdcall -DSQLITE_SYSAPI=__stdcall -DINCLUDE_SQLITE_TCL_H=1 -DSQLITE_TCLAPI=__cdecl
# <>
!ELSE
CORE_CCONV_OPTS =
@@ -1248,7 +1248,7 @@ LIBOBJS0 = vdbe.lo parse.lo alter.lo analyze.lo attach.lo auth.lo \
fts3_tokenize_vtab.lo fts3_unicode.lo fts3_unicode2.lo fts3_write.lo \
fts5.lo \
func.lo global.lo hash.lo \
- icu.lo insert.lo json1.lo legacy.lo loadext.lo \
+ icu.lo insert.lo json.lo legacy.lo loadext.lo \
main.lo malloc.lo mem0.lo mem1.lo mem2.lo mem3.lo mem5.lo \
memdb.lo memjournal.lo \
mutex.lo mutex_noop.lo mutex_unix.lo mutex_w32.lo \
@@ -1315,6 +1315,7 @@ SRC00 = \
$(TOP)\src\global.c \
$(TOP)\src\hash.c \
$(TOP)\src\insert.c \
+ $(TOP)\src\json.c \
$(TOP)\src\legacy.c \
$(TOP)\src\loadext.c \
$(TOP)\src\main.c \
@@ -1445,7 +1446,6 @@ SRC07 = \
$(TOP)\ext\rtree\rtree.c \
$(TOP)\ext\session\sqlite3session.c \
$(TOP)\ext\rbu\sqlite3rbu.c \
- $(TOP)\ext\misc\json1.c \
$(TOP)\ext\misc\stmt.c
# Extension header files, part 1.
@@ -1991,6 +1991,9 @@ hash.lo: $(TOP)\src\hash.c $(HDR)
insert.lo: $(TOP)\src\insert.c $(HDR)
$(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\insert.c
+json.lo: $(TOP)\src\json.c $(HDR)
+ $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\json.c
+
legacy.lo: $(TOP)\src\legacy.c $(HDR)
$(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\legacy.c
@@ -2299,9 +2302,6 @@ fts3_unicode2.lo: $(TOP)\ext\fts3\fts3_unicode2.c $(HDR) $(EXTHDR)
fts3_write.lo: $(TOP)\ext\fts3\fts3_write.c $(HDR) $(EXTHDR)
$(LTCOMPILE) $(CORE_COMPILE_OPTS) $(NO_WARN) -DSQLITE_CORE -c $(TOP)\ext\fts3\fts3_write.c
-json1.lo: $(TOP)\ext\misc\json1.c $(HDR) $(EXTHDR)
- $(LTCOMPILE) $(CORE_COMPILE_OPTS) $(NO_WARN) -DSQLITE_CORE -c $(TOP)\ext\misc\json1.c
-
stmt.lo: $(TOP)\ext\misc\stmt.c $(HDR) $(EXTHDR)
$(LTCOMPILE) $(CORE_COMPILE_OPTS) $(NO_WARN) -DSQLITE_CORE -c $(TOP)\ext\misc\stmt.c
diff --git a/README.md b/README.md
index b79fc67f15..9e8bb2610e 100644
--- a/README.md
+++ b/README.md
@@ -309,9 +309,11 @@ describes its purpose and role within the larger system.
The `manifest` file at the root directory of the source tree
contains either a SHA3-256 hash (for newer files) or a SHA1 hash (for
older files) for every source file in the repository.
-The SHA3-256 hash of the `manifest`
-file itself is the official name of the version of the source tree that you
-have. The `manifest.uuid` file should contain the SHA3-256 hash of the
+The name of the version of the entire source tree is just the
+SHA3-256 hash of the `manifest` file itself, possibly with the
+last line of that file omitted if the last line begins with
+"`# Remove this line`".
+The `manifest.uuid` file should contain the SHA3-256 hash of the
`manifest` file. If all of the above hash comparisons are correct, then
you can be confident that your source tree is authentic and unadulterated.
diff --git a/VERSION b/VERSION
index c03c47aa89..4f7d6a223d 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-3.37.0
+3.38.0
diff --git a/autoconf/Makefile.msc b/autoconf/Makefile.msc
index 40d0e8113d..524aeb6f41 100644
--- a/autoconf/Makefile.msc
+++ b/autoconf/Makefile.msc
@@ -502,12 +502,12 @@ RCC = $(RC) -DSQLITE_OS_WIN=1 -I. -I$(TOP) $(RCOPTS) $(RCCOPTS)
#
!IF $(USE_STDCALL)!=0 || $(FOR_WIN10)!=0
!IF "$(PLATFORM)"=="x86"
-CORE_CCONV_OPTS = -Gz -DSQLITE_CDECL=__cdecl -DSQLITE_APICALL=__stdcall -DSQLITE_CALLBACK=__stdcall -DSQLITE_SYSAPI=__stdcall
-SHELL_CCONV_OPTS = -Gz -DSQLITE_CDECL=__cdecl -DSQLITE_APICALL=__stdcall -DSQLITE_CALLBACK=__stdcall -DSQLITE_SYSAPI=__stdcall
+CORE_CCONV_OPTS = -Gz -guard:cf -DSQLITE_CDECL=__cdecl -DSQLITE_APICALL=__stdcall -DSQLITE_CALLBACK=__stdcall -DSQLITE_SYSAPI=__stdcall
+SHELL_CCONV_OPTS = -Gz -guard:cf -DSQLITE_CDECL=__cdecl -DSQLITE_APICALL=__stdcall -DSQLITE_CALLBACK=__stdcall -DSQLITE_SYSAPI=__stdcall
!ELSE
!IFNDEF PLATFORM
-CORE_CCONV_OPTS = -Gz -DSQLITE_CDECL=__cdecl -DSQLITE_APICALL=__stdcall -DSQLITE_CALLBACK=__stdcall -DSQLITE_SYSAPI=__stdcall
-SHELL_CCONV_OPTS = -Gz -DSQLITE_CDECL=__cdecl -DSQLITE_APICALL=__stdcall -DSQLITE_CALLBACK=__stdcall -DSQLITE_SYSAPI=__stdcall
+CORE_CCONV_OPTS = -Gz -guard:cf -DSQLITE_CDECL=__cdecl -DSQLITE_APICALL=__stdcall -DSQLITE_CALLBACK=__stdcall -DSQLITE_SYSAPI=__stdcall
+SHELL_CCONV_OPTS = -Gz -guard:cf -DSQLITE_CDECL=__cdecl -DSQLITE_APICALL=__stdcall -DSQLITE_CALLBACK=__stdcall -DSQLITE_SYSAPI=__stdcall
!ELSE
CORE_CCONV_OPTS =
SHELL_CCONV_OPTS =
diff --git a/configure b/configure
index 8da48f587a..abb182d5eb 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.37.0.
+# Generated by GNU Autoconf 2.69 for sqlite 3.38.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.37.0'
-PACKAGE_STRING='sqlite 3.37.0'
+PACKAGE_VERSION='3.38.0'
+PACKAGE_STRING='sqlite 3.38.0'
PACKAGE_BUGREPORT=''
PACKAGE_URL=''
@@ -770,11 +770,11 @@ ac_includes_default="\
ac_subst_vars='LTLIBOBJS
LIBOBJS
BUILD_CFLAGS
+AMALGAMATION_LINE_MACROS
USE_GCOV
OPT_FEATURE_FLAGS
HAVE_ZLIB
USE_AMALGAMATION
-AMALGAMATION_LINE_MACROS
TARGET_DEBUG
TARGET_HAVE_EDITLINE
TARGET_HAVE_READLINE
@@ -903,16 +903,15 @@ with_readline_lib
with_readline_inc
enable_debug
enable_amalgamation
-amalgamation_line_macros
enable_load_extension
enable_math
+enable_json
enable_all
enable_memsys5
enable_memsys3
enable_fts3
enable_fts4
enable_fts5
-enable_json1
enable_update_limit
enable_geopoly
enable_rtree
@@ -1469,7 +1468,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.37.0 to adapt to many kinds of systems.
+\`configure' configures sqlite 3.38.0 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1534,7 +1533,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
- short | recursive ) echo "Configuration of sqlite 3.37.0:";;
+ short | recursive ) echo "Configuration of sqlite 3.38.0:";;
esac
cat <<\_ACEOF
@@ -1561,13 +1560,13 @@ Optional Features:
--disable-load-extension
Disable loading of external extensions
--disable-math Disable math functions
- --enable-all Enable FTS4, FTS5, Geopoly, JSON, RTree, Sessions
+ --disable-json Disable JSON functions
+ --enable-all Enable FTS4, FTS5, Geopoly, RTree, Sessions
--enable-memsys5 Enable MEMSYS5
--enable-memsys3 Enable MEMSYS3
--enable-fts3 Enable the FTS3 extension
--enable-fts4 Enable the FTS4 extension
--enable-fts5 Enable the FTS5 extension
- --enable-json1 Enable the JSON1 extension
--enable-update-limit Enable the UPDATE/DELETE LIMIT clause
--enable-geopoly Enable the GEOPOLY extension
--enable-rtree Enable the RTREE extension
@@ -1662,7 +1661,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
-sqlite configure 3.37.0
+sqlite configure 3.38.0
generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc.
@@ -2081,7 +2080,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.37.0, which was
+It was created by sqlite $as_me 3.38.0, which was
generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@
@@ -3939,13 +3938,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:3940: $ac_compile\"" >&5)
+ (eval echo "\"\$as_me:3941: $ac_compile\"" >&5)
(eval "$ac_compile" 2>conftest.err)
cat conftest.err >&5
- (eval echo "\"\$as_me:3943: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
+ (eval echo "\"\$as_me:3944: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
(eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
cat conftest.err >&5
- (eval echo "\"\$as_me:3946: output\"" >&5)
+ (eval echo "\"\$as_me:3947: output\"" >&5)
cat conftest.out >&5
if $GREP 'External.*some_variable' conftest.out > /dev/null; then
lt_cv_nm_interface="MS dumpbin"
@@ -5151,7 +5150,7 @@ ia64-*-hpux*)
;;
*-*-irix6*)
# Find out which ABI we are using.
- echo '#line 5152 "configure"' > conftest.$ac_ext
+ echo '#line 5153 "configure"' > conftest.$ac_ext
if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
(eval $ac_compile) 2>&5
ac_status=$?
@@ -6676,11 +6675,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:6677: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:6678: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
- echo "$as_me:6681: \$? = $ac_status" >&5
+ echo "$as_me:6682: \$? = $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.
@@ -7015,11 +7014,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:7016: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:7017: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
- echo "$as_me:7020: \$? = $ac_status" >&5
+ echo "$as_me:7021: \$? = $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.
@@ -7120,11 +7119,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:7121: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:7122: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
- echo "$as_me:7125: \$? = $ac_status" >&5
+ echo "$as_me:7126: \$? = $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
@@ -7175,11 +7174,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:7176: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:7177: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
- echo "$as_me:7180: \$? = $ac_status" >&5
+ echo "$as_me:7181: \$? = $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
@@ -9555,7 +9554,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
-#line 9556 "configure"
+#line 9557 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -9651,7 +9650,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
-#line 9652 "configure"
+#line 9653 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -10307,13 +10306,6 @@ done
#
USE_AMALGAMATION=1
-#########
-# By default, amalgamation sqlite3.c will have #line directives.
-# This is a build option not shown by ./configure --help
-# To control it, use configure option: amalgamation_line_macros=?
-# where ? is no to suppress #line directives or yes to create them.
-AMALGAMATION_LINE_MACROS=--linemacros=0
-
#########
# See whether we can run specific tclsh versions known to work well;
# if not, then we fall back to plain tclsh.
@@ -11284,19 +11276,6 @@ if test "${enable_amalgamation}" = "no" ; then
USE_AMALGAMATION=0
fi
-########
-# See whether --disable
-if test "${amalgamation_line_macros+set}" = set; then :
- enableval=$amalgamation_line_macros;
-fi
-
-if test "${amalgamation_line_macros}" = "yes" ; then
- AMALGAMATION_LINE_MACROS=--linemacros=1
-fi
-if test "${amalgamation_line_macros}" = "no" ; then
- AMALGAMATION_LINE_MACROS=--linemacros=0
-fi
-
#########
# Look for zlib. Only needed by extensions and by the sqlite3.exe shell
@@ -11518,6 +11497,24 @@ fi
fi
+##########
+# Do we want to support JSON functions
+#
+# Check whether --enable-json was given.
+if test "${enable_json+set}" = set; then :
+ enableval=$enable_json;
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to support JSON functions" >&5
+$as_echo_n "checking whether to support JSON functions... " >&6; }
+if test "$enable_json" = "no"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_OMIT_JSON"
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+fi
########
# The --enable-all argument is short-hand to enable
@@ -11722,24 +11719,6 @@ else
$as_echo "no" >&6; }
fi
-#########
-# See whether we should enable JSON1
-# Check whether --enable-json1 was given.
-if test "${enable_json1+set}" = set; then :
- enableval=$enable_json1;
-fi
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to support JSON" >&5
-$as_echo_n "checking whether to support JSON... " >&6; }
-if test "${enable_json1}" = "yes" -o "${enable_all}" = "yes" ; then
- OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_JSON1"
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
#########
# See whether we should enable the LIMIT clause on UPDATE and DELETE
# statements.
@@ -11882,6 +11861,17 @@ else
fi
+#########
+# Enable/disabled amalagamation line macros
+########
+AMALGAMATION_LINE_MACROS=--linemacros=0
+if test "${amalgamation_line_macros}" = "yes" ; then
+ AMALGAMATION_LINE_MACROS=--linemacros=1
+fi
+if test "${amalgamation_line_macros}" = "no" ; then
+ AMALGAMATION_LINE_MACROS=--linemacros=0
+fi
+
#########
# Output the config header
@@ -12400,7 +12390,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.37.0, which was
+This file was extended by sqlite $as_me 3.38.0, which was
generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -12466,7 +12456,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.37.0
+sqlite config.status 3.38.0
configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\"
diff --git a/configure.ac b/configure.ac
index 70664dd411..cc805a00d5 100644
--- a/configure.ac
+++ b/configure.ac
@@ -605,12 +605,24 @@ else
AC_SEARCH_LIBS(ceil, m)
fi
+##########
+# Do we want to support JSON functions
+#
+AC_ARG_ENABLE(json,
+AC_HELP_STRING([--disable-json],[Disable JSON functions]))
+AC_MSG_CHECKING([whether to support JSON functions])
+if test "$enable_json" = "no"; then
+ AC_MSG_RESULT([no])
+ OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_OMIT_JSON"
+else
+ AC_MSG_RESULT([yes])
+fi
########
# The --enable-all argument is short-hand to enable
# multiple extensions.
AC_ARG_ENABLE(all, AC_HELP_STRING([--enable-all],
- [Enable FTS4, FTS5, Geopoly, JSON, RTree, Sessions]))
+ [Enable FTS4, FTS5, Geopoly, RTree, Sessions]))
##########
# Do we want to support memsys3 and/or memsys5
@@ -666,17 +678,6 @@ else
AC_MSG_RESULT([no])
fi
-#########
-# See whether we should enable JSON1
-AC_ARG_ENABLE(json1, AC_HELP_STRING([--enable-json1],[Enable the JSON1 extension]))
-AC_MSG_CHECKING([whether to support JSON])
-if test "${enable_json1}" = "yes" -o "${enable_all}" = "yes" ; then
- OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_JSON1"
- AC_MSG_RESULT([yes])
-else
- AC_MSG_RESULT([no])
-fi
-
#########
# See whether we should enable the LIMIT clause on UPDATE and DELETE
# statements.
@@ -791,6 +792,17 @@ else
fi
AC_SUBST(USE_GCOV)
+#########
+# Enable/disabled amalagamation line macros
+########
+AMALGAMATION_LINE_MACROS=--linemacros=0
+if test "${amalgamation_line_macros}" = "yes" ; then
+ AMALGAMATION_LINE_MACROS=--linemacros=1
+fi
+if test "${amalgamation_line_macros}" = "no" ; then
+ AMALGAMATION_LINE_MACROS=--linemacros=0
+fi
+AC_SUBST(AMALGAMATION_LINE_MACROS)
#########
# Output the config header
diff --git a/doc/json-enhancements.md b/doc/json-enhancements.md
new file mode 100644
index 0000000000..bc03e8978c
--- /dev/null
+++ b/doc/json-enhancements.md
@@ -0,0 +1,144 @@
+# JSON Functions Enhancements (2022)
+
+This document summaries enhancements to the SQLite JSON support added in
+early 2022.
+
+## 1.0 Change summary:
+
+ 1. New **->** and **->>** operators that work like MySQL and PostgreSQL (PG).
+ 2. JSON functions are built-in rather than being an extension. They
+ are included by default, but can be omitted using the
+ -DSQLITE_OMIT_JSON compile-time option.
+
+
+## 2.0 New operators **->** and **->>**
+
+The SQLite language adds two new binary operators **->** and **->>**.
+Both operators are similar to json_extract(). The left operand is
+JSON and the right operand is a JSON path expression (possibly abbreviated
+for compatibility with PG - see below). So they are similar to a
+two-argument call to json_extract().
+
+The difference between -> and ->> (and json_extract()) is as follows:
+
+ * The -> operator always returns JSON.
+
+ * The ->> operator converts the answer into a primitive SQL datatype
+ such as TEXT, INTEGER, REAL, or NULL. If a JSON object or array
+ is selected, that object or array is rendered as text. If a JSON
+ value is selected, that value is converted into its corresponding
+ SQL type
+
+ * The json_extract() interface returns JSON when a JSON object or
+ array is selected, or a primitive SQL datatype when a JSON value
+ is selected. This is different from MySQL, in which json_extract()
+ always returns JSON, but the difference is retained because it has
+ worked that way for 6 years and changing it now would likely break
+ a lot of legacy code.
+
+In MySQL and PG, the ->> operator always returns TEXT (or NULL) and never
+INTEGER or REAL. This is due to limitations in the type handling capabilities
+of those systems. In MySQL and PG, the result type a function or operator
+may only depend on the type of its arguments, never the value of its arguments.
+But the underlying JSON type depends on the value of the JSON path
+expression, not the type of the JSON path expression (which is always TEXT).
+Hence, the result type of ->> in MySQL and PG is unable to vary according
+to the type of the JSON value being extracted.
+
+The type system in SQLite is more general. Functions in SQLite are able
+to return different datatypes depending on the value of their arguments.
+So the ->> operator in SQLite is able to return TEXT, INTEGER, REAL, or NULL
+depending on the JSON type of the value being extracted. This means that
+the behavior of the ->> is slightly different in SQLite versus MySQL and PG
+in that it will sometimes return INTEGER and REAL values, depending on its
+inputs. It is possible to implement the ->> operator in SQLite so that it
+always operates exactly like MySQL and PG and always returns TEXT or NULL,
+but I have been unable to think of any situations where returning the
+actual JSON value this would cause problems, so I'm including the enhanced
+functionality in SQLite.
+
+The table below attempts to summarize the differences between the
+-> and ->> operators and the json_extract() function, for SQLite, MySQL,
+and PG. JSON values are shown using their SQL text representation but
+in a bold font.
+
+
+
+JSON | PATH | -> operator (all) | ->> operator (MySQL/PG)
+ | ->> operator (SQLite) | json_extract() (SQLite)
+ |
---|
**'{"a":123}'** | '$.a' | **'123'** | '123' | 123 | 123
+ |
**'{"a":4.5}'** | '$.a' | **'4.5'** | '4.5' | 4.5 | 4.5
+ |
**'{"a":"xyz"}'** | '$.a' | **'"xyz"'** | 'xyz' | 'xyz' | 'xyz'
+ |
**'{"a":null}'** | '$.a' | **'null'** | NULL | NULL | NULL
+ |
**'{"a":[6,7,8]}'** | '$.a' | **'[6,7,8]'** | '[6,7,8]' | '[6,7,8]' | **'[6,7,8]'**
+ |
**'{"a":{"x":9}}'** | '$.a' | **'{"x":9}'** | '{"x":9}' | '{"x":9}' | **'{"x":9}'**
+ |
**'{"b":999}'** | '$.a' | NULL | NULL | NULL | NULL
+ |
+
+Important points about the table above:
+
+ * The -> operator always returns either JSON or NULL.
+
+ * The ->> operator never returns JSON. It always returns TEXT or NULL, or in the
+ case of SQLite, INTEGER or REAL.
+
+ * The MySQL json_extract() function works exactly the same
+ as the MySQL -> operator.
+
+ * The SQLite json_extract() operator works like -> for JSON objects and
+ arrays, and like ->> for JSON values.
+
+ * The -> operator works the same for all systems.
+
+ * The only difference in ->> between SQLite and other systems is that
+ when the JSON value is numeric, SQLite returns a numeric SQL value,
+ whereas the other systems return a text representation of the numeric
+ value.
+
+### 2.1 Abbreviated JSON path expressions for PG compatibility
+
+The table above always shows the full JSON path expression: '$.a'. But
+PG does not accept this syntax. PG only allows a single JSON object label
+name or a single integer array index. In order to provide compatibility
+with PG, The -> and ->> operators in SQLite are extended to also support
+a JSON object label or an integer array index for the right-hand side
+operand, in addition to a full JSON path expression.
+
+Thus, a -> or ->> operator that works on MySQL will work in
+SQLite. And a -> or ->> operator that works in PG will work in SQLite.
+But because SQLite supports the union of the disjoint capabilities of
+MySQL and PG, there will always be -> and ->> operators that work in
+SQLite that do not work in one of MySQL and PG. This is an unavoidable
+consequence of the different syntax for -> and ->> in MySQL and PG.
+
+In the following table, assume that "value1" is a JSON object and
+"value2" is a JSON array.
+
+
+SQL expression | Works in MySQL? | Works in PG? | Works in SQLite
+ |
---|
value1->'$.a' | yes | no | yes
+ |
value1->'a' | no | yes | yes
+ |
value2->'$[2]' | yes | no | yes
+ |
value2->2 | no | yes | yes
+ |
+
+The abbreviated JSON path expressions only work for the -> and ->> operators
+in SQLite. The json_extract() function, and all other built-in SQLite
+JSON functions, continue to require complete JSON path expressions for their
+PATH arguments.
+
+## 3.0 JSON moved into the core
+
+The JSON interface is now moved into the SQLite core.
+
+When originally written in 2015, the JSON functions were an extension
+that could be optionally included at compile-time, or loaded at run-time.
+The implementation was in a source file named ext/misc/json1.c in the
+source tree. JSON functions were only compiled in if the
+-DSQLITE_ENABLE_JSON1 compile-time option was used.
+
+After these enhancements, the JSON functions are now built-ins.
+The source file that implements the JSON functions is moved to src/json.c.
+No special compile-time options are needed to load JSON into the build.
+Instead, there is a new -DSQLITE_OMIT_JSON compile-time option to leave
+them out.
diff --git a/ext/expert/sqlite3expert.c b/ext/expert/sqlite3expert.c
index a5eb109b46..f29b8a9e0b 100644
--- a/ext/expert/sqlite3expert.c
+++ b/ext/expert/sqlite3expert.c
@@ -697,17 +697,25 @@ static int idxGetTableInfo(
){
sqlite3_stmt *p1 = 0;
int nCol = 0;
- int nTab = STRLEN(zTab);
- int nByte = sizeof(IdxTable) + nTab + 1;
+ int nTab;
+ int nByte;
IdxTable *pNew = 0;
int rc, rc2;
char *pCsr = 0;
int nPk = 0;
+ *ppOut = 0;
+ if( zTab==0 ) return SQLITE_ERROR;
+ nTab = STRLEN(zTab);
+ nByte = sizeof(IdxTable) + nTab + 1;
rc = idxPrintfPrepareStmt(db, &p1, pzErrmsg, "PRAGMA table_xinfo=%Q", zTab);
while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(p1) ){
const char *zCol = (const char*)sqlite3_column_text(p1, 1);
const char *zColSeq = 0;
+ if( zCol==0 ){
+ rc = SQLITE_ERROR;
+ break;
+ }
nByte += 1 + STRLEN(zCol);
rc = sqlite3_table_column_metadata(
db, "main", zTab, zCol, 0, &zColSeq, 0, 0, 0
@@ -734,7 +742,9 @@ static int idxGetTableInfo(
while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(p1) ){
const char *zCol = (const char*)sqlite3_column_text(p1, 1);
const char *zColSeq = 0;
- int nCopy = STRLEN(zCol) + 1;
+ int nCopy;
+ if( zCol==0 ) continue;
+ nCopy = STRLEN(zCol) + 1;
pNew->aCol[nCol].zName = pCsr;
pNew->aCol[nCol].iPk = (sqlite3_column_int(p1, 5)==1 && nPk==1);
memcpy(pCsr, zCol, nCopy);
@@ -886,6 +896,7 @@ static int idxFindCompatible(
IdxConstraint *pT = pTail;
sqlite3_stmt *pInfo = 0;
const char *zIdx = (const char*)sqlite3_column_text(pIdxList, 1);
+ if( zIdx==0 ) continue;
/* Zero the IdxConstraint.bFlag values in the pEq list */
for(pIter=pEq; pIter; pIter=pIter->pLink) pIter->bFlag = 0;
@@ -1168,7 +1179,7 @@ static void idxWriteFree(IdxWrite *pTab){
** runs all the queries to see which indexes they prefer, and populates
** IdxStatement.zIdx and IdxStatement.zEQP with the results.
*/
-int idxFindIndexes(
+static int idxFindIndexes(
sqlite3expert *p,
char **pzErr /* OUT: Error message (sqlite3_malloc) */
){
@@ -1297,6 +1308,7 @@ static int idxProcessOneTrigger(
rc = idxPrintfPrepareStmt(p->db, &pSelect, pzErr, zSql, zTab, zTab);
while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSelect) ){
const char *zCreate = (const char*)sqlite3_column_text(pSelect, 0);
+ if( zCreate==0 ) continue;
rc = sqlite3_exec(p->dbv, zCreate, 0, 0, pzErr);
}
idxFinalize(&rc, pSelect);
@@ -1399,8 +1411,9 @@ static int idxCreateVtabSchema(sqlite3expert *p, char **pzErrmsg){
const char *zName = (const char*)sqlite3_column_text(pSchema, 1);
const char *zSql = (const char*)sqlite3_column_text(pSchema, 2);
+ if( zType==0 || zName==0 ) continue;
if( zType[0]=='v' || zType[1]=='r' ){
- rc = sqlite3_exec(p->dbv, zSql, 0, 0, pzErrmsg);
+ if( zSql ) rc = sqlite3_exec(p->dbv, zSql, 0, 0, pzErrmsg);
}else{
IdxTable *pTab;
rc = idxGetTableInfo(p->db, zName, &pTab, pzErrmsg);
@@ -1537,6 +1550,7 @@ static void idxRemFunc(
case SQLITE_BLOB:
case SQLITE_TEXT: {
int nByte = sqlite3_value_bytes(argv[1]);
+ const void *pData = 0;
if( nByte>pSlot->nByte ){
char *zNew = (char*)sqlite3_realloc(pSlot->z, nByte*2);
if( zNew==0 ){
@@ -1548,9 +1562,11 @@ static void idxRemFunc(
}
pSlot->n = nByte;
if( pSlot->eType==SQLITE_BLOB ){
- memcpy(pSlot->z, sqlite3_value_blob(argv[1]), nByte);
+ pData = sqlite3_value_blob(argv[1]);
+ if( pData ) memcpy(pSlot->z, pData, nByte);
}else{
- memcpy(pSlot->z, sqlite3_value_text(argv[1]), nByte);
+ pData = sqlite3_value_text(argv[1]);
+ memcpy(pSlot->z, pData, nByte);
}
break;
}
@@ -1761,6 +1777,7 @@ static int idxPopulateStat1(sqlite3expert *p, char **pzErr){
i64 iRowid = sqlite3_column_int64(pAllIndex, 0);
const char *zTab = (const char*)sqlite3_column_text(pAllIndex, 1);
const char *zIdx = (const char*)sqlite3_column_text(pAllIndex, 2);
+ if( zTab==0 || zIdx==0 ) continue;
if( p->iSample<100 && iPrev!=iRowid ){
samplectx.target = (double)p->iSample / 100.0;
samplectx.iTarget = p->iSample;
@@ -1827,14 +1844,14 @@ sqlite3expert *sqlite3_expert_new(sqlite3 *db, char **pzErrmsg){
/* Copy the entire schema of database [db] into [dbm]. */
if( rc==SQLITE_OK ){
- sqlite3_stmt *pSql;
+ sqlite3_stmt *pSql = 0;
rc = idxPrintfPrepareStmt(pNew->db, &pSql, pzErrmsg,
"SELECT sql FROM sqlite_schema WHERE name NOT LIKE 'sqlite_%%'"
" AND sql NOT LIKE 'CREATE VIRTUAL %%'"
);
while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSql) ){
const char *zSql = (const char*)sqlite3_column_text(pSql, 0);
- rc = sqlite3_exec(pNew->dbm, zSql, 0, 0, pzErrmsg);
+ if( zSql ) rc = sqlite3_exec(pNew->dbm, zSql, 0, 0, pzErrmsg);
}
idxFinalize(&rc, pSql);
}
diff --git a/ext/fts3/fts3.c b/ext/fts3/fts3.c
index d729454634..097338f547 100644
--- a/ext/fts3/fts3.c
+++ b/ext/fts3/fts3.c
@@ -308,6 +308,12 @@
SQLITE_EXTENSION_INIT1
#endif
+typedef struct Fts3HashWrapper Fts3HashWrapper;
+struct Fts3HashWrapper {
+ Fts3Hash hash; /* Hash table */
+ int nRef; /* Number of pointers to this object */
+};
+
static int fts3EvalNext(Fts3Cursor *pCsr);
static int fts3EvalStart(Fts3Cursor *pCsr);
static int fts3TermSegReaderCursor(
@@ -1172,7 +1178,7 @@ static int fts3InitVtab(
sqlite3_vtab **ppVTab, /* Write the resulting vtab structure here */
char **pzErr /* Write any error message here */
){
- Fts3Hash *pHash = (Fts3Hash *)pAux;
+ Fts3Hash *pHash = &((Fts3HashWrapper*)pAux)->hash;
Fts3Table *p = 0; /* Pointer to allocated vtab */
int rc = SQLITE_OK; /* Return code */
int i; /* Iterator variable */
@@ -4007,9 +4013,12 @@ static const sqlite3_module fts3Module = {
** allocated for the tokenizer hash table.
*/
static void hashDestroy(void *p){
- Fts3Hash *pHash = (Fts3Hash *)p;
- sqlite3Fts3HashClear(pHash);
- sqlite3_free(pHash);
+ Fts3HashWrapper *pHash = (Fts3HashWrapper *)p;
+ pHash->nRef--;
+ if( pHash->nRef<=0 ){
+ sqlite3Fts3HashClear(&pHash->hash);
+ sqlite3_free(pHash);
+ }
}
/*
@@ -4039,7 +4048,7 @@ void sqlite3Fts3IcuTokenizerModule(sqlite3_tokenizer_module const**ppModule);
*/
int sqlite3Fts3Init(sqlite3 *db){
int rc = SQLITE_OK;
- Fts3Hash *pHash = 0;
+ Fts3HashWrapper *pHash = 0;
const sqlite3_tokenizer_module *pSimple = 0;
const sqlite3_tokenizer_module *pPorter = 0;
#ifndef SQLITE_DISABLE_FTS3_UNICODE
@@ -4067,23 +4076,24 @@ int sqlite3Fts3Init(sqlite3 *db){
sqlite3Fts3PorterTokenizerModule(&pPorter);
/* Allocate and initialize the hash-table used to store tokenizers. */
- pHash = sqlite3_malloc(sizeof(Fts3Hash));
+ pHash = sqlite3_malloc(sizeof(Fts3HashWrapper));
if( !pHash ){
rc = SQLITE_NOMEM;
}else{
- sqlite3Fts3HashInit(pHash, FTS3_HASH_STRING, 1);
+ sqlite3Fts3HashInit(&pHash->hash, FTS3_HASH_STRING, 1);
+ pHash->nRef = 0;
}
/* Load the built-in tokenizers into the hash table */
if( rc==SQLITE_OK ){
- if( sqlite3Fts3HashInsert(pHash, "simple", 7, (void *)pSimple)
- || sqlite3Fts3HashInsert(pHash, "porter", 7, (void *)pPorter)
+ if( sqlite3Fts3HashInsert(&pHash->hash, "simple", 7, (void *)pSimple)
+ || sqlite3Fts3HashInsert(&pHash->hash, "porter", 7, (void *)pPorter)
#ifndef SQLITE_DISABLE_FTS3_UNICODE
- || sqlite3Fts3HashInsert(pHash, "unicode61", 10, (void *)pUnicode)
+ || sqlite3Fts3HashInsert(&pHash->hash, "unicode61", 10, (void *)pUnicode)
#endif
#ifdef SQLITE_ENABLE_ICU
- || (pIcu && sqlite3Fts3HashInsert(pHash, "icu", 4, (void *)pIcu))
+ || (pIcu && sqlite3Fts3HashInsert(&pHash->hash, "icu", 4, (void *)pIcu))
#endif
){
rc = SQLITE_NOMEM;
@@ -4092,7 +4102,7 @@ int sqlite3Fts3Init(sqlite3 *db){
#ifdef SQLITE_TEST
if( rc==SQLITE_OK ){
- rc = sqlite3Fts3ExprInitTestInterface(db, pHash);
+ rc = sqlite3Fts3ExprInitTestInterface(db, &pHash->hash);
}
#endif
@@ -4101,23 +4111,26 @@ int sqlite3Fts3Init(sqlite3 *db){
** module with sqlite.
*/
if( SQLITE_OK==rc
- && SQLITE_OK==(rc = sqlite3Fts3InitHashTable(db, pHash, "fts3_tokenizer"))
+ && SQLITE_OK==(rc=sqlite3Fts3InitHashTable(db,&pHash->hash,"fts3_tokenizer"))
&& SQLITE_OK==(rc = sqlite3_overload_function(db, "snippet", -1))
&& SQLITE_OK==(rc = sqlite3_overload_function(db, "offsets", 1))
&& SQLITE_OK==(rc = sqlite3_overload_function(db, "matchinfo", 1))
&& SQLITE_OK==(rc = sqlite3_overload_function(db, "matchinfo", 2))
&& SQLITE_OK==(rc = sqlite3_overload_function(db, "optimize", 1))
){
+ pHash->nRef++;
rc = sqlite3_create_module_v2(
db, "fts3", &fts3Module, (void *)pHash, hashDestroy
);
if( rc==SQLITE_OK ){
+ pHash->nRef++;
rc = sqlite3_create_module_v2(
- db, "fts4", &fts3Module, (void *)pHash, 0
+ db, "fts4", &fts3Module, (void *)pHash, hashDestroy
);
}
if( rc==SQLITE_OK ){
- rc = sqlite3Fts3InitTok(db, (void *)pHash);
+ pHash->nRef++;
+ rc = sqlite3Fts3InitTok(db, (void *)pHash, hashDestroy);
}
return rc;
}
@@ -4126,7 +4139,7 @@ int sqlite3Fts3Init(sqlite3 *db){
/* An error has occurred. Delete the hash table and return the error code. */
assert( rc!=SQLITE_OK );
if( pHash ){
- sqlite3Fts3HashClear(pHash);
+ sqlite3Fts3HashClear(&pHash->hash);
sqlite3_free(pHash);
}
return rc;
@@ -4473,7 +4486,7 @@ void sqlite3Fts3DoclistPrev(
assert( nDoclist>0 );
assert( *pbEof==0 );
- assert( p || *piDocid==0 );
+ assert_fts3_nc( p || *piDocid==0 );
assert( !p || (p>aDoclist && p<&aDoclist[nDoclist]) );
if( p==0 ){
diff --git a/ext/fts3/fts3Int.h b/ext/fts3/fts3Int.h
index 3a62ccc7a7..0626486edf 100644
--- a/ext/fts3/fts3Int.h
+++ b/ext/fts3/fts3Int.h
@@ -641,7 +641,7 @@ int sqlite3Fts3MsrOvfl(Fts3Cursor *, Fts3MultiSegReader *, int *);
int sqlite3Fts3MsrIncrRestart(Fts3MultiSegReader *pCsr);
/* fts3_tokenize_vtab.c */
-int sqlite3Fts3InitTok(sqlite3*, Fts3Hash *);
+int sqlite3Fts3InitTok(sqlite3*, Fts3Hash *, void(*xDestroy)(void*));
/* fts3_unicode2.c (functions generated by parsing unicode text files) */
#ifndef SQLITE_DISABLE_FTS3_UNICODE
diff --git a/ext/fts3/fts3_tokenize_vtab.c b/ext/fts3/fts3_tokenize_vtab.c
index 8bd22230cc..65d7eef4c3 100644
--- a/ext/fts3/fts3_tokenize_vtab.c
+++ b/ext/fts3/fts3_tokenize_vtab.c
@@ -420,7 +420,7 @@ static int fts3tokRowidMethod(
** Register the fts3tok module with database connection db. Return SQLITE_OK
** if successful or an error code if sqlite3_create_module() fails.
*/
-int sqlite3Fts3InitTok(sqlite3 *db, Fts3Hash *pHash){
+int sqlite3Fts3InitTok(sqlite3 *db, Fts3Hash *pHash, void(*xDestroy)(void*)){
static const sqlite3_module fts3tok_module = {
0, /* iVersion */
fts3tokConnectMethod, /* xCreate */
@@ -449,7 +449,9 @@ int sqlite3Fts3InitTok(sqlite3 *db, Fts3Hash *pHash){
};
int rc; /* Return code */
- rc = sqlite3_create_module(db, "fts3tokenize", &fts3tok_module, (void*)pHash);
+ rc = sqlite3_create_module_v2(
+ db, "fts3tokenize", &fts3tok_module, (void*)pHash, xDestroy
+ );
return rc;
}
diff --git a/ext/fts3/mkfts3amal.tcl b/ext/fts3/mkfts3amal.tcl
deleted file mode 100644
index 059048717f..0000000000
--- a/ext/fts3/mkfts3amal.tcl
+++ /dev/null
@@ -1,115 +0,0 @@
-#!/usr/bin/tclsh
-#
-# This script builds a single C code file holding all of FTS3 code.
-# The name of the output file is fts3amal.c. To build this file,
-# first do:
-#
-# make target_source
-#
-# The make target above moves all of the source code files into
-# a subdirectory named "tsrc". (This script expects to find the files
-# there and will not work if they are not found.)
-#
-# After the "tsrc" directory has been created and populated, run
-# this script:
-#
-# tclsh mkfts3amal.tcl
-#
-# The amalgamated FTS3 code will be written into fts3amal.c
-#
-
-# Open the output file and write a header comment at the beginning
-# of the file.
-#
-set out [open fts3amal.c w]
-set today [clock format [clock seconds] -format "%Y-%m-%d %H:%M:%S UTC" -gmt 1]
-puts $out [subst \
-{/******************************************************************************
-** This file is an amalgamation of separate C source files from the SQLite
-** Full Text Search extension 2 (fts3). By combining all the individual C
-** code files into this single large file, the entire code can be compiled
-** as a one translation unit. This allows many compilers to do optimizations
-** that would not be possible if the files were compiled separately. It also
-** makes the code easier to import into other projects.
-**
-** This amalgamation was generated on $today.
-*/}]
-
-# These are the header files used by FTS3. The first time any of these
-# files are seen in a #include statement in the C code, include the complete
-# text of the file in-line. The file only needs to be included once.
-#
-foreach hdr {
- fts3.h
- fts3_hash.h
- fts3_tokenizer.h
- sqlite3.h
- sqlite3ext.h
-} {
- set available_hdr($hdr) 1
-}
-
-# 78 stars used for comment formatting.
-set s78 \
-{*****************************************************************************}
-
-# Insert a comment into the code
-#
-proc section_comment {text} {
- global out s78
- set n [string length $text]
- set nstar [expr {60 - $n}]
- set stars [string range $s78 0 $nstar]
- puts $out "/************** $text $stars/"
-}
-
-# Read the source file named $filename and write it into the
-# sqlite3.c output file. If any #include statements are seen,
-# process them approprately.
-#
-proc copy_file {filename} {
- global seen_hdr available_hdr out
- set tail [file tail $filename]
- section_comment "Begin file $tail"
- set in [open $filename r]
- while {![eof $in]} {
- set line [gets $in]
- if {[regexp {^#\s*include\s+["<]([^">]+)[">]} $line all hdr]} {
- if {[info exists available_hdr($hdr)]} {
- if {$available_hdr($hdr)} {
- section_comment "Include $hdr in the middle of $tail"
- copy_file tsrc/$hdr
- section_comment "Continuing where we left off in $tail"
- }
- } elseif {![info exists seen_hdr($hdr)]} {
- set seen_hdr($hdr) 1
- puts $out $line
- }
- } elseif {[regexp {^#ifdef __cplusplus} $line]} {
- puts $out "#if 0"
- } elseif {[regexp {^#line} $line]} {
- # Skip #line directives.
- } else {
- puts $out $line
- }
- }
- close $in
- section_comment "End of $tail"
-}
-
-
-# Process the source files. Process files containing commonly
-# used subroutines first in order to help the compiler find
-# inlining opportunities.
-#
-foreach file {
- fts3.c
- fts3_hash.c
- fts3_porter.c
- fts3_tokenizer.c
- fts3_tokenizer1.c
-} {
- copy_file tsrc/$file
-}
-
-close $out
diff --git a/ext/fts5/fts5_index.c b/ext/fts5/fts5_index.c
index 54efb340c3..6b88f31c02 100644
--- a/ext/fts5/fts5_index.c
+++ b/ext/fts5/fts5_index.c
@@ -1879,8 +1879,12 @@ static void fts5SegIterReverseNewPage(Fts5Index *p, Fts5SegIter *pIter){
int iRowidOff;
iRowidOff = fts5LeafFirstRowidOff(pNew);
if( iRowidOff ){
- pIter->pLeaf = pNew;
- pIter->iLeafOffset = iRowidOff;
+ if( iRowidOff>=pNew->szLeaf ){
+ p->rc = FTS5_CORRUPT;
+ }else{
+ pIter->pLeaf = pNew;
+ pIter->iLeafOffset = iRowidOff;
+ }
}
}
@@ -5561,7 +5565,7 @@ int sqlite3Fts5IndexQuery(
if( sqlite3Fts5BufferSize(&p->rc, &buf, nToken+1)==0 ){
int iIdx = 0; /* Index to search */
int iPrefixIdx = 0; /* +1 prefix index */
- if( nToken ) memcpy(&buf.p[1], pToken, nToken);
+ if( nToken>0 ) memcpy(&buf.p[1], pToken, nToken);
/* Figure out which index to search and set iIdx accordingly. If this
** is a prefix query for which there is no prefix index, set iIdx to
diff --git a/ext/fts5/test/fts5corrupt6.test b/ext/fts5/test/fts5corrupt6.test
new file mode 100644
index 0000000000..6403d3a406
--- /dev/null
+++ b/ext/fts5/test/fts5corrupt6.test
@@ -0,0 +1,54 @@
+# 2015 Apr 24
+#
+# 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 tests that FTS5 handles corrupt databases (i.e. internal
+# inconsistencies in the backing tables) correctly. In this case
+# "correctly" means without crashing.
+#
+
+source [file join [file dirname [info script]] fts5_common.tcl]
+set testprefix fts5corrupt6
+
+# If SQLITE_ENABLE_FTS5 is defined, omit this file.
+ifcapable !fts5 {
+ finish_test
+ return
+}
+sqlite3_fts5_may_be_corrupt 1
+database_may_be_corrupt
+
+proc editblock {block} {
+ binary format Sa* 20000 [string range $block 2 end]
+}
+db func editblock editblock
+
+do_execsql_test 1.0 {
+ CREATE VIRTUAL TABLE ft USING fts5(abc, def);
+ WITH a(i) AS (
+ SELECT 1 UNION ALL SELECT i+1 FROM a WHERE i<1000
+ )
+ INSERT INTO ft SELECT
+ 'abc abc abc abc abc abc abc abc abc abc',
+ 'def def def def def def def def def def'
+ FROM a;
+ UPDATE ft_data SET block = editblock(block) WHERE id=(
+ SELECT id FROM ft_data ORDER BY id LIMIT 1 OFFSET 5
+ );
+}
+
+do_catchsql_test 1.1 {
+ SELECT rowid FROM ft('def') ORDER BY rowid DESC LIMIT 1 OFFSET 9999;
+} {1 {database disk image is malformed}}
+
+
+sqlite3_fts5_may_be_corrupt 0
+finish_test
+
diff --git a/ext/fts5/test/fts5eb.test b/ext/fts5/test/fts5eb.test
index 9d6f251ed1..ce40e471aa 100644
--- a/ext/fts5/test/fts5eb.test
+++ b/ext/fts5/test/fts5eb.test
@@ -83,7 +83,7 @@ for {set i 0} {$i < 255} {incr i} {
do_execsql_test 3.0 {
CREATE VIRTUAL TABLE e1 USING fts5(text, tokenize = 'porter unicode61');
- INSERT INTO e1 VALUES ("just a few words with a / inside");
+ INSERT INTO e1 VALUES ('just a few words with a / inside');
}
do_execsql_test 3.1 {
SELECT rowid, bm25(e1) FROM e1 WHERE e1 MATCH '"just"' ORDER BY rank;
diff --git a/ext/fts5/test/fts5integrity.test b/ext/fts5/test/fts5integrity.test
index d922ad3b86..4038830861 100644
--- a/ext/fts5/test/fts5integrity.test
+++ b/ext/fts5/test/fts5integrity.test
@@ -188,11 +188,11 @@ foreach {tn pgsz} {
INSERT INTO hh(hh, rank) VALUES('pgsz', $pgsz);
WITH s(i) AS (SELECT 0 UNION ALL SELECT i+1 FROM s WHERE i<999)
- INSERT INTO hh SELECT printf("%.3d%.3d%.3d %.3d%.3d%.3d",i,i,i,i+1,i+1,i+1)
+ INSERT INTO hh SELECT printf('%.3d%.3d%.3d %.3d%.3d%.3d',i,i,i,i+1,i+1,i+1)
FROM s;
WITH s(i) AS (SELECT 0 UNION ALL SELECT i+1 FROM s WHERE i<999)
- INSERT INTO hh SELECT printf("%.3d%.3d%.3d %.3d%.3d%.3d",i,i,i,i+1,i+1,i+1)
+ INSERT INTO hh SELECT printf('%.3d%.3d%.3d %.3d%.3d%.3d',i,i,i,i+1,i+1,i+1)
FROM s;
INSERT INTO hh(hh) VALUES('optimize');
diff --git a/ext/misc/fileio.c b/ext/misc/fileio.c
index c9988f6078..7cdbd5968f 100644
--- a/ext/misc/fileio.c
+++ b/ext/misc/fileio.c
@@ -368,10 +368,11 @@ static int writeFile(
mode_t mode, /* MODE parameter passed to writefile() */
sqlite3_int64 mtime /* MTIME parameter (or -1 to not set time) */
){
+ if( zFile==0 ) return 1;
#if !defined(_WIN32) && !defined(WIN32)
if( S_ISLNK(mode) ){
const char *zTo = (const char*)sqlite3_value_text(pData);
- if( symlink(zTo, zFile)<0 ) return 1;
+ if( zTo==0 || symlink(zTo, zFile)<0 ) return 1;
}else
#endif
{
diff --git a/ext/misc/regexp.c b/ext/misc/regexp.c
index f282e777f0..b626ca424a 100644
--- a/ext/misc/regexp.c
+++ b/ext/misc/regexp.c
@@ -759,13 +759,15 @@ int sqlite3_regexp_init(
int rc = SQLITE_OK;
SQLITE_EXTENSION_INIT2(pApi);
(void)pzErrMsg; /* Unused */
- rc = sqlite3_create_function(db, "regexp", 2, SQLITE_UTF8|SQLITE_INNOCUOUS,
- 0, re_sql_func, 0, 0);
+ rc = sqlite3_create_function(db, "regexp", 2,
+ SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_DETERMINISTIC,
+ 0, re_sql_func, 0, 0);
if( rc==SQLITE_OK ){
/* The regexpi(PATTERN,STRING) function is a case-insensitive version
** of regexp(PATTERN,STRING). */
- rc = sqlite3_create_function(db, "regexpi", 2, SQLITE_UTF8|SQLITE_INNOCUOUS,
- (void*)db, re_sql_func, 0, 0);
+ rc = sqlite3_create_function(db, "regexpi", 2,
+ SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_DETERMINISTIC,
+ (void*)db, re_sql_func, 0, 0);
}
return rc;
}
diff --git a/ext/misc/series.c b/ext/misc/series.c
index e8d8c10aec..3941d96c47 100644
--- a/ext/misc/series.c
+++ b/ext/misc/series.c
@@ -386,7 +386,7 @@ static int seriesBestIndex(
** the preferred case */
pIdxInfo->estimatedCost = (double)(2 - ((idxNum&4)!=0));
pIdxInfo->estimatedRows = 1000;
- if( pIdxInfo->nOrderBy==1 ){
+ if( pIdxInfo->nOrderBy>=1 && pIdxInfo->aOrderBy[0].iColumn==0 ){
if( pIdxInfo->aOrderBy[0].desc ){
idxNum |= 8;
}else{
diff --git a/ext/misc/sha1.c b/ext/misc/sha1.c
index 9fe6cae740..9790a1d877 100644
--- a/ext/misc/sha1.c
+++ b/ext/misc/sha1.c
@@ -71,7 +71,7 @@ struct SHA1Context {
/*
* Hash a single 512-bit block. This is the core of the algorithm.
*/
-void SHA1Transform(unsigned int state[5], const unsigned char buffer[64]){
+static void SHA1Transform(unsigned int state[5], const unsigned char buffer[64]){
unsigned int qq[5]; /* a, b, c, d, e; */
static int one = 1;
unsigned int block[16];
diff --git a/ext/misc/shathree.c b/ext/misc/shathree.c
index ef25cb56c6..1f100986ea 100644
--- a/ext/misc/shathree.c
+++ b/ext/misc/shathree.c
@@ -436,6 +436,7 @@ static void SHA3Update(
unsigned int nData
){
unsigned int i = 0;
+ if( aData==0 ) return;
#if SHA3_BYTEORDER==1234
if( (p->nLoaded % 8)==0 && ((aData - (const unsigned char*)0)&7)==0 ){
for(; i+7z[0]) ) p->z++;
+ while( fast_isspace(p->z[0]) ) p->z++;
return p->z[0];
}
diff --git a/ext/rtree/rtreeA.test b/ext/rtree/rtreeA.test
index 921ba0b510..301cd4fc62 100644
--- a/ext/rtree/rtreeA.test
+++ b/ext/rtree/rtreeA.test
@@ -165,7 +165,7 @@ do_corruption_tests rtreeA-3.1 {
}
do_execsql_test rtreeA-3.1.0.3 {
- SELECT rtreecheck('main', 't1')!="ok"
+ SELECT rtreecheck('main', 't1')!='ok'
} {1}
do_test rtreeA-3.2.0 { set_tree_depth t1 1000 } {1000}
@@ -221,7 +221,7 @@ do_corruption_tests rtreeA-5.1 {
}
do_execsql_test rtreeA-5.2 {
- SELECT rtreecheck('main', 't1')!="ok"
+ SELECT rtreecheck('main', 't1')!='ok'
} {1}
#-------------------------------------------------------------------------
@@ -238,7 +238,7 @@ do_corruption_tests rtreeA-6.1 {
}
do_execsql_test rtreeA-6.2 {
- SELECT rtreecheck('main', 't1')!="ok"
+ SELECT rtreecheck('main', 't1')!='ok'
} {1}
#-------------------------------------------------------------------------
diff --git a/ext/rtree/rtreecheck.test b/ext/rtree/rtreecheck.test
index 545f4478a9..17f359aa8a 100644
--- a/ext/rtree/rtreecheck.test
+++ b/ext/rtree/rtreecheck.test
@@ -117,13 +117,13 @@ sqlite3_db_config db DEFENSIVE 0
do_execsql_test 3.2 {
BEGIN;
UPDATE r2_node SET data = X'123456';
- SELECT rtreecheck('r2')!="ok";
+ SELECT rtreecheck('r2')!='ok';
} {1}
do_execsql_test 3.3 {
ROLLBACK;
UPDATE r2_node SET data = X'00001234';
- SELECT rtreecheck('r2')!="ok";
+ SELECT rtreecheck('r2')!='ok';
} {1}
do_execsql_test 4.0 {
diff --git a/ext/rtree/test_rtreedoc.c b/ext/rtree/test_rtreedoc.c
index 3272d89eca..119be0e0ad 100644
--- a/ext/rtree/test_rtreedoc.c
+++ b/ext/rtree/test_rtreedoc.c
@@ -304,7 +304,7 @@ static int box_query(sqlite3_rtree_query_info *pInfo){
static void box_query_destroy(void *p){
BoxQueryCtx *pCtx = (BoxQueryCtx*)p;
Tcl_DecrRefCount(pCtx->pScript);
- ckfree(pCtx);
+ ckfree((char*)pCtx);
}
static int SQLITE_TCLAPI register_box_query(
diff --git a/ext/session/session8.test b/ext/session/session8.test
index 9f70fe2829..884da0e775 100644
--- a/ext/session/session8.test
+++ b/ext/session/session8.test
@@ -63,7 +63,7 @@ proc do_then_undo {tn sql} {
do_execsql_test 1.1 {
CREATE TABLE t1(a PRIMARY KEY, b);
INSERT INTO t1 VALUES(1, 2);
- INSERT INTO t1 VALUES("abc", "xyz");
+ INSERT INTO t1 VALUES('abc', 'xyz');
}
do_then_undo 1.2 { INSERT INTO t1 VALUES(3, 4); }
do_then_undo 1.3 { DELETE FROM t1 WHERE b=2; }
diff --git a/main.mk b/main.mk
index 33774fab47..47f68d094b 100644
--- a/main.mk
+++ b/main.mk
@@ -64,7 +64,7 @@ LIBOBJ+= vdbe.o parse.o \
fts3_tokenize_vtab.o \
fts3_unicode.o fts3_unicode2.o \
fts3_write.o fts5.o func.o global.o hash.o \
- icu.o insert.o json1.o legacy.o loadext.o \
+ icu.o insert.o json.o legacy.o loadext.o \
main.o malloc.o mem0.o mem1.o mem2.o mem3.o mem5.o \
memdb.o memjournal.o \
mutex.o mutex_noop.o mutex_unix.o mutex_w32.o \
@@ -111,6 +111,7 @@ SRC = \
$(TOP)/src/hash.h \
$(TOP)/src/hwtime.h \
$(TOP)/src/insert.c \
+ $(TOP)/src/json.c \
$(TOP)/src/legacy.c \
$(TOP)/src/loadext.c \
$(TOP)/src/main.c \
@@ -244,7 +245,6 @@ SRC += \
$(TOP)/ext/rbu/sqlite3rbu.c \
$(TOP)/ext/rbu/sqlite3rbu.h
SRC += \
- $(TOP)/ext/misc/json1.c \
$(TOP)/ext/misc/stmt.c
@@ -680,9 +680,6 @@ sqlite3-all.c: sqlite3.c $(TOP)/tool/split-sqlite3c.tcl
fts2amal.c: target_source $(TOP)/ext/fts2/mkfts2amal.tcl
tclsh $(TOP)/ext/fts2/mkfts2amal.tcl
-fts3amal.c: target_source $(TOP)/ext/fts3/mkfts3amal.tcl
- tclsh $(TOP)/ext/fts3/mkfts3amal.tcl
-
# Rules to build the LEMON compiler generator
#
lemon: $(TOP)/tool/lemon.c $(TOP)/tool/lempar.c
@@ -833,9 +830,6 @@ fts3_write.o: $(TOP)/ext/fts3/fts3_write.c $(HDR) $(EXTHDR)
fts5.o: fts5.c sqlite3ext.h sqlite3.h
$(TCCX) -DSQLITE_CORE -c fts5.c
-json1.o: $(TOP)/ext/misc/json1.c sqlite3ext.h sqlite3.h
- $(TCCX) -DSQLITE_CORE -c $(TOP)/ext/misc/json1.c
-
stmt.o: $(TOP)/ext/misc/stmt.c sqlite3ext.h sqlite3.h
$(TCCX) -DSQLITE_CORE -c $(TOP)/ext/misc/stmt.c
@@ -933,12 +927,6 @@ amalgamation-testfixture$(EXE): sqlite3.c $(TESTSRC) $(TOP)/src/tclsqlite.c \
$(TOP)/ext/session/test_session.c \
-o testfixture$(EXE) $(LIBTCL) $(THREADLIB)
-fts3-testfixture$(EXE): sqlite3.c fts3amal.c $(TESTSRC) $(TOP)/src/tclsqlite.c
- $(TCCX) $(TCL_FLAGS) $(TESTFIXTURE_FLAGS) \
- -DSQLITE_ENABLE_FTS3=1 \
- $(TESTSRC) $(TOP)/src/tclsqlite.c sqlite3.c fts3amal.c \
- -o testfixture$(EXE) $(LIBTCL) $(THREADLIB)
-
coretestprogs: $(TESTPROGS)
testprogs: coretestprogs srcck1$(EXE) fuzzcheck$(EXE) sessionfuzz$(EXE)
diff --git a/manifest b/manifest
index 8db75f34fa..beb535c254 100644
--- a/manifest
+++ b/manifest
@@ -1,13 +1,13 @@
-C Merge\scheckpoint-on-close\sfix\sfrom\swal2\sbranch.
-D 2021-12-15T13:42:40.710
+C Merge\sthe\slatest\strunk\senhancements\sinto\sthe\sbegin-concurrent-pnu-wal2\sbranch.
+D 2022-01-17T19:46:10.859
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
-F Makefile.in 51fc06b371261469b0e18b61533fc8b523fedf0096bcacdf5afac96b65c58e88
+F Makefile.in 95adc067f0340ec77a71cb07f79141c4819a63d488b0d12ac6c08b40f52cc28d
F Makefile.linux-gcc f609543700659711fbd230eced1f01353117621dccae7b9fb70daa64236c5241
-F Makefile.msc 3f6e8e2d1461acf7837481eceb6e9b3d88677e50f94a9c2c265a3e1ff9f19640
-F README.md 27fb76aa7eb57ed63a53bbba7292b6bf71f51125554f79f16b5d040edd1e6110
-F VERSION c6595fef606851f2bc3ebed6a7386c73751835fc909feab7c093739fa4b3c1d1
+F Makefile.msc c73d82b80836e90df926e25bcaea7acfd46b6d3ec3d6fecdfbf6810c48a75360
+F README.md 2dd87a5c1d108b224921f3dd47dea567973f706e1f6959386282a626f459a70c
+F VERSION 392c2f83569705069415a5d98b1c138ec8fe8a56a663a0d94cea019e806537b2
F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50
F art/sqlite370.eps aa97a671332b432a54e1d74ff5e8775be34200c2
F art/sqlite370.ico af56c1d00fee7cd4753e8631ed60703ed0fc6e90
@@ -15,7 +15,7 @@ F art/sqlite370.jpg d512473dae7e378a67e28ff96a34da7cb331def2
F autoconf/INSTALL 83e4a25da9fd053c7b3665eaaaf7919707915903
F autoconf/Makefile.am a8d1d24affe52ebf8d7ddcf91aa973fa0316618ab95bb68c87cabf8faf527dc8
F autoconf/Makefile.fallback 22fe523eb36dfce31e0f6349f782eb084e86a5620b2b0b4f84a2d6133f53f5ac
-F autoconf/Makefile.msc d146a08ebbdf7f881ba600a49cd8dce40c4c807addcdb4b9b6a507e4b40ce837
+F autoconf/Makefile.msc 262dad10223b39a6853c4faefadb0f71931ca55c742fa285f8ee8d56b7543ddc
F autoconf/README.first 6c4f34fe115ff55d4e8dbfa3cecf04a0188292f7
F autoconf/README.txt 4f04b0819303aabaa35fff5f7b257fb0c1ef95f1
F autoconf/configure.ac a8ba2a9e61216f5093d44f3b7d2cb8fe1890d6b7dc330a02f802d8efaa1fdc79
@@ -34,11 +34,12 @@ F autoconf/tea/win/rules.vc c511f222b80064096b705dbeb97060ee1d6b6d63
F config.guess 883205ddf25b46f10c181818bf42c09da9888884af96f79e1719264345053bd6
F config.h.in 6376abec766e9a0785178b1823b5a587e9f1ccbc
F config.sub c2d0260f17f3e4bc0b6808fccf1b291cb5e9126c14fc5890efc77b9fd0175559
-F configure e8003577b8c433cf61371d27d4beeca3a3ed37611a504ff5f4d4286923b87d03 x
-F configure.ac 4e4b58b32f88c8da9914a2f2c3158f80e69907eccc019fcc7e3ba14ffd91c640
+F configure a2877fe63cc821af0df41abe70f1f7c4e97cb7e23a42e0a1402e8a2f55a88aa2 x
+F configure.ac 3ef6eeff4387585bfcab76b0c3f6e15a0618587bb90245dd5d44e4378141bb35
F contrib/sqlitecon.tcl 210a913ad63f9f991070821e599d600bd913e0ad
F doc/F2FS.txt c1d4a0ae9711cfe0e1d8b019d154f1c29e0d3abfe820787ba1e9ed7691160fcd
F doc/begin_concurrent.md 4bee2c3990d1eb800f1ce3726a911292a8e4b889300b2ffd4b08d357370db299
+F doc/json-enhancements.md e356fc834781f1f1aa22ee300027a270b2c960122468499bf347bb123ce1ea4f
F doc/lemon.html efc0cd2345d66905505d98f862e1c571512def0ceb5b016cb658fd4918eb76a3
F doc/pager-invariants.txt 27fed9a70ddad2088750c4a2b493b63853da2710
F doc/trusted-schema.md 33625008620e879c7bcfbbfa079587612c434fa094d338b08242288d358c3e8a
@@ -53,7 +54,7 @@ F ext/async/sqlite3async.h 46b47c79357b97ad85d20d2795942c0020dc20c532114a4980828
F ext/expert/README.md b321c2762bb93c18ea102d5a5f7753a4b8bac646cb392b3b437f633caf2020c3
F ext/expert/expert.c d548d603a4cc9e61f446cc179c120c6713511c413f82a4a32b1e1e69d3f086a4
F ext/expert/expert1.test 3c642a4e7bbb14f21ddab595436fb465a4733f47a0fe5b2855e1d5ff900ef08e
-F ext/expert/sqlite3expert.c 921a00823a826150cbb9a3341285a8edec7533480b71281e77737f19559b4b14
+F ext/expert/sqlite3expert.c 6ca30d73b9ed75bd56d6e0d7f2c962d2affaa72c505458619d0ff5d9cdfac204
F ext/expert/sqlite3expert.h ca81efc2679a92373a13a3e76a6138d0310e32be53d6c3bfaedabd158ea8969b
F ext/expert/test_expert.c d56c194b769bdc90cf829a14c9ecbc1edca9c850b837a4d0b13be14095c32a72
F ext/fts1/README.txt 20ac73b006a70bcfd80069bdaf59214b6cf1db5e
@@ -86,9 +87,9 @@ F ext/fts3/README.content b9078d0843a094d86af0d48dffbff13c906702b4c3558012e67b9c
F ext/fts3/README.syntax a19711dc5458c20734b8e485e75fb1981ec2427a
F ext/fts3/README.tokenizers b92bdeb8b46503f0dd301d364efc5ef59ef9fa8e2758b8e742f39fa93a2e422d
F ext/fts3/README.txt 8c18f41574404623b76917b9da66fcb0ab38328d
-F ext/fts3/fts3.c da41de21622774b1cb8c3415e8d2a6961ad7c978ab534f2a54434f76a5c4dfbc
+F ext/fts3/fts3.c 6634a3854e70afa8710ee5e3a7253cd0f0c89d4cce207fcbfe2ead3bad1db7d5
F ext/fts3/fts3.h 3a10a0af180d502cecc50df77b1b22df142817fe
-F ext/fts3/fts3Int.h cff59b8b13dafe9d59924a5d710f771ed8b121a55cccbc99b6e2a723fcde14dc
+F ext/fts3/fts3Int.h dafdc371f9fbab175744b06cfe019d5f040cdfdbd11fea752f5dc28d45b04c05
F ext/fts3/fts3_aux.c f0dc9bd98582615b7750218899bd0c729879b6bbf94d1be57ca1833ff49afc6f
F ext/fts3/fts3_expr.c 903bfb9433109fffb10e910d7066c49cbf8eeae316adc93f0499c4da7dfc932a
F ext/fts3/fts3_hash.c 8b6e31bfb0844c27dc6092c2620bdb1fca17ed613072db057d96952c6bdb48b7
@@ -98,7 +99,7 @@ F ext/fts3/fts3_porter.c 3565faf04b626cddf85f03825e86056a4562c009
F ext/fts3/fts3_snippet.c f9a8149173553113f3c495a503843e30028b5dc3723d0ca798c5ad6142e130e6
F ext/fts3/fts3_term.c f45a1e7c6ef464abb1231245d123dae12266b69e05cc56e14045b76591ae92d1
F ext/fts3/fts3_test.c d8d7b2734f894e8a489987447658e374cdd3a3bc8575c401decf1911cb7c6454
-F ext/fts3/fts3_tokenize_vtab.c 8d15b148e7d88a4280389a200b26e8d52abda4c4ec2e9a35e9d7a1fa50e5aa03
+F ext/fts3/fts3_tokenize_vtab.c a95feda3590f3c3e17672fe35b67ea6112471aeea4c07ef7744a6606b66549aa
F ext/fts3/fts3_tokenizer.c 6d8fc150c48238955d5182bf661498db0dd473c8a2a80e00c16994a646fa96e7
F ext/fts3/fts3_tokenizer.h 64c6ef6c5272c51ebe60fc607a896e84288fcbc3
F ext/fts3/fts3_tokenizer1.c 5c98225a53705e5ee34824087478cf477bdb7004
@@ -106,7 +107,6 @@ F ext/fts3/fts3_unicode.c de426ff05c1c2e7bce161cf6b706638419c3a1d9c2667de9cb9dc0
F ext/fts3/fts3_unicode2.c 416eb7e1e81142703520d284b768ca2751d40e31fa912cae24ba74860532bf0f
F ext/fts3/fts3_write.c 3109c1a232da86474e196cc7db754445a354409f141e08cb11c846cdb17bdf31
F ext/fts3/fts3speed.tcl b54caf6a18d38174f1a6e84219950d85e98bb1e9
-F ext/fts3/mkfts3amal.tcl 252ecb7fe6467854f2aa237bf2c390b74e71f100
F ext/fts3/tool/fts3cov.sh c331d006359456cf6f8f953e37f2b9c7d568f3863f00bb5f7eb87fea4ac01b73
F ext/fts3/tool/fts3view.c 413c346399159df81f86c4928b7c4a455caab73bfbc8cd68f950f632e5751674
F ext/fts3/unicode/CaseFolding.txt 8c678ca52ecc95e16bc7afc2dbf6fc9ffa05db8c
@@ -121,7 +121,7 @@ F ext/fts5/fts5_buffer.c 3001fbabb585d6de52947b44b455235072b741038391f830d6b7292
F ext/fts5/fts5_config.c 501e7d3566bc92766b0e11c0109a7c5a6146bc41144195459af5422f6c2078aa
F ext/fts5/fts5_expr.c fcd0770d53028c2b53a15d0f53bf6d0e01b1bf3dd97630b9fedf0801f03aa3ec
F ext/fts5/fts5_hash.c d4fb70940359f2120ccd1de7ffe64cc3efe65de9e8995b822cd536ff64c96982
-F ext/fts5/fts5_index.c a3ada4897c3b14b8a15a8695d2cb3a46b5761137aae0964fc44efe96a877ddd0
+F ext/fts5/fts5_index.c fdfbc8a62827ec1d1b6f207a1e59c1c4986c3ce245592b5128ffe738867cfcd1
F ext/fts5/fts5_main.c 7c6092a53e6802962fa07b0fad3e61cb077b6c98b74b727d8d44ac2cf63bd914
F ext/fts5/fts5_storage.c 76c6085239eb44424004c022e9da17a5ecd5aaec859fba90ad47d3b08f4c8082
F ext/fts5/fts5_tcl.c b1445cbe69908c411df8084a10b2485500ac70a9c747cdc8cda175a3da59d8ae
@@ -165,13 +165,14 @@ F ext/fts5/test/fts5corrupt2.test 7453752ba12ce91690c469a6449d412561cc604b1dec99
F ext/fts5/test/fts5corrupt3.test 0e473620582a53ac61f468f364db8a151c1e18d2a879b16439d172c12c4c9828
F ext/fts5/test/fts5corrupt4.test f4c08e2182a48d8b70975fd869ee5391855c06d8a0ff87b6a2529e7c5a88a1d3
F ext/fts5/test/fts5corrupt5.test 550d0884c14424f9acad051a741f1dd99ec9342277d938e91ff3daf9123d1209
+F ext/fts5/test/fts5corrupt6.test bf8eeae07825b088b9665d9d8e4accbd8dc9bf3cb85b6c64cf6c9e18ccc420a4
F ext/fts5/test/fts5delete.test 619295b20dbc1d840b403ee07c878f52378849c3c02e44f2ee143b3e978a0aa7
F ext/fts5/test/fts5detail.test 54015e9c43ec4ba542cfb93268abdf280e0300f350efd08ee411284b03595cc4
F ext/fts5/test/fts5determin.test 1b77879b2ae818b5b71c859e534ee334dac088b7cf3ff3bf76a2c82b1c788d11
F ext/fts5/test/fts5dlidx.test b90852c55881b29dbac6380b274de27beae623ac4b6d567c6c8fb9cdc315a86e
F ext/fts5/test/fts5doclist.test faa9e9cc3c0645fa6203667cb5f007c359447c6ee66753f71a58175c2497cacd
F ext/fts5/test/fts5ea.test b01e3a18cdfabbff8104a96a5242a06a68a998a0
-F ext/fts5/test/fts5eb.test 239bb2f02571f8cccfc7018d08f502df1cd8cc6a69b65ed1dde5f6a070e3f669
+F ext/fts5/test/fts5eb.test a973baadac524dbbb4ad9b0e99030e12cabde2c6b28e0ac437298007b642cd12
F ext/fts5/test/fts5fault1.test d28a65caee75db6897c3cf1358c5230d3bb2a3bf7fb31062c19c7e5382b3d2bd
F ext/fts5/test/fts5fault2.test 69c8fdbef830cd0d450908d4504d5bb86609e255af99c421c20a0756251fe344
F ext/fts5/test/fts5fault3.test da2f9e3e56ff5740d68ebdd6877c97089e7ed28ddff28a0da87a6afea27e5522
@@ -189,7 +190,7 @@ F ext/fts5/test/fts5first.test 3fcf2365c00a15fc9704233674789a3b95131d12de18a9b99
F ext/fts5/test/fts5full.test e1701a112354e0ff9a1fdffb0c940c576530c33732ee20ac5e8361777070d717
F ext/fts5/test/fts5fuzz1.test 238d8c45f3b81342aa384de3e581ff2fa330bf922a7b69e484bbc06051a1080e
F ext/fts5/test/fts5hash.test dc7bc7e0cdeb42cfce31294ad2f8fcf43192bfd0145bb7f3ecc5465d8c72696f
-F ext/fts5/test/fts5integrity.test e387b2bd1c83e50f4a12f58a5fd399111bbab36be2f1c9fd5bb974be08a32de6
+F ext/fts5/test/fts5integrity.test 62147a1e85405b986691177e0312be5a64ec9e67b17994e83892d9afa6247600
F ext/fts5/test/fts5interrupt.test 09613247b273a99889808ef852898177e671406fe71fdde7ea00e78ea283d227
F ext/fts5/test/fts5lastrowid.test be98fe3e03235296585b72daad7aed5717ba0062bae5e5c18dd6e04e194c6b28
F ext/fts5/test/fts5leftjoin.test c0b4cafb9661379e576dc4405c0891d8fcc2782680740513c4d1fc114b43d4ad
@@ -305,11 +306,10 @@ F ext/misc/dbdump.c b8592f6f2da292c62991a13864a60d6c573c47a9cc58362131b9e6a64f82
F ext/misc/decimal.c 09f967dcf4a1ee35a76309829308ec278d3648168733f4a1147820e11ebefd12
F ext/misc/eval.c 04bc9aada78c888394204b4ed996ab834b99726fb59603b0ee3ed6e049755dc1
F ext/misc/explain.c 0086fab288d4352ea638cf40ac382aad3b0dc5e845a1ea829a694c015fd970fe
-F ext/misc/fileio.c 57fefd0efc535e62bb8b07fa146875171481da81a759bbfbe2fc91bab90058e0
+F ext/misc/fileio.c 4e7f7cd30de8df4820c552f14af3c9ca451c5ffe1f2e7bef34d598a12ebfb720
F ext/misc/fossildelta.c 1240b2d3e52eab1d50c160c7fe1902a9bd210e052dc209200a750bbf885402d5
F ext/misc/fuzzer.c eae560134f66333e9e1ca4c8ffea75df42056e2ce8456734565dbe1c2a92bf3d
F ext/misc/ieee754.c 91a5594071143a4ab79c638fe9f059af1db09932faf2e704c3e29216a7d4f511
-F ext/misc/json1.c 89a988f06dcb3da0d0af9fdb2b09892452ad12dfd8f432600ee6437a6dcac310
F ext/misc/memstat.c 3017a0832c645c0f8c773435620d663855f04690172316bd127270d1a7523d4d
F ext/misc/memtrace.c 7c0d115d2ef716ad0ba632c91e05bd119cb16c1aedf3bec9f06196ead2d5537b
F ext/misc/memvfs.c 7dffa8cc89c7f2d73da4bd4ccea1bcbd2bd283e3bb4cea398df7c372a197291b
@@ -319,13 +319,13 @@ F ext/misc/noop.c 81efe4cad9ec740e64388b14281cb983e6e2c223fed43eb77ab3e34946e0c1
F ext/misc/normalize.c bd84355c118e297522aba74de34a4fd286fc775524e0499b14473918d09ea61f
F ext/misc/percentile.c b9086e223d583bdaf8cb73c98a6539d501a2fc4282654adbfea576453d82e691
F ext/misc/prefixes.c 0f4f8cff5aebc00a7e3ac4021fd59cfe1a8e17c800ceaf592859ecb9cbc38196
-F ext/misc/regexp.c 8cd0d2d904bf7014ba28beab8c1d502b5154e04a8c738b079d88e4ecca1b3981
+F ext/misc/regexp.c b267fd05ff8d38b22f4c2809d7b7a2c61d522e9faf2feb928dbb9662e4a3a386
F ext/misc/remember.c add730f0f7e7436cd15ea3fd6a90fd83c3f706ab44169f7f048438b7d6baa69c
F ext/misc/rot13.c 51ac5f51e9d5fd811db58a9c23c628ad5f333c173f1fc53c8491a3603d38556c
F ext/misc/scrub.c 2a44b0d44c69584c0580ad2553f6290a307a49df4668941d2812135bfb96a946
-F ext/misc/series.c f9896e76b029e3c6553c520552555e803e26e7dfe1890d5866243cf072d938d0
-F ext/misc/sha1.c c8f2253c8792ffab9517695ea7d88c079f0395a5505eefef5c8198fe184ed5ac
-F ext/misc/shathree.c e984f31731de4cf302a0386be5fe664580f63d8204c47b9b41cc4b997745f9ec
+F ext/misc/series.c 8d79354f2c3d46b95ee21272a07cf0bcabb58d1f2b06d9e7b8a31dca1dacb3e5
+F ext/misc/sha1.c 4011aef176616872b2a0d5bccf0ecfb1f7ce3fe5c3d107f3a8e949d8e1e3f08d
+F ext/misc/shathree.c 9b6fce315bf8b37bd72786086d1f0974701f651e83022a93244e0e8f56f98a45
F ext/misc/showauth.c 732578f0fe4ce42d577e1c86dc89dd14a006ab52
F ext/misc/spellfix.c 94df9bbfa514a563c1484f684a2df3d128a2f7209a84ca3ca100c68a0163e29f
F ext/misc/sqlar.c 0ace5d3c10fe736dc584bf1159a36b8e2e60fab309d310cd8a0eecd9036621b6
@@ -341,7 +341,7 @@ F ext/misc/vfsstat.c 474d08efc697b8eba300082cb1eb74a5f0f3df31ed257db1cb07e72ab0e
F ext/misc/vtablog.c 5538acd0c8ddaae372331bee11608d76973436b77d6a91e8635cfc9432fba5ae
F ext/misc/vtshim.c 1976e6dd68dd0d64508c91a6dfab8e75f8aaf6cd
F ext/misc/wholenumber.c a838d1bea913c514ff316c69695efbb49ea3b8cb37d22afc57f73b6b010b4546
-F ext/misc/zipfile.c 5dcbbdae13ba45db5d3843b6f32a8f99df7ab0349a704857a3000618f9ea9ecb
+F ext/misc/zipfile.c 238ccb990ed45a74e24d0fbb449d7752a568c2b7c1d5b255d451f11703ced592
F ext/misc/zorder.c b0ff58fa643afa1d846786d51ea8d5c4b6b35aa0254ab5a82617db92f3adda64
F ext/rbu/rbu.c 801450b24eaf14440d8fd20385aacc751d5c9d6123398df41b1b5aa804bf4ce8
F ext/rbu/rbu1.test c62904bd9526dcdc3496a21199aaf14ae191bbadbf67f076bf16be6b3f2115c2
@@ -384,7 +384,7 @@ F ext/rbu/rbuvacuum.test 55e101e90168c2b31df6c9638fe73dc7f7cc666b6142266d1563697
F ext/rbu/rbuvacuum2.test 886add83fd74bcb02e6dd016ae5b585367bd58c5d0694c9d9ca7bdb1d1f578c2
F ext/rbu/rbuvacuum3.test 8addd82e4b83b4c93fa47428eae4fd0dbf410f8512c186f38e348feb49ba03dc
F ext/rbu/rbuvacuum4.test a78898e438a44803eb2bc897ba3323373c9f277418e2d6d76e90f2f1dbccfd10
-F ext/rbu/sqlite3rbu.c 3658f1c6603955c7426952b74a6896337b1f672d326cd565e5af20e18d5744f0
+F ext/rbu/sqlite3rbu.c 8737cabdfbee84bb25a7851ecef8b1312be332761238da9be6ddb10c62ad4291
F ext/rbu/sqlite3rbu.h 1dc88ab7bd32d0f15890ea08d23476c4198d3da3056985403991f8c9cd389812
F ext/rbu/test_rbu.c 03f6f177096a5f822d68d8e4069ad8907fe572c62ff2d19b141f59742821828a
F ext/repair/README.md 92f5e8aae749a4dae14f02eea8e1bb42d4db2b6ce5e83dbcdd6b1446997e0c15
@@ -397,7 +397,7 @@ F ext/repair/test/checkfreelist01.test 3e8aa6aeb4007680c94a8d07b41c339aa635cc782
F ext/repair/test/checkindex01.test b530f141413b587c9eb78ff734de6bb79bc3515c335096108c12c01bddbadcec
F ext/repair/test/test.tcl 686d76d888dffd021f64260abf29a55c57b2cedfa7fc69150b42b1d6119aac3c
F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761
-F ext/rtree/geopoly.c a7021cb524621573ccda213a35b0339371849dd4acc4909f689786ee1f964b7f
+F ext/rtree/geopoly.c cc3f89c11abcf114fa60d74709ae8b5bc1eae5a261b30bc1bb7085089c03bfab
F ext/rtree/rtree.c d7b4b8b81d8d54376a7f81de5be85ec58b37c11604bcf42984a8418b34158d93
F ext/rtree/rtree.h 4a690463901cb5e6127cf05eb8e642f127012fd5003830dbc974eca5802d9412
F ext/rtree/rtree1.test 35c3bc0def71317b7601ee0d1149e7df2cd8fc4f13ec89a64761ac3f46ca123f
@@ -409,7 +409,7 @@ F ext/rtree/rtree6.test 9ce3691c1aac43070a9f194f0ebf54372db346c5a82241fd11b525ed
F ext/rtree/rtree7.test c8fb2e555b128dd0f0bdb520c61380014f497f8a23c40f2e820acc9f9e4fdce5
F ext/rtree/rtree8.test 2d99006a1386663978c9e1df167554671e4f711c419175b39f332719deb1ce0e
F ext/rtree/rtree9.test fd3c9384ef8aabbc127b3878764070398f136eebc551cd20484b570f2cc1956a
-F ext/rtree/rtreeA.test c0d8e91e25052d5f3fbda17632ca843b82ca13c4181fb6000a0d63bd2d7e70ce
+F ext/rtree/rtreeA.test a7fd235d8194115fa2e14d300337931eb2e960fe8a46cdfb66add2206412ea41
F ext/rtree/rtreeB.test 4cec297f8e5c588654bbf3c6ed0903f10612be8a2878055dd25faf8c71758bc9
F ext/rtree/rtreeC.test c4bfa9a61c6788c03e4a9ce40ab2cfc6100982559effd9842d1b658e1d47aa5f
F ext/rtree/rtreeD.test fe46aa7f012e137bd58294409b16c0d43976c3bb92c8f710481e577c4a1100dc
@@ -420,7 +420,7 @@ F ext/rtree/rtreeH.test 0885151ee8429242625600ae47142cca935332c70a06737f35af53a7
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
+F ext/rtree/rtreecheck.test 1f542257f21c8a22ce3462c852ec1a0847fa8b3133053abfab3972764210e8bc
F ext/rtree/rtreecirc.test aec664eb21ae943aeb344191407afff5d392d3ae9d12b9a112ced0d9c5de298e
F ext/rtree/rtreeconnect.test 225ad3fcb483d36cbee423a25052a6bbae762c9576ae9268332360c68c170d3d
F ext/rtree/rtreedoc.test 27a5703cb1200f6f69051de68da546cef3dfdcf59be73afadfc50b9f9c9960d9
@@ -428,7 +428,7 @@ F ext/rtree/rtreedoc2.test 194ebb7d561452dcdc10bf03f44e30c082c2f0c14efeb07f5e02c
F ext/rtree/rtreedoc3.test 555a878c4d79c4e37fa439a1c3b02ee65d3ebaf75d9e8d96a9c55d66db3efbf8
F ext/rtree/rtreefuzz001.test 0fc793f67897c250c5fde96cefee455a5e2fb92f4feeabde5b85ea02040790ee
F ext/rtree/sqlite3rtree.h 03c8db3261e435fbddcfc961471795cbf12b24e03001d0015b2636b0f3881373
-F ext/rtree/test_rtreedoc.c 0167f9243a56d08e79230f604f3979d6b7cde4816355acf7a7d436d9d788bf38
+F ext/rtree/test_rtreedoc.c 5ad4029d6804eb9efafcac1598a9e0582f6119e48f818854f5b4db1788ca8bd4
F ext/rtree/tkt3363.test 142ab96eded44a3615ec79fba98c7bde7d0f96de
F ext/rtree/util/randomshape.tcl 54ee03d0d4a1c621806f7f44d5b78d2db8fac26e0e8687c36c4bd0203b27dbff
F ext/rtree/viewrtree.tcl eea6224b3553599ae665b239bd827e182b466024
@@ -444,7 +444,7 @@ F ext/session/session3.test ce9ce3dfa489473987f899e9f6a0f2db9bde3479
F ext/session/session4.test 6778997065b44d99c51ff9cece047ff9244a32856b328735ae27ddef68979c40
F ext/session/session5.test 716bc6fafd625ce60dfa62ae128971628c1a1169
F ext/session/session6.test 35279f2ec45448cd2e24a61688219dc6cf7871757716063acf4a8b5455e1e926
-F ext/session/session8.test 8e194b3f655d861ca36de5d4de53f702751bab3b
+F ext/session/session8.test 326f3273abf9d5d2d7d559eee8f5994c4ea74a5d935562454605e6607ee29904
F ext/session/session9.test 5409d90d8141881d08285ed1c2c0d8d10fb92069
F ext/session/sessionA.test 1feeab0b8e03527f08f2f1defb442da25480138f
F ext/session/sessionB.test c4fb7f8a688787111606e123a555f18ee04f65bb9f2a4bb2aa71d55ce4e6d02c
@@ -479,7 +479,7 @@ F ext/userauth/userauth.c 7f00cded7dcaa5d47f54539b290a43d2e59f4b1eb5f447545fa865
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60
-F main.mk 04bd3898932b55cb878a8ddb969e6ced44a2a73204b20705ed482a48b5d269a3
+F main.mk 33660d5cd3a0cc1373e5c1f5ec8bd619fc3e78b6e1a14a55d12d77ff5cc182bb
F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83
F mptest/config01.test 3c6adcbc50b991866855f1977ff172eb6d901271
F mptest/config02.test 4415dfe36c48785f751e16e32c20b077c28ae504
@@ -491,37 +491,38 @@ F spec.template 86a4a43b99ebb3e75e6b9a735d5fd293a24e90ca
F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
F sqlite3.1 fc7ad8990fc8409983309bb80de8c811a7506786
F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a
-F src/alter.c 23743384e59f9d36df870ce41adfdf7934fd0adb619d7fa6fd1aac77c28a7533
+F src/alter.c 67ef8e685f547038b7ad93a7c6571f790d0a5bb1c00632d5466ffb4ccf3ee6e8
F src/analyze.c 7518b99e07c5494111fe3bd867f28f804b6c5c1ad0703ec3d116de9bab3fa516
F src/attach.c e3f9d9a2a4a844750f3f348f37afb244535f21382cbfcd840152cb21cb41cfaf
F src/auth.c f4fa91b6a90bbc8e0d0f738aa284551739c9543a367071f55574681e0f24f8cf
F src/backup.c 3014889fa06e20e6adfa0d07b60097eec1f6e5b06671625f476a714d2356513d
F src/bitvec.c 3907fcbe8a0c8c2db58d97087d15cdabbf2842adb9125df9ab9ff87d3db16775
F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6
-F src/btree.c 5943ec18ac160ade910bb7b59470b5cd53b66eaf2dcc40fecdc1c5c285be0bfc
+F src/btree.c a7f304a0c872b6d1f1fc162123b5b0a43dd1874b30ecdf26a77956f2e3e12c7f
F src/btree.h 900067641b64d619e6e2a93bd115c952a52f41d3bee32e551e2a4ceee05fc431
F src/btreeInt.h 3f19f0be5af0b68cff55e58df4b11e7a0692d9e8a820ceaeba4084659a86cf28
-F src/build.c 7b4705bfa97af3845573aa1530ff5ca992e60b84ad018115e23bbf0c0559318f
-F src/callback.c 106b585da1edd57d75fa579d823a5218e0bf37f191dbf7417eeb4a8a9a267dbc
+F src/build.c 99a4dee6e4e18d0e5f9340f4739637fa8b5b52b3efa1a94fc6c3210819dc16b2
+F src/callback.c 4c19af69835787bfe790ac560f3071a824eb629f34e41f97b52ce5235c77de1c
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
-F src/ctime.c 8159d5f706551861c18ec6c8f6bdf105e15ea00367f05d9ab65d31a1077facc1
-F src/date.c fa928630fecf1d436cdc7a7a5c950c781709023ca782c21b7a43cc7361a9451e
+F src/ctime.c 2cce39df1a13e05b7633e6d21b651f21492471f991dd7b323a4ee4e7b7f0b7f1
+F src/date.c ab8e01d928f201f5dee0bc6d54d6702fdcec96dff4d58c387447671f6a46d191
F src/dbpage.c 8a01e865bf8bc6d7b1844b4314443a6436c07c3efe1d488ed89e81719047833a
F src/dbstat.c 861e08690fcb0f2ee1165eff0060ea8d4f3e2ea10f80dab7d32ad70443a6ff2d
-F src/delete.c 0c151975fa99560767d7747f9b60543d0093d9f8b89f13d2d6058e9c83ad19e7
-F src/expr.c 4b6dfb224b6234ff4f529023993b503048e1b045ff49cbb911e7d28a28cca795
+F src/delete.c 19814f621cde10b1771a0dea7fe25d3d7d39975b8d4be4888537d30860e7c08c
+F src/expr.c 827179c78d2ca7cc318392811de8151c60eacf7ce804b13e61bb7ef38f954846
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
-F src/fkey.c 187b67af20c5795953a592832c5d985e4313fe503ebd8f95e3e9e9ad5a730bb5
-F src/func.c a5dce8a8ff85310e2c88262a25bcded0a7e92be9a4bda24bbf6eab78e99c2f13
+F src/fkey.c 5b73f7a7c00f06017531a5bd258cbc2c7a294e55a7f84a729fe27aa525242560
+F src/func.c 88b07637d07b3bf7f89a6fe2da8edad7d34f962a69708afe48d4c28aa682515e
F src/global.c 1f56aead86e8a18c4415638f5e6c4d0a0550427f4b3f5d065ba5164cc09c22e8
F src/hash.c 8d7dda241d0ebdafb6ffdeda3149a412d7df75102cecfc1021c98d6219823b19
F src/hash.h 3340ab6e1d13e725571d7cee6d3e3135f0779a7d8e76a9ce0a85971fa3953c51
F src/hwtime.h cb1d7e3e1ed94b7aa6fde95ae2c2daccc3df826be26fc9ed7fd90d1750ae6144
F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
-F src/insert.c 7fcbbe9114ac402ea3c0c6a3810f13fc89cae8131ea1659ec472be7caac10192
+F src/insert.c e528416ff5d86fc5d656ea6a26f03fde39836b6175f93048c32a03cb2ee16743
+F src/json.c 78fdec9af3a8bfb5ae685707b2701276fec1942b8f5f26689b2701debe32bcd2 w ext/misc/json1.c
F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa
-F src/loadext.c e1dcff1c916bf6834e150b492eddda5d9792453182d2ad64294d2266b6e93c4c
-F src/main.c 6144b8771876e5717a81a1b7599e610e57971d5fd925ff53888f6bd22712ca4a
+F src/loadext.c 95db1fe62c5973f1c5d9c53f6083e21a73ece14cdd47eeca0639691332e85c4d
+F src/main.c 4806307e415189bbf91df6467d6ff923643fdeb84e782ef0d5451a14465db935
F src/malloc.c ef796bcc0e81d845d59a469f1cf235056caf9024172fd524e32136e65593647b
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
F src/mem1.c c12a42539b1ba105e3707d0e628ad70e611040d8f5e38cf942cee30c867083de
@@ -529,7 +530,7 @@ F src/mem2.c c8bfc9446fd0798bddd495eb5d9dbafa7d4b7287d8c22d50a83ac9daa26d8a75
F src/mem3.c 30301196cace2a085cbedee1326a49f4b26deff0af68774ca82c1f7c06fda4f6
F src/mem5.c 9bf955937b07f8c32541c8a9991f33ce3173d944
F src/memdb.c c2dc88f97c410eb68a24468344b65526685e18354ddfd15906750c1eaf9dc2dd
-F src/memjournal.c a85f0dc5c02a42453d0bc3819ecfb5666cb6433e5deefcd93ccbe05c9f088b83
+F src/memjournal.c ff4336a98b05ede2adee7595f22d6f7d1cdc6bf0f0a5c3d77b0acdf017b2e8b2
F src/msvc.h 3a15918220367a8876be3fa4f2abe423a861491e84b864fb2b7426bf022a28f8
F src/mutex.c 5e3409715552348732e97b9194abe92fdfcd934cfb681df4ba0ab87ac6c18d25
F src/mutex.h a7b2293c48db5f27007c3bdb21d438873637d12658f5a0bf8ad025bb96803c4a
@@ -544,30 +545,30 @@ F src/os_setup.h 0dbaea40a7d36bf311613d31342e0b99e2536586
F src/os_unix.c d38bf73a08bd1e721839fd9e4b5c67b10212d5ae44a28976d73e4e800d7d54ce
F src/os_win.c 77d39873836f1831a9b0b91894fec45ab0e9ca8e067dc8c549e1d1eca1566fe9
F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
-F src/pager.c 17e8d78f77faa53bd91f7ee148315135c867636ac182b08eb29ce37d1df9b802
+F src/pager.c d27496ff0ceae1a7fe5a3815ea1d8ed34bac76ed96aecf45cfef9a493eeba826
F src/pager.h 034a193e53d6649bdb641aa996e38094dbb7cbe365d8c10eba871a38a0f5ebb3
-F src/parse.y 59631359574901cc5cd4780939a6740f6bc597bd473334e744c1a1c32d9adef3
+F src/parse.y c7c307018e6d328523833cf7ee7738cf95e81c2b272e97076665caf9221fc9a2
F src/pcache.c 084e638432c610f95aea72b8509f0845d2791293f39d1b82f0c0a7e089c3bb6b
F src/pcache.h 4f87acd914cef5016fae3030343540d75f5b85a1877eed1a2a19b9f284248586
F src/pcache1.c 54881292a9a5db202b2c0ac541c5e3ef9a5e8c4f1c1383adb2601d5499a60e65
F src/pragma.c cb0cc54e1ae56082f6eabc4c0013ee3fd31844bda83e9c5aaf95616572db2439
F src/pragma.h f98354c48571c490927029510566839bf9e7242569bfbb48032dafeb008481d2
-F src/prepare.c 7520a371f1de8a53e3023eba75bc0d3473196833c6363d285cad8d002eabef0b
-F src/printf.c 5901672228f305f7d493cbc4e7d76a61a5caecdbc1cd06b1f9ec42ea4265cf8d
+F src/prepare.c 45fe7408eb78d80eca8392669070a6e5caf231b09e5c7b1ff65c1ad64a3734c5
+F src/printf.c 975f1f5417f2526365b6e6d7f22332e3e11806dad844701d92846292b654ba9a
F src/random.c c6e61d041f230d46c658e6dfe7165fc1ecb0093d5fe28cfe74f389d261dc3af8
-F src/resolve.c 4a1db4aadd802683db40ca2dbbb268187bd195f10cbdb7206dbd8ac988795571
+F src/resolve.c 359bc0e445d427583d2ab6110433a5dc777f64a0ecdf8d24826d8b475233ead9
F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92
-F src/select.c 7e8082835f8b8891a0785dc163724a13b5c200abd0931fd3204b2578339c49bc
-F src/shell.c.in 975f268ef261773fcbed1e519dfa10c4f33e8b1cffc12120563e61857fff07c6
-F src/sqlite.h.in 32f7d112cb85d3f2fd56500e11a6bd6d19a969306650200dcde97c2638cfecfc
+F src/select.c df53cc54f99fbfc3807c1a3d9ee238301069f49b482ffe6d7b42d24371354d75
+F src/shell.c.in 4690f216dc4da0c104a8fd9f9e12bec0483242e630324aa7a3ccd155922e346e
+F src/sqlite.h.in c9b6376ff29699b8061357c39e37ec29522d367982d2e0b5af74d8d48c557910
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
-F src/sqlite3ext.h 8ff2fd2c166150b2e48639f5e506fb44e29f1a3f65031710b9e89d1c126ac839
-F src/sqliteInt.h fb84d6eaa6fb1fc408065d137d79838e93e1ee2a72ea45d77aa0c2d5801be716
+F src/sqlite3ext.h 01eb85e4f2759a5ee79c183f4b2877889d4ffdc49d27ae74529c9579e3c8c0ef
+F src/sqliteInt.h 60518b1113603dd132dab78d2d30f856e6f5b402bd094409b952b65536e80ef0
F src/sqliteLimit.h d7323ffea5208c6af2734574bae933ca8ed2ab728083caa117c9738581a31657
F src/status.c 4b8bc2a6905163a38b739854a35b826c737333fab5b1f8e03fa7eb9a4799c4c1
F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
F src/tclsqlite.c 48f291e1a7e672a7204884d4c164a8ed3a522ff087c361ada2991f5d54e987f6
-F src/test1.c 2785b6fd05e4810f7215bf8de01c15670f39a19e49e3d927045f5e72ab08b4cd
+F src/test1.c 545b5b782d80b8a13e5496ac3ded6a80beb3f4c3a6ee9f1cd80f36ac26746c7b
F src/test2.c 3efb99ab7f1fc8d154933e02ae1378bac9637da5
F src/test3.c 61798bb0d38b915067a8c8e03f5a534b431181f802659a6616f9b4ff7d872644
F src/test4.c 7c4420e01c577b5c4add2cb03119743b1a357543d347773b9e717195ea967159
@@ -587,7 +588,7 @@ F src/test_delete.c e2fe07646dff6300b48d49b2fee2fe192ed389e834dd635e3b3bac0ce0bf
F src/test_demovfs.c 86142ba864d4297d54c5b2e972e74f3141ae4b30f05b3a95824184ed2d3d7f91
F src/test_devsym.c aff2255ea290d7718da08af30cdf18e470ff7325a5eff63e0057b1496ed66593
F src/test_fs.c ba1e1dc18fd3159fdba0b9c4256f14032159785320dfbd6776eb9973cb75d480
-F src/test_func.c 181f992e5495644434c4f0e3cc72362a78c295eb2cf3ff4d02498b8bde7aa276
+F src/test_func.c 24df3a346c012b1fc9e1001d346db6054deb426db0a7437e92490630e71c9b0a
F src/test_hexio.c a605a100e628d39330044ae5f34cb19d50843061ed3178c3f83b37aef65f7e0a
F src/test_init.c 4413c211a94b62157ca4c145b3f27c497f03c664
F src/test_intarray.c 39b4181662a0f33a427748d87218e7578d913e683dc27eab7098bb41617cac71
@@ -621,33 +622,33 @@ F src/test_windirent.h 90dfbe95442c9762357fe128dc7ae3dc199d006de93eb33ba3972e0a9
F src/test_window.c cdae419fdcea5bad6dcd9368c685abdad6deb59e9fc8b84b153de513d394ba3f
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c
-F src/tokenize.c 865911afa00fed589cd03b25c140ca88544842aaef7b81f7d41ed769a7a54120
+F src/tokenize.c b74d878aa7c82ec8460779468061a96185e22257f68ab785b69abce354b70446
F src/treeview.c 9dfdb7ff7f6645d0a6458dbdf4ffac041c071c4533a6db8bb6e502b979ac67bc
-F src/trigger.c 2ef56f0b7b75349a5557d0604b475126329c2e1a02432e7d49c4c710613e8254
-F src/update.c dc362b5c6b459cb1915cadb94270f1f0de68657a82293eb5ce9aaf880d0af1ba
+F src/trigger.c 40e7c3dcff57a770d5fa38ba21ed4725572fd2e224c58af61eb980598b60f9c8
+F src/update.c 457fbf994ccc67f99e4c2c54018b553be65a3d38910c5b88e67abeacd65eac1e
F src/upsert.c 8789047a8f0a601ea42fa0256d1ba3190c13746b6ba940fe2d25643a7e991937
F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0
-F src/util.c 30df8356e231dad33be10bb27897655002668343280004ba28c734489414a167
+F src/util.c 89e51820bcb468ff3877a8d942f5cc807208087f021227e0927693e928a195bc
F src/vacuum.c 72867c740476d13f1c397015e4d3168b4e96a237a80b9afa67e1bb8500bfeeab
-F src/vdbe.c 280f2449f841354362055c82d6595b23a83bfdc949850f0f7754b739c6b714d1
+F src/vdbe.c e120656de4cfbc078253e970cd9f0f0891378a66efbd3890ec956dd44a62b8dd
F src/vdbe.h 25dabb25c7e157b84e59260cfb5b466c3ac103ede9f36f4db371332c47601abe
-F src/vdbeInt.h 31fbabdc1ed61d9695337dfe5269ea94e1cf615c17f5cafeaa1bb01066820bab
+F src/vdbeInt.h d89d5d2150500cfb08615329fd20aea9d746bba5f2c3ecb8a17e2d2d9be029e5
F src/vdbeapi.c 22c79072ae7d8a01e9bcae8ba16e918d60d202eaa9553b5fda38f99f7464d99a
-F src/vdbeaux.c 60377ffca1a1c963e2f704910b1441ee518f56e735f966560d6c420979934547
+F src/vdbeaux.c 00fc867d51b1080550784c0a2c49abca472c73d2bb53767e8199299eb582cbca
F src/vdbeblob.c 29c4118f7ee615cdee829e8401f6ead1b96b95d545b4de0042f6de39c962c652
-F src/vdbemem.c a3d91dc9bb9ef725db77e4e9de7e1acef43192c9f8406c307665d503e3c2837c
-F src/vdbesort.c 513b481c8bab4a6578c92194a60cf3bc3b48736e4a53f8d2d7918121c5b594e7
+F src/vdbemem.c da4d594084d581be6436582bb44bb128feeb138a3e6c313eda6749ebdc3a65ec
+F src/vdbesort.c 43756031ca7430f7aec3ef904824a7883c4ede783e51f280d99b9b65c0796e35
F src/vdbetrace.c fe0bc29ebd4e02c8bc5c1945f1d2e6be5927ec12c06d89b03ef2a4def34bf823
F src/vdbevtab.c f99b275366c5fc5e2d99f734729880994ab9500bdafde7fae3b02d562b9d323c
-F src/vtab.c 9d5c3f49d3a6959b6eef287bb8fa773563102a80a835c3314c57144412709e78
+F src/vtab.c a47cc12ebaa350800c0c87b6b0095debbb5a6ed32727bcab9d82ad070a81b738
F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
F src/wal.c 5b92441319c3c7cf2833e64d7d1f38efa59a9458240c991b67a105541432c3d1
F src/wal.h 7a733af13b966ecb81872ce397e862116b3575ea53245b90b139a2873ee87825
F src/walker.c f890a3298418d7cba3b69b8803594fdc484ea241206a8dfa99db6dd36f8cbb3b
-F src/where.c de0d4ff409c7b62a8803f9f267cc2c7fedddbc00de9ab7b5382c507383c18665
-F src/whereInt.h 83877a75a1bce056ea44aff02f1dfa958ad1d6038c213ddadb8652003b45151d
-F src/wherecode.c 1f5b62f46d284c8886945eb7438415bc27e23e87bb60b9ee468fa6bd31268f33
-F src/whereexpr.c 17bdbf4f5b490e70a18635498f0b910a558f953a9bf80af7f19cbde6e60e6825
+F src/where.c eedf0311d59095bcd8523bd13bf25865e1caf1fab9beddbff9093340a1a409c7
+F src/whereInt.h 91865afa4a3540bb3bd643619acc56fbceff7defeb8f249b8e157fd5325d88be
+F src/wherecode.c 6a594ed25bfbeb60d455868b7be62637575e4f1949152de4336e4825e0c54ba6
+F src/whereexpr.c 9f64c39e53070584e99e4d20c1dd3397e125fabbae8fd414ffec574c410ac7d3
F src/window.c 5d3b397b0c026d0ff5890244ac41359e524c01ae31e78782e1ff418c3e271a9e
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
F test/affinity2.test ce1aafc86e110685b324e9a763eab4f2a73f737842ec3b687bd965867de90627
@@ -662,7 +663,7 @@ F test/alter3.test ffc4ab29ce78a3517a66afd69b2730667e3471622509c283b2bd4c46f680f
F test/alter4.test 716caa071dd8a3c6d57225778d15d3c3cbf5e34b2e84ae44199aeb2bbf50a707
F test/alterauth.test 63442ba61ceb0c1eeb63aac1f4f5cebfa509d352276059d27106ae256bafc959
F test/alterauth2.test 381b1ab603c9ef96314a3158528ea17f7964449385a28eeaf8191120b2e24a8d
-F test/altercol.test b11fa1b131e80ab5b6ecfb3b725fb0419c14ca6efba5adb57aeabfc9baa0c8f3
+F test/altercol.test 9471187fe155d9c4211ae185e104ff48ce8f114262ee1256cf1e110b339c725f
F test/altercorrupt.test 2e1d705342cf9d7de884518ddbb053fd52d7e60d2b8869b7b63b2fda68435c12
F test/alterdropcol.test a653a3945f964d26845ec0cd0a8e74189f46de3119a984c5bc45457da392612e
F test/alterdropcol2.test 527fce683b200d620f560f666c44ae33e22728e990a10a48a543280dfd4b4d41
@@ -671,7 +672,7 @@ F test/alterlegacy.test f38c6d06cda39e1f7b955bbce57f2e3ef5b7cb566d3d1234502093e2
F test/altermalloc.test 167a47de41b5c638f5f5c6efb59784002b196fff70f98d9b4ed3cd74a3fb80c9
F test/altermalloc2.test ca3ebc01670d9313953a2b7628d8cc00dc5ea9988f229b3cbbbe1cca506dae45
F test/altermalloc3.test 4660ac6240a8c82ba3947b927612dcc7c05a8eec3fe3c9f38e047ca69a789a33
-F test/alterqf.test 6b2482a957692606b23567ebd2cf80eb773e3c826086f5f151eee9c5a962623d
+F test/alterqf.test 3008318ba9e16b4ac0b5f83cf7683caa4b0a3154aafe3b4099838a250d4ba74a
F test/altertab.test 7273b8506eab46342be016af78028df49f3bd99037412f997a8f1011b37a6912
F test/altertab2.test b0d62f323ca5dab42b0bc028c52e310ebdd13e655e8fac070fe622bad7852c2b
F test/altertab3.test 5929f522fd6fd708396ad9f317d4af9ff1a93e460df85bb1d54d4499eeb94960
@@ -712,7 +713,7 @@ F test/autoinc.test 997d6f185f138229dc4251583a1d04816423dddc2fc034871a01aeb1d728
F test/autoindex1.test fe27af92eaf884bd9c38f94be3e8afa04ec494e5eefb189902026181a6175f5e
F test/autoindex2.test 12ef578928102baaa0dc23ad397601a2f4ecb0df
F test/autoindex3.test 2d13958a5617e987624a428d7aed91bf51f322b49b476e3573fadec697ce6da5
-F test/autoindex4.test 49d3cd791a9baa16fb461d7ea3de80d019a819cf
+F test/autoindex4.test 75cb1191a552b8201351f5a50d160fcb9387a0fbbfb820c77798bfee7da3f8cf
F test/autoindex5.test 2ee94f033b87ca0160e08d81034c507aff8e230df2627f0304fa309b2fee19a3
F test/autovacuum.test 00671369bbf96c6a49989a9425f5b78b94075d6a4b031e5e00000c2c32f365df
F test/autovacuum2.test 76f7eb4fe6a6bf6d33a196a7141dba98886d2fb53a268d7feca285d5da4759d7
@@ -773,13 +774,13 @@ F test/carray01.test d55d57bf66b1af1c7ac55fae66ff4910884a8f5d21a90a18797ce386212
F test/cast.test 336fa21989b5170ebcaf90c24266be22dd97b3e23d1fad5ecf6ad4efb04c4423
F test/cffault.test 9d6b20606afe712374952eec4f8fd74b1a8097ef
F test/changes.test 9dd8e597d84072122fc8a4fcdea837f4a54a461e6e536053ea984303e8ca937b
-F test/check.test 4a2a91ed67eee84a6be16057c48d5198b6fb24849cd6da6cd855981de3fbb416
+F test/check.test 56e4ed457e9f8683b9fc56f5b964f461f6e8a8dd5a13f3d495408215d66419ed
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 532b4992f78e91dd80c2e3c7bd944fada8cbe3d6c0ded0b20f7182b4dfca0006
+F test/collate1.test 71a6f27fdc93a92f14d8ab80c05e1937656a5a03197e1a10157314554d630ce8
F test/collate2.test 9aaa410a00734e48bcb27f3872617d6f69b2a621
F test/collate3.test 89defc49983ddfbf0a0555aca8c0521a676f56a5
F test/collate4.test c953715fb498b87163e3e73dd94356bff1f317bd
@@ -847,7 +848,7 @@ F test/crashtest1.c 09c1c7d728ccf4feb9e481671e29dda5669bbcc2
F test/createtab.test 85cdfdae5c3de331cd888d6c66e1aba575b47c2e3c3cc4a1d6f54140699f5165
F test/cse.test 00b3aea44b16828833c94fbe92475fd6977583fcb064ae0bc590986812b38d0c
F test/csv01.test c9c3af0d58c34e9ac970c5875a77939edb958762c8aafb95409e19a3f088b6cd
-F test/ctime.test 78749e6c9a5f0010d67985be80788f841e3cd2da18114e2ed6010399a7d807f3
+F test/ctime.test 340f362f41f92972bbd71f44e10569a5cc694062b692231bd08aa6fe6c1c4773
F test/cursorhint.test 0175e4404181ace3ceca8b114eb0a98eae600d565aa4e2705abbe6614c7fe201
F test/cursorhint2.test 6f3aa9cb19e7418967a10ec6905209bcbb5968054da855fc36c8beee9ae9c42f
F test/dataversion1.test 6e5e86ac681f0782e766ebcb56c019ae001522d114e0e111e5ebf68ccf2a7bb8
@@ -907,12 +908,12 @@ F test/enc3.test 6807f7a7740a00361ca8d0ccd66bc60c8dc5f2b6
F test/enc4.test c8f1ce3618508fd0909945beb8b8831feef2c020
F test/eqp.test bfe979eb1f4b8ab7a3bd7db6d16c2e6c6be0e5a3aada2227716f3fd3a9d76b69
F test/errmsg.test eae9f091eb39ce7e20305de45d8e5d115b68fa856fba4ea6757b6ca3705ff7f9
-F test/eval.test a64c9105d6ff163df7cf09d6ac29cdad5922078c
+F test/eval.test 73969a2d43a511bf44080c44485a8c4d796b6a4f038d19e491867081155692c0
F test/exclusive.test 7ff63be7503990921838d5c9f77f6e33e68e48ed1a9d48cd28745bf650bf0747
F test/exclusive2.test 984090e8e9d1b331d2e8111daf6e5d61dda0bef7
F test/exec.test e949714dc127eaa5ecc7d723efec1ec27118fdd7
F test/exists.test 79a75323c78f02bbe9c251ea502a092f9ef63dac
-F test/expr.test 26cd01e8485bc48c8aa6a1add598e9ce1e706b4eb4f3f554e0b0223022e8c2cf
+F test/expr.test e1afcdb1038e4d3fa67a3df323347c38750946e2e1b4e385bdc75d26284f2dac
F test/expr2.test c27327ae9c017a7ff6280123f67aff496f912da74d78c888926d68b46ec75fd8
F test/exprfault.test 497cc0b8fe6a677f49b55cb485e040f709ec2834b84f25912fe9c2dfeeda33db
F test/extension01.test 00d13cec817f331a687a243e0e5a2d87b0e358c9
@@ -925,7 +926,7 @@ F test/filter1.test 6c483ecf7886c8843a8612c021aa23f33c581f584151f251842b3a3592c9
F test/filter2.tcl 44e525497ce07382915f01bd29ffd0fa49dab3adb87253b5e5103ba8f93393e8
F test/filter2.test 485cf95d1f6d6ceee5632201ca52a71868599836f430cdee42e5f7f14666e30a
F test/filterfault.test c08fb491d698e8df6c122c98f7db1c65ffcfcad2c1ab0e07fa8a5be1b34eaa8b
-F test/fkey1.test 03503639d266d565db90ee3b8fe211ba446624030ac4eb24895cec265e9631d0
+F test/fkey1.test 55663090ab6735319a52647057b9f19f8ec8c6c7d7da25170b71a75e3e5bdeb7
F test/fkey2.test 1063d65e5923c054cfb8f0555a92a3ae0fa8c067275a33ee1715bd856cdb304c
F test/fkey3.test 76d475c80b84ee7a5d062e56ccb6ea68882e2b49
F test/fkey4.test 86446017011273aad8f9a99c1a65019e7bd9ca9d
@@ -982,8 +983,8 @@ F test/fts3af.test d394978c534eabf22dd0837e718b913fd66b499c
F test/fts3ag.test c003672a215124df7fc6000036d896f498b26b53
F test/fts3ah.test dc9f66c32c296f1bc8bcc4535126bddfeca62894
F test/fts3ai.test 24058fdc6e9e5102c1fd8459591b114b6a85d285
-F test/fts3aj.test 0ed71e1dd9b03b843a857dc3eb9b15630e0104fc
-F test/fts3ak.test bd14deafe9d1586e8e9bf032411026ac4f8c925d
+F test/fts3aj.test 1560a7ce5642dc887e8ecfcc4693bcfce1dbb3d1771a735c845f0061e525deb2
+F test/fts3ak.test 36ea92f609efb390cf018cdb5d389c12e62b650abe31cfc88261b252daf88174
F test/fts3al.test 07d64326e79bbdbab20ee87fc3328fbf01641c9f
F test/fts3am.test 218aa6ba0dfc50c7c16b2022aac5c6be593d08d8
F test/fts3an.test a49ccadc07a2f7d646ec1b81bc09da2d85a85b18
@@ -996,7 +997,7 @@ F test/fts3b.test c15c4a9d04e210d0be67e54ce6a87b927168fbf9c1e3faec8c1a732c366fd4
F test/fts3c.test fc723a9cf10b397fdfc2b32e73c53c8b1ec02958
F test/fts3comp1.test a0f5b16a2df44dd0b15751787130af2183167c0c
F test/fts3conf.test c84bbaec81281c1788aa545ac6e78a6bd6cde2bdbbce2da261690e3659f5a76b
-F test/fts3corrupt.test 79a32ffdcd5254e2f7fa121d9656e61949ad049c3c6554229911b7ceac37c9c6
+F test/fts3corrupt.test 43c6c89b994e90997590ece4dfa9c9325c9b61cddd7c97e158498da8b1de79f8
F test/fts3corrupt2.test e318f0676e5e78d5a4b702637e2bb25265954c08a1b1e4aaf93c7880bb0c67d0
F test/fts3corrupt3.test 0d5b69a0998b4adf868cc301fc78f3d0707745f1d984ce044c205cdb764b491f
F test/fts3corrupt4.test 799ff994b964fed7201be6b6b62c7ff2ef7bb3da6c02b9eaf0d96a5a4d9b6ca3
@@ -1008,6 +1009,7 @@ F test/fts3defer.test f4c20e4c7153d20a98ee49ee5f3faef624fefc9a067f8d8d629db380c4
F test/fts3defer2.test 3da52ca2114e300e9971eee2f0cc1a2e5f27e6a9ee67957d49e63e41fdfcc0e7
F test/fts3defer3.test dd53fc13223c6d8264a98244e9b19abd35ed71cd
F test/fts3drop.test 1b906e293d6773812587b3dc458cb9e8f3f0c297
+F test/fts3dropmod.test 7de242ea1c8a713a8b143ea54468f4b1c4953fa068349e23ac178e2c90c59889
F test/fts3e.test 1f6c6ac9cc8b772ca256e6b22aaeed50c9350851
F test/fts3expr.test ebae205a7a89446c32583bcd492dcb817b9f6b31819bb4dde2583bb99c77e526
F test/fts3expr2.test 18da930352e5693eaa163a3eacf96233b7290d1a
@@ -1053,7 +1055,7 @@ F test/fts4merge3.test 8d9ccb4a3d41c4c617a149d6c4b13ad02de797d0
F test/fts4merge4.test d895b1057a7798b67e03455d0fa50e9ea836c47b
F test/fts4merge5.test 69932d85cda8a1c4dcfb742865900ed8fbda51724b8cf9a45bbe226dfd06c596
F test/fts4min.test 1c11e4bde16674a0c795953509cbc3731a7d9cbd1ddc7f35467bf39d632d749f
-F test/fts4noti.test 5553d7bb2e20bf4a06b23e849352efc022ce6309
+F test/fts4noti.test d5d933705b1b1516b67a5e3f8e514ecb19c6522fb3357bb744776d48427c2292
F test/fts4onepass.test d69ddc4ee3415e40b0c5d1d0408488a87614d4f63ba9c44f3e52db541d6b7cc7
F test/fts4opt.test 0fd0cc84000743ff2a883b9b84b4a5be07249f0ba790c8848a757164cdd46b2a
F test/fts4record.test a48508f69a84c9287c8019d3a1ae712f5730d8335ffaf8e2101e691d078950bb
@@ -1062,14 +1064,14 @@ F test/fts4umlaut.test fcaca4471de7e78c9d1f7e8976e3e8704d7d8ad979d57a739d00f3f75
F test/fts4unicode.test 82a9c16b68ba2f358a856226bb2ee02f81583797bc4744061c54401bf1a0f4c9
F test/fts4upfrom.test f25835162c989dffd5e2ef91ec24c4848cc9973093e2d492d1c7b32afac1b49d
F test/full.test 6b3c8fb43c6beab6b95438c1675374b95fab245d
-F test/func.test 3a65ddb6c1998f71aa86492501a6be87904197e62bfb5b70b2493552b558abd1
+F test/func.test 4be8bed4be235e333f1e0ea31e32f5be3c9f456c30780363e7fcb15e3ff3e6bc
F test/func2.test 772d66227e4e6684b86053302e2d74a2500e1e0f
F test/func3.test 600a632c305a88f3946d38f9a51efe145c989b2e13bd2b2a488db47fe76bab6a
F test/func4.test 2285fb5792d593fef442358763f0fd9de806eda47dbc7a5934df57ffdc484c31
F test/func5.test 863e6d1bd0013d09c17236f8a13ea34008dd857d87d85a13a673960e4c25d82a
F test/func6.test 90e42b64c4f9fb6f04f44cb8a1da586c8542502e926b19c76504fe74ff2a9b7c
F test/func7.test b9e2a1a30a8562b00841b4a21a5d2d81754fa3ab99275fd71fd5279287b44b1c
-F test/fuzz-oss1.test e58330d01cbbd8215ee636b17a03fe220b37dbfa
+F test/fuzz-oss1.test 514dcabb24687818ea949fa6760229eaacad74ca70157743ef36d35bbe01ffb0
F test/fuzz.test 96083052bf5765e4518c1ba686ce2bab785670d1
F test/fuzz2.test 76dc35b32b6d6f965259508508abce75a6c4d7e1
F test/fuzz3.test 9c813e6613b837cb7a277b0383cd66bfa07042b4cf0317157c35852f30043c31
@@ -1084,7 +1086,7 @@ F test/fuzzdata4.db b502c7d5498261715812dd8b3c2005bad08b3a26e6489414bd13926cd3e4
F test/fuzzdata5.db e35f64af17ec48926481cfaf3b3855e436bd40d1cfe2d59a9474cb4b748a52a5
F test/fuzzdata6.db 92a80e4afc172c24f662a10a612d188fb272de4a9bd19e017927c95f737de6d7
F test/fuzzdata7.db 0166b56fd7a6b9636a1d60ef0a060f86ddaecf99400a666bb6e5bbd7199ad1f2
-F test/fuzzdata8.db ef4d280ee69d6da0ebda7f81c0c66839fa577a97b29cc5790a564fde88be7183
+F test/fuzzdata8.db a0c7af954bcbb226ed7ae087b3b6d6e48eaac8fac5671150ffd23c35b55bffe6
F test/fuzzer1.test 3d4c4b7e547aba5e5511a2991e3e3d07166cfbb8
F test/fuzzer2.test a85ef814ce071293bce1ad8dffa217cbbaad4c14
F test/fuzzerfault.test f64c4aef4c9e9edf1d6dc0d3f1e65dcc81e67c996403c88d14f09b74807a42bc
@@ -1099,7 +1101,7 @@ F test/hook2.test b9ff3b8c6519fb67f33192f1afe86e7782ee4ac8
F test/icu.test 716a6b89fbabe5cc63e0cd4c260befb08fd7b9d761f04d43669233292f0753b1
F test/ieee754.test b0945d12be7d255f3dfa18e2511b17ca37e0edd2b803231c52d05b86c04ab26e
F test/imposter1.test c3f1db2d3db2c24611a6596a3fc0ffc14f1466c8
-F test/in.test 688ed2011d922d83141a45af431601738674a4c0bdde34b6351f688b82a169b3
+F test/in.test 15de58ee017f43d36390812e9a51217d1b2db7758f97d0df48296ef178ea560b
F test/in2.test 5d4c61d17493c832f7d2d32bef785119e87bde75
F test/in3.test 3cbf58c87f4052cee3a58b37b6389777505aa0c0
F test/in4.test fdd1d8134da8376985c2edba6035a2de1f6c731524d2ffa651419e8fe2cd1c5a
@@ -1116,7 +1118,7 @@ F test/incrvacuum.test 3fa6145f5e71f603554fd7b8ec3da4290b1341029682313285cb5f9e1
F test/incrvacuum2.test 7d26cfda66c7e55898d196de54ac4ec7d86a4e3d
F test/incrvacuum3.test 75256fb1377e7c39ef2de62bfc42bbff67be295a
F test/incrvacuum_ioerr.test 6ae2f783424e47a0033304808fe27789cf93e635
-F test/index.test a2e948ed949e575487b5c1d521767d4584ac42d352f2dcd8e48004638e7bc7dc
+F test/index.test d866054c88b394fd42cbf2825628f127ca24dfac525fa019069a936674d92cbe
F test/index2.test f835d5e13ca163bd78c4459ca15fd2e4ed487407
F test/index3.test 51685f39345462b84fcf77eb8537af847fdf438cc96b05c45d6aaca4e473ade0
F test/index4.test ab92e736d5946840236cd61ac3191f91a7856bf6
@@ -1151,11 +1153,11 @@ F test/ioerr4.test f130fe9e71008577b342b8874d52984bd04ede2c
F test/ioerr5.test 2edfa4fb0f896f733071303b42224df8bedd9da4
F test/ioerr6.test a395a6ab144b26a9e3e21059a1ab6a7149cca65b
F test/istrue.test e7f285bb70282625c258e866ce6337d4c762922f5a300e1b50f958aef6e7d9c9
-F test/join.test 25da4f53523a4aa17c893134b47fba6aa4799bb33350517b157785878290e238
+F test/join.test 25cf0ac11c3b81fedfd166f9062166bdb39dea92f5a7c16cacbf6dc1f7f67020
F test/join2.test 9bdc615841b91c97a16d68bad9508aea11fa0c6b34e5689847bcc4dac70e4990
F test/join3.test 6f0c774ff1ba0489e6c88a3e77b9d3528fb4fda0
F test/join4.test 1a352e4e267114444c29266ce79e941af5885916
-F test/join5.test f418fccdfefa41f1659663463aa517431ddcf3e30ccbb80e64173b7d615a03f4
+F test/join5.test d22395f7d4020a58cabbc8316f300a5cfef84aee9e8ba7ce79b33cc43a3e1e2e
F test/join6.test f809c025fa253f9e150c0e9afd4cef8813257bceeb6f46e04041228c9403cc2c
F test/journal1.test c7b768041b7f494471531e17abc2f4f5ebf9e5096984f43ed17c4eb80ba34497
F test/journal2.test 9dac6b4ba0ca79c3b21446bbae993a462c2397c4
@@ -1164,7 +1166,7 @@ F test/jrnlmode.test 9b5bc01dac22223cb60ec2d5f97acf568d73820794386de5634dcadbea9
F test/jrnlmode2.test 8759a1d4657c064637f8b079592651530db738419e1d649c6df7048cd724363d
F test/jrnlmode3.test 556b447a05be0e0963f4311e95ab1632b11c9eaa
F test/json101.test bb71538005f2d9e18620bdd3b76839a93ca0be61903eb8d751a64e78cf99b8fb
-F test/json102.test eeb54efa221e50b74a2d6fb9259963b48d7414dca3ce2fdfdeed45cb28487bc1
+F test/json102.test 86edc7d283085addff8593b178997e75875530d1385f5926717543d3475e6b01
F test/json103.test aff6b7a4c17d5a20b487a7bc1a274bfdc63b829413bdfb83bedac42ec7f67e3b
F test/json104.test 2cb7ff2cca2c8214d3e5260eeb9ce45faec0926f68b3e40c1aaa6ca247284144
F test/json105.test 45f7d6a9a54c85f8a9589b68d3e7a1f42d02f2359911a8cdbad1f9988f571173
@@ -1220,14 +1222,16 @@ F test/mem5.test c6460fba403c5703141348cd90de1c294188c68f
F test/memdb.test c1f2a343ad14398d5d6debda6ea33e80d0dafcc7
F test/memdb1.test 2c4e9cc10d21c6bf4e217d72b7f6b8ba9b2605971bb2c5e6df76018e189f98f5
F test/memjournal.test 70f3a00c7f84ee2978ad14e831231caa1e7f23915a2c54b4f775a021d5740c6c
+F test/memjournal2.test 89a4e0d1084170a281efa4d54c2677599f986f44227f98f7dfae282802737b65
F test/memleak.test 10b9c6c57e19fc68c32941495e9ba1c50123f6e2
F test/memsubsys1.test 9e7555a22173b8f1c96c281ce289b338fcba2abe8b157f8798ca195bbf1d347e
F test/memsubsys2.test 3e4a8d0c05fd3e5fa92017c64666730a520c7e08
+F test/merge1.test c5abf7d4eca25b3d5ee96927efff18efc3cee5a8af54b8415cbddd6d4471fd70
F test/minmax.test fe638b55d77d2375531a8f549b338eafcd9adfbd2f72df37ed77d9b26ca0a71a
F test/minmax2.test cf9311babb6f0518d04e42fd6a42c619531c4309a9dd790a2c4e9b3bc595e0de
F test/minmax3.test cc1e8b010136db0d01a6f2a29ba5a9f321034354
F test/minmax4.test 272ca395257f05937dc96441c9dde4bc9fbf116a8d4fa02baeb0d13d50e36c87
-F test/misc1.test e3fa5732080cc9a2b77bd5dd4ebb55bd6785b02565f8806092686b83ac58d600
+F test/misc1.test 294c97185354030c4ce40e7141b72f7a589585f2a44b666825381eb3df98f07c
F test/misc2.test 71e746af479119386ac2ed7ab7d81d99970e75b49ffd3e8efffee100b4b5f350
F test/misc3.test cf3dda47d5dda3e53fc5804a100d3c82be736c9d
F test/misc4.test 10cd6addb2fa9093df4751a1b92b50440175dd5468a6ec84d0386e78f087db0e
@@ -1313,7 +1317,7 @@ F test/quick.test 1681febc928d686362d50057c642f77a02c62e57
F test/quota-glob.test 32901e9eed6705d68ca3faee2a06b73b57cb3c26
F test/quota.test bfb269ce81ea52f593f9648316cd5013d766dd2a
F test/quota2.test 7dc12e08b11cbc4c16c9ba2aa2e040ea8d8ab4b8
-F test/quote.test f33f95990e4032d1227b98c0ef314c0a077d162f3f2e61b3039ed69e6f8adbbf
+F test/quote.test ffb40f0eb7a25c1d8cfe11ee2fe67f8e85fbf3fed348810834114be1fdada142
F test/randexpr1.tcl 40dec52119ed3a2b8b2a773bce24b63a3a746459
F test/randexpr1.test eda062a97e60f9c38ae8d806b03b0ddf23d796df
F test/rbu.test 168573d353cd0fd10196b87b0caa322c144ef736
@@ -1325,7 +1329,8 @@ F test/reindex.test cd9d6021729910ece82267b4f5e1b5ac2911a7566c43b43c176a6a4732e2
F test/releasetest_data.tcl 7cea6c852ae6bb3a9ff1a2b910e4dd13c16a05f74443984dfd52159b0b01ea55
F test/resetdb.test 8062cf10a09d8c048f8de7711e94571c38b38168db0e5877ba7561789e5eeb2b
F test/resolver01.test f4022acafda7f4d40eca94dbf16bc5fc4ac30ceb
-F test/returning1.test f96c7245f6ac16038e802760cd90b93479369939a8a7a44e2329ee5aed28239c
+F test/returning1.test ee0b115162b17f59fe486767899596b1e8290bcd845db05d7d1d9e6c2dad1b8b
+F test/returningfault.test ae4c4b5e8745813287a359d9ccdb9d5c883c2e68afb18fb0767937d5de5692a4
F test/rollback.test 06680159bc6746d0f26276e339e3ae2f951c64812468308838e0a3362d911eaa
F test/rollback2.test 3f3a4e20401825017df7e7671e9f31b6de5fae5620c2b9b49917f52f8c160a8f
F test/rollbackfault.test 0e646aeab8840c399cfbfa43daab46fd609cf04a
@@ -1369,7 +1374,7 @@ F test/select2.test 352480e0e9c66eda9c3044e412abdf5be0215b56
F test/select3.test c49fbb758903f3718e2de5aa4655eda4838131cbea24a86db908f8b6889aa68c
F test/select4.test f0684d3da3bccacbe2a1ebadf6fb49d9df6f53acb4c6ebc228a88d0d6054cc7b
F test/select5.test 8afc5e5dcdebc2be54472e73ebd9cd1adef1225fd15d37a1c62f969159f390ae
-F test/select6.test 319d45e414cdd321bf17cfacedaf19e3935ad64dac357c53f1492338c6e9b801
+F test/select6.test 9b2fb4ffedf52e1b5703cfcae1212e7a4a063f014c0458d78d29aca3db766d1f
F test/select7.test f659f231489349e8c5734e610803d7654207318f
F test/select8.test 8c8f5ae43894c891efc5755ed905467d1d67ad5d
F test/select9.test f7586b207ce2304ab80dc93d3146469a28fd4403621dd3a82d06644563d3c812
@@ -1396,11 +1401,11 @@ F test/sharedA.test 49d87ec54ab640fbbc3786ee3c01de94aaa482a3a9f834ad3fe92770eb69
F test/sharedB.test 16cc7178e20965d75278f410943109b77b2e645e
F test/shared_err.test 32634e404a3317eeb94abc7a099c556a346fdb8fb3858dbe222a4cbb8926a939
F test/sharedlock.test 5ede3c37439067c43b0198f580fd374ebf15d304
-F test/shell1.test c354008b27c904f0166c2138abd7382013ea070b41114114ecbdfb32c726a807
+F test/shell1.test 70f46b5d07776a107335c3c2c9cbd0431d44637bfeae1f6b9ded5e33b4c7c0bf
F test/shell2.test f00a0501c00583cbc46f7510e1d713366326b2b3e63d06d15937284171a8787c
F test/shell3.test cb4b835a901742c9719437a89171172ecc4a8823ad97349af8e4e841e6f82566
F test/shell4.test 3ed6c4b42fd695efcbc25d69ef759dbb15855ca8e52ba6c5ee076f8b435f48be
-F test/shell5.test 6e4aa0e531dcb8dcf74b7920a2a7442c6712d4dff8422bbc81f768f9dee8a0e3
+F test/shell5.test b85069bfcf3159b225228629ab2c3e69aa923d098fea8ea074b5dcd743522e2c
F test/shell6.test 1ceb51b2678c472ba6cf1e5da96679ce8347889fe2c3bf93a0e0fa73f00b00d3
F test/shell7.test 115132f66d0463417f408562cc2cf534f6bbc6d83a6d50f0072a9eb171bae97f
F test/shell8.test 388471d16e4de767333107e30653983f186232c0e863f4490bb230419e830aae
@@ -1453,13 +1458,13 @@ F test/stmtvtab1.test 6873dfb24f8e79cbb5b799b95c2e4349060eb7a3b811982749a84b3594
F test/strict1.test a3ec495471f24c1a6e1a1664bd23e24ccdb27ae93b1a763ee1942ec955b68e71
F test/strict2.test b22c7a98b5000aef937f1990776497f0e979b1a23bc4f63e2d53b00e59b20070
F test/subjournal.test 8d4e2572c0ee9a15549f0d8e40863161295107e52f07a3e8012a2e1fdd093c49
-F test/subquery.test d7268d193dd33d5505df965399d3a594e76ae13f
+F test/subquery.test 3a1a5b600b8d4f504d2a2c61f33db820983dba94a0ef3e4aedca8f0165eaecb8
F test/subquery2.test 90cf944b9de8204569cf656028391e4af1ccc8c0cc02d4ef38ee3be8de1ffb12
F test/subselect.test 0966aa8e720224dbd6a5e769a3ec2a723e332303
F test/substr.test a673e3763e247e9b5e497a6cacbaf3da2bd8ec8921c0677145c109f2e633f36b
F test/subtype1.test 7fe09496352f97053af1437150751be2d0a0cae8
F test/superlock.test ec94f0556b6488d97f71c79f9061ae08d9ab8f12
-F test/swarmvtab.test 9a3fd5ab3e9b3c976ad1b3d7646aab725114f2ac26b59395d0778b33bab6cdaf
+F test/swarmvtab.test 250231404fcac88f61a6c147bb0e3a118ed879278cd3ccb0ae2d3a729e1e8e26
F test/swarmvtab2.test c948cb2fdfc5b01d85e8f6d6504854202dc1a0782ab2a0ed61538f27cbd0aa5c
F test/swarmvtab3.test 247aa38b6ebd2b99db2075847ae47e789ac34f1c2ab5c720dfcffd990004c544
F test/swarmvtabfault.test 8a67a9f27c61073a47990829e92bc0c64420a807cb642b15a25f6c788210ed95
@@ -1469,7 +1474,7 @@ F test/sync.test 89539f4973c010eda5638407e71ca7fddbcd8e0594f4c9980229f804d433309
F test/sync2.test 8f9f7d4f6d5be8ca8941a8dadcc4299e558cb6a1ff653a9469146c7a76ef2039
F test/syscall.test a39d9a36f852ae6e4800f861bc2f2e83f68bbc2112d9399931ecfadeabd2d69d
F test/sysfault.test c9f2b0d8d677558f74de750c75e12a5454719d04
-F test/tabfunc01.test d6821e7042e5653104dac0c63d75eff24a2415ab1889fc68b5db7fde59464c59
+F test/tabfunc01.test 241425ce3998687ab24adba09cb95e8012e17499b84a0ed47e128ab45e588bef
F test/table.test eb3463b7add9f16a5bb836badf118cf391b809d09fdccd1f79684600d07ec132
F test/tableapi.test ecbcc29c4ab62c1912c3717c48ea5c5e59f7d64e4a91034e6148bd2b82f177f4
F test/tableopts.test dba698ba97251017b7c80d738c198d39ab747930
@@ -1521,7 +1526,7 @@ F test/tkt-6bfb98dfc0.test 24780633627b5cfc0635a5500c2389ebfb563336
F test/tkt-752e1646fc.test ea78d88d14fe9866bdd991c634483334639e13bf
F test/tkt-78e04e52ea.test b731f2ab7d1c2482ac5152097da02ef4805a45147ba9498d3cd9da27072f34d1
F test/tkt-7a31705a7e6.test 9e9c057b6a9497c8f7ba7b16871029414ccf6550e7345d9085d6d71c9a56bb6f
-F test/tkt-7bbfb7d442.test 7b2cd79c7a17ae6750e75ec1a7846712a69c9d18
+F test/tkt-7bbfb7d442.test e87b59e620700b5a52ecd92f05d56686c1cad9e1aa17456eada55e0bb821b698
F test/tkt-80ba201079.test 105a721e6aad0ae3c5946d7615d1e4d03f6145b8
F test/tkt-80e031a00f.test 9ee36348b761bf7c14261e002b75a4c0d5a04d4c
F test/tkt-8454a207b9.test aff2e76143cfa443ddce6f7d85968a2e9b57a3deb0b881b730120740555f9e2f
@@ -1604,7 +1609,7 @@ F test/tkt3346.test 6f67c3ed7db94dfc5df4f5f0b63809a1f611e01a
F test/tkt3357.test 77c37c6482b526fe89941ce951c22d011f5922ed
F test/tkt3419.test 1bbf36d7ea03b638c15804251287c2391f5c1f6b
F test/tkt3424.test 61f831bd2b071bd128fa5d00fbda57e656ca5812
-F test/tkt3442.test 6287173de5bb2d43693b1f822426018a209f9df49ce2f454808bac1771852330
+F test/tkt3442.test c9d95b4c8f4f35a51b523f35d2afd0ce124937812af296545ad551ff763504fd
F test/tkt3457.test 5651e2cbb94645b677ec663160b9e192b87b7d365aecdfb24e19f749575a6fc2
F test/tkt3461.test 228ea328a5a21e8663f80ee3d212a6ad92549a19
F test/tkt3493.test 1686cbde85f8721fc1bdc0ee72f2ef2f63139218
@@ -1628,7 +1633,7 @@ F test/tkt3810.test 3a3be9965d1861bd84019875851ad5ea90fd8d76b638361514a36a48ea53
F test/tkt3824.test 150aa00bb6220672e5f0eb14dc8eaa36750425f0
F test/tkt3832.test 2300d10d57562b89875b72148338ac3e14f8847d
F test/tkt3838.test 292e72489101cd1320d7278dc111c173ebf334d4
-F test/tkt3841.test 4659845bc53f809a5932c61c6ce8c5bb9d6b947f
+F test/tkt3841.test c4be3870f777f82aa788a588e40b4fb6627c3874e19f336d0d92894f929ffbfe
F test/tkt3871.test d921703d07c68f4fd5312073215a17fa34b0401d
F test/tkt3879.test 2ad5bef2c87e9991ce941e054c31abe26ef7fb90
F test/tkt3911.test 74cd324f3ba653040cc6d94cc4857b290d12d633
@@ -1685,15 +1690,15 @@ F test/unique.test 93f8b2ef5ea51b9495f8d6493429b1fd0f465264
F test/unique2.test 3674e9f2a3f1fbbfd4772ac74b7a97090d0f77d2
F test/unixexcl.test d936ba2b06794018e136418addd59a2354eeae97
F test/unordered.test 0edaf3411d300693bca595897c5201421c6c5ec787990a1dfe2f7f60ae93f1e2
-F test/update.test ef3ebbafeb4be5c96db831f40796e2e77ee846da5ee8b61cfedb1ff1b9e0cc23
+F test/update.test eb7f4eb172ce270e51bb67d7867521f33a63635bb671e261bbafccaef3bd6db2
F test/update2.test 67455bc61fcbcf96923c45b3bc4f87bc72be7d67575ad35f134906148c7b06d3
F test/upfrom1.tcl 8859d9d437f03b44174c4524a7a734a391fd4526fcff65be08285dafc9dc9041
F test/upfrom1.test 8cb06689e99cd707d884faa16da0e8eb26ff658bb01c47ddf72fadade666e6e1
F test/upfrom2.test 88d39cb755db5789541e645d4e2764abc697a56958f28a3f8451a0e9342bbd6b
F test/upfrom3.test 6130f24ebf97f5ea865e5d2a14a2d543fe5428a62e87cc60f62d875e45c1f5f0
F test/upfromfault.test 3a10075a0043f0c4fad6614b2c371f88a8ba5a4acab68b907438413865d6a8d6
-F test/upsert1.test 88f9e258c6a0eeeb85937b08831e8daad440ba41f125af48439e9d33f266fb18
-F test/upsert2.test 9c3cdbb1a890227f6504ce4b0e3de68f4cdfa16bb21d8641208a9239896c5a09
+F test/upsert1.test b0ae2f58680c5205b4bc1cdeed3c3d444057c506f6c44494fa3eac60731d68a2
+F test/upsert2.test 720e94d09f7362a282bc69b3c6b83d51daeaaf0440eb4920a08b86518b8c7496
F test/upsert3.test 88d7d590a1948a9cb6eac1b54b0642f67a9f35a1fc0f19b200e97d5d39e3179c
F test/upsert4.test 25d2a1da92f149331ae0c51ca6e3eee78189577585eab92de149900d62994fa5
F test/upsert5.test fff0dcfce73c649204543088d8e5bde01172676063ec9b8f8fc7f195abc386fe
@@ -1701,7 +1706,7 @@ F test/upsertfault.test f21ca47740841fdb4d61acfa7b17646d773e67724fe8c185b71c018d
F test/uri.test a2becabcb9fe25d08d1ae49c0788f4a75dda97bfe4c8641c2d04e224faf7a6e2
F test/uri2.test 9d3ba7a53ee167572d53a298ee4a5d38ec4a8fb7
F test/userauth01.test e740a2697a7b40d7c5003a7d7edaee16acd349a9
-F test/utf16align.test 54cd35a27c005a9b6e7815d887718780b6a462ae
+F test/utf16align.test 9fde0bb5d3a821594aa68c6829ab9c5453a084384137ebb9f6153e2d678039da
F test/vacuum-into.test f0b8c091df5305728b6973e9cce4166c861955b650dd3c599cb045d7160d3971
F test/vacuum.test ce91c39f7f91a4273bf620efad21086b5aa6ef1d
F test/vacuum2.test 9fd45ce6ce29f5614c249e03938d3567c06a9e772d4f155949f8eafe2d8af520
@@ -1719,7 +1724,7 @@ F test/vtab2.test 14d4ab26cee13ba6cf5c5601b158e4f57552d3b055cdd9406cf7f711e9c840
F test/vtab3.test b45f47d20f225ccc9c28dc915d92740c2dee311e
F test/vtab4.test 8e73ed268f3d596bc3590f45fc948fb40f28e9c3
F test/vtab5.test 889f444970393c73f1e077e2bdc5d845e157a391
-F test/vtab6.test 8e789f526e6594cf7ae933d1adee0caa87dc9f78
+F test/vtab6.test 82d5bb8fd3c0643102c1209e9ea353b168b7eb9c8db4406ab2ee2cbbdaead62c
F test/vtab7.test 70c6f4a1d6177144a8236e4172d5fba92e683440374664ad1f04851fbb335d3c
F test/vtab8.test e19fa4a538fcd1bb66c22825fa8f71618fb13583
F test/vtab9.test ea58d2b95d61955f87226381716b2d0b1d4e4f9b
@@ -1825,7 +1830,7 @@ F test/window3.test e9959a993c8a71e96433be8daaa1827d78b8921e4f12debd7bdbeb3c856e
F test/window4.tcl 6f85307eb67242b654d051f7da32a996a66aee039a09c5ae358541aa61720742
F test/window4.test fbead87f681400ac07ef3555e0488b544a47d35491f8bf09a7474b6f76ce9b4e
F test/window5.test d328dd18221217c49c144181975eea17339eaeaf0e9aa558cee3afb84652821e
-F test/window6.test f8d674254b23289cc17c84d79dec7eda7caa1dfb7836c43122cfdf3640d1df32
+F test/window6.test 311de885bd7e453134fa6747680bfb4a1be87c91720bf58703db945891e7d30b
F test/window7.tcl 6a1210f05d40ec89c22960213a22cd3f98d4e2f2eb20646c83c8c30d4d76108f
F test/window7.test 1d31276961ae7801edc72173edaf7593e3cbc79c06d1f1f09e20d8418af403cd
F test/window8.tcl 5e02e41d9d9a80f597063aed1a381eb19d1d0ef677a4f0df352c5365cf23f79c
@@ -1833,7 +1838,7 @@ F test/window8.test 4ab16817414af0c904abe2ebdf88eb6c2b00058b84f9748c6174ff11fc45
F test/window9.test 349c71eab4288a1ffc19e2f65872ec2c37e6cf8a1dda2ad300364b7450ae4836
F test/windowA.test 6d63dc1260daa17141a55007600581778523a8b420629f1282d2acfc36af23be
F test/windowB.test b67bda5645f3226790e1a360c4225241840b84adb5aa2e69bfb0b27eef3b84d9
-F test/windowC.test 8799158a2a3ea365980371400f08fd4dff70eadffa5a1e45d42430246da70706
+F test/windowC.test 6fd75f5bb2f1343d34e470e36e68f0ff638d8a42f6aa7d99471261b31a0d42f2
F test/windowerr.tcl f5acd6fbc210d7b5546c0e879d157888455cd4a17a1d3f28f07c1c8a387019e0
F test/windowerr.test a8b752402109c15aa1c5efe1b93ccb0ce1ef84fa964ae1cd6684dd0b3cc1819b
F test/windowfault.test 15094c1529424e62f798bc679e3fe9dfab6e8ba2f7dfe8c923b6248c31660a7c
@@ -1845,7 +1850,7 @@ F test/with4.test 257be66c0c67fee1defbbac0f685c3465e2cad037f21ce65f23f86084f1982
F test/with5.test 6248213c41fab36290b5b73aa3f937309dfba337004d9d8434c3fabc8c7d4be8
F test/with6.test 661d7e416bef6c0a2556b2c9f0c8178a5b15932bed65246abed99723a8d4e7c0
F test/withM.test 693b61765f2b387b5e3e24a4536e2e82de15ff64
-F test/without_rowid1.test df3de14f1cc422d2b0f9b79969b5ef8e51c86ed87834ab35fb5139403e7f5a03
+F test/without_rowid1.test 78fd9b437f4cdb46f76e6a510d545334e4f58e3e4ce37aaf19384eda5b27de8c
F test/without_rowid2.test af260339f79d13cb220288b67cd287fbcf81ad99
F test/without_rowid3.test 39ab0dd773eaa62e59b17093f875327630f54c4145458f6d2b053d68d4b2f67b
F test/without_rowid4.test 4e08bcbaee0399f35d58b5581881e7a6243d458a
@@ -1881,16 +1886,16 @@ F tool/genfkey.test b6afd7b825d797a1e1274f519ab5695373552ecad5cd373530c63533638a
F tool/getlock.c f4c39b651370156cae979501a7b156bdba50e7ce
F tool/index_usage.c f62a0c701b2c7ff2f3e21d206f093c123f222dbf07136a10ffd1ca15a5c706c5
F tool/kvtest-speed.sh 4761a9c4b3530907562314d7757995787f7aef8f
-F tool/lemon.c 258881835bd5bccd0c74fb110fe54244ff18e8e7ef3d949cbdab7187f02132bb
+F tool/lemon.c 1c5a14f6044193e42864c36de48359026fa2cdcf205a43cc1a31116101e27258
F tool/lempar.c 57478ea48420da05faa873c6d1616321caa5464644588c97fbe8e0ea04450748
F tool/libvers.c caafc3b689638a1d88d44bc5f526c2278760d9b9
F tool/loadfts.c c3c64e4d5e90e8ba41159232c2189dba4be7b862
-F tool/logest.c 11346aa019e2e77a00902aa7d0cabd27bd2e8cca
+F tool/logest.c c34e5944318415de513d29a6098df247a9618c96d83c38d4abd88641fe46e669
F tool/max-limits.c cbb635fbb37ae4d05f240bfb5b5270bb63c54439
F tool/merge-test.tcl de76b62f2de2a92d4c1ca4f976bce0aea6899e0229e250479b229b2a1914b176
F tool/mkautoconfamal.sh f62353eb6c06ab264da027fd4507d09914433dbdcab9cb011cdc18016f1ab3b8
F tool/mkccode.tcl 86463e68ce9c15d3041610fedd285ce32a5cf7a58fc88b3202b8b76837650dbe x
-F tool/mkctimec.tcl 5ef1891ed3d0e8143ff39bad7c01ed60c2817a2fb2d9a09487f7ccad2df621e4
+F tool/mkctimec.tcl 3147e9dfc4ad774e94f80084789ebaada9da9b6e66ddab16438cfc07999b6047 x
F tool/mkkeywordhash.c 35bfc41adacc4aa6ef6fca7fd0c63e0ec0534b78daf4d0cfdebe398216bbffc3
F tool/mkmsvcmin.tcl 6ecab9fe22c2c8de4d82d4c46797bda3d2deac8e763885f5a38d0c44a895ab33
F tool/mkopcodec.tcl 33d20791e191df43209b77d37f0ff0904620b28465cca6990cf8d60da61a07ef
@@ -1901,7 +1906,7 @@ F tool/mkshellc.tcl df5d249617f9cc94d5c48eb0401673eb3f31f383ecbc54e8a13ca3dd97e8
F tool/mksourceid.c 36aa8020014aed0836fd13c51d6dc9219b0df1761d6b5f58ff5b616211b079b9
F tool/mkspeedsql.tcl a1a334d288f7adfe6e996f2e712becf076745c97
F tool/mksqlite3c-noext.tcl 4f7cfef5152b0c91920355cbfc1d608a4ad242cb819f1aea07f6d0274f584a7f
-F tool/mksqlite3c.tcl bf9b40811aba68f73f2a8848fad9b1fb09fd54ab5b77e5227f18eea87ab60d92
+F tool/mksqlite3c.tcl 6f9e05facb51e906a1a7ef9f95274ef2ec91bf88b96732a9aed40647c605f419
F tool/mksqlite3h.tcl 1f5e4a1dbbbc43c83cc6e74fe32c6c620502240b66c7c0f33a51378e78fc4edf
F tool/mksqlite3internalh.tcl eb994013e833359137eb53a55acdad0b5ae1049b
F tool/mkvsix.tcl b9e0777a213c23156b6542842c238479e496ebf5
@@ -1913,7 +1918,7 @@ F tool/replace.tcl 937c931ad560688e85bdd6258bdc754371bb1e2732e1fb28ef441e44c9228
F tool/restore_jrnl.tcl 6957a34f8f1f0f8285e07536225ec3b292a9024a
F tool/rollback-test.c 9fc98427d1e23e84429d7e6d07d9094fbdec65a5
F tool/run-speed-test.sh f95d19fd669b68c4c38b6b475242841d47c66076
-F tool/showdb.c 7cc12c6deeddfe40ba5d948b408730696d8365988da05fcb6b6a90ea4965e2b4
+F tool/showdb.c 72239e95e1d05a2941c6a1d86b4d857812be4dadd71f24e381db572f350fc172
F tool/showjournal.c 5bad7ae8784a43d2b270d953060423b8bd480818
F tool/showlocks.c 9cc5e66d4ebbf2d194f39db2527ece92077e86ae627ddd233ee48e16e8142564
F tool/showshm.c a0ab6ec32dd1f11218ca2a4018f8fb875b59414801ab8ceed8b2e69b7b45a809
@@ -1965,7 +1970,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P 2171996a02ad2ec571570749ccee421bc0859a690c8393c5edda6cf164d2c8db b0a70a2356c44d65c54c6d9bdf05972071462e72c28d6c6e593147ffa3d27ef2
-R a8bdc946bdcbc515532b753a755a4462
-U dan
-Z 007a67a7baf46f1b69e8ed1cd0cfdb34
+P a92eca6c9ca45208df5764e50dec2b257244176f5893b4bee7f9475c4e8d8c8b 82f031b41dbf041cdbdfb2f3ccc8d118b22d9e523e54a32e882a67535e9973c5
+R 2fdaa4db2743ba577b9d263296a14e36
+U drh
+Z 99557125a79fbfb6d45a17bf98121af0
+# Remove this line to create a well-formed Fossil manifest.
diff --git a/manifest.uuid b/manifest.uuid
index f5b5a8fdd1..037008113e 100644
--- a/manifest.uuid
+++ b/manifest.uuid
@@ -1 +1 @@
-a92eca6c9ca45208df5764e50dec2b257244176f5893b4bee7f9475c4e8d8c8b
\ No newline at end of file
+45fa7efecb8d28dd68b844c9f74b751aab6e7ad7d03f03e8a5881f0e09fb86a2
\ No newline at end of file
diff --git a/src/alter.c b/src/alter.c
index bb43edbeda..f3f4f570e6 100644
--- a/src/alter.c
+++ b/src/alter.c
@@ -450,7 +450,7 @@ void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
" THEN raise(ABORT,'CHECK constraint failed')"
" ELSE raise(ABORT,'NOT NULL constraint failed')"
" END"
- " FROM pragma_quick_check(\"%w\",\"%w\")"
+ " FROM pragma_quick_check(%Q,%Q)"
" WHERE quick_check GLOB 'CHECK*' OR quick_check GLOB 'NULL*'",
zTab, zDb
);
@@ -1126,7 +1126,6 @@ static int renameParseSql(
int bTemp /* True if SQL is from temp schema */
){
int rc;
- char *zErr = 0;
db->init.iDb = bTemp ? 1 : sqlite3FindDbName(db, zDb);
@@ -1137,10 +1136,7 @@ static int renameParseSql(
p->eParseMode = PARSE_MODE_RENAME;
p->db = db;
p->nQueryLoop = 1;
- rc = zSql ? sqlite3RunParser(p, zSql, &zErr) : SQLITE_NOMEM;
- assert( p->zErrMsg==0 );
- assert( rc!=SQLITE_OK || zErr==0 );
- p->zErrMsg = zErr;
+ rc = zSql ? sqlite3RunParser(p, zSql) : SQLITE_NOMEM;
if( db->mallocFailed ) rc = SQLITE_NOMEM;
if( rc==SQLITE_OK
&& p->pNewTable==0 && p->pNewIndex==0 && p->pNewTrigger==0
diff --git a/src/btree.c b/src/btree.c
index f4c29ea60e..ea267a2a27 100644
--- a/src/btree.c
+++ b/src/btree.c
@@ -1465,18 +1465,32 @@ static void btreeParseCellPtr(
**
** pIter += getVarint(pIter, (u64*)&pInfo->nKey);
**
- ** The code is inlined to avoid a function call.
+ ** The code is inlined and the loop is unrolled for performance.
+ ** This routine is a high-runner.
*/
iKey = *pIter;
if( iKey>=0x80 ){
- u8 *pEnd = &pIter[7];
- iKey &= 0x7f;
- while(1){
- iKey = (iKey<<7) | (*++pIter & 0x7f);
- if( (*pIter)<0x80 ) break;
- if( pIter>=pEnd ){
- iKey = (iKey<<8) | *++pIter;
- break;
+ u8 x;
+ iKey = ((iKey&0x7f)<<7) | ((x = *++pIter) & 0x7f);
+ if( x>=0x80 ){
+ iKey = (iKey<<7) | ((x =*++pIter) & 0x7f);
+ if( x>=0x80 ){
+ iKey = (iKey<<7) | ((x = *++pIter) & 0x7f);
+ if( x>=0x80 ){
+ iKey = (iKey<<7) | ((x = *++pIter) & 0x7f);
+ if( x>=0x80 ){
+ iKey = (iKey<<7) | ((x = *++pIter) & 0x7f);
+ if( x>=0x80 ){
+ iKey = (iKey<<7) | ((x = *++pIter) & 0x7f);
+ if( x>=0x80 ){
+ iKey = (iKey<<7) | ((x = *++pIter) & 0x7f);
+ if( x>=0x80 ){
+ iKey = (iKey<<8) | (*++pIter);
+ }
+ }
+ }
+ }
+ }
}
}
}
@@ -1486,7 +1500,7 @@ static void btreeParseCellPtr(
pInfo->nPayload = nPayload;
pInfo->pPayload = pIter;
testcase( nPayload==pPage->maxLocal );
- testcase( nPayload==pPage->maxLocal+1 );
+ testcase( nPayload==(u32)pPage->maxLocal+1 );
if( nPayload<=pPage->maxLocal ){
/* This is the (easy) common case where the entire payload fits
** on the local page. No overflow is required.
@@ -1523,7 +1537,7 @@ static void btreeParseCellPtrIndex(
pInfo->nPayload = nPayload;
pInfo->pPayload = pIter;
testcase( nPayload==pPage->maxLocal );
- testcase( nPayload==pPage->maxLocal+1 );
+ testcase( nPayload==(u32)pPage->maxLocal+1 );
if( nPayload<=pPage->maxLocal ){
/* This is the (easy) common case where the entire payload fits
** on the local page. No overflow is required.
@@ -1586,7 +1600,7 @@ static u16 cellSizePtr(MemPage *pPage, u8 *pCell){
while( (*pIter++)&0x80 && pItermaxLocal );
- testcase( nSize==pPage->maxLocal+1 );
+ testcase( nSize==(u32)pPage->maxLocal+1 );
if( nSize<=pPage->maxLocal ){
nSize += (u32)(pIter - pCell);
if( nSize<4 ) nSize = 4;
@@ -1594,7 +1608,7 @@ static u16 cellSizePtr(MemPage *pPage, u8 *pCell){
int minLocal = pPage->minLocal;
nSize = minLocal + (nSize - minLocal) % (pPage->pBt->usableSize - 4);
testcase( nSize==pPage->maxLocal );
- testcase( nSize==pPage->maxLocal+1 );
+ testcase( nSize==(u32)pPage->maxLocal+1 );
if( nSize>pPage->maxLocal ){
nSize = minLocal;
}
@@ -2944,30 +2958,38 @@ static int removeFromSharingList(BtShared *pBt){
** MX_CELL_SIZE(pBt) bytes with a 4-byte prefix for a left-child
** pointer.
*/
-static void allocateTempSpace(BtShared *pBt){
- if( !pBt->pTmpSpace ){
- pBt->pTmpSpace = sqlite3PageMalloc( pBt->pageSize );
-
- /* One of the uses of pBt->pTmpSpace is to format cells before
- ** inserting them into a leaf page (function fillInCell()). If
- ** a cell is less than 4 bytes in size, it is rounded up to 4 bytes
- ** by the various routines that manipulate binary cells. Which
- ** can mean that fillInCell() only initializes the first 2 or 3
- ** bytes of pTmpSpace, but that the first 4 bytes are copied from
- ** it into a database page. This is not actually a problem, but it
- ** does cause a valgrind error when the 1 or 2 bytes of unitialized
- ** data is passed to system call write(). So to avoid this error,
- ** zero the first 4 bytes of temp space here.
- **
- ** Also: Provide four bytes of initialized space before the
- ** beginning of pTmpSpace as an area available to prepend the
- ** left-child pointer to the beginning of a cell.
- */
- if( pBt->pTmpSpace ){
- memset(pBt->pTmpSpace, 0, 8);
- pBt->pTmpSpace += 4;
- }
+static SQLITE_NOINLINE int allocateTempSpace(BtShared *pBt){
+ assert( pBt!=0 );
+ assert( pBt->pTmpSpace==0 );
+ /* This routine is called only by btreeCursor() when allocating the
+ ** first write cursor for the BtShared object */
+ assert( pBt->pCursor!=0 && (pBt->pCursor->curFlags & BTCF_WriteFlag)!=0 );
+ pBt->pTmpSpace = sqlite3PageMalloc( pBt->pageSize );
+ if( pBt->pTmpSpace==0 ){
+ BtCursor *pCur = pBt->pCursor;
+ pBt->pCursor = pCur->pNext; /* Unlink the cursor */
+ memset(pCur, 0, sizeof(*pCur));
+ return SQLITE_NOMEM_BKPT;
}
+
+ /* One of the uses of pBt->pTmpSpace is to format cells before
+ ** inserting them into a leaf page (function fillInCell()). If
+ ** a cell is less than 4 bytes in size, it is rounded up to 4 bytes
+ ** by the various routines that manipulate binary cells. Which
+ ** can mean that fillInCell() only initializes the first 2 or 3
+ ** bytes of pTmpSpace, but that the first 4 bytes are copied from
+ ** it into a database page. This is not actually a problem, but it
+ ** does cause a valgrind error when the 1 or 2 bytes of unitialized
+ ** data is passed to system call write(). So to avoid this error,
+ ** zero the first 4 bytes of temp space here.
+ **
+ ** Also: Provide four bytes of initialized space before the
+ ** beginning of pTmpSpace as an area available to prepend the
+ ** left-child pointer to the beginning of a cell.
+ */
+ memset(pBt->pTmpSpace, 0, 8);
+ pBt->pTmpSpace += 4;
+ return SQLITE_OK;
}
/*
@@ -3464,9 +3486,13 @@ static int lockBtree(BtShared *pBt){
pageSize-usableSize);
return rc;
}
- if( sqlite3WritableSchema(pBt->db)==0 && nPage>nPageFile ){
- rc = SQLITE_CORRUPT_BKPT;
- goto page1_init_failed;
+ if( nPage>nPageFile ){
+ if( sqlite3WritableSchema(pBt->db)==0 ){
+ rc = SQLITE_CORRUPT_BKPT;
+ goto page1_init_failed;
+ }else{
+ nPage = nPageFile;
+ }
}
/* EVIDENCE-OF: R-28312-64704 However, the usable size is not allowed to
** be less than 480. In other words, if the page size is 512, then the
@@ -4692,7 +4718,7 @@ static void btreeSetNPage(BtShared *pBt, MemPage *pPage1){
int nPage = get4byte(&pPage1->aData[28]);
testcase( nPage==0 );
if( nPage==0 ) sqlite3PagerPagecount(pBt->pPager, &nPage);
- testcase( pBt->nPage!=nPage );
+ testcase( pBt->nPage!=(u32)nPage );
pBt->nPage = nPage;
}
@@ -4908,10 +4934,6 @@ static int btreeCursor(
assert( pBt->pPage1 && pBt->pPage1->aData );
assert( wrFlag==0 || (pBt->btsFlags & BTS_READ_ONLY)==0 );
- if( wrFlag ){
- allocateTempSpace(pBt);
- if( pBt->pTmpSpace==0 ) return SQLITE_NOMEM_BKPT;
- }
if( iTable<=1 ){
if( iTable<1 ){
return SQLITE_CORRUPT_BKPT;
@@ -4928,19 +4950,25 @@ static int btreeCursor(
pCur->pKeyInfo = pKeyInfo;
pCur->pBtree = p;
pCur->pBt = pBt;
- pCur->curFlags = wrFlag ? BTCF_WriteFlag : 0;
- pCur->curPagerFlags = wrFlag ? 0 : PAGER_GET_READONLY;
+ pCur->curFlags = 0;
/* If there are two or more cursors on the same btree, then all such
** cursors *must* have the BTCF_Multiple flag set. */
for(pX=pBt->pCursor; pX; pX=pX->pNext){
if( pX->pgnoRoot==iTable ){
pX->curFlags |= BTCF_Multiple;
- pCur->curFlags |= BTCF_Multiple;
+ pCur->curFlags = BTCF_Multiple;
}
}
+ pCur->eState = CURSOR_INVALID;
pCur->pNext = pBt->pCursor;
pBt->pCursor = pCur;
- pCur->eState = CURSOR_INVALID;
+ if( wrFlag ){
+ pCur->curFlags |= BTCF_WriteFlag;
+ pCur->curPagerFlags = 0;
+ if( pBt->pTmpSpace==0 ) return allocateTempSpace(pBt);
+ }else{
+ pCur->curPagerFlags = PAGER_GET_READONLY;
+ }
return SQLITE_OK;
}
static int btreeCursorWithLock(
@@ -5721,7 +5749,7 @@ static int moveToRoot(BtCursor *pCur){
while( --pCur->iPage ){
releasePageNotNull(pCur->apPage[pCur->iPage]);
}
- pCur->pPage = pCur->apPage[0];
+ pRoot = pCur->pPage = pCur->apPage[0];
goto skip_init;
}
}else if( pCur->pgnoRoot==0 ){
@@ -5769,7 +5797,6 @@ skip_init:
pCur->info.nSize = 0;
pCur->curFlags &= ~(BTCF_AtLast|BTCF_ValidNKey|BTCF_ValidOvfl);
- pRoot = pCur->pPage;
if( pRoot->nCell>0 ){
pCur->eState = CURSOR_VALID;
}else if( !pRoot->leaf ){
@@ -6010,7 +6037,6 @@ int sqlite3BtreeTableMoveto(
upr = pPage->nCell-1;
assert( biasRight==0 || biasRight==1 );
idx = upr>>(1-biasRight); /* idx = biasRight ? upr : (lwr+upr)/2; */
- pCur->ix = (u16)idx;
for(;;){
i64 nCellKey;
pCell = findCellPastPtr(pPage, idx);
@@ -6152,7 +6178,6 @@ int sqlite3BtreeIndexMoveto(
lwr = 0;
upr = pPage->nCell-1;
idx = upr>>1; /* idx = (lwr+upr)/2; */
- pCur->ix = (u16)idx;
for(;;){
int nCell; /* Size of the pCell cell in bytes */
pCell = findCellPastPtr(pPage, idx);
@@ -7277,16 +7302,18 @@ static void dropCell(MemPage *pPage, int idx, int sz, int *pRC){
int hdr; /* Beginning of the header. 0 most pages. 100 page 1 */
if( *pRC ) return;
- assert( idx>=0 && idxnCell );
+ assert( idx>=0 );
+ assert( idxnCell );
assert( CORRUPT_DB || sz==cellSize(pPage, idx) );
assert( sqlite3PagerIswriteable(pPage->pDbPage) );
assert( sqlite3_mutex_held(pPage->pBt->mutex) );
assert( pPage->nFree>=0 );
data = pPage->aData;
ptr = &pPage->aCellIdx[2*idx];
+ assert( pPage->pBt->usableSize > (u32)(ptr-data) );
pc = get2byte(ptr);
hdr = pPage->hdrOffset;
- testcase( pc==get2byte(&data[hdr+5]) );
+ testcase( pc==(u32)get2byte(&data[hdr+5]) );
testcase( pc+sz==pPage->pBt->usableSize );
if( pc+sz > pPage->pBt->usableSize ){
*pRC = SQLITE_CORRUPT_BKPT;
@@ -7577,7 +7604,7 @@ static int rebuildPage(
assert( i(u32)usableSize) ){ j = 0; }
+ if( j>(u32)usableSize ){ j = 0; }
memcpy(&pTmp[j], &aData[j], usableSize - j);
for(k=0; pCArray->ixNx[k]<=i && ALWAYS(kpPg->aDataEnd) ) goto editpage_fail;
+ if( pData>pPg->aDataEnd ) goto editpage_fail;
/* Add cells to the start of the page */
if( iNewpBtree;
BtShared *pBt = p->pBt;
- int rc; /* Return code */
- MemPage *pPage; /* Page to delete cell from */
- unsigned char *pCell; /* Pointer to cell to delete */
- int iCellIdx; /* Index of cell to delete */
- int iCellDepth; /* Depth of node containing pCell */
- CellInfo info; /* Size of the cell being deleted */
- int bSkipnext = 0; /* Leaf cursor in SKIPNEXT state */
- u8 bPreserve = flags & BTREE_SAVEPOSITION; /* Keep cursor valid */
+ int rc; /* Return code */
+ MemPage *pPage; /* Page to delete cell from */
+ unsigned char *pCell; /* Pointer to cell to delete */
+ int iCellIdx; /* Index of cell to delete */
+ int iCellDepth; /* Depth of node containing pCell */
+ CellInfo info; /* Size of the cell being deleted */
+ u8 bPreserve; /* Keep cursor valid. 2 for CURSOR_SKIPNEXT */
assert( cursorOwnsBtShared(pCur) );
assert( pBt->inTransaction==TRANS_WRITE );
@@ -9712,18 +9738,31 @@ int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){
iCellDepth = pCur->iPage;
iCellIdx = pCur->ix;
pPage = pCur->pPage;
+ if( pPage->nCell<=iCellIdx ){
+ return SQLITE_CORRUPT_BKPT;
+ }
pCell = findCell(pPage, iCellIdx);
- if( pPage->nFree<0 && btreeComputeFreeSpace(pPage) ) return SQLITE_CORRUPT;
+ if( pPage->nFree<0 && btreeComputeFreeSpace(pPage) ){
+ return SQLITE_CORRUPT_BKPT;
+ }
- /* If the bPreserve flag is set to true, then the cursor position must
+ /* If the BTREE_SAVEPOSITION bit is on, then the cursor position must
** be preserved following this delete operation. If the current delete
** will cause a b-tree rebalance, then this is done by saving the cursor
** key and leaving the cursor in CURSOR_REQUIRESEEK state before
** returning.
**
- ** Or, if the current delete will not cause a rebalance, then the cursor
+ ** If the current delete will not cause a rebalance, then the cursor
** will be left in CURSOR_SKIPNEXT state pointing to the entry immediately
- ** before or after the deleted entry. In this case set bSkipnext to true. */
+ ** before or after the deleted entry.
+ **
+ ** The bPreserve value records which path is required:
+ **
+ ** bPreserve==0 Not necessary to save the cursor position
+ ** bPreserve==1 Use CURSOR_REQUIRESEEK to save the cursor position
+ ** bPreserve==2 Cursor won't move. Set CURSOR_SKIPNEXT.
+ */
+ bPreserve = (flags & BTREE_SAVEPOSITION)!=0;
if( bPreserve ){
if( !pPage->leaf
|| (pPage->nFree+cellSizePtr(pPage,pCell)+2)>(int)(pBt->usableSize*2/3)
@@ -9734,7 +9773,7 @@ int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){
rc = saveCursorKey(pCur);
if( rc ) return rc;
}else{
- bSkipnext = 1;
+ bPreserve = 2;
}
}
@@ -9834,8 +9873,8 @@ int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){
}
if( rc==SQLITE_OK ){
- if( bSkipnext ){
- assert( bPreserve && (pCur->iPage==iCellDepth || CORRUPT_DB) );
+ if( bPreserve>1 ){
+ assert( (pCur->iPage==iCellDepth || CORRUPT_DB) );
assert( pPage==pCur->pPage || CORRUPT_DB );
assert( (pPage->nCell>0 || CORRUPT_DB) && iCellIdx<=pPage->nCell );
pCur->eState = CURSOR_SKIPNEXT;
diff --git a/src/build.c b/src/build.c
index 0d9c571292..b242d7d734 100644
--- a/src/build.c
+++ b/src/build.c
@@ -170,9 +170,10 @@ void sqlite3FinishCoding(Parse *pParse){
int i;
int reg;
- if( pReturning->nRetCol==0 ){
+ if( NEVER(pReturning->nRetCol==0) ){
assert( CORRUPT_DB );
}else{
+ sqlite3VdbeAddOp0(v, OP_FkCheck);
addrRewind =
sqlite3VdbeAddOp1(v, OP_Rewind, pReturning->iRetCur);
VdbeCoverage(v);
@@ -265,7 +266,7 @@ void sqlite3FinishCoding(Parse *pParse){
if( pParse->bReturning ){
Returning *pRet = pParse->u1.pReturning;
- if( pRet->nRetCol==0 ){
+ if( NEVER(pRet->nRetCol==0) ){
assert( CORRUPT_DB );
}else{
sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pRet->iRetCur, pRet->nRetCol);
@@ -306,7 +307,6 @@ void sqlite3FinishCoding(Parse *pParse){
void sqlite3NestedParse(Parse *pParse, const char *zFormat, ...){
va_list ap;
char *zSql;
- char *zErrMsg = 0;
sqlite3 *db = pParse->db;
u32 savedDbFlags = db->mDbFlags;
char saveBuf[PARSE_TAIL_SZ];
@@ -328,9 +328,8 @@ void sqlite3NestedParse(Parse *pParse, const char *zFormat, ...){
memcpy(saveBuf, PARSE_TAIL(pParse), PARSE_TAIL_SZ);
memset(PARSE_TAIL(pParse), 0, PARSE_TAIL_SZ);
db->mDbFlags |= DBFLAG_PreferBuiltin;
- sqlite3RunParser(pParse, zSql, &zErrMsg);
+ sqlite3RunParser(pParse, zSql);
db->mDbFlags = savedDbFlags;
- sqlite3DbFree(db, zErrMsg);
sqlite3DbFree(db, zSql);
memcpy(PARSE_TAIL(pParse), saveBuf, PARSE_TAIL_SZ);
pParse->nested--;
@@ -4405,13 +4404,13 @@ void sqlite3CreateIndex(
/* Add an entry in sqlite_schema for this index
*/
sqlite3NestedParse(pParse,
- "INSERT INTO %Q." LEGACY_SCHEMA_TABLE " VALUES('index',%Q,%Q,#%d,%Q);",
- db->aDb[iDb].zDbSName,
- pIndex->zName,
- pTab->zName,
- iMem,
- zStmt
- );
+ "INSERT INTO %Q." LEGACY_SCHEMA_TABLE " VALUES('index',%Q,%Q,#%d,%Q);",
+ db->aDb[iDb].zDbSName,
+ pIndex->zName,
+ pTab->zName,
+ iMem,
+ zStmt
+ );
sqlite3DbFree(db, zStmt);
/* Fill the index with data and reparse the schema. Code an OP_Expire
@@ -4959,7 +4958,7 @@ SrcList *sqlite3SrcListAppendFromTerm(
pItem->pUsing = pUsing;
return p;
- append_from_error:
+append_from_error:
assert( p==0 );
sqlite3ExprDelete(db, pOn);
sqlite3IdListDelete(db, pUsing);
diff --git a/src/callback.c b/src/callback.c
index 936c374abd..7d8f9dcbce 100644
--- a/src/callback.c
+++ b/src/callback.c
@@ -358,7 +358,6 @@ void sqlite3InsertBuiltinFuncs(
const char *zName = aDef[i].zName;
int nName = sqlite3Strlen30(zName);
int h = SQLITE_FUNC_HASH(zName[0], nName);
- assert( zName[0]>='a' && zName[0]<='z' );
assert( aDef[i].funcFlags & SQLITE_FUNC_BUILTIN );
pOther = sqlite3FunctionSearch(h, zName);
if( pOther ){
diff --git a/src/ctime.c b/src/ctime.c
index de68ea7f57..1463e4f552 100644
--- a/src/ctime.c
+++ b/src/ctime.c
@@ -1,3 +1,11 @@
+/* DO NOT EDIT!
+** This file is automatically generated by the script in the canonical
+** SQLite source tree at tool/mkctimec.tcl.
+**
+** To modify this header, edit any of the various lists in that script
+** which specify categories of generated conditionals in this file.
+*/
+
/*
** 2010 February 23
**
@@ -46,9 +54,6 @@
*/
static const char * const sqlite3azCompileOpt[] = {
-/*
-** BEGIN CODE GENERATED BY tool/mkctime.tcl
-*/
#ifdef SQLITE_32BIT_ROWID
"32BIT_ROWID",
#endif
@@ -257,9 +262,6 @@ static const char * const sqlite3azCompileOpt[] = {
#ifdef SQLITE_ENABLE_IOTRACE
"ENABLE_IOTRACE",
#endif
-#ifdef SQLITE_ENABLE_JSON1
- "ENABLE_JSON1",
-#endif
#ifdef SQLITE_ENABLE_LOAD_EXTENSION
"ENABLE_LOAD_EXTENSION",
#endif
@@ -583,6 +585,9 @@ static const char * const sqlite3azCompileOpt[] = {
#ifdef SQLITE_OMIT_INTROSPECTION_PRAGMAS
"OMIT_INTROSPECTION_PRAGMAS",
#endif
+#ifdef SQLITE_OMIT_JSON
+ "OMIT_JSON",
+#endif
#ifdef SQLITE_OMIT_LIKE_OPTIMIZATION
"OMIT_LIKE_OPTIMIZATION",
#endif
@@ -771,10 +776,8 @@ static const char * const sqlite3azCompileOpt[] = {
#ifdef SQLITE_ZERO_MALLOC
"ZERO_MALLOC",
#endif
-/*
-** END CODE GENERATED BY tool/mkctime.tcl
-*/
-};
+
+} ;
const char **sqlite3CompileOptions(int *pnOpt){
*pnOpt = sizeof(sqlite3azCompileOpt) / sizeof(sqlite3azCompileOpt[0]);
diff --git a/src/date.c b/src/date.c
index 20a0a5d175..b018c39f68 100644
--- a/src/date.c
+++ b/src/date.c
@@ -523,7 +523,9 @@ static int osLocaltime(time_t *t, struct tm *pTm){
if( sqlite3GlobalConfig.bLocaltimeFault ) pX = 0;
#endif
if( pX ) *pTm = *pX;
+#if SQLITE_THREADSAFE>0
sqlite3_mutex_leave(mutex);
+#endif
rc = pX==0;
#else
#ifndef SQLITE_UNTESTABLE
@@ -615,18 +617,17 @@ static sqlite3_int64 localtimeOffset(
** of several units of time.
*/
static const struct {
- u8 eType; /* Transformation type code */
- u8 nName; /* Length of th name */
- char *zName; /* Name of the transformation */
- double rLimit; /* Maximum NNN value for this transform */
- double rXform; /* Constant used for this transform */
+ u8 nName; /* Length of the name */
+ char zName[7]; /* Name of the transformation */
+ float rLimit; /* Maximum NNN value for this transform */
+ float rXform; /* Constant used for this transform */
} aXformType[] = {
- { 0, 6, "second", 464269060800.0, 1000.0 },
- { 0, 6, "minute", 7737817680.0, 60000.0 },
- { 0, 4, "hour", 128963628.0, 3600000.0 },
- { 0, 3, "day", 5373485.0, 86400000.0 },
- { 1, 5, "month", 176546.0, 2592000000.0 },
- { 2, 4, "year", 14713.0, 31536000000.0 },
+ { 6, "second", 4.6427e+14, 1.0 },
+ { 6, "minute", 7.7379e+12, 60.0 },
+ { 4, "hour", 1.2897e+11, 3600.0 },
+ { 3, "day", 5373485.0, 86400.0 },
+ { 5, "month", 176546.0, 2592000.0 },
+ { 4, "year", 14713.0, 31536000.0 },
};
/*
@@ -662,6 +663,45 @@ static int parseModifier(
int rc = 1;
double r;
switch(sqlite3UpperToLower[(u8)z[0]] ){
+ case 'a': {
+ /*
+ ** auto
+ **
+ ** If rawS is available, then interpret as a julian day number, or
+ ** a unix timestamp, depending on its magnitude.
+ */
+ if( sqlite3_stricmp(z, "auto")==0 ){
+ if( !p->rawS || p->validJD ){
+ rc = 0;
+ p->rawS = 0;
+ }else if( p->s>=-210866760000 && p->s<=253402300799 ){
+ r = p->s*1000.0 + 210866760000000.0;
+ clearYMD_HMS_TZ(p);
+ p->iJD = (sqlite3_int64)(r + 0.5);
+ p->validJD = 1;
+ p->rawS = 0;
+ rc = 0;
+ }
+ }
+ break;
+ }
+ case 'j': {
+ /*
+ ** julianday
+ **
+ ** Always interpret the prior number as a julian-day value. If this
+ ** is not the first modifier, or if the prior argument is not a numeric
+ ** value in the allowed range of julian day numbers understood by
+ ** SQLite (0..5373484.5) then the result will be NULL.
+ */
+ if( sqlite3_stricmp(z, "julianday")==0 ){
+ if( p->validJD && p->rawS ){
+ rc = 0;
+ p->rawS = 0;
+ }
+ }
+ break;
+ }
#ifndef SQLITE_OMIT_LOCALTIME
case 'l': {
/* localtime
@@ -824,9 +864,10 @@ static int parseModifier(
&& sqlite3_strnicmp(aXformType[i].zName, z, n)==0
&& r>-aXformType[i].rLimit && rM += (int)r;
x = p->M>0 ? (p->M-1)/12 : (p->M-12)/12;
@@ -836,8 +877,9 @@ static int parseModifier(
r -= (int)r;
break;
}
- case 2: { /* Special processing to add years */
+ case 5: { /* Special processing to add years */
int y = (int)r;
+ assert( strcmp(aXformType[i].zName,"year")==0 );
computeYMD_HMS(p);
p->Y += y;
p->validJD = 0;
@@ -846,7 +888,7 @@ static int parseModifier(
}
}
computeJD(p);
- p->iJD += (sqlite3_int64)(r*aXformType[i].rXform + rRounder);
+ p->iJD += (sqlite3_int64)(r*1000.0*aXformType[i].rXform + rRounder);
rc = 0;
break;
}
@@ -926,6 +968,24 @@ static void juliandayFunc(
}
}
+/*
+** unixepoch( TIMESTRING, MOD, MOD, ...)
+**
+** Return the number of seconds (including fractional seconds) since
+** the unix epoch of 1970-01-01 00:00:00 GMT.
+*/
+static void unixepochFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ DateTime x;
+ if( isDate(context, argc, argv, &x)==0 ){
+ computeJD(&x);
+ sqlite3_result_int64(context, x.iJD/1000 - 21086676*(i64)10000);
+ }
+}
+
/*
** datetime( TIMESTRING, MOD, MOD, ...)
**
@@ -1202,6 +1262,7 @@ void sqlite3RegisterDateTimeFunctions(void){
static FuncDef aDateTimeFuncs[] = {
#ifndef SQLITE_OMIT_DATETIME_FUNCS
PURE_DATE(julianday, -1, 0, 0, juliandayFunc ),
+ PURE_DATE(unixepoch, -1, 0, 0, unixepochFunc ),
PURE_DATE(date, -1, 0, 0, dateFunc ),
PURE_DATE(time, -1, 0, 0, timeFunc ),
PURE_DATE(datetime, -1, 0, 0, datetimeFunc ),
diff --git a/src/delete.c b/src/delete.c
index e2b283ea47..9c56858e79 100644
--- a/src/delete.c
+++ b/src/delete.c
@@ -44,6 +44,16 @@ Table *sqlite3SrcListLookup(Parse *pParse, SrcList *pSrc){
return pTab;
}
+/* Generate byte-code that will report the number of rows modified
+** by a DELETE, INSERT, or UPDATE statement.
+*/
+void sqlite3CodeChangeCount(Vdbe *v, int regCounter, const char *zColName){
+ sqlite3VdbeAddOp0(v, OP_FkCheck);
+ sqlite3VdbeAddOp2(v, OP_ResultRow, regCounter, 1);
+ sqlite3VdbeSetNumCols(v, 1);
+ sqlite3VdbeSetColName(v, 0, COLNAME_NAME, zColName, SQLITE_STATIC);
+}
+
/* Return true if table pTab is read-only.
**
** A table is read-only if any of the following are true:
@@ -619,9 +629,7 @@ void sqlite3DeleteFrom(
** invoke the callback function.
*/
if( memCnt ){
- sqlite3VdbeAddOp2(v, OP_ChngCntRow, memCnt, 1);
- sqlite3VdbeSetNumCols(v, 1);
- sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows deleted", SQLITE_STATIC);
+ sqlite3CodeChangeCount(v, memCnt, "rows deleted");
}
delete_from_cleanup:
diff --git a/src/expr.c b/src/expr.c
index 2a00748846..a51d37a7b7 100644
--- a/src/expr.c
+++ b/src/expr.c
@@ -2457,7 +2457,7 @@ int sqlite3ExprCanBeNull(const Expr *p){
return ExprHasProperty(p, EP_CanBeNull) ||
p->y.pTab==0 || /* Reference to column of index on expression */
(p->iColumn>=0
- && ALWAYS(p->y.pTab->aCol!=0) /* Defense against OOM problems */
+ && p->y.pTab->aCol!=0 /* Possible due to prior error */
&& p->y.pTab->aCol[p->iColumn].notNull==0);
default:
return 1;
diff --git a/src/fkey.c b/src/fkey.c
index 13b08dfe19..6ee35bf320 100644
--- a/src/fkey.c
+++ b/src/fkey.c
@@ -702,6 +702,25 @@ static void fkTriggerDelete(sqlite3 *dbMem, Trigger *p){
}
}
+/*
+** Clear the apTrigger[] cache of CASCADE triggers for all foreign keys
+** in a particular database. This needs to happen when the schema
+** changes.
+*/
+void sqlite3FkClearTriggerCache(sqlite3 *db, int iDb){
+ HashElem *k;
+ Hash *pHash = &db->aDb[iDb].pSchema->tblHash;
+ for(k=sqliteHashFirst(pHash); k; k=sqliteHashNext(k)){
+ Table *pTab = sqliteHashData(k);
+ FKey *pFKey;
+ if( !IsOrdinaryTable(pTab) ) continue;
+ for(pFKey=pTab->u.tab.pFKey; pFKey; pFKey=pFKey->pNextFrom){
+ fkTriggerDelete(db, pFKey->apTrigger[0]); pFKey->apTrigger[0] = 0;
+ fkTriggerDelete(db, pFKey->apTrigger[1]); pFKey->apTrigger[1] = 0;
+ }
+ }
+}
+
/*
** This function is called to generate code that runs when table pTab is
** being dropped from the database. The SrcList passed as the second argument
diff --git a/src/func.c b/src/func.c
index fdcc82e52c..05629d6d8b 100644
--- a/src/func.c
+++ b/src/func.c
@@ -97,6 +97,17 @@ static void typeofFunc(
sqlite3_result_text(context, azType[i], -1, SQLITE_STATIC);
}
+/* subtype(X)
+**
+** Return the subtype of X
+*/
+static void subtypeFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ sqlite3_result_int(context, sqlite3_value_subtype(argv[0]));
+}
/*
** Implementation of the length() function
@@ -258,7 +269,7 @@ endInstrOOM:
}
/*
-** Implementation of the printf() function.
+** Implementation of the printf() (a.k.a. format()) SQL function.
*/
static void printfFunc(
sqlite3_context *context,
@@ -1029,39 +1040,42 @@ static const char hexdigits[] = {
};
/*
-** Implementation of the QUOTE() function. This function takes a single
-** argument. If the argument is numeric, the return value is the same as
-** the argument. If the argument is NULL, the return value is the string
-** "NULL". Otherwise, the argument is enclosed in single quotes with
-** single-quote escapes.
+** Append to pStr text that is the SQL literal representation of the
+** value contained in pValue.
*/
-static void quoteFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
- assert( argc==1 );
- UNUSED_PARAMETER(argc);
- switch( sqlite3_value_type(argv[0]) ){
+void sqlite3QuoteValue(StrAccum *pStr, sqlite3_value *pValue){
+ /* As currently implemented, the string must be initially empty.
+ ** we might relax this requirement in the future, but that will
+ ** require enhancements to the implementation. */
+ assert( pStr!=0 && pStr->nChar==0 );
+
+ switch( sqlite3_value_type(pValue) ){
case SQLITE_FLOAT: {
double r1, r2;
- char zBuf[50];
- r1 = sqlite3_value_double(argv[0]);
- sqlite3_snprintf(sizeof(zBuf), zBuf, "%!.15g", r1);
- sqlite3AtoF(zBuf, &r2, 20, SQLITE_UTF8);
- if( r1!=r2 ){
- sqlite3_snprintf(sizeof(zBuf), zBuf, "%!.20e", r1);
+ const char *zVal;
+ r1 = sqlite3_value_double(pValue);
+ sqlite3_str_appendf(pStr, "%!.15g", r1);
+ zVal = sqlite3_str_value(pStr);
+ if( zVal ){
+ sqlite3AtoF(zVal, &r2, pStr->nChar, SQLITE_UTF8);
+ if( r1!=r2 ){
+ sqlite3_str_reset(pStr);
+ sqlite3_str_appendf(pStr, "%!.20e", r1);
+ }
}
- sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT);
break;
}
case SQLITE_INTEGER: {
- sqlite3_result_value(context, argv[0]);
+ sqlite3_str_appendf(pStr, "%lld", sqlite3_value_int64(pValue));
break;
}
case SQLITE_BLOB: {
- char *zText = 0;
- char const *zBlob = sqlite3_value_blob(argv[0]);
- int nBlob = sqlite3_value_bytes(argv[0]);
- assert( zBlob==sqlite3_value_blob(argv[0]) ); /* No encoding change */
- zText = (char *)contextMalloc(context, (2*(i64)nBlob)+4);
- if( zText ){
+ char const *zBlob = sqlite3_value_blob(pValue);
+ int nBlob = sqlite3_value_bytes(pValue);
+ assert( zBlob==sqlite3_value_blob(pValue) ); /* No encoding change */
+ sqlite3StrAccumEnlarge(pStr, nBlob*2 + 4);
+ if( pStr->accError==0 ){
+ char *zText = pStr->zText;
int i;
for(i=0; i>4)&0x0F];
@@ -1071,42 +1085,47 @@ static void quoteFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
zText[(nBlob*2)+3] = '\0';
zText[0] = 'X';
zText[1] = '\'';
- sqlite3_result_text(context, zText, -1, SQLITE_TRANSIENT);
- sqlite3_free(zText);
+ pStr->nChar = nBlob*2 + 3;
}
break;
}
case SQLITE_TEXT: {
- int i,j;
- u64 n;
- const unsigned char *zArg = sqlite3_value_text(argv[0]);
- char *z;
-
- if( zArg==0 ) return;
- for(i=0, n=0; zArg[i]; i++){ if( zArg[i]=='\'' ) n++; }
- z = contextMalloc(context, ((i64)i)+((i64)n)+3);
- if( z ){
- z[0] = '\'';
- for(i=0, j=1; zArg[i]; i++){
- z[j++] = zArg[i];
- if( zArg[i]=='\'' ){
- z[j++] = '\'';
- }
- }
- z[j++] = '\'';
- z[j] = 0;
- sqlite3_result_text(context, z, j, sqlite3_free);
- }
+ const unsigned char *zArg = sqlite3_value_text(pValue);
+ sqlite3_str_appendf(pStr, "%Q", zArg);
break;
}
default: {
- assert( sqlite3_value_type(argv[0])==SQLITE_NULL );
- sqlite3_result_text(context, "NULL", 4, SQLITE_STATIC);
+ assert( sqlite3_value_type(pValue)==SQLITE_NULL );
+ sqlite3_str_append(pStr, "NULL", 4);
break;
}
}
}
+/*
+** Implementation of the QUOTE() function.
+**
+** The quote(X) function returns the text of an SQL literal which is the
+** value of its argument suitable for inclusion into an SQL statement.
+** Strings are surrounded by single-quotes with escapes on interior quotes
+** as needed. BLOBs are encoded as hexadecimal literals. Strings with
+** embedded NUL characters cannot be represented as string literals in SQL
+** and hence the returned string literal is truncated prior to the first NUL.
+*/
+static void quoteFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
+ sqlite3_str str;
+ sqlite3 *db = sqlite3_context_db_handle(context);
+ assert( argc==1 );
+ UNUSED_PARAMETER(argc);
+ sqlite3StrAccumInit(&str, db, 0, 0, db->aLimit[SQLITE_LIMIT_LENGTH]);
+ sqlite3QuoteValue(&str,argv[0]);
+ sqlite3_result_text(context, sqlite3StrAccumFinish(&str), str.nChar,
+ SQLITE_DYNAMIC);
+ if( str.accError==SQLITE_NOMEM ){
+ sqlite3_result_error_nomem(context);
+ }
+}
+
/*
** The unicode() function. Return the integer unicode code-point value
** for the first character of the input string.
@@ -2240,9 +2259,11 @@ void sqlite3RegisterBuiltinFunctions(void){
WAGGREGATE(max, 1, 1, 1, minmaxStep, minMaxFinalize, minMaxValue, 0,
SQLITE_FUNC_MINMAX|SQLITE_FUNC_ANYORDER ),
FUNCTION2(typeof, 1, 0, 0, typeofFunc, SQLITE_FUNC_TYPEOF),
+ FUNCTION2(subtype, 1, 0, 0, subtypeFunc, SQLITE_FUNC_TYPEOF),
FUNCTION2(length, 1, 0, 0, lengthFunc, SQLITE_FUNC_LENGTH),
FUNCTION(instr, 2, 0, 0, instrFunc ),
FUNCTION(printf, -1, 0, 0, printfFunc ),
+ FUNCTION(format, -1, 0, 0, printfFunc ),
FUNCTION(unicode, 1, 0, 0, unicodeFunc ),
FUNCTION(char, -1, 0, 0, charFunc ),
FUNCTION(abs, 1, 0, 0, absFunc ),
@@ -2341,6 +2362,7 @@ void sqlite3RegisterBuiltinFunctions(void){
#endif
sqlite3WindowFunctions();
sqlite3RegisterDateTimeFunctions();
+ sqlite3RegisterJsonFunctions();
sqlite3InsertBuiltinFuncs(aBuiltinFunc, ArraySize(aBuiltinFunc));
#if 0 /* Enable to print out how the built-in functions are hashed */
diff --git a/src/insert.c b/src/insert.c
index 97205cb2ae..9a02ec6954 100644
--- a/src/insert.c
+++ b/src/insert.c
@@ -43,7 +43,7 @@ void sqlite3OpenTable(
}else{
Index *pPk = sqlite3PrimaryKeyIndex(pTab);
assert( pPk!=0 );
- assert( pPk->tnum==pTab->tnum );
+ assert( pPk->tnum==pTab->tnum || CORRUPT_DB );
sqlite3VdbeAddOp3(v, opcode, iCur, pPk->tnum, iDb);
sqlite3VdbeSetP4KeyInfo(pParse, pPk);
VdbeComment((v, "%s", pTab->zName));
@@ -1382,9 +1382,7 @@ insert_end:
** invoke the callback function.
*/
if( regRowCount ){
- sqlite3VdbeAddOp2(v, OP_ChngCntRow, regRowCount, 1);
- sqlite3VdbeSetNumCols(v, 1);
- sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows inserted", SQLITE_STATIC);
+ sqlite3CodeChangeCount(v, regRowCount, "rows inserted");
}
insert_cleanup:
@@ -2009,6 +2007,7 @@ void sqlite3GenerateConstraintChecks(
if( onError==OE_Replace /* IPK rule is REPLACE */
&& onError!=overrideError /* Rules for other constraints are different */
&& pTab->pIndex /* There exist other constraints */
+ && !upsertIpkDelay /* IPK check already deferred by UPSERT */
){
ipkTop = sqlite3VdbeAddOp0(v, OP_Goto)+1;
VdbeComment((v, "defer IPK REPLACE until last"));
@@ -2417,6 +2416,7 @@ void sqlite3GenerateConstraintChecks(
if( ipkTop ){
sqlite3VdbeGoto(v, ipkTop);
VdbeComment((v, "Do IPK REPLACE"));
+ assert( ipkBottom>0 );
sqlite3VdbeJumpHere(v, ipkBottom);
}
@@ -2547,7 +2547,6 @@ void sqlite3CompleteInsertion(
}
pik_flags = (useSeekResult ? OPFLAG_USESEEKRESULT : 0);
if( IsPrimaryKeyIndex(pIdx) && !HasRowid(pTab) ){
- assert( pParse->nested==0 );
pik_flags |= OPFLAG_NCHANGE;
pik_flags |= (update_flags & OPFLAG_SAVEPOSITION);
if( update_flags==0 ){
diff --git a/ext/misc/json1.c b/src/json.c
similarity index 90%
rename from ext/misc/json1.c
rename to src/json.c
index 7fcd7342a6..3f12f03fd1 100644
--- a/ext/misc/json1.c
+++ b/src/json.c
@@ -10,10 +10,10 @@
**
******************************************************************************
**
-** This SQLite extension implements JSON functions. The interface is
-** modeled after MySQL JSON functions:
+** This SQLite JSON functions.
**
-** https://dev.mysql.com/doc/refman/5.7/en/json.html
+** This file began as an extension in ext/misc/json1.c in 2015. That
+** extension proved so useful that it has now been moved into the core.
**
** For the time being, all JSON is stored as pure text. (We might add
** a JSONB type in the future which stores a binary encoding of JSON in
@@ -21,48 +21,8 @@
** This implementation parses JSON text at 250 MB/s, so it is hard to see
** how JSONB might improve on that.)
*/
-#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_JSON1)
-#if !defined(SQLITEINT_H)
-#include "sqlite3ext.h"
-#endif
-SQLITE_EXTENSION_INIT1
-#include
-#include
-#include
-#include
-
-/* Mark a function parameter as unused, to suppress nuisance compiler
-** warnings. */
-#ifndef UNUSED_PARAM
-# define UNUSED_PARAM(X) (void)(X)
-#endif
-
-#ifndef LARGEST_INT64
-# define LARGEST_INT64 (0xffffffff|(((sqlite3_int64)0x7fffffff)<<32))
-# define SMALLEST_INT64 (((sqlite3_int64)-1) - LARGEST_INT64)
-#endif
-
-#ifndef deliberate_fall_through
-# define deliberate_fall_through
-#endif
-
-/*
-** Versions of isspace(), isalnum() and isdigit() to which it is safe
-** to pass signed char values.
-*/
-#ifdef sqlite3Isdigit
- /* Use the SQLite core versions if this routine is part of the
- ** SQLite amalgamation */
-# define safe_isdigit(x) sqlite3Isdigit(x)
-# define safe_isalnum(x) sqlite3Isalnum(x)
-# define safe_isxdigit(x) sqlite3Isxdigit(x)
-#else
- /* Use the standard library for separate compilation */
-#include /* amalgamator: keep */
-# define safe_isdigit(x) isdigit((unsigned char)(x))
-# define safe_isalnum(x) isalnum((unsigned char)(x))
-# define safe_isxdigit(x) isxdigit((unsigned char)(x))
-#endif
+#ifndef SQLITE_OMIT_JSON
+#include "sqliteInt.h"
/*
** Growing our own isspace() routine this way is twice as fast as
@@ -87,44 +47,14 @@ static const char jsonIsSpace[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
};
-#define safe_isspace(x) (jsonIsSpace[(unsigned char)x])
+#define fast_isspace(x) (jsonIsSpace[(unsigned char)x])
-#ifndef SQLITE_AMALGAMATION
- /* Unsigned integer types. These are already defined in the sqliteInt.h,
- ** but the definitions need to be repeated for separate compilation. */
- typedef sqlite3_uint64 u64;
- typedef unsigned int u32;
- typedef unsigned short int u16;
- typedef unsigned char u8;
-# if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_MUTATION_TEST)
-# define SQLITE_OMIT_AUXILIARY_SAFETY_CHECKS 1
-# endif
-# if defined(SQLITE_OMIT_AUXILIARY_SAFETY_CHECKS)
-# define ALWAYS(X) (1)
-# define NEVER(X) (0)
-# elif !defined(NDEBUG)
-# define ALWAYS(X) ((X)?1:(assert(0),0))
-# define NEVER(X) ((X)?(assert(0),1):0)
-# else
-# define ALWAYS(X) (X)
-# define NEVER(X) (X)
-# endif
-# define testcase(X)
-#endif
#if !defined(SQLITE_DEBUG) && !defined(SQLITE_COVERAGE_TEST)
# define VVA(X)
#else
# define VVA(X) X
#endif
-/*
-** Some of the testcase() macros in this file are problematic for gcov
-** in that they generate false-miss errors randomly. This is a gcov problem,
-** not a problem in this case. But to work around it, we disable the
-** problematic test cases for production builds.
-*/
-#define json_testcase(X)
-
/* Objects */
typedef struct JsonString JsonString;
typedef struct JsonNode JsonNode;
@@ -582,10 +512,10 @@ static u8 jsonHexToInt(int h){
*/
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]) );
+ assert( sqlite3Isxdigit(z[0]) );
+ assert( sqlite3Isxdigit(z[1]) );
+ assert( sqlite3Isxdigit(z[2]) );
+ assert( sqlite3Isxdigit(z[3]) );
v = (jsonHexToInt(z[0])<<12)
+ (jsonHexToInt(z[1])<<8)
+ (jsonHexToInt(z[2])<<4)
@@ -820,7 +750,7 @@ static int jsonParseAddNode(
*/
static int jsonIs4Hex(const char *z){
int i;
- for(i=0; i<4; i++) if( !safe_isxdigit(z[i]) ) return 0;
+ for(i=0; i<4; i++) if( !sqlite3Isxdigit(z[i]) ) return 0;
return 1;
}
@@ -839,13 +769,13 @@ static int jsonParseValue(JsonParse *pParse, u32 i){
int x;
JsonNode *pNode;
const char *z = pParse->zJson;
- while( safe_isspace(z[i]) ){ i++; }
+ while( fast_isspace(z[i]) ){ i++; }
if( (c = z[i])=='{' ){
/* Parse object */
iThis = jsonParseAddNode(pParse, JSON_OBJECT, 0, 0);
if( iThis<0 ) return -1;
for(j=i+1;;j++){
- while( safe_isspace(z[j]) ){ j++; }
+ while( fast_isspace(z[j]) ){ j++; }
if( ++pParse->iDepth > JSON_MAX_DEPTH ) return -1;
x = jsonParseValue(pParse, j);
if( x<0 ){
@@ -858,14 +788,14 @@ static int jsonParseValue(JsonParse *pParse, u32 i){
if( pNode->eType!=JSON_STRING ) return -1;
pNode->jnFlags |= JNODE_LABEL;
j = x;
- while( safe_isspace(z[j]) ){ j++; }
+ while( fast_isspace(z[j]) ){ j++; }
if( z[j]!=':' ) return -1;
j++;
x = jsonParseValue(pParse, j);
pParse->iDepth--;
if( x<0 ) return -1;
j = x;
- while( safe_isspace(z[j]) ){ j++; }
+ while( fast_isspace(z[j]) ){ j++; }
c = z[j];
if( c==',' ) continue;
if( c!='}' ) return -1;
@@ -879,7 +809,7 @@ static int jsonParseValue(JsonParse *pParse, u32 i){
if( iThis<0 ) return -1;
memset(&pParse->aNode[iThis].u, 0, sizeof(pParse->aNode[iThis].u));
for(j=i+1;;j++){
- while( safe_isspace(z[j]) ){ j++; }
+ while( fast_isspace(z[j]) ){ j++; }
if( ++pParse->iDepth > JSON_MAX_DEPTH ) return -1;
x = jsonParseValue(pParse, j);
pParse->iDepth--;
@@ -888,7 +818,7 @@ static int jsonParseValue(JsonParse *pParse, u32 i){
return -1;
}
j = x;
- while( safe_isspace(z[j]) ){ j++; }
+ while( fast_isspace(z[j]) ){ j++; }
c = z[j];
if( c==',' ) continue;
if( c!=']' ) return -1;
@@ -925,17 +855,17 @@ static int jsonParseValue(JsonParse *pParse, u32 i){
return j+1;
}else if( c=='n'
&& strncmp(z+i,"null",4)==0
- && !safe_isalnum(z[i+4]) ){
+ && !sqlite3Isalnum(z[i+4]) ){
jsonParseAddNode(pParse, JSON_NULL, 0, 0);
return i+4;
}else if( c=='t'
&& strncmp(z+i,"true",4)==0
- && !safe_isalnum(z[i+4]) ){
+ && !sqlite3Isalnum(z[i+4]) ){
jsonParseAddNode(pParse, JSON_TRUE, 0, 0);
return i+4;
}else if( c=='f'
&& strncmp(z+i,"false",5)==0
- && !safe_isalnum(z[i+5]) ){
+ && !sqlite3Isalnum(z[i+5]) ){
jsonParseAddNode(pParse, JSON_FALSE, 0, 0);
return i+5;
}else if( c=='-' || (c>='0' && c<='9') ){
@@ -1006,7 +936,7 @@ static int jsonParse(
if( pParse->oom ) i = -1;
if( i>0 ){
assert( pParse->iDepth==0 );
- while( safe_isspace(zJson[i]) ) i++;
+ while( fast_isspace(zJson[i]) ) i++;
if( zJson[i] ) i = -1;
}
if( i<=0 ){
@@ -1234,7 +1164,7 @@ static JsonNode *jsonLookupStep(
}else if( zPath[0]=='[' ){
i = 0;
j = 1;
- while( safe_isdigit(zPath[j]) ){
+ while( sqlite3Isdigit(zPath[j]) ){
i = i*10 + zPath[j] - '0';
j++;
}
@@ -1255,13 +1185,13 @@ static JsonNode *jsonLookupStep(
j = 1;
}
j = 2;
- if( zPath[2]=='-' && safe_isdigit(zPath[3]) ){
+ if( zPath[2]=='-' && sqlite3Isdigit(zPath[3]) ){
unsigned int x = 0;
j = 3;
do{
x = x*10 + zPath[j] - '0';
j++;
- }while( safe_isdigit(zPath[j]) );
+ }while( sqlite3Isdigit(zPath[j]) );
if( x>i ) return 0;
i -= x;
}
@@ -1480,7 +1410,7 @@ static void jsonTest1Func(
int argc,
sqlite3_value **argv
){
- UNUSED_PARAM(argc);
+ UNUSED_PARAMETER(argc);
sqlite3_result_int(ctx, sqlite3_value_subtype(argv[0])==JSON_SUBTYPE);
}
#endif /* SQLITE_DEBUG */
@@ -1501,7 +1431,7 @@ static void jsonQuoteFunc(
sqlite3_value **argv
){
JsonString jx;
- UNUSED_PARAM(argc);
+ UNUSED_PARAMETER(argc);
jsonInit(&jx, ctx);
jsonAppendValue(&jx, argv[0]);
@@ -1572,13 +1502,34 @@ static void jsonArrayLengthFunc(
sqlite3_result_int64(ctx, n);
}
+/*
+** Bit values for the flags passed into jsonExtractFunc() or
+** jsonSetFunc() via the user-data value.
+*/
+#define JSON_JSON 0x01 /* Result is always JSON */
+#define JSON_SQL 0x02 /* Result is always SQL */
+#define JSON_ABPATH 0x03 /* Allow abbreviated JSON path specs */
+#define JSON_ISSET 0x04 /* json_set(), not json_insert() */
+
/*
** json_extract(JSON, PATH, ...)
+** "->"(JSON,PATH)
+** "->>"(JSON,PATH)
**
-** Return the element described by PATH. Return NULL if there is no
-** PATH element. If there are multiple PATHs, then return a JSON array
-** with the result from each path. Throw an error if the JSON or any PATH
-** is malformed.
+** Return the element described by PATH. Return NULL if that PATH element
+** is not found.
+**
+** If JSON_JSON is set or if more that one PATH argument is supplied then
+** always return a JSON representation of the result. If JSON_SQL is set,
+** then always return an SQL representation of the result. If neither flag
+** is present and argc==2, then return JSON for objects and arrays and SQL
+** for all other values.
+**
+** When multiple PATH arguments are supplied, the result is a JSON array
+** containing the result of each PATH.
+**
+** Abbreviated JSON path expressions are allows if JSON_ABPATH, for
+** compatibility with PG.
*/
static void jsonExtractFunc(
sqlite3_context *ctx,
@@ -1588,35 +1539,77 @@ static void jsonExtractFunc(
JsonParse *p; /* The parse */
JsonNode *pNode;
const char *zPath;
+ int flags = SQLITE_PTR_TO_INT(sqlite3_user_data(ctx));
JsonString jx;
- int i;
if( argc<2 ) return;
p = jsonParseCached(ctx, argv, ctx);
if( p==0 ) return;
- jsonInit(&jx, ctx);
- jsonAppendChar(&jx, '[');
- for(i=1; inErr ) break;
- if( argc>2 ){
+ if( argc==2 ){
+ /* With a single PATH argument */
+ zPath = (const char*)sqlite3_value_text(argv[1]);
+ if( zPath==0 ) return;
+ if( flags & JSON_ABPATH ){
+ if( zPath[0]!='$' ){
+ /* The -> and ->> operators accept abbreviated PATH arguments. This
+ ** is mostly for compatibility with PostgreSQL, but also for
+ ** convenience.
+ **
+ ** NUMBER ==> $[NUMBER] // PG compatible
+ ** LABEL ==> $.LABEL // PG compatible
+ ** [NUMBER] ==> $[NUMBER] // Not PG. Purely for convenience
+ */
+ jsonInit(&jx, ctx);
+ if( sqlite3Isdigit(zPath[0]) ){
+ jsonAppendRaw(&jx, "$[", 2);
+ jsonAppendRaw(&jx, zPath, (int)strlen(zPath));
+ jsonAppendRaw(&jx, "]", 2);
+ }else{
+ jsonAppendRaw(&jx, "$.", 1 + (zPath[0]!='['));
+ jsonAppendRaw(&jx, zPath, (int)strlen(zPath));
+ jsonAppendChar(&jx, 0);
+ }
+ pNode = jx.bErr ? 0 : jsonLookup(p, jx.zBuf, 0, ctx);
+ jsonReset(&jx);
+ }else{
+ pNode = jsonLookup(p, zPath, 0, ctx);
+ }
+ if( pNode ){
+ if( flags & JSON_JSON ){
+ jsonReturnJson(pNode, ctx, 0);
+ }else{
+ jsonReturn(pNode, ctx, 0);
+ sqlite3_result_subtype(ctx, 0);
+ }
+ }
+ }else{
+ pNode = jsonLookup(p, zPath, 0, ctx);
+ if( p->nErr==0 && pNode ) jsonReturn(pNode, ctx, 0);
+ }
+ }else{
+ /* Two or more PATH arguments results in a JSON array with each
+ ** element of the array being the value selected by one of the PATHs */
+ int i;
+ jsonInit(&jx, ctx);
+ jsonAppendChar(&jx, '[');
+ for(i=1; inErr ) break;
jsonAppendSeparator(&jx);
if( pNode ){
jsonRenderNode(pNode, &jx, 0);
}else{
jsonAppendRaw(&jx, "null", 4);
}
- }else if( pNode ){
- jsonReturn(pNode, ctx, 0);
}
+ if( i==argc ){
+ jsonAppendChar(&jx, ']');
+ jsonResult(&jx);
+ sqlite3_result_subtype(ctx, JSON_SUBTYPE);
+ }
+ jsonReset(&jx);
}
- if( argc>2 && i==argc ){
- jsonAppendChar(&jx, ']');
- jsonResult(&jx);
- sqlite3_result_subtype(ctx, JSON_SUBTYPE);
- }
- jsonReset(&jx);
}
/* This is the RFC 7396 MergePatch algorithm.
@@ -1712,7 +1705,7 @@ static void jsonPatchFunc(
JsonParse y; /* The patch */
JsonNode *pResult; /* The result of the merge */
- UNUSED_PARAM(argc);
+ UNUSED_PARAMETER(argc);
if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return;
if( jsonParse(&y, ctx, (const char*)sqlite3_value_text(argv[1])) ){
jsonParseReset(&x);
@@ -1833,7 +1826,7 @@ static void jsonReplaceFunc(
if( x.nErr ) goto replace_err;
if( pNode ){
assert( pNode->eU==0 || pNode->eU==1 || pNode->eU==4 );
- json_testcase( pNode->eU!=0 && pNode->eU!=1 );
+ testcase( pNode->eU!=0 && pNode->eU!=1 );
pNode->jnFlags |= (u8)JNODE_REPLACE;
VVA( pNode->eU = 4 );
pNode->u.iReplace = i + 1;
@@ -1849,6 +1842,7 @@ replace_err:
jsonParseReset(&x);
}
+
/*
** json_set(JSON, PATH, VALUE, ...)
**
@@ -1871,7 +1865,7 @@ static void jsonSetFunc(
const char *zPath;
u32 i;
int bApnd;
- int bIsSet = *(int*)sqlite3_user_data(ctx);
+ int bIsSet = sqlite3_user_data(ctx)!=0;
if( argc<1 ) return;
if( (argc&1)==0 ) {
@@ -1890,8 +1884,8 @@ static void jsonSetFunc(
}else if( x.nErr ){
goto jsonSetDone;
}else if( pNode && (bApnd || bIsSet) ){
- json_testcase( pNode->eU!=0 && pNode->eU!=1 && pNode->eU!=4 );
- assert( pNode->eU!=3 || pNode->eU!=5 );
+ testcase( pNode->eU!=0 && pNode->eU!=1 );
+ assert( pNode->eU!=3 && pNode->eU!=5 );
VVA( pNode->eU = 4 );
pNode->jnFlags |= (u8)JNODE_REPLACE;
pNode->u.iReplace = i + 1;
@@ -1911,8 +1905,8 @@ jsonSetDone:
** json_type(JSON)
** json_type(JSON, PATH)
**
-** Return the top-level "type" of a JSON string. Throw an error if
-** either the JSON or PATH inputs are not well-formed.
+** Return the top-level "type" of a JSON string. json_type() raises an
+** error if either the JSON or PATH inputs are not well-formed.
*/
static void jsonTypeFunc(
sqlite3_context *ctx,
@@ -1948,7 +1942,7 @@ static void jsonValidFunc(
sqlite3_value **argv
){
JsonParse *p; /* The parse */
- UNUSED_PARAM(argc);
+ UNUSED_PARAMETER(argc);
p = jsonParseCached(ctx, argv, 0);
sqlite3_result_int(ctx, p!=0);
}
@@ -1968,7 +1962,7 @@ static void jsonArrayStep(
sqlite3_value **argv
){
JsonString *pStr;
- UNUSED_PARAM(argc);
+ UNUSED_PARAMETER(argc);
pStr = (JsonString*)sqlite3_aggregate_context(ctx, sizeof(*pStr));
if( pStr ){
if( pStr->zBuf==0 ){
@@ -2028,8 +2022,8 @@ static void jsonGroupInverse(
char *z;
char c;
JsonString *pStr;
- UNUSED_PARAM(argc);
- UNUSED_PARAM(argv);
+ UNUSED_PARAMETER(argc);
+ UNUSED_PARAMETER(argv);
pStr = (JsonString*)sqlite3_aggregate_context(ctx, 0);
#ifdef NEVER
/* pStr is always non-NULL since jsonArrayStep() or jsonObjectStep() will
@@ -2073,7 +2067,7 @@ static void jsonObjectStep(
JsonString *pStr;
const char *z;
u32 n;
- UNUSED_PARAM(argc);
+ UNUSED_PARAMETER(argc);
pStr = (JsonString*)sqlite3_aggregate_context(ctx, sizeof(*pStr));
if( pStr ){
if( pStr->zBuf==0 ){
@@ -2164,10 +2158,10 @@ static int jsonEachConnect(
#define JEACH_JSON 8
#define JEACH_ROOT 9
- UNUSED_PARAM(pzErr);
- UNUSED_PARAM(argv);
- UNUSED_PARAM(argc);
- UNUSED_PARAM(pAux);
+ UNUSED_PARAMETER(pzErr);
+ UNUSED_PARAMETER(argv);
+ UNUSED_PARAMETER(argc);
+ UNUSED_PARAMETER(pAux);
rc = sqlite3_declare_vtab(db,
"CREATE TABLE x(key,value,type,atom,id,parent,fullkey,path,"
"json HIDDEN,root HIDDEN)");
@@ -2190,7 +2184,7 @@ static int jsonEachDisconnect(sqlite3_vtab *pVtab){
static int jsonEachOpenEach(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
JsonEachCursor *pCur;
- UNUSED_PARAM(p);
+ UNUSED_PARAMETER(p);
pCur = sqlite3_malloc( sizeof(*pCur) );
if( pCur==0 ) return SQLITE_NOMEM;
memset(pCur, 0, sizeof(*pCur));
@@ -2250,7 +2244,7 @@ static int jsonEachNext(sqlite3_vtab_cursor *cur){
p->eType = pUp->eType;
if( pUp->eType==JSON_ARRAY ){
assert( pUp->eU==0 || pUp->eU==3 );
- json_testcase( pUp->eU==3 );
+ testcase( pUp->eU==3 );
VVA( pUp->eU = 3 );
if( iUp==p->i-1 ){
pUp->u.iKey = 0;
@@ -2437,7 +2431,7 @@ static int jsonEachBestIndex(
/* This implementation assumes that JSON and ROOT are the last two
** columns in the table */
assert( JEACH_ROOT == JEACH_JSON+1 );
- UNUSED_PARAM(tab);
+ UNUSED_PARAMETER(tab);
aIdx[0] = aIdx[1] = -1;
pConstraint = pIdxInfo->aConstraint;
for(i=0; inConstraint; i++, pConstraint++){
@@ -2493,8 +2487,8 @@ static int jsonEachFilter(
const char *zRoot = 0;
sqlite3_int64 n;
- UNUSED_PARAM(idxStr);
- UNUSED_PARAM(argc);
+ UNUSED_PARAMETER(idxStr);
+ UNUSED_PARAMETER(argc);
jsonEachCursorReset(p);
if( idxNum==0 ) return SQLITE_OK;
z = (const char*)sqlite3_value_text(argv[0]);
@@ -2619,103 +2613,63 @@ static sqlite3_module jsonTreeModule = {
0 /* xShadowName */
};
#endif /* SQLITE_OMIT_VIRTUALTABLE */
+#endif /* !defined(SQLITE_OMIT_JSON) */
-/****************************************************************************
-** The following routines are the only publically visible identifiers in this
-** file. Call the following routines in order to register the various SQL
-** functions and the virtual table implemented by this file.
-****************************************************************************/
-
-int sqlite3Json1Init(sqlite3 *db){
- int rc = SQLITE_OK;
- unsigned int i;
- static const struct {
- const char *zName;
- int nArg;
- int flag;
- void (*xFunc)(sqlite3_context*,int,sqlite3_value**);
- } aFunc[] = {
- { "json", 1, 0, jsonRemoveFunc },
- { "json_array", -1, 0, jsonArrayFunc },
- { "json_array_length", 1, 0, jsonArrayLengthFunc },
- { "json_array_length", 2, 0, jsonArrayLengthFunc },
- { "json_extract", -1, 0, jsonExtractFunc },
- { "json_insert", -1, 0, jsonSetFunc },
- { "json_object", -1, 0, jsonObjectFunc },
- { "json_patch", 2, 0, jsonPatchFunc },
- { "json_quote", 1, 0, jsonQuoteFunc },
- { "json_remove", -1, 0, jsonRemoveFunc },
- { "json_replace", -1, 0, jsonReplaceFunc },
- { "json_set", -1, 1, jsonSetFunc },
- { "json_type", 1, 0, jsonTypeFunc },
- { "json_type", 2, 0, jsonTypeFunc },
- { "json_valid", 1, 0, jsonValidFunc },
-
+/*
+** Register JSON functions.
+*/
+void sqlite3RegisterJsonFunctions(void){
+#ifndef SQLITE_OMIT_JSON
+ static FuncDef aJsonFunc[] = {
+ JFUNCTION(json, 1, 0, jsonRemoveFunc),
+ JFUNCTION(json_array, -1, 0, jsonArrayFunc),
+ JFUNCTION(json_array_length, 1, 0, jsonArrayLengthFunc),
+ JFUNCTION(json_array_length, 2, 0, jsonArrayLengthFunc),
+ JFUNCTION(json_extract, -1, 0, jsonExtractFunc),
+ JFUNCTION(->, 2, JSON_JSON, jsonExtractFunc),
+ JFUNCTION(->>, 2, JSON_SQL, jsonExtractFunc),
+ JFUNCTION(json_insert, -1, 0, jsonSetFunc),
+ JFUNCTION(json_object, -1, 0, jsonObjectFunc),
+ JFUNCTION(json_patch, 2, 0, jsonPatchFunc),
+ JFUNCTION(json_quote, 1, 0, jsonQuoteFunc),
+ JFUNCTION(json_remove, -1, 0, jsonRemoveFunc),
+ JFUNCTION(json_replace, -1, 0, jsonReplaceFunc),
+ JFUNCTION(json_set, -1, JSON_ISSET, jsonSetFunc),
+ JFUNCTION(json_type, 1, 0, jsonTypeFunc),
+ JFUNCTION(json_type, 2, 0, jsonTypeFunc),
+ JFUNCTION(json_valid, 1, 0, jsonValidFunc),
#if SQLITE_DEBUG
- /* DEBUG and TESTING functions */
- { "json_parse", 1, 0, jsonParseFunc },
- { "json_test1", 1, 0, jsonTest1Func },
+ JFUNCTION(json_parse, 1, 0, jsonParseFunc),
+ JFUNCTION(json_test1, 1, 0, jsonTest1Func),
#endif
+ WAGGREGATE(json_group_array, 1, 0, 0,
+ jsonArrayStep, jsonArrayFinal, jsonArrayValue, jsonGroupInverse,
+ SQLITE_SUBTYPE|SQLITE_UTF8|SQLITE_DETERMINISTIC|SQLITE_INNOCUOUS),
+ WAGGREGATE(json_group_object, 2, 0, 0,
+ jsonObjectStep, jsonObjectFinal, jsonObjectValue, jsonGroupInverse,
+ SQLITE_SUBTYPE|SQLITE_UTF8|SQLITE_DETERMINISTIC|SQLITE_INNOCUOUS)
};
+ sqlite3InsertBuiltinFuncs(aJsonFunc, ArraySize(aJsonFunc));
+#endif
+}
+
+#if !defined(SQLITE_OMIT_VIRTUALTABLE) && !defined(SQLITE_OMIT_JSON)
+/*
+** Register the JSON table-valued functions
+*/
+int sqlite3JsonTableFunctions(sqlite3 *db){
+ int rc = SQLITE_OK;
static const struct {
- const char *zName;
- int nArg;
- void (*xStep)(sqlite3_context*,int,sqlite3_value**);
- void (*xFinal)(sqlite3_context*);
- void (*xValue)(sqlite3_context*);
- } aAgg[] = {
- { "json_group_array", 1,
- jsonArrayStep, jsonArrayFinal, jsonArrayValue },
- { "json_group_object", 2,
- jsonObjectStep, jsonObjectFinal, jsonObjectValue },
- };
-#ifndef SQLITE_OMIT_VIRTUALTABLE
- static const struct {
- const char *zName;
- sqlite3_module *pModule;
+ const char *zName;
+ sqlite3_module *pModule;
} aMod[] = {
{ "json_each", &jsonEachModule },
{ "json_tree", &jsonTreeModule },
};
-#endif
- static const int enc =
- SQLITE_UTF8 |
- SQLITE_DETERMINISTIC |
- SQLITE_INNOCUOUS;
- for(i=0; ierrCode ){
+ sqlite3_mutex_enter(db->mutex);
+ iOffset = db->errByteOffset;
+ sqlite3_mutex_leave(db->mutex);
+ }
+ return iOffset;
+}
+
#ifndef SQLITE_OMIT_UTF16
/*
** Return UTF-16 encoded English language explanation of the most recent
@@ -2857,6 +2867,8 @@ int sqlite3_limit(sqlite3 *db, int limitId, int newLimit){
if( newLimit>=0 ){ /* IMP: R-52476-28732 */
if( newLimit>aHardLimit[limitId] ){
newLimit = aHardLimit[limitId]; /* IMP: R-51463-25634 */
+ }else if( newLimit<1 && limitId==SQLITE_LIMIT_LENGTH ){
+ newLimit = 1;
}
db->aLimit[limitId] = newLimit;
}
@@ -4260,12 +4272,16 @@ int sqlite3_test_control(int op, ...){
*/
case SQLITE_TESTCTRL_IMPOSTER: {
sqlite3 *db = va_arg(ap, sqlite3*);
+ int iDb;
sqlite3_mutex_enter(db->mutex);
- db->init.iDb = sqlite3FindDbName(db, va_arg(ap,const char*));
- db->init.busy = db->init.imposterTable = va_arg(ap,int);
- db->init.newTnum = va_arg(ap,int);
- if( db->init.busy==0 && db->init.newTnum>0 ){
- sqlite3ResetAllSchemasOfConnection(db);
+ iDb = sqlite3FindDbName(db, va_arg(ap,const char*));
+ if( iDb>=0 ){
+ db->init.iDb = iDb;
+ db->init.busy = db->init.imposterTable = va_arg(ap,int);
+ db->init.newTnum = va_arg(ap,int);
+ if( db->init.busy==0 && db->init.newTnum>0 ){
+ sqlite3ResetAllSchemasOfConnection(db);
+ }
}
sqlite3_mutex_leave(db->mutex);
break;
@@ -4341,6 +4357,26 @@ int sqlite3_test_control(int op, ...){
break;
}
+ /* sqlite3_test_control(SQLITE_TESTCTRL_LOGEST,
+ ** double fIn, // Input value
+ ** int *pLogEst, // sqlite3LogEstFromDouble(fIn)
+ ** u64 *pInt, // sqlite3LogEstToInt(*pLogEst)
+ ** int *pLogEst2 // sqlite3LogEst(*pInt)
+ ** );
+ **
+ ** Test access for the LogEst conversion routines.
+ */
+ case SQLITE_TESTCTRL_LOGEST: {
+ double rIn = va_arg(ap, double);
+ LogEst rLogEst = sqlite3LogEstFromDouble(rIn);
+ u64 iInt = sqlite3LogEstToInt(rLogEst);
+ va_arg(ap, int*)[0] = rLogEst;
+ va_arg(ap, u64*)[0] = iInt;
+ va_arg(ap, int*)[0] = sqlite3LogEst(iInt);
+ break;
+ }
+
+
#if defined(SQLITE_DEBUG) && !defined(SQLITE_OMIT_WSD)
/* sqlite3_test_control(SQLITE_TESTCTRL_TUNE, id, *piValue)
**
diff --git a/src/memjournal.c b/src/memjournal.c
index 598d5cc026..63ef2ad7b9 100644
--- a/src/memjournal.c
+++ b/src/memjournal.c
@@ -265,7 +265,7 @@ static int memjrnlTruncate(sqlite3_file *pJfd, sqlite_int64 size){
p->pFirst = 0;
}else{
i64 iOff = p->nChunkSize;
- for(pIter=p->pFirst; ALWAYS(pIter) && iOff<=size; pIter=pIter->pNext){
+ for(pIter=p->pFirst; ALWAYS(pIter) && iOffpNext){
iOff += p->nChunkSize;
}
if( ALWAYS(pIter) ){
diff --git a/src/pager.c b/src/pager.c
index a28e5121a0..ffbe2e82d4 100644
--- a/src/pager.c
+++ b/src/pager.c
@@ -3962,8 +3962,7 @@ static int pager_wait_on_lock(Pager *pPager, int locktype){
** current database image, in pages, OR
**
** b) if the page content were written at this time, it would not
-** be necessary to write the current content out to the sub-journal
-** (as determined by function subjRequiresPage()).
+** be necessary to write the current content out to the sub-journal.
**
** If the condition asserted by this function were not true, and the
** dirty page were to be discarded from the cache via the pagerStress()
@@ -3978,8 +3977,16 @@ static int pager_wait_on_lock(Pager *pPager, int locktype){
*/
#if defined(SQLITE_DEBUG)
static void assertTruncateConstraintCb(PgHdr *pPg){
+ Pager *pPager = pPg->pPager;
assert( pPg->flags&PGHDR_DIRTY );
- assert( !subjRequiresPage(pPg) || pPg->pgno<=pPg->pPager->dbSize );
+ if( pPg->pgno>pPager->dbSize ){ /* if (a) is false */
+ Pgno pgno = pPg->pgno;
+ int i;
+ for(i=0; ipPager->nSavepoint; i++){
+ PagerSavepoint *p = &pPager->aSavepoint[i];
+ assert( p->nOrigpInSavepoint,pgno) );
+ }
+ }
}
static void assertTruncateConstraint(Pager *pPager){
sqlite3PcacheIterateDirty(pPager->pPCache, assertTruncateConstraintCb);
@@ -4000,8 +4007,7 @@ static void assertTruncateConstraint(Pager *pPager){
** then continue writing to the database.
*/
void sqlite3PagerTruncateImage(Pager *pPager, Pgno nPage){
- assert( pPager->dbSize>=nPage || CORRUPT_DB );
- testcase( pPager->dbSizedbSize>=nPage );
assert( pPager->eState>=PAGER_WRITER_CACHEMOD );
pPager->dbSize = nPage;
@@ -5329,7 +5335,7 @@ int sqlite3PagerSharedLock(Pager *pPager){
** may mean that the pager was in the error-state when this
** function was called and the journal file does not exist.
*/
- if( !isOpen(pPager->jfd) ){
+ if( !isOpen(pPager->jfd) && pPager->journalMode!=PAGER_JOURNALMODE_OFF ){
sqlite3_vfs * const pVfs = pPager->pVfs;
int bExists; /* True if journal file exists */
rc = sqlite3OsAccess(
@@ -5743,6 +5749,7 @@ int sqlite3PagerGet(
DbPage **ppPage, /* Write a pointer to the page here */
int flags /* PAGER_GET_XXX flags */
){
+ /* printf("PAGE %u\n", pgno); fflush(stdout); */
return pPager->xGet(pPager, pgno, ppPage, flags);
}
@@ -7423,13 +7430,13 @@ int sqlite3PagerSetJournalMode(Pager *pPager, int eMode){
u8 eOld = pPager->journalMode; /* Prior journalmode */
/* The eMode parameter is always valid */
- assert( eMode==PAGER_JOURNALMODE_DELETE
- || eMode==PAGER_JOURNALMODE_TRUNCATE
- || eMode==PAGER_JOURNALMODE_PERSIST
- || eMode==PAGER_JOURNALMODE_OFF
- || eMode==PAGER_JOURNALMODE_WAL
- || eMode==PAGER_JOURNALMODE_WAL2
- || eMode==PAGER_JOURNALMODE_MEMORY );
+ assert( eMode==PAGER_JOURNALMODE_DELETE /* 0 */
+ || eMode==PAGER_JOURNALMODE_PERSIST /* 1 */
+ || eMode==PAGER_JOURNALMODE_OFF /* 2 */
+ || eMode==PAGER_JOURNALMODE_TRUNCATE /* 3 */
+ || eMode==PAGER_JOURNALMODE_MEMORY /* 4 */
+ || eMode==PAGER_JOURNALMODE_WAL /* 5 */
+ || eMode==PAGER_JOURNALMODE_WAL2 /* 6 */ );
/* This routine is only called from the OP_JournalMode opcode, and
** the logic there will never allow a temporary file to be changed
@@ -7469,7 +7476,6 @@ int sqlite3PagerSetJournalMode(Pager *pPager, int eMode){
if( !pPager->exclusiveMode && (eOld & 5)==1 && (eMode & 1)==0
&& eMode!=PAGER_JOURNALMODE_WAL2 /* TODO: fix this if possible */
){
-
/* In this case we would like to delete the journal file. If it is
** not possible, then that is not a problem. Deleting the journal file
** here is an optimization only.
diff --git a/src/parse.y b/src/parse.y
index 989b990f23..9ef2a2fec6 100644
--- a/src/parse.y
+++ b/src/parse.y
@@ -302,7 +302,7 @@ columnname(A) ::= nm(A) typetoken(Y). {sqlite3AddColumn(pParse,A,Y);}
%left BITAND BITOR LSHIFT RSHIFT.
%left PLUS MINUS.
%left STAR SLASH REM.
-%left CONCAT.
+%left CONCAT PTR.
%left COLLATE.
%right BITNOT.
%nonassoc ON.
@@ -1250,6 +1250,12 @@ expr(A) ::= PLUS|MINUS(B) expr(X). [BITNOT] {
/*A-overwrites-B*/
}
+expr(A) ::= expr(B) PTR(C) expr(D). {
+ ExprList *pList = sqlite3ExprListAppend(pParse, 0, B);
+ pList = sqlite3ExprListAppend(pParse, pList, D);
+ A = sqlite3ExprFunction(pParse, pList, &C, 0);
+}
+
%type between_op {int}
between_op(A) ::= BETWEEN. {A = 0;}
between_op(A) ::= NOT BETWEEN. {A = 1;}
diff --git a/src/prepare.c b/src/prepare.c
index 14b5dbad6d..d2cc2d098c 100644
--- a/src/prepare.c
+++ b/src/prepare.c
@@ -570,6 +570,10 @@ int sqlite3SchemaToIndex(sqlite3 *db, Schema *pSchema){
*/
void sqlite3ParserReset(Parse *pParse){
sqlite3 *db = pParse->db;
+ assert( pParse->nested==0 );
+#ifndef SQLITE_OMIT_SHARED_CACHE
+ sqlite3DbFree(db, pParse->aTableLock);
+#endif
while( pParse->pCleanup ){
ParseCleanup *pCleanup = pParse->pCleanup;
pParse->pCleanup = pCleanup->pNext;
@@ -649,7 +653,6 @@ static int sqlite3Prepare(
sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */
const char **pzTail /* OUT: End of parsed string */
){
- char *zErrMsg = 0; /* Error message */
int rc = SQLITE_OK; /* Result code */
int i; /* Loop counter */
Parse sParse; /* Parsing context */
@@ -724,14 +727,14 @@ static int sqlite3Prepare(
}
zSqlCopy = sqlite3DbStrNDup(db, zSql, nBytes);
if( zSqlCopy ){
- sqlite3RunParser(&sParse, zSqlCopy, &zErrMsg);
+ sqlite3RunParser(&sParse, zSqlCopy);
sParse.zTail = &zSql[sParse.zTail-zSqlCopy];
sqlite3DbFree(db, zSqlCopy);
}else{
sParse.zTail = &zSql[nBytes];
}
}else{
- sqlite3RunParser(&sParse, zSql, &zErrMsg);
+ sqlite3RunParser(&sParse, zSql);
}
assert( 0==sParse.nQueryLoop );
@@ -747,7 +750,7 @@ static int sqlite3Prepare(
sParse.checkSchema = 0;
}
if( sParse.rc!=SQLITE_OK && sParse.rc!=SQLITE_DONE ){
- if( sParse.checkSchema ){
+ if( sParse.checkSchema && db->init.busy==0 ){
schemaIsValid(&sParse);
}
if( sParse.pVdbe ){
@@ -755,14 +758,14 @@ static int sqlite3Prepare(
}
assert( 0==(*ppStmt) );
rc = sParse.rc;
- if( zErrMsg ){
- sqlite3ErrorWithMsg(db, rc, "%s", zErrMsg);
- sqlite3DbFree(db, zErrMsg);
+ if( sParse.zErrMsg ){
+ sqlite3ErrorWithMsg(db, rc, "%s", sParse.zErrMsg);
+ sqlite3DbFree(db, sParse.zErrMsg);
}else{
sqlite3Error(db, rc);
}
}else{
- assert( zErrMsg==0 );
+ assert( sParse.zErrMsg==0 );
*ppStmt = (sqlite3_stmt*)sParse.pVdbe;
rc = SQLITE_OK;
sqlite3ErrorClear(db);
@@ -808,6 +811,7 @@ static int sqlite3LockAndPrepare(
** reset is considered a permanent error. */
rc = sqlite3Prepare(db, zSql, nBytes, prepFlags, pOld, ppStmt, pzTail);
assert( rc==SQLITE_OK || *ppStmt==0 );
+ if( rc==SQLITE_OK || db->mallocFailed ) break;
}while( rc==SQLITE_ERROR_RETRY
|| (rc==SQLITE_SCHEMA && (sqlite3ResetOneSchema(db,-1), cnt++)==0) );
sqlite3BtreeLeaveAll(db);
diff --git a/src/printf.c b/src/printf.c
index e63518450c..9fea2d6ef0 100644
--- a/src/printf.c
+++ b/src/printf.c
@@ -855,6 +855,7 @@ void sqlite3_str_vappendf(
assert( bArgList==0 );
if( pToken && pToken->n ){
sqlite3_str_append(pAccum, (const char*)pToken->z, pToken->n);
+ sqlite3RecordErrorByteOffset(pAccum->db, pToken->z);
}
length = width = 0;
break;
@@ -909,6 +910,30 @@ void sqlite3_str_vappendf(
}/* End for loop over the format string */
} /* End of function */
+
+/*
+** The z string points to the first character of a token that is
+** associated with an error. If db does not already have an error
+** byte offset recorded, try to compute the error byte offset for
+** z and set the error byte offset in db.
+*/
+void sqlite3RecordErrorByteOffset(sqlite3 *db, const char *z){
+ const Parse *pParse;
+ const char *zText;
+ const char *zEnd;
+ assert( z!=0 );
+ if( NEVER(db==0) ) return;
+ if( db->errByteOffset!=(-2) ) return;
+ pParse = db->pParse;
+ if( NEVER(pParse==0) ) return;
+ zText =pParse->zTail;
+ if( NEVER(zText==0) ) return;
+ zEnd = &zText[strlen(zText)];
+ if( SQLITE_WITHIN(z,zText,zEnd) ){
+ db->errByteOffset = (int)(z-zText);
+ }
+}
+
/*
** Enlarge the memory allocation on a StrAccum object so that it is
** able to accept at least N more bytes of text.
@@ -916,7 +941,7 @@ void sqlite3_str_vappendf(
** Return the number of bytes of text that StrAccum is able to accept
** after the attempted enlargement. The value returned might be zero.
*/
-static int sqlite3StrAccumEnlarge(StrAccum *p, int N){
+int sqlite3StrAccumEnlarge(StrAccum *p, int N){
char *zNew;
assert( p->nChar+(i64)N >= p->nAlloc ); /* Only called if really needed */
if( p->accError ){
diff --git a/src/resolve.c b/src/resolve.c
index 27b260e059..5bcaf8dcd6 100644
--- a/src/resolve.c
+++ b/src/resolve.c
@@ -320,8 +320,9 @@ static int lookupName(
}
if( hit || zTab==0 ) continue;
}
- if( zDb && pTab->pSchema!=pSchema ){
- continue;
+ if( zDb ){
+ if( pTab->pSchema!=pSchema ) continue;
+ if( pSchema==0 && strcmp(zDb,"*")!=0 ) continue;
}
if( zTab ){
const char *zTabName = pItem->zAlias ? pItem->zAlias : pTab->zName;
@@ -452,6 +453,7 @@ static int lookupName(
pExpr->y.pTab = pTab;
if( pParse->bReturning ){
eNewExprOp = TK_REGISTER;
+ pExpr->op2 = TK_COLUMN;
pExpr->iTable = pNC->uNC.iBaseReg + (pTab->nCol+1)*pExpr->iTable +
sqlite3TableColumnToStorage(pTab, iCol) + 1;
}else{
diff --git a/src/select.c b/src/select.c
index b9231fa455..432d015de0 100644
--- a/src/select.c
+++ b/src/select.c
@@ -1575,6 +1575,9 @@ static void generateSortTail(
iTab = pSort->iECursor;
if( eDest==SRT_Output || eDest==SRT_Coroutine || eDest==SRT_Mem ){
+ if( eDest==SRT_Mem && p->iOffset ){
+ sqlite3VdbeAddOp2(v, OP_Null, 0, pDest->iSdst);
+ }
regRowid = 0;
regRow = pDest->iSdst;
}else{
@@ -3296,6 +3299,8 @@ static int multiSelectOrderBy(
){
int i, j; /* Loop counters */
Select *pPrior; /* Another SELECT immediately to our left */
+ Select *pSplit; /* Left-most SELECT in the right-hand group */
+ int nSelect; /* Number of SELECT statements in the compound */
Vdbe *v; /* Generate code to this VDBE */
SelectDest destA; /* Destination for coroutine A */
SelectDest destB; /* Destination for coroutine B */
@@ -3341,8 +3346,7 @@ static int multiSelectOrderBy(
/* Patch up the ORDER BY clause
*/
op = p->op;
- pPrior = p->pPrior;
- assert( pPrior->pOrderBy==0 );
+ assert( p->pPrior->pOrderBy==0 );
pOrderBy = p->pOrderBy;
assert( pOrderBy );
nOrderBy = pOrderBy->nExpr;
@@ -3392,11 +3396,6 @@ static int multiSelectOrderBy(
pKeyMerge = 0;
}
- /* Reattach the ORDER BY clause to the query.
- */
- p->pOrderBy = pOrderBy;
- pPrior->pOrderBy = sqlite3ExprListDup(pParse->db, pOrderBy, 0);
-
/* Allocate a range of temporary registers and the KeyInfo needed
** for the logic that removes duplicate result rows when the
** operator is UNION, EXCEPT, or INTERSECT (but not UNION ALL).
@@ -3421,12 +3420,29 @@ static int multiSelectOrderBy(
/* Separate the left and the right query from one another
*/
- p->pPrior = 0;
- pPrior->pNext = 0;
- sqlite3ResolveOrderGroupBy(pParse, p, p->pOrderBy, "ORDER");
- if( pPrior->pPrior==0 ){
- sqlite3ResolveOrderGroupBy(pParse, pPrior, pPrior->pOrderBy, "ORDER");
+ nSelect = 1;
+ if( (op==TK_ALL || op==TK_UNION)
+ && OptimizationEnabled(db, SQLITE_BalancedMerge)
+ ){
+ for(pSplit=p; pSplit->pPrior!=0 && pSplit->op==op; pSplit=pSplit->pPrior){
+ nSelect++;
+ assert( pSplit->pPrior->pNext==pSplit );
+ }
}
+ if( nSelect<=3 ){
+ pSplit = p;
+ }else{
+ pSplit = p;
+ for(i=2; ipPrior; }
+ }
+ pPrior = pSplit->pPrior;
+ pSplit->pPrior = 0;
+ pPrior->pNext = 0;
+ assert( p->pOrderBy == pOrderBy );
+ assert( pOrderBy!=0 || db->mallocFailed );
+ pPrior->pOrderBy = sqlite3ExprListDup(pParse->db, pOrderBy, 0);
+ sqlite3ResolveOrderGroupBy(pParse, p, p->pOrderBy, "ORDER");
+ sqlite3ResolveOrderGroupBy(pParse, pPrior, pPrior->pOrderBy, "ORDER");
/* Compute the limit registers */
computeLimitRegisters(pParse, p, labelEnd);
@@ -3577,12 +3593,11 @@ static int multiSelectOrderBy(
/* Reassembly the compound query so that it will be freed correctly
** by the calling function */
- if( p->pPrior ){
- sqlite3SelectDelete(db, p->pPrior);
+ if( pSplit->pPrior ){
+ sqlite3SelectDelete(db, pSplit->pPrior);
}
- p->pPrior = pPrior;
- pPrior->pNext = p;
-
+ pSplit->pPrior = pPrior;
+ pPrior->pNext = pSplit;
sqlite3ExprListDelete(db, pPrior->pOrderBy);
pPrior->pOrderBy = 0;
diff --git a/src/shell.c.in b/src/shell.c.in
index b4b4e2fcce..c15d2e54d4 100644
--- a/src/shell.c.in
+++ b/src/shell.c.in
@@ -427,15 +427,6 @@ static sqlite3 *globalDb = 0;
*/
static volatile int seenInterrupt = 0;
-#ifdef SQLITE_DEBUG
-/*
-** Out-of-memory simulator variables
-*/
-static unsigned int oomCounter = 0; /* Simulate OOM when equals 1 */
-static unsigned int oomRepeat = 0; /* Number of OOMs in a row */
-static void*(*defaultMalloc)(int) = 0; /* The low-level malloc routine */
-#endif /* SQLITE_DEBUG */
-
/*
** This is the name of our program. It is set in main(), used
** in a number of other places, mostly for error messages.
@@ -487,48 +478,12 @@ static void shell_out_of_memory(void){
exit(1);
}
-#ifdef SQLITE_DEBUG
-/* This routine is called when a simulated OOM occurs. It is broken
-** out as a separate routine to make it easy to set a breakpoint on
-** the OOM
+/* Check a pointer to see if it is NULL. If it is NULL, exit with an
+** out-of-memory error.
*/
-void shellOomFault(void){
- if( oomRepeat>0 ){
- oomRepeat--;
- }else{
- oomCounter--;
- }
+static void shell_check_oom(void *p){
+ if( p==0 ) shell_out_of_memory();
}
-#endif /* SQLITE_DEBUG */
-
-#ifdef SQLITE_DEBUG
-/* This routine is a replacement malloc() that is used to simulate
-** Out-Of-Memory (OOM) errors for testing purposes.
-*/
-static void *oomMalloc(int nByte){
- if( oomCounter ){
- if( oomCounter==1 ){
- shellOomFault();
- return 0;
- }else{
- oomCounter--;
- }
- }
- return defaultMalloc(nByte);
-}
-#endif /* SQLITE_DEBUG */
-
-#ifdef SQLITE_DEBUG
-/* Register the OOM simulator. This must occur before any memory
-** allocations */
-static void registerOomSimulator(void){
- sqlite3_mem_methods mem;
- sqlite3_config(SQLITE_CONFIG_GETMALLOC, &mem);
- defaultMalloc = mem.xMalloc;
- mem.xMalloc = oomMalloc;
- sqlite3_config(SQLITE_CONFIG_MALLOC, &mem);
-}
-#endif
/*
** Write I/O traces to the following stream.
@@ -685,7 +640,7 @@ static char *local_getline(char *zLine, FILE *in){
if( n+100>nLine ){
nLine = nLine*2 + 100;
zLine = realloc(zLine, nLine);
- if( zLine==0 ) shell_out_of_memory();
+ shell_check_oom(zLine);
}
if( fgets(&zLine[n], nLine - n, in)==0 ){
if( n==0 ){
@@ -712,7 +667,7 @@ static char *local_getline(char *zLine, FILE *in){
int nTrans = strlen30(zTrans)+1;
if( nTrans>nLine ){
zLine = realloc(zLine, nTrans);
- if( zLine==0 ) shell_out_of_memory();
+ shell_check_oom(zLine);
}
memcpy(zLine, zTrans, nTrans);
sqlite3_free(zTrans);
@@ -859,7 +814,7 @@ static void appendText(ShellText *p, char const *zAppend, char quote){
if( p->z==0 || p->n+len>=p->nAlloc ){
p->nAlloc = p->nAlloc*2 + len + 20;
p->z = realloc(p->z, p->nAlloc);
- if( p->z==0 ) shell_out_of_memory();
+ shell_check_oom(p->z);
}
if( quote ){
@@ -914,6 +869,7 @@ static char *shellFakeSchema(
zSql = sqlite3_mprintf("PRAGMA \"%w\".table_info=%Q;",
zSchema ? zSchema : "main", zName);
+ shell_check_oom(zSql);
sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
sqlite3_free(zSql);
initText(&s);
@@ -930,6 +886,7 @@ static char *shellFakeSchema(
nRow++;
appendText(&s, zDiv, 0);
zDiv = ",";
+ if( zCol==0 ) zCol = "";
cQuote = quoteChar(zCol);
appendText(&s, zCol, cQuote);
}
@@ -953,9 +910,11 @@ static void shellModuleSchema(
int nVal,
sqlite3_value **apVal
){
- const char *zName = (const char*)sqlite3_value_text(apVal[0]);
- char *zFake = shellFakeSchema(sqlite3_context_db_handle(pCtx), 0, zName);
+ const char *zName;
+ char *zFake;
UNUSED_PARAMETER(nVal);
+ zName = (const char*)sqlite3_value_text(apVal[0]);
+ zFake = zName ? shellFakeSchema(sqlite3_context_db_handle(pCtx), 0, zName) : 0;
if( zFake ){
sqlite3_result_text(pCtx, sqlite3_mprintf("/* %s */", zFake),
-1, sqlite3_free);
@@ -1253,6 +1212,8 @@ struct ShellState {
#define MODE_Markdown 14 /* Markdown formatting */
#define MODE_Table 15 /* MySQL-style table formatting */
#define MODE_Box 16 /* Unicode box-drawing characters */
+#define MODE_Count 17 /* Output only a count of the rows of output */
+#define MODE_Off 18 /* No query output shown */
static const char *modeDescr[] = {
"line",
@@ -1271,7 +1232,9 @@ static const char *modeDescr[] = {
"json",
"markdown",
"table",
- "box"
+ "box",
+ "count",
+ "off"
};
/*
@@ -1771,6 +1734,7 @@ static void output_csv(ShellState *p, const char *z, int bSep){
}
if( i==0 || strstr(z, p->colSeparator)!=0 ){
char *zQuoted = sqlite3_mprintf("\"%w\"", z);
+ shell_check_oom(zQuoted);
utf8_printf(out, "%s", zQuoted);
sqlite3_free(zQuoted);
}else{
@@ -1945,7 +1909,7 @@ static void eqp_append(ShellState *p, int iEqpId, int p2, const char *zText){
utf8_printf(p->out, "%d,%d,%s\n", iEqpId, p2, zText);
}
pNew = sqlite3_malloc64( sizeof(*pNew) + nText );
- if( pNew==0 ) shell_out_of_memory();
+ shell_check_oom(pNew);
pNew->iEqpId = iEqpId;
pNew->iParentId = p2;
memcpy(pNew->zText, zText, nText+1);
@@ -2093,6 +2057,10 @@ static int shell_callback(
if( azArg==0 ) return 0;
switch( p->cMode ){
+ case MODE_Count:
+ case MODE_Off: {
+ break;
+ }
case MODE_Line: {
int w = 5;
if( azArg==0 ) break;
@@ -2162,6 +2130,7 @@ static int shell_callback(
break;
}
z = sqlite3_mprintf("%s", azArg[0]);
+ shell_check_oom(z);
j = 0;
for(i=0; IsSpace(z[i]); i++){}
for(; (c = z[i])!=0; i++){
@@ -2293,6 +2262,7 @@ static int shell_callback(
if( i>0 ) raw_printf(p->out, ",");
if( quoteChar(azCol[i]) ){
char *z = sqlite3_mprintf("\"%w\"", azCol[i]);
+ shell_check_oom(z);
utf8_printf(p->out, "%s", z);
sqlite3_free(z);
}else{
@@ -2538,7 +2508,7 @@ static void set_table_name(ShellState *p, const char *zName){
n = strlen30(zName);
if( cQuote ) n += n+2;
z = p->zDestTable = malloc( n+1 );
- if( z==0 ) shell_out_of_memory();
+ shell_check_oom(z);
n = 0;
if( cQuote ) z[n++] = cQuote;
for(i=0; zName[i]; i++){
@@ -2549,6 +2519,47 @@ static void set_table_name(ShellState *p, const char *zName){
z[n] = 0;
}
+/*
+** Maybe construct two lines of text that point out the position of a
+** syntax error. Return a pointer to the text, in memory obtained from
+** sqlite3_malloc(). Or, if the most recent error does not involve a
+** specific token that we can point to, return an empty string.
+**
+** In all cases, the memory returned is obtained from sqlite3_malloc64()
+** and should be released by the caller invoking sqlite3_free().
+*/
+static char *shell_error_context(const char *zSql, sqlite3 *db){
+ int iOffset;
+ size_t len;
+ char *zCode;
+ char *zMsg;
+ int i;
+ if( db==0
+ || zSql==0
+ || (iOffset = sqlite3_error_offset(db))<0
+ ){
+ return sqlite3_mprintf("");
+ }
+ while( iOffset>50 ){
+ iOffset--;
+ zSql++;
+ while( (zSql[0]&0xc0)==0x80 ){ zSql++; iOffset--; }
+ }
+ len = strlen(zSql);
+ if( len>78 ){
+ len = 78;
+ while( (zSql[len]&0xc0)==0x80 ) len--;
+ }
+ zCode = sqlite3_mprintf("%.*s", len, zSql);
+ for(i=0; zCode[i]; i++){ if( IsSpace(zSql[i]) ) zCode[i] = ' '; }
+ if( iOffset<25 ){
+ zMsg = sqlite3_mprintf("\n %z\n %*s^--- error here", zCode, iOffset, "");
+ }else{
+ zMsg = sqlite3_mprintf("\n %z\n %*serror here ---^", zCode, iOffset-14, "");
+ }
+ return zMsg;
+}
+
/*
** Execute a query statement that will generate SQL output. Print
@@ -2571,8 +2582,10 @@ static int run_table_dump_query(
const char *z;
rc = sqlite3_prepare_v2(p->db, zSelect, -1, &pSelect, 0);
if( rc!=SQLITE_OK || !pSelect ){
- utf8_printf(p->out, "/**** ERROR: (%d) %s *****/\n", rc,
- sqlite3_errmsg(p->db));
+ char *zContext = shell_error_context(zSelect, p->db);
+ utf8_printf(p->out, "/**** ERROR: (%d) %s *****/\n%s", rc,
+ sqlite3_errmsg(p->db), zContext);
+ sqlite3_free(zContext);
if( (rc&0xff)!=SQLITE_CORRUPT ) p->nErr++;
return rc;
}
@@ -2608,11 +2621,17 @@ static int run_table_dump_query(
static char *save_err_msg(
sqlite3 *db, /* Database to query */
const char *zWhen, /* Qualifier (format) wrapper */
- int rc /* Error code returned from API */
+ int rc, /* Error code returned from API */
+ const char *zSql /* SQL string, or NULL */
){
- if( zWhen==0 )
- zWhen = "%s (%d)";
- return sqlite3_mprintf(zWhen, sqlite3_errmsg(db), rc);
+ char *zErr;
+ char *zContext;
+ if( zWhen==0 ) zWhen = "%s (%d)%s";
+ zContext = shell_error_context(zSql, db);
+ zErr = sqlite3_mprintf(zWhen, sqlite3_errmsg(db), rc, zContext);
+ shell_check_oom(zErr);
+ sqlite3_free(zContext);
+ return zErr;
}
#ifdef __linux__
@@ -2790,6 +2809,7 @@ static int display_stats(
}
if( pArg->pStmt ){
+ int iHit, iMiss;
iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_FULLSCAN_STEP,
bReset);
raw_printf(pArg->out, "Fullscan Steps: %d\n", iCur);
@@ -2797,6 +2817,12 @@ static int display_stats(
raw_printf(pArg->out, "Sort Operations: %d\n", iCur);
iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_AUTOINDEX,bReset);
raw_printf(pArg->out, "Autoindex Inserts: %d\n", iCur);
+ iHit = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_FILTER_HIT, bReset);
+ iMiss = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_FILTER_MISS, bReset);
+ if( iHit || iMiss ){
+ raw_printf(pArg->out, "Bloom filter bypass taken: %d/%d\n",
+ iHit, iHit+iMiss);
+ }
iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_VM_STEP, bReset);
raw_printf(pArg->out, "Virtual Machine Steps: %d\n", iCur);
iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_REPREPARE,bReset);
@@ -2953,9 +2979,9 @@ static void explain_data_prepare(ShellState *p, sqlite3_stmt *pSql){
}
nAlloc += 100;
p->aiIndent = (int*)sqlite3_realloc64(p->aiIndent, nAlloc*sizeof(int));
- if( p->aiIndent==0 ) shell_out_of_memory();
+ shell_check_oom(p->aiIndent);
abYield = (int*)sqlite3_realloc64(abYield, nAlloc*sizeof(int));
- if( abYield==0 ) shell_out_of_memory();
+ shell_check_oom(abYield);
}
abYield[iOp] = str_in_array(zOp, azYield);
p->aiIndent[iOp] = 0;
@@ -3164,7 +3190,7 @@ static void exec_prepared_stmt_columnar(
nAlloc = nColumn*4;
if( nAlloc<=0 ) nAlloc = 1;
azData = sqlite3_malloc64( nAlloc*sizeof(char*) );
- if( azData==0 ) shell_out_of_memory();
+ shell_check_oom(azData);
for(i=0; i= nAlloc ){
nAlloc *= 2;
azData = sqlite3_realloc64(azData, nAlloc*sizeof(char*));
- if( azData==0 ) shell_out_of_memory();
+ shell_check_oom(azData);
}
nRow++;
for(i=0; ip->nWidth ){
p->colWidth = realloc(p->colWidth, (nColumn+1)*2*sizeof(int));
- if( p->colWidth==0 ) shell_out_of_memory();
+ shell_check_oom(p->colWidth);
for(i=p->nWidth; icolWidth[i] = 0;
p->nWidth = nColumn;
p->actualWidth = &p->colWidth[nColumn];
@@ -3303,6 +3329,7 @@ static void exec_prepared_stmt(
sqlite3_stmt *pStmt /* Statment to run */
){
int rc;
+ sqlite3_uint64 nRow = 0;
if( pArg->cMode==MODE_Column
|| pArg->cMode==MODE_Table
@@ -3335,10 +3362,14 @@ static void exec_prepared_stmt(
azCols[i] = (char *)sqlite3_column_name(pStmt, i);
}
do{
+ nRow++;
/* extract the data and data types */
for(i=0; icMode==MODE_Insert ){
+ if( x==SQLITE_BLOB
+ && pArg
+ && (pArg->cMode==MODE_Insert || pArg->cMode==MODE_Quote)
+ ){
azVals[i] = "";
}else{
azVals[i] = (char*)sqlite3_column_text(pStmt, i);
@@ -3362,6 +3393,11 @@ static void exec_prepared_stmt(
sqlite3_free(pData);
if( pArg->cMode==MODE_Json ){
fputs("]\n", pArg->out);
+ }else if( pArg->cMode==MODE_Count ){
+ char zBuf[200];
+ sqlite3_snprintf(sizeof(zBuf), zBuf, "%llu row%s\n",
+ nRow, nRow!=1 ? "s" : "");
+ printf("%s", zBuf);
}
}
}
@@ -3485,7 +3521,7 @@ static int expertDotCommand(
if( rc==SQLITE_OK ){
pState->expert.pExpert = sqlite3_expert_new(pState->db, &zErr);
if( pState->expert.pExpert==0 ){
- raw_printf(stderr, "sqlite3_expert_new: %s\n", zErr);
+ raw_printf(stderr, "sqlite3_expert_new: %s\n", zErr ? zErr : "out of memory");
rc = SQLITE_ERROR;
}else{
sqlite3_expert_config(
@@ -3493,6 +3529,7 @@ static int expertDotCommand(
);
}
}
+ sqlite3_free(zErr);
return rc;
}
@@ -3534,7 +3571,7 @@ static int shell_exec(
rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zLeftover);
if( SQLITE_OK != rc ){
if( pzErrMsg ){
- *pzErrMsg = save_err_msg(db, "in prepare, %s (%d)", rc);
+ *pzErrMsg = save_err_msg(db, "in prepare, %s (%d)%s", rc, zSql);
}
}else{
if( !pStmt ){
@@ -3569,6 +3606,7 @@ static int shell_exec(
sqlite3_db_config(db, SQLITE_DBCONFIG_TRIGGER_EQP, 1, 0);
}
zEQP = sqlite3_mprintf("EXPLAIN QUERY PLAN %s", zStmtSql);
+ shell_check_oom(zEQP);
rc = sqlite3_prepare_v2(db, zEQP, -1, &pExplain, 0);
if( rc==SQLITE_OK ){
while( sqlite3_step(pExplain)==SQLITE_ROW ){
@@ -3586,6 +3624,7 @@ static int shell_exec(
if( pArg->autoEQP>=AUTOEQP_full ){
/* Also do an EXPLAIN for ".eqp full" mode */
zEQP = sqlite3_mprintf("EXPLAIN %s", zStmtSql);
+ shell_check_oom(zEQP);
rc = sqlite3_prepare_v2(db, zEQP, -1, &pExplain, 0);
if( rc==SQLITE_OK ){
pArg->cMode = MODE_Explain;
@@ -3648,7 +3687,7 @@ static int shell_exec(
zSql = zLeftover;
while( IsSpace(zSql[0]) ) zSql++;
}else if( pzErrMsg ){
- *pzErrMsg = save_err_msg(db, "stepping, %s (%d)", rc);
+ *pzErrMsg = save_err_msg(db, "stepping, %s (%d)", rc, 0);
}
/* clear saved stmt handle */
@@ -3698,6 +3737,7 @@ static char **tableColumnList(ShellState *p, const char *zTab){
int rc;
zSql = sqlite3_mprintf("PRAGMA table_info=%Q", zTab);
+ shell_check_oom(zSql);
rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
sqlite3_free(zSql);
if( rc ) return 0;
@@ -3705,9 +3745,10 @@ static char **tableColumnList(ShellState *p, const char *zTab){
if( nCol>=nAlloc-2 ){
nAlloc = nAlloc*2 + nCol + 10;
azCol = sqlite3_realloc(azCol, nAlloc*sizeof(azCol[0]));
- if( azCol==0 ) shell_out_of_memory();
+ shell_check_oom(azCol);
}
azCol[++nCol] = sqlite3_mprintf("%s", sqlite3_column_text(pStmt, 1));
+ shell_check_oom(azCol[nCol]);
if( sqlite3_column_int(pStmt, 5) ){
nPK++;
if( nPK==1
@@ -3741,6 +3782,7 @@ static char **tableColumnList(ShellState *p, const char *zTab){
*/
zSql = sqlite3_mprintf("SELECT 1 FROM pragma_index_list(%Q)"
" WHERE origin='pk'", zTab);
+ shell_check_oom(zSql);
rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
sqlite3_free(zSql);
if( rc ){
@@ -3832,6 +3874,7 @@ static int dump_callback(void *pArg, int nArg, char **azArg, char **azNotUsed){
"INSERT INTO sqlite_schema(type,name,tbl_name,rootpage,sql)"
"VALUES('table','%q','%q',0,'%q');",
zTable, zTable, zSql);
+ shell_check_oom(zIns);
utf8_printf(p->out, "%s\n", zIns);
sqlite3_free(zIns);
return 0;
@@ -4027,6 +4070,7 @@ static const char *(azHelp[]) = {
" --ascii Use \\037 and \\036 as column and row separators",
" --csv Use , and \\n as column and row separators",
" --skip N Skip the first N rows of input",
+ " --schema S Target table to be S.TABLE",
" -v \"Verbose\" - increase auxiliary output",
" Notes:",
" * If TABLE does not exist, it is created. The first row of input",
@@ -4075,9 +4119,6 @@ static const char *(azHelp[]) = {
" --bom Put a UTF8 byte-order mark at the beginning",
" -e Send output to the system text editor",
" -x Send output as CSV to a spreadsheet (same as \".excel\")",
-#ifdef SQLITE_DEBUG
- ".oom ?--repeat M? ?N? Simulate an OOM error on the N-th allocation",
-#endif
".open ?OPTIONS? ?FILE? Close existing database and reopen FILE",
" Options:",
" --append Use appendvfs to append database to the end of FILE",
@@ -4113,7 +4154,8 @@ static const char *(azHelp[]) = {
#endif
".prompt MAIN CONTINUE Replace the standard prompts",
".quit Exit this program",
- ".read FILE Read input from FILE",
+ ".read FILE Read input from FILE or command output",
+ " If FILE begins with \"|\", it is a command that generates the input.",
#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB)
".recover Recover as much data as possible from corrupt db.",
" --freelist-corrupt Assume the freelist is corrupt",
@@ -4233,6 +4275,7 @@ static int showHelp(FILE *out, const char *zPattern){
}else{
/* Look for commands that for which zPattern is an exact prefix */
zPat = sqlite3_mprintf(".%s*", zPattern);
+ shell_check_oom(zPat);
for(i=0; i65536 || (pgsz&(pgsz-1))!=0 ) goto readHexDb_error;
n = (n+pgsz-1)&~(pgsz-1); /* Round n up to the next multiple of pgsz */
a = sqlite3_malloc( n ? n : 1 );
- if( a==0 ){
- utf8_printf(stderr, "Out of memory!\n");
- goto readHexDb_error;
- }
+ shell_check_oom(a);
memset(a, 0, n);
if( pgsz<512 || pgsz>65536 || (pgsz & (pgsz-1))!=0 ){
utf8_printf(stderr, "invalid pagesize\n");
@@ -4577,7 +4618,7 @@ static void shellEscapeCrnl(
){
const char *zText = (const char*)sqlite3_value_text(argv[0]);
UNUSED_PARAMETER(argc);
- if( zText[0]=='\'' ){
+ if( zText && zText[0]=='\'' ){
int nText = sqlite3_value_bytes(argv[0]);
int i;
char zBuf1[20];
@@ -4754,6 +4795,7 @@ static void open_db(ShellState *p, int openFlags){
if( p->openMode==SHELL_OPEN_ZIPFILE ){
char *zSql = sqlite3_mprintf(
"CREATE VIRTUAL TABLE zip USING zipfile(%Q);", zDbFilename);
+ shell_check_oom(zSql);
sqlite3_exec(p->db, zSql, 0, 0, 0);
sqlite3_free(zSql);
}
@@ -4811,11 +4853,13 @@ static char *readline_completion_generator(const char *text, int state){
sqlite3_finalize(pStmt);
zSql = sqlite3_mprintf("SELECT DISTINCT candidate COLLATE nocase"
" FROM completion(%Q) ORDER BY 1", text);
+ shell_check_oom(zSql);
sqlite3_prepare_v2(globalDb, zSql, -1, &pStmt, 0);
sqlite3_free(zSql);
}
if( sqlite3_step(pStmt)==SQLITE_ROW ){
- zRet = strdup((const char*)sqlite3_column_text(pStmt, 0));
+ const char *z = (const char*)sqlite3_column_text(pStmt,0);
+ zRet = z ? strdup(z) : 0;
}else{
sqlite3_finalize(pStmt);
pStmt = 0;
@@ -4848,13 +4892,14 @@ static void linenoise_completion(const char *zLine, linenoiseCompletions *lc){
zSql = sqlite3_mprintf("SELECT DISTINCT candidate COLLATE nocase"
" FROM completion(%Q,%Q) ORDER BY 1",
&zLine[iStart], zLine);
+ shell_check_oom(zSql);
sqlite3_prepare_v2(globalDb, zSql, -1, &pStmt, 0);
sqlite3_free(zSql);
sqlite3_exec(globalDb, "PRAGMA page_count", 0, 0, 0); /* Load the schema */
while( sqlite3_step(pStmt)==SQLITE_ROW ){
const char *zCompletion = (const char*)sqlite3_column_text(pStmt, 0);
int nCompletion = sqlite3_column_bytes(pStmt, 0);
- if( iStart+nCompletion < sizeof(zBuf)-1 ){
+ if( iStart+nCompletion < sizeof(zBuf)-1 && zCompletion ){
memcpy(zBuf+iStart, zCompletion, nCompletion+1);
linenoiseAddCompletion(lc, zBuf);
}
@@ -5089,7 +5134,7 @@ static void import_append_char(ImportCtx *p, int c){
if( p->n+1>=p->nAlloc ){
p->nAlloc += p->nAlloc + 100;
p->z = sqlite3_realloc64(p->z, p->nAlloc);
- if( p->z==0 ) shell_out_of_memory();
+ shell_check_oom(p->z);
}
p->z[p->n++] = (char)c;
}
@@ -5241,6 +5286,7 @@ static void tryToCloneData(
const int spinRate = 10000;
zQuery = sqlite3_mprintf("SELECT * FROM \"%w\"", zTable);
+ shell_check_oom(zQuery);
rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
if( rc ){
utf8_printf(stderr, "Error %d: %s on [%s]\n",
@@ -5250,7 +5296,7 @@ static void tryToCloneData(
}
n = sqlite3_column_count(pQuery);
zInsert = sqlite3_malloc64(200 + nTable + n*3);
- if( zInsert==0 ) shell_out_of_memory();
+ shell_check_oom(zInsert);
sqlite3_snprintf(200+nTable,zInsert,
"INSERT OR IGNORE INTO \"%s\" VALUES(?", zTable);
i = strlen30(zInsert);
@@ -5313,6 +5359,7 @@ static void tryToCloneData(
sqlite3_free(zQuery);
zQuery = sqlite3_mprintf("SELECT * FROM \"%w\" ORDER BY rowid DESC;",
zTable);
+ shell_check_oom(zQuery);
rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
if( rc ){
utf8_printf(stderr, "Warning: cannot step \"%s\" backwards", zTable);
@@ -5349,6 +5396,7 @@ static void tryToCloneSchema(
zQuery = sqlite3_mprintf("SELECT name, sql FROM sqlite_schema"
" WHERE %s", zWhere);
+ shell_check_oom(zQuery);
rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
if( rc ){
utf8_printf(stderr, "Error: (%d) %s on [%s]\n",
@@ -5359,6 +5407,7 @@ static void tryToCloneSchema(
while( (rc = sqlite3_step(pQuery))==SQLITE_ROW ){
zName = sqlite3_column_text(pQuery, 0);
zSql = sqlite3_column_text(pQuery, 1);
+ if( zName==0 || zSql==0 ) continue;
printf("%s... ", zName); fflush(stdout);
sqlite3_exec(newDb, (const char*)zSql, 0, 0, &zErrMsg);
if( zErrMsg ){
@@ -5376,6 +5425,7 @@ static void tryToCloneSchema(
sqlite3_free(zQuery);
zQuery = sqlite3_mprintf("SELECT name, sql FROM sqlite_schema"
" WHERE %s ORDER BY rowid DESC", zWhere);
+ shell_check_oom(zQuery);
rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
if( rc ){
utf8_printf(stderr, "Error: (%d) %s on [%s]\n",
@@ -5386,6 +5436,7 @@ static void tryToCloneSchema(
while( sqlite3_step(pQuery)==SQLITE_ROW ){
zName = sqlite3_column_text(pQuery, 0);
zSql = sqlite3_column_text(pQuery, 1);
+ if( zName==0 || zSql==0 ) continue;
printf("%s... ", zName); fflush(stdout);
sqlite3_exec(newDb, (const char*)zSql, 0, 0, &zErrMsg);
if( zErrMsg ){
@@ -5770,9 +5821,7 @@ static void newTempFile(ShellState *p, const char *zSuffix){
}else{
p->zTempFile = sqlite3_mprintf("%z.%s", p->zTempFile, zSuffix);
}
- if( p->zTempFile==0 ){
- shell_out_of_memory();
- }
+ shell_check_oom(p->zTempFile);
}
@@ -5953,14 +6002,14 @@ static int lintFkeyIndexes(
const char *zCI = (const char*)sqlite3_column_text(pSql, 4);
const char *zParent = (const char*)sqlite3_column_text(pSql, 5);
+ if( zEQP==0 ) continue;
+ if( zGlob==0 ) continue;
rc = sqlite3_prepare_v2(db, zEQP, -1, &pExplain, 0);
if( rc!=SQLITE_OK ) break;
if( SQLITE_ROW==sqlite3_step(pExplain) ){
const char *zPlan = (const char*)sqlite3_column_text(pExplain, 3);
- res = (
- 0==sqlite3_strglob(zGlob, zPlan)
- || 0==sqlite3_strglob(zGlobIPK, zPlan)
- );
+ res = zPlan!=0 && ( 0==sqlite3_strglob(zGlob, zPlan)
+ || 0==sqlite3_strglob(zGlobIPK, zPlan));
}
rc = sqlite3_finalize(pExplain);
if( rc!=SQLITE_OK ) break;
@@ -7065,6 +7114,7 @@ static RecoverTable *recoverNewTable(
if( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pPkFinder) ){
pTab->iPk = sqlite3_column_int(pPkFinder, 0);
zPk = (const char*)sqlite3_column_text(pPkFinder, 1);
+ if( zPk==0 ){ zPk = "_"; /* Defensive. Should never happen */ }
}
}
@@ -7149,8 +7199,10 @@ static RecoverTable *recoverFindTable(
if( sqlite3_stricmp(zType, "table")==0 ){
zName = (const char*)sqlite3_column_text(pStmt, 1);
zSql = (const char*)sqlite3_column_text(pStmt, 2);
- pRet = recoverNewTable(pRc, zName, zSql, bIntkey, nCol);
- break;
+ if( zName!=0 && zSql!=0 ){
+ pRet = recoverNewTable(pRc, zName, zSql, bIntkey, nCol);
+ break;
+ }
}
}
@@ -7844,8 +7896,9 @@ static int do_meta_command(char *zLine, ShellState *p){
while( sqlite3_step(pStmt)==SQLITE_ROW ){
const char *zSchema = (const char *)sqlite3_column_text(pStmt,1);
const char *zFile = (const char*)sqlite3_column_text(pStmt,2);
+ if( zSchema==0 || zFile==0 ) continue;
azName = sqlite3_realloc(azName, (nName+1)*2*sizeof(char*));
- if( azName==0 ){ shell_out_of_memory(); /* Does not return */ }
+ shell_check_oom(azName);
azName[nName*2] = strdup(zSchema);
azName[nName*2+1] = strdup(zFile);
nName++;
@@ -8101,8 +8154,15 @@ static int do_meta_command(char *zLine, ShellState *p){
#ifndef SQLITE_OMIT_VIRTUALTABLE
if( c=='e' && strncmp(azArg[0], "expert", n)==0 ){
- open_db(p, 0);
- expertDotCommand(p, azArg, nArg);
+ if( p->bSafeMode ){
+ raw_printf(stderr,
+ "Cannot run experimental commands such as \"%s\" in safe mode\n",
+ azArg[0]);
+ rc = 1;
+ }else{
+ open_db(p, 0);
+ expertDotCommand(p, azArg, nArg);
+ }
}else
#endif
@@ -8323,6 +8383,7 @@ static int do_meta_command(char *zLine, ShellState *p){
if( c=='i' && strncmp(azArg[0], "import", n)==0 ){
char *zTable = 0; /* Insert data into this table */
+ char *zSchema = "main"; /* within this schema */
char *zFile = 0; /* Name of file to extra content from */
sqlite3_stmt *pStmt = NULL; /* A statement */
int nCol; /* Number of columns in the table */
@@ -8365,6 +8426,8 @@ static int do_meta_command(char *zLine, ShellState *p){
}
}else if( strcmp(z,"-v")==0 ){
eVerbose++;
+ }else if( strcmp(z,"-schema")==0 && i=2 || (eVerbose>=1 && useOutputMode) ){
char zSep[2];
zSep[1] = 0;
@@ -8470,7 +8534,7 @@ static int do_meta_command(char *zLine, ShellState *p){
while( (nSkip--)>0 ){
while( xRead(&sCtx) && sCtx.cTerm==sCtx.cColSep ){}
}
- zSql = sqlite3_mprintf("SELECT * FROM \"%w\"", zTable);
+ zSql = sqlite3_mprintf("SELECT * FROM \"%w\".\"%w\"", zSchema, zTable);
if( zSql==0 ){
import_cleanup(&sCtx);
shell_out_of_memory();
@@ -8479,7 +8543,8 @@ static int do_meta_command(char *zLine, ShellState *p){
rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
import_append_char(&sCtx, 0); /* To ensure sCtx.z is allocated */
if( rc && sqlite3_strglob("no such table: *", sqlite3_errmsg(p->db))==0 ){
- char *zCreate = sqlite3_mprintf("CREATE TABLE \"%w\"", zTable);
+ char *zCreate = sqlite3_mprintf("CREATE TABLE \"%w\".\"%w\"",
+ zSchema, zTable);
char cSep = '(';
while( xRead(&sCtx) ){
zCreate = sqlite3_mprintf("%z%c\n \"%w\" TEXT", zCreate, cSep, sCtx.z);
@@ -8498,14 +8563,14 @@ static int do_meta_command(char *zLine, ShellState *p){
utf8_printf(p->out, "%s\n", zCreate);
}
rc = sqlite3_exec(p->db, zCreate, 0, 0, 0);
- sqlite3_free(zCreate);
if( rc ){
- utf8_printf(stderr, "CREATE TABLE \"%s\"(...) failed: %s\n", zTable,
- sqlite3_errmsg(p->db));
+ utf8_printf(stderr, "%s failed:\n%s\n", zCreate, sqlite3_errmsg(p->db));
+ sqlite3_free(zCreate);
import_cleanup(&sCtx);
rc = 1;
goto meta_command_exit;
}
+ sqlite3_free(zCreate);
rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
}
sqlite3_free(zSql);
@@ -8525,7 +8590,8 @@ static int do_meta_command(char *zLine, ShellState *p){
import_cleanup(&sCtx);
shell_out_of_memory();
}
- sqlite3_snprintf(nByte+20, zSql, "INSERT INTO \"%w\" VALUES(?", zTable);
+ sqlite3_snprintf(nByte+20, zSql, "INSERT INTO \"%w\".\"%w\" VALUES(?",
+ zSchema, zTable);
j = strlen30(zSql);
for(i=1; imode = MODE_Table;
}else if( c2=='b' && strncmp(azArg[1],"box",n2)==0 ){
p->mode = MODE_Box;
+ }else if( c2=='c' && strncmp(azArg[1],"count",n2)==0 ){
+ p->mode = MODE_Count;
+ }else if( c2=='o' && strncmp(azArg[1],"off",n2)==0 ){
+ p->mode = MODE_Off;
}else if( c2=='j' && strncmp(azArg[1],"json",n2)==0 ){
p->mode = MODE_Json;
}else if( nArg==1 ){
@@ -8890,7 +8960,8 @@ static int do_meta_command(char *zLine, ShellState *p){
raw_printf(stderr, "Usage: .nonce NONCE\n");
rc = 1;
}else if( p->zNonce==0 || strcmp(azArg[1],p->zNonce)!=0 ){
- raw_printf(stderr, "line %d: incorrect nonce: \"%s\"\n", p->lineno, azArg[1]);
+ raw_printf(stderr, "line %d: incorrect nonce: \"%s\"\n",
+ p->lineno, azArg[1]);
exit(1);
}else{
p->bSafeMode = 0;
@@ -8909,48 +8980,13 @@ static int do_meta_command(char *zLine, ShellState *p){
}
}else
-#ifdef SQLITE_DEBUG
- if( c=='o' && strcmp(azArg[0],"oom")==0 ){
- int i;
- for(i=1; iout, "missing argument on \"%s\"\n", azArg[i]);
- rc = 1;
- }else{
- oomRepeat = (int)integerValue(azArg[++i]);
- }
- }else if( IsDigit(z[0]) ){
- oomCounter = (int)integerValue(azArg[i]);
- }else{
- raw_printf(p->out, "unknown argument: \"%s\"\n", azArg[i]);
- raw_printf(p->out, "Usage: .oom [--repeat N] [M]\n");
- rc = 1;
- }
- }
- if( rc==0 ){
- raw_printf(p->out, "oomCounter = %d\n", oomCounter);
- raw_printf(p->out, "oomRepeat = %d\n", oomRepeat);
- }
- }else
-#endif /* SQLITE_DEBUG */
-
if( c=='o' && strncmp(azArg[0], "open", n)==0 && n>=2 ){
+ const char *zFN = 0; /* Pointer to constant filename */
char *zNewFilename = 0; /* Name of the database file to open */
int iName = 1; /* Index in azArg[] of the filename */
int newFlag = 0; /* True to delete file before opening */
- /* Close the existing database */
- session_close_all(p, -1);
- close_db(p->db);
- p->db = 0;
- p->pAuxDb->zDbFilename = 0;
- sqlite3_free(p->pAuxDb->zFreeOnClose);
- p->pAuxDb->zFreeOnClose = 0;
- p->openMode = SHELL_OPEN_UNSPEC;
- p->openFlags = 0;
- p->szMax = 0;
+ int openMode = SHELL_OPEN_UNSPEC;
+
/* Check for command-line arguments */
for(iName=1; iNameopenMode = SHELL_OPEN_ZIPFILE;
+ openMode = SHELL_OPEN_ZIPFILE;
#endif
}else if( optionMatch(z, "append") ){
- p->openMode = SHELL_OPEN_APPENDVFS;
+ openMode = SHELL_OPEN_APPENDVFS;
}else if( optionMatch(z, "readonly") ){
- p->openMode = SHELL_OPEN_READONLY;
+ openMode = SHELL_OPEN_READONLY;
}else if( optionMatch(z, "nofollow") ){
p->openFlags |= SQLITE_OPEN_NOFOLLOW;
#ifndef SQLITE_OMIT_DESERIALIZE
}else if( optionMatch(z, "deserialize") ){
- p->openMode = SHELL_OPEN_DESERIALIZE;
+ openMode = SHELL_OPEN_DESERIALIZE;
}else if( optionMatch(z, "hexdb") ){
- p->openMode = SHELL_OPEN_HEXDB;
+ openMode = SHELL_OPEN_HEXDB;
}else if( optionMatch(z, "maxsize") && iName+1szMax = integerValue(azArg[++iName]);
#endif /* SQLITE_OMIT_DESERIALIZE */
@@ -8978,24 +9014,42 @@ static int do_meta_command(char *zLine, ShellState *p){
utf8_printf(stderr, "unknown option: %s\n", z);
rc = 1;
goto meta_command_exit;
- }else if( zNewFilename ){
+ }else if( zFN ){
utf8_printf(stderr, "extra argument: \"%s\"\n", z);
rc = 1;
goto meta_command_exit;
}else{
- zNewFilename = sqlite3_mprintf("%s", z);
+ zFN = z;
}
}
+
+ /* Close the existing database */
+ session_close_all(p, -1);
+ close_db(p->db);
+ p->db = 0;
+ p->pAuxDb->zDbFilename = 0;
+ sqlite3_free(p->pAuxDb->zFreeOnClose);
+ p->pAuxDb->zFreeOnClose = 0;
+ p->openMode = openMode;
+ p->openFlags = 0;
+ p->szMax = 0;
+
/* If a filename is specified, try to open it first */
- if( zNewFilename || p->openMode==SHELL_OPEN_HEXDB ){
- if( newFlag && !p->bSafeMode ) shellDeleteFile(zNewFilename);
+ if( zFN || p->openMode==SHELL_OPEN_HEXDB ){
+ if( newFlag && zFN && !p->bSafeMode ) shellDeleteFile(zFN);
if( p->bSafeMode
&& p->openMode!=SHELL_OPEN_HEXDB
- && zNewFilename
- && strcmp(zNewFilename,":memory:")!=0
+ && zFN
+ && strcmp(zFN,":memory:")!=0
){
failIfSafeMode(p, "cannot open disk-based database files in safe mode");
}
+ if( zFN ){
+ zNewFilename = sqlite3_mprintf("%s", zFN);
+ shell_check_oom(zNewFilename);
+ }else{
+ zNewFilename = 0;
+ }
p->pAuxDb->zDbFilename = zNewFilename;
open_db(p, OPEN_DB_KEEPALIVE);
if( p->db==0 ){
@@ -9049,7 +9103,7 @@ static int do_meta_command(char *zLine, ShellState *p){
}
}else if( zFile==0 && eMode!='e' && eMode!='x' ){
zFile = sqlite3_mprintf("%s", z);
- if( zFile[0]=='|' ){
+ if( zFile && zFile[0]=='|' ){
while( i+1outCount = 2;
}else{
@@ -9089,6 +9145,7 @@ static int do_meta_command(char *zLine, ShellState *p){
zFile = sqlite3_mprintf("%s", p->zTempFile);
}
#endif /* SQLITE_NOHAVE_SYSTEM */
+ shell_check_oom(zFile);
if( zFile[0]=='|' ){
#ifdef SQLITE_OMIT_POPEN
raw_printf(stderr, "Error: pipes are not supported in this OS\n");
@@ -9185,7 +9242,7 @@ static int do_meta_command(char *zLine, ShellState *p){
zSql = sqlite3_mprintf(
"REPLACE INTO temp.sqlite_parameters(key,value)"
"VALUES(%Q,%s);", zKey, zValue);
- if( zSql==0 ) shell_out_of_memory();
+ shell_check_oom(zSql);
pStmt = 0;
rx = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
sqlite3_free(zSql);
@@ -9195,7 +9252,7 @@ static int do_meta_command(char *zLine, ShellState *p){
zSql = sqlite3_mprintf(
"REPLACE INTO temp.sqlite_parameters(key,value)"
"VALUES(%Q,%Q);", zKey, zValue);
- if( zSql==0 ) shell_out_of_memory();
+ shell_check_oom(zSql);
rx = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
sqlite3_free(zSql);
if( rx!=SQLITE_OK ){
@@ -9216,7 +9273,7 @@ static int do_meta_command(char *zLine, ShellState *p){
if( nArg==3 && strcmp(azArg[1],"unset")==0 ){
char *zSql = sqlite3_mprintf(
"DELETE FROM temp.sqlite_parameters WHERE key=%Q", azArg[2]);
- if( zSql==0 ) shell_out_of_memory();
+ shell_check_oom(zSql);
sqlite3_exec(p->db, zSql, 0, 0, 0);
sqlite3_free(zSql);
}else
@@ -9442,6 +9499,7 @@ static int do_meta_command(char *zLine, ShellState *p){
" rootpage integer,\n"
" sql text\n"
")", zName);
+ shell_check_oom(new_argv[0]);
new_argv[1] = 0;
new_colv[0] = "sql";
new_colv[1] = 0;
@@ -9493,8 +9551,10 @@ static int do_meta_command(char *zLine, ShellState *p){
appendText(&sSelect, ") WHERE ", 0);
if( zName ){
char *zQarg = sqlite3_mprintf("%Q", zName);
- int bGlob = strchr(zName, '*') != 0 || strchr(zName, '?') != 0 ||
- strchr(zName, '[') != 0;
+ int bGlob;
+ shell_check_oom(zQarg);
+ bGlob = strchr(zName, '*') != 0 || strchr(zName, '?') != 0 ||
+ strchr(zName, '[') != 0;
if( strchr(zName, '.') ){
appendText(&sSelect, "lower(printf('%s.%s',sname,tbl_name))", 0);
}else{
@@ -9657,7 +9717,8 @@ static int do_meta_command(char *zLine, ShellState *p){
exit(1);
}
for(ii=1; iiazFilter[ii-1] = sqlite3_mprintf("%s", azCmd[ii]);
+ char *x = pSession->azFilter[ii-1] = sqlite3_mprintf("%s", azCmd[ii]);
+ shell_check_oom(x);
}
pSession->nFilter = ii-1;
}
@@ -9729,6 +9790,7 @@ static int do_meta_command(char *zLine, ShellState *p){
sqlite3session_table_filter(pSession->p, session_filter, pSession);
pAuxDb->nSession++;
pSession->zName = sqlite3_mprintf("%s", zName);
+ shell_check_oom(pSession->zName);
}else
/* If no command name matches, show a syntax error */
session_syntax_error:
@@ -9822,11 +9884,12 @@ static int do_meta_command(char *zLine, ShellState *p){
const char *zSql = (const char*)sqlite3_column_text(pStmt, 2);
const char *zAns = (const char*)sqlite3_column_text(pStmt, 3);
+ if( zOp==0 ) continue;
+ if( zSql==0 ) continue;
+ if( zAns==0 ) continue;
k = 0;
if( bVerbose>0 ){
- char *zQuote = sqlite3_mprintf("%q", zSql);
printf("%d: %s %s\n", tno, zOp, zSql);
- sqlite3_free(zQuote);
}
if( strcmp(zOp,"memo")==0 ){
utf8_printf(p->out, "%s\n", zSql);
@@ -9944,6 +10007,7 @@ static int do_meta_command(char *zLine, ShellState *p){
zSep = "VALUES(";
while( SQLITE_ROW==sqlite3_step(pStmt) ){
const char *zTab = (const char*)sqlite3_column_text(pStmt,0);
+ if( zTab==0 ) continue;
if( zLike && sqlite3_strlike(zLike, zTab, 0)!=0 ) continue;
if( strncmp(zTab, "sqlite_",7)!=0 ){
appendText(&sQuery,"SELECT * FROM ", 0);
@@ -9984,6 +10048,7 @@ static int do_meta_command(char *zLine, ShellState *p){
" FROM [sha3sum$query]",
sSql.z, iSize);
}
+ shell_check_oom(zSql);
freeText(&sQuery);
freeText(&sSql);
if( bDebug ){
@@ -10007,11 +10072,11 @@ static int do_meta_command(char *zLine, ShellState *p){
goto meta_command_exit;
}
zCmd = sqlite3_mprintf(strchr(azArg[1],' ')==0?"%s":"\"%s\"", azArg[1]);
- for(i=2; ibSafeMode ){
+ utf8_printf(stderr,
+ "line %d: \".testctrl %s\" may not be used in safe mode\n",
+ p->lineno, aCtrl[iCtrl].zCtrlName);
+ exit(1);
}else{
switch(testctrl){
@@ -10915,7 +10986,7 @@ static int process_input(ShellState *p){
/* Grow buffer by half-again increments when big. */
nAlloc = nSql+(nSql>>1)+nLine+100;
zSql = realloc(zSql, nAlloc);
- if( zSql==0 ) shell_out_of_memory();
+ shell_check_oom(zSql);
}
if( nSql==0 ){
int i;
@@ -11047,6 +11118,7 @@ static void process_sqliterc(
return;
}
zBuf = sqlite3_mprintf("%s/.sqliterc",home_dir);
+ shell_check_oom(zBuf);
sqliterc = zBuf;
}
p->in = fopen(sqliterc,"rb");
@@ -11245,10 +11317,6 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
stdin_is_interactive = isatty(0);
stdout_is_console = isatty(1);
-#ifdef SQLITE_DEBUG
- registerOomSimulator();
-#endif
-
#if !defined(_WIN32_WCE)
if( getenv("SQLITE_DEBUG_BREAK") ){
if( isatty(0) && isatty(2) ){
@@ -11288,16 +11356,16 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
#if !SQLITE_SHELL_IS_UTF8
sqlite3_initialize();
argvToFree = malloc(sizeof(argv[0])*argc*2);
+ shell_check_oom(argvToFree);
argcToFree = argc;
argv = argvToFree + argc;
- if( argv==0 ) shell_out_of_memory();
for(i=0; i
** sqlite3_errcode()
** sqlite3_extended_errcode()
** sqlite3_errmsg()
** sqlite3_errmsg16()
+** sqlite3_error_offset()
**
**
** ^The sqlite3_errmsg() and sqlite3_errmsg16() return English-language
@@ -3845,6 +3846,13 @@ void sqlite3_free_filename(char*);
** ^(Memory to hold the error message string is managed internally
** and must not be freed by the application)^.
**
+** ^If the most recent error references a specific token in the input
+** SQL, the sqlite3_error_offset() interface returns the byte offset
+** of the start of that token. ^The byte offset returned by
+** sqlite3_error_offset() assumes that the input SQL is UTF8.
+** ^If the most error does not reference a specific token in the input
+** SQL, then the sqlite3_error_offset() function returns -1.
+**
** When the serialized [threading mode] is in use, it might be the
** case that a second error occurs on a separate thread in between
** the time of the first error and the call to these interfaces.
@@ -3864,6 +3872,7 @@ int sqlite3_extended_errcode(sqlite3 *db);
const char *sqlite3_errmsg(sqlite3*);
const void *sqlite3_errmsg16(sqlite3*);
const char *sqlite3_errstr(int);
+int sqlite3_error_offset(sqlite3 *db);
/*
** CAPI3REF: Prepared Statement Object
@@ -7944,7 +7953,8 @@ int sqlite3_test_control(int op, ...);
#define SQLITE_TESTCTRL_SEEK_COUNT 30
#define SQLITE_TESTCTRL_TRACEFLAGS 31
#define SQLITE_TESTCTRL_TUNE 32
-#define SQLITE_TESTCTRL_LAST 32 /* Largest TESTCTRL */
+#define SQLITE_TESTCTRL_LOGEST 33
+#define SQLITE_TESTCTRL_LAST 33 /* Largest TESTCTRL */
/*
** CAPI3REF: SQL Keyword Checking
@@ -8467,6 +8477,16 @@ int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg);
** The counter is incremented on the first [sqlite3_step()] call of each
** cycle.
**
+** [[SQLITE_STMTSTATUS_FILTER_MISS]]
+** [[SQLITE_STMTSTATUS_FILTER HIT]]
+** SQLITE_STMTSTATUS_FILTER_HIT
+** SQLITE_STMTSTATUS_FILTER_MISS
+** ^SQLITE_STMTSTATUS_FILTER_HIT is the number of times that a join
+** step was bypassed because a Bloom filter returned not-found. The
+** corresponding SQLITE_STMTSTATUS_FILTER_MISS value is the number of
+** times that the Bloom filter returned a find, and thus the join step
+** had to be processed as normal.
+**
** [[SQLITE_STMTSTATUS_MEMUSED]] SQLITE_STMTSTATUS_MEMUSED
** ^This is the approximate number of bytes of heap memory
** used to store the prepared statement. ^This value is not actually
@@ -8481,6 +8501,8 @@ int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg);
#define SQLITE_STMTSTATUS_VM_STEP 4
#define SQLITE_STMTSTATUS_REPREPARE 5
#define SQLITE_STMTSTATUS_RUN 6
+#define SQLITE_STMTSTATUS_FILTER_MISS 7
+#define SQLITE_STMTSTATUS_FILTER_HIT 8
#define SQLITE_STMTSTATUS_MEMUSED 99
/*
@@ -9451,14 +9473,33 @@ int sqlite3_vtab_nochange(sqlite3_context*);
** CAPI3REF: Determine The Collation For a Virtual Table Constraint
**
** This function may only be called from within a call to the [xBestIndex]
-** method of a [virtual table].
+** method of a [virtual table]. This function returns a pointer to a string
+** that is the name of the appropriate collation sequence to use for text
+** comparisons on the constraint identified by its arguments.
**
-** The first argument must be the sqlite3_index_info object that is the
-** first parameter to the xBestIndex() method. The second argument must be
-** an index into the aConstraint[] array belonging to the sqlite3_index_info
-** structure passed to xBestIndex. This function returns a pointer to a buffer
-** containing the name of the collation sequence for the corresponding
-** constraint.
+** The first argument must be the pointer to the sqlite3_index_info object
+** that is the first parameter to the xBestIndex() method. The second argument
+** must be an index into the aConstraint[] array belonging to the
+** sqlite3_index_info structure passed to xBestIndex.
+**
+** Important:
+** The first parameter must be the same pointer that is passed into the
+** xBestMethod() method. The first parameter may not be a pointer to a
+** different sqlite3_index_info object, even an exact copy.
+**
+** The return value is computed as follows:
+**
+**
+** If the constraint comes from a WHERE clause expression that contains
+** a [COLLATE operator], then the name of the collation specified by
+** that COLLATE operator is returned.
+**
If there is no COLLATE operator, but the column that is the subject
+** of the constraint specifies an alternative collating sequence via
+** a [COLLATE clause] on the column definition within the CREATE TABLE
+** statement that was passed into [sqlite3_declare_vtab()], then the
+** name of that alternative collating sequence is returned.
+**
Otherwise, "BINARY" is returned.
+**
*/
SQLITE_EXPERIMENTAL const char *sqlite3_vtab_collation(sqlite3_index_info*,int);
diff --git a/src/sqlite3ext.h b/src/sqlite3ext.h
index 9767daa01d..5b82346227 100644
--- a/src/sqlite3ext.h
+++ b/src/sqlite3ext.h
@@ -344,6 +344,8 @@ struct sqlite3_api_routines {
int (*autovacuum_pages)(sqlite3*,
unsigned int(*)(void*,const char*,unsigned int,unsigned int,unsigned int),
void*, void(*)(void*));
+ /* Version 3.38.0 and later */
+ int (*error_offset)(sqlite3*);
};
/*
@@ -655,6 +657,8 @@ typedef int (*sqlite3_loadext_entry)(
#define sqlite3_total_changes64 sqlite3_api->total_changes64
/* Version 3.37.0 and later */
#define sqlite3_autovacuum_pages sqlite3_api->autovacuum_pages
+/* Version 3.38.0 and later */
+#define sqlite3_error_offset sqlite3_api->error_offset
#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 b673d77716..53c2969265 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -1536,6 +1536,7 @@ struct sqlite3 {
u32 nSchemaLock; /* Do not reset the schema when non-zero */
unsigned int openFlags; /* Flags passed to sqlite3_vfs.xOpen() */
int errCode; /* Most recent error code (SQLITE_*) */
+ int errByteOffset; /* Byte offset of error in SQL statement */
int errMask; /* & result codes with this before returning */
int iSysErrno; /* Errno value from last system error */
u32 dbOptFlags; /* Flags to enable/disable optimizations */
@@ -1780,6 +1781,9 @@ struct sqlite3 {
#define SQLITE_SeekScan 0x00020000 /* The OP_SeekScan optimization */
#define SQLITE_OmitOrderBy 0x00040000 /* Omit pointless ORDER BY */
/* TH3 expects this value ^^^^^^^^^^ to be 0x40000. Coordinate any change */
+#define SQLITE_BloomFilter 0x00080000 /* Use a Bloom filter on searches */
+#define SQLITE_BloomPulldown 0x00100000 /* Run Bloom filters early */
+#define SQLITE_BalancedMerge 0x00200000 /* Balance multi-way merges */
#define SQLITE_AllOpts 0xffffffff /* All optimizations */
/*
@@ -1953,7 +1957,7 @@ struct FuncDestructor {
** are interpreted in the same way as the first 4 parameters to
** FUNCTION().
**
-** WFUNCTION(zName, nArg, iArg, xStep, xFinal, xValue, xInverse)
+** WAGGREGATE(zName, nArg, iArg, xStep, xFinal, xValue, xInverse)
** Used to create an aggregate function definition implemented by
** the C functions xStep and xFinal. The first four parameters
** are interpreted in the same way as the first 4 parameters to
@@ -1980,6 +1984,10 @@ struct FuncDestructor {
#define MFUNCTION(zName, nArg, xPtr, xFunc) \
{nArg, SQLITE_FUNC_BUILTIN|SQLITE_FUNC_CONSTANT|SQLITE_UTF8, \
xPtr, 0, xFunc, 0, 0, 0, #zName, {0} }
+#define JFUNCTION(zName, nArg, iArg, xFunc) \
+ {nArg, SQLITE_FUNC_BUILTIN|SQLITE_DETERMINISTIC|SQLITE_INNOCUOUS|\
+ SQLITE_FUNC_CONSTANT|SQLITE_UTF8, \
+ SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, 0, #zName, {0} }
#define INLINE_FUNC(zName, nArg, iArg, mFlags) \
{nArg, SQLITE_FUNC_BUILTIN|\
SQLITE_UTF8|SQLITE_FUNC_INLINE|SQLITE_FUNC_CONSTANT|(mFlags), \
@@ -3574,6 +3582,8 @@ struct Parse {
AutoincInfo *pAinc; /* Information about AUTOINCREMENT counters */
Parse *pToplevel; /* Parse structure for main program (or NULL) */
Table *pTriggerTab; /* Table triggers are being coded for */
+ TriggerPrg *pTriggerPrg; /* Linked list of coded triggers */
+ ParseCleanup *pCleanup; /* List of cleanup operations to run after parse */
union {
int addrCrTab; /* Address of OP_CreateBtree on CREATE TABLE */
Returning *pReturning; /* The RETURNING clause */
@@ -3628,9 +3638,7 @@ struct Parse {
Token sArg; /* Complete text of a module argument */
Table **apVtabLock; /* Pointer to virtual tables needing locking */
#endif
- TriggerPrg *pTriggerPrg; /* Linked list of coded triggers */
With *pWith; /* Current WITH clause, or NULL */
- ParseCleanup *pCleanup; /* List of cleanup operations to run after parse */
#ifndef SQLITE_OMIT_ALTERTABLE
RenameToken *pRename; /* Tokens subject to renaming by ALTER TABLE */
#endif
@@ -4421,7 +4429,7 @@ void sqlite3DequoteExpr(Expr*);
void sqlite3DequoteToken(Token*);
void sqlite3TokenInit(Token*,char*);
int sqlite3KeywordCode(const unsigned char*, int);
-int sqlite3RunParser(Parse*, const char*, char **);
+int sqlite3RunParser(Parse*, const char*);
void sqlite3FinishCoding(Parse*);
int sqlite3GetTempReg(Parse*);
void sqlite3ReleaseTempReg(Parse*,int);
@@ -4582,6 +4590,7 @@ void sqlite3OpenTable(Parse*, int iCur, int iDb, Table*, int);
#if defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) && !defined(SQLITE_OMIT_SUBQUERY)
Expr *sqlite3LimitWhere(Parse*,SrcList*,Expr*,ExprList*,Expr*,char*);
#endif
+void sqlite3CodeChangeCount(Vdbe*,int,const char*);
void sqlite3DeleteFrom(Parse*, SrcList*, Expr*, ExprList*, Expr*);
void sqlite3Update(Parse*, SrcList*, ExprList*,Expr*,int,ExprList*,Expr*,
Upsert*);
@@ -4702,9 +4711,14 @@ Select *sqlite3SelectDup(sqlite3*,const Select*,int);
FuncDef *sqlite3FunctionSearch(int,const char*);
void sqlite3InsertBuiltinFuncs(FuncDef*,int);
FuncDef *sqlite3FindFunction(sqlite3*,const char*,int,u8,u8);
+void sqlite3QuoteValue(StrAccum*,sqlite3_value*);
void sqlite3RegisterBuiltinFunctions(void);
void sqlite3RegisterDateTimeFunctions(void);
+void sqlite3RegisterJsonFunctions(void);
void sqlite3RegisterPerConnectionBuiltinFunctions(sqlite3*);
+#if !defined(SQLITE_OMIT_VIRTUALTABLE) && !defined(SQLITE_OMIT_JSON)
+ int sqlite3JsonTableFunctions(sqlite3*);
+#endif
int sqlite3SafetyCheckOk(sqlite3*);
int sqlite3SafetyCheckSickOrOk(sqlite3*);
void sqlite3ChangeCookie(Parse*, int);
@@ -4794,14 +4808,8 @@ int sqlite3Utf8CharLen(const char *pData, int nByte);
u32 sqlite3Utf8Read(const u8**);
LogEst sqlite3LogEst(u64);
LogEst sqlite3LogEstAdd(LogEst,LogEst);
-#ifndef SQLITE_OMIT_VIRTUALTABLE
LogEst sqlite3LogEstFromDouble(double);
-#endif
-#if defined(SQLITE_ENABLE_STMT_SCANSTATUS) || \
- defined(SQLITE_ENABLE_STAT4) || \
- defined(SQLITE_EXPLAIN_ESTIMATED_ROWS)
u64 sqlite3LogEstToInt(LogEst);
-#endif
VList *sqlite3VListAdd(sqlite3*,VList*,const char*,int,int);
const char *sqlite3VListNumToName(VList*,int);
int sqlite3VListNameToNum(VList*,const char*,int);
@@ -4994,11 +5002,13 @@ int sqlite3ApiExit(sqlite3 *db, int);
int sqlite3OpenTempDatabase(Parse *);
void sqlite3StrAccumInit(StrAccum*, sqlite3*, char*, int, int);
+int sqlite3StrAccumEnlarge(StrAccum*, int);
char *sqlite3StrAccumFinish(StrAccum*);
void sqlite3StrAccumSetError(StrAccum*, u8);
void sqlite3ResultStrAccum(sqlite3_context*,StrAccum*);
void sqlite3SelectDestInit(SelectDest*,int,int);
Expr *sqlite3CreateColumnExpr(sqlite3 *, SrcList *, int, int);
+void sqlite3RecordErrorByteOffset(sqlite3*,const char*);
void sqlite3BackupRestart(sqlite3_backup *);
void sqlite3BackupUpdate(sqlite3_backup *, Pgno, const u8 *);
@@ -5166,6 +5176,7 @@ const char *sqlite3JournalModename(int);
int sqlite3FkRequired(Parse*, Table*, int*, int);
u32 sqlite3FkOldmask(Parse*, Table*);
FKey *sqlite3FkReferences(Table *);
+ void sqlite3FkClearTriggerCache(sqlite3*,int);
#else
#define sqlite3FkActions(a,b,c,d,e,f)
#define sqlite3FkCheck(a,b,c,d,e,f)
@@ -5173,6 +5184,7 @@ const char *sqlite3JournalModename(int);
#define sqlite3FkOldmask(a,b) 0
#define sqlite3FkRequired(a,b,c,d) 0
#define sqlite3FkReferences(a) 0
+ #define sqlite3FkClearTriggerCache(a,b)
#endif
#ifndef SQLITE_OMIT_FOREIGN_KEY
void sqlite3FkDelete(sqlite3 *, Table*);
diff --git a/src/test1.c b/src/test1.c
index 55b78a3008..b68b038458 100644
--- a/src/test1.c
+++ b/src/test1.c
@@ -1097,7 +1097,7 @@ static int SQLITE_TCLAPI test_drop_modules(
){
sqlite3 *db;
- if( argc!=2 ){
+ if( argc<2 ){
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
" DB\"", 0);
return TCL_ERROR;
@@ -4366,6 +4366,34 @@ static int SQLITE_TCLAPI test_errmsg(
return TCL_OK;
}
+
+/*
+** Usage: sqlite3_error_offset DB
+**
+** Return the byte offset into the input UTF8 SQL for the most recent
+** error, or -1 of the error does not refer to a specific token.
+*/
+static int SQLITE_TCLAPI test_error_offset(
+ void * clientData,
+ Tcl_Interp *interp,
+ int objc,
+ Tcl_Obj *CONST objv[]
+){
+ sqlite3 *db;
+ int iByteOffset;
+
+ if( objc!=2 ){
+ Tcl_AppendResult(interp, "wrong # args: should be \"",
+ Tcl_GetString(objv[0]), " DB", 0);
+ return TCL_ERROR;
+ }
+ if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
+
+ iByteOffset = sqlite3_error_offset(db);
+ Tcl_SetObjResult(interp, Tcl_NewIntObj(iByteOffset));
+ return TCL_OK;
+}
+
/*
** Usage: test_errmsg16 DB
**
@@ -7484,6 +7512,7 @@ static int SQLITE_TCLAPI optimization_control(
{ "stat4", SQLITE_Stat4 },
{ "skip-scan", SQLITE_SkipScan },
{ "push-down", SQLITE_PushDown },
+ { "balanced-merge", SQLITE_BalancedMerge },
};
if( objc!=4 ){
@@ -8457,6 +8486,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
{ "sqlite3_errcode", test_errcode ,0 },
{ "sqlite3_extended_errcode", test_ex_errcode ,0 },
{ "sqlite3_errmsg", test_errmsg ,0 },
+ { "sqlite3_error_offset", test_error_offset ,0 },
{ "sqlite3_errmsg16", test_errmsg16 ,0 },
{ "sqlite3_open", test_open ,0 },
{ "sqlite3_open16", test_open16 ,0 },
diff --git a/src/test_func.c b/src/test_func.c
index b7c9e08ceb..fa52438261 100644
--- a/src/test_func.c
+++ b/src/test_func.c
@@ -499,7 +499,8 @@ static void test_extract(
mem.db = db;
mem.enc = ENC(db);
pHdr += sqlite3GetVarint(pHdr, &iSerialType);
- pBody += sqlite3VdbeSerialGet(pBody, (u32)iSerialType, &mem);
+ sqlite3VdbeSerialGet(pBody, (u32)iSerialType, &mem);
+ pBody += sqlite3VdbeSerialTypeLen((u32)iSerialType);
if( iCurrent==iIdx ){
sqlite3_result_value(context, &mem);
@@ -547,7 +548,8 @@ static void test_decode(
mem.db = db;
mem.enc = ENC(db);
pHdr += sqlite3GetVarint(pHdr, &iSerialType);
- pBody += sqlite3VdbeSerialGet(pBody, (u32)iSerialType, &mem);
+ sqlite3VdbeSerialGet(pBody, (u32)iSerialType, &mem);
+ pBody += sqlite3VdbeSerialTypeLen((u32)iSerialType);
switch( sqlite3_value_type(&mem) ){
case SQLITE_TEXT:
diff --git a/src/tokenize.c b/src/tokenize.c
index e128d16148..347fd57323 100644
--- a/src/tokenize.c
+++ b/src/tokenize.c
@@ -290,6 +290,9 @@ int sqlite3GetToken(const unsigned char *z, int *tokenType){
for(i=2; (c=z[i])!=0 && c!='\n'; i++){}
*tokenType = TK_SPACE; /* IMP: R-22934-25134 */
return i;
+ }else if( z[1]=='>' ){
+ *tokenType = TK_PTR;
+ return 2 + (z[2]=='>');
}
*tokenType = TK_MINUS;
return 1;
@@ -559,13 +562,9 @@ int sqlite3GetToken(const unsigned char *z, int *tokenType){
}
/*
-** Run the parser on the given SQL string. The parser structure is
-** passed in. An SQLITE_ status code is returned. If an error occurs
-** then an and attempt is made to write an error message into
-** memory obtained from sqlite3_malloc() and to make *pzErrMsg point to that
-** error message.
+** Run the parser on the given SQL string.
*/
-int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
+int sqlite3RunParser(Parse *pParse, const char *zSql){
int nErr = 0; /* Number of errors encountered */
void *pEngine; /* The LEMON-generated LALR(1) parser */
int n = 0; /* Length of the next token token */
@@ -586,7 +585,6 @@ int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
}
pParse->rc = SQLITE_OK;
pParse->zTail = zSql;
- assert( pzErrMsg!=0 );
#ifdef SQLITE_DEBUG
if( db->flags & SQLITE_ParserTrace ){
printf("parser: [[[%s]]]\n", zSql);
@@ -629,6 +627,7 @@ int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
#endif /* SQLITE_OMIT_WINDOWFUNC */
if( AtomicLoad(&db->u1.isInterrupted) ){
pParse->rc = SQLITE_INTERRUPT;
+ pParse->nErr++;
break;
}
if( tokenType==TK_SPACE ){
@@ -686,41 +685,26 @@ int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
if( db->mallocFailed ){
pParse->rc = SQLITE_NOMEM_BKPT;
}
- if( pParse->rc!=SQLITE_OK && pParse->rc!=SQLITE_DONE && pParse->zErrMsg==0 ){
- pParse->zErrMsg = sqlite3MPrintf(db, "%s", sqlite3ErrStr(pParse->rc));
- }
- assert( pzErrMsg!=0 );
- if( pParse->zErrMsg ){
- *pzErrMsg = pParse->zErrMsg;
- sqlite3_log(pParse->rc, "%s in \"%s\"",
- *pzErrMsg, pParse->zTail);
- pParse->zErrMsg = 0;
+ if( pParse->zErrMsg || (pParse->rc!=SQLITE_OK && pParse->rc!=SQLITE_DONE) ){
+ if( pParse->zErrMsg==0 ){
+ pParse->zErrMsg = sqlite3MPrintf(db, "%s", sqlite3ErrStr(pParse->rc));
+ }
+ sqlite3_log(pParse->rc, "%s in \"%s\"", pParse->zErrMsg, pParse->zTail);
nErr++;
}
pParse->zTail = zSql;
- if( pParse->pVdbe && pParse->nErr>0 && pParse->nested==0 ){
- sqlite3VdbeDelete(pParse->pVdbe);
- pParse->pVdbe = 0;
- }
-#ifndef SQLITE_OMIT_SHARED_CACHE
- if( pParse->nested==0 ){
- sqlite3DbFree(db, pParse->aTableLock);
- pParse->aTableLock = 0;
- pParse->nTableLock = 0;
- }
-#endif
#ifndef SQLITE_OMIT_VIRTUALTABLE
sqlite3_free(pParse->apVtabLock);
#endif
- if( !IN_SPECIAL_PARSE ){
+ if( pParse->pNewTable && !IN_SPECIAL_PARSE ){
/* If the pParse->declareVtab flag is set, do not delete any table
** structure built up in pParse->pNewTable. The calling code (see vtab.c)
** will take responsibility for freeing the Table structure.
*/
sqlite3DeleteTable(db, pParse->pNewTable);
}
- if( !IN_RENAME_OBJECT ){
+ if( pParse->pNewTrigger && !IN_RENAME_OBJECT ){
sqlite3DeleteTrigger(db, pParse->pNewTrigger);
}
sqlite3DbFree(db, pParse->pVList);
diff --git a/src/trigger.c b/src/trigger.c
index a80ad40734..6b71c9816e 100644
--- a/src/trigger.c
+++ b/src/trigger.c
@@ -933,7 +933,7 @@ static void codeReturningTrigger(
}
sqlite3ExprListDelete(db, sSelect.pEList);
pNew = sqlite3ExpandReturning(pParse, pReturning->pReturnEL, pTab);
- if( pNew ){
+ if( !db->mallocFailed ){
NameContext sNC;
memset(&sNC, 0, sizeof(sNC));
if( pReturning->nRetCol==0 ){
@@ -945,7 +945,9 @@ static void codeReturningTrigger(
sNC.ncFlags = NC_UBaseReg;
pParse->eTriggerOp = pTrigger->op;
pParse->pTriggerTab = pTab;
- if( sqlite3ResolveExprListNames(&sNC, pNew)==SQLITE_OK ){
+ if( sqlite3ResolveExprListNames(&sNC, pNew)==SQLITE_OK
+ && !db->mallocFailed
+ ){
int i;
int nCol = pNew->nExpr;
int reg = pParse->nMem+1;
@@ -953,16 +955,20 @@ static void codeReturningTrigger(
pReturning->iRetReg = reg;
for(i=0; ia[i].pExpr;
+ assert( pCol!=0 ); /* Due to !db->mallocFailed ~9 lines above */
sqlite3ExprCodeFactorable(pParse, pCol, reg+i);
+ if( sqlite3ExprAffinity(pCol)==SQLITE_AFF_REAL ){
+ sqlite3VdbeAddOp1(v, OP_RealAffinity, reg+i);
+ }
}
sqlite3VdbeAddOp3(v, OP_MakeRecord, reg, i, reg+i);
sqlite3VdbeAddOp2(v, OP_NewRowid, pReturning->iRetCur, reg+i+1);
sqlite3VdbeAddOp3(v, OP_Insert, pReturning->iRetCur, reg+i, reg+i+1);
}
- sqlite3ExprListDelete(db, pNew);
- pParse->eTriggerOp = 0;
- pParse->pTriggerTab = 0;
}
+ sqlite3ExprListDelete(db, pNew);
+ pParse->eTriggerOp = 0;
+ pParse->pTriggerTab = 0;
}
diff --git a/src/update.c b/src/update.c
index 35684386dd..b174e1eb50 100644
--- a/src/update.c
+++ b/src/update.c
@@ -1132,9 +1132,7 @@ void sqlite3Update(
** that information.
*/
if( regRowCount ){
- sqlite3VdbeAddOp2(v, OP_ChngCntRow, regRowCount, 1);
- sqlite3VdbeSetNumCols(v, 1);
- sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows updated", SQLITE_STATIC);
+ sqlite3CodeChangeCount(v, regRowCount, "rows updated");
}
update_cleanup:
diff --git a/src/util.c b/src/util.c
index 8452aea665..dec205df43 100644
--- a/src/util.c
+++ b/src/util.c
@@ -117,7 +117,11 @@ static SQLITE_NOINLINE void sqlite3ErrorFinish(sqlite3 *db, int err_code){
void sqlite3Error(sqlite3 *db, int err_code){
assert( db!=0 );
db->errCode = err_code;
- if( err_code || db->pErr ) sqlite3ErrorFinish(db, err_code);
+ if( err_code || db->pErr ){
+ sqlite3ErrorFinish(db, err_code);
+ }else{
+ db->errByteOffset = -1;
+ }
}
/*
@@ -127,6 +131,7 @@ void sqlite3Error(sqlite3 *db, int err_code){
void sqlite3ErrorClear(sqlite3 *db){
assert( db!=0 );
db->errCode = SQLITE_OK;
+ db->errByteOffset = -1;
if( db->pErr ) sqlite3ValueSetNull(db->pErr);
}
@@ -147,17 +152,8 @@ void sqlite3SystemError(sqlite3 *db, int rc){
** handle "db". The error code is set to "err_code".
**
** If it is not NULL, string zFormat specifies the format of the
-** error string in the style of the printf functions: The following
-** format characters are allowed:
-**
-** %s Insert a string
-** %z A string that should be freed after use
-** %d Insert an integer
-** %T Insert a token
-** %S Insert the first element of a SrcList
-**
-** zFormat and any string tokens that follow it are assumed to be
-** encoded in UTF-8.
+** error string. zFormat and any string tokens that follow it are
+** assumed to be encoded in UTF-8.
**
** To clear the most recent error for sqlite handle "db", sqlite3Error
** should be called with err_code set to SQLITE_OK and zFormat set
@@ -181,13 +177,6 @@ void sqlite3ErrorWithMsg(sqlite3 *db, int err_code, const char *zFormat, ...){
/*
** Add an error message to pParse->zErrMsg and increment pParse->nErr.
-** The following formatting characters are allowed:
-**
-** %s Insert a string
-** %z A string that should be freed after use
-** %d Insert an integer
-** %T Insert a token
-** %S Insert the first element of a SrcList
**
** This function should be used to report any error that occurs while
** compiling an SQL statement (i.e. within sqlite3_prepare()). The
@@ -200,9 +189,11 @@ void sqlite3ErrorMsg(Parse *pParse, const char *zFormat, ...){
char *zMsg;
va_list ap;
sqlite3 *db = pParse->db;
+ db->errByteOffset = -2;
va_start(ap, zFormat);
zMsg = sqlite3VMPrintf(db, zFormat, ap);
va_end(ap);
+ if( db->errByteOffset<-1 ) db->errByteOffset = -1;
if( db->suppressErr ){
sqlite3DbFree(db, zMsg);
}else{
@@ -1586,7 +1577,6 @@ LogEst sqlite3LogEst(u64 x){
return a[x&7] + y - 10;
}
-#ifndef SQLITE_OMIT_VIRTUALTABLE
/*
** Convert a double into a LogEst
** In other words, compute an approximation for 10*log2(x).
@@ -1601,16 +1591,9 @@ LogEst sqlite3LogEstFromDouble(double x){
e = (a>>52) - 1022;
return e*10;
}
-#endif /* SQLITE_OMIT_VIRTUALTABLE */
-#if defined(SQLITE_ENABLE_STMT_SCANSTATUS) || \
- defined(SQLITE_ENABLE_STAT4) || \
- defined(SQLITE_EXPLAIN_ESTIMATED_ROWS)
/*
** Convert a LogEst into an integer.
-**
-** Note that this routine is only used when one or more of various
-** non-standard compile-time options is enabled.
*/
u64 sqlite3LogEstToInt(LogEst x){
u64 n;
@@ -1618,17 +1601,9 @@ u64 sqlite3LogEstToInt(LogEst x){
x /= 10;
if( n>=5 ) n -= 2;
else if( n>=1 ) n -= 1;
-#if defined(SQLITE_ENABLE_STMT_SCANSTATUS) || \
- defined(SQLITE_EXPLAIN_ESTIMATED_ROWS)
if( x>60 ) return (u64)LARGEST_INT64;
-#else
- /* If only SQLITE_ENABLE_STAT4 is on, then the largest input
- ** possible to this routine is 310, resulting in a maximum x of 31 */
- assert( x<=60 );
-#endif
return x>=3 ? (n+8)<<(x-3) : (n+8)>>(3-x);
}
-#endif /* defined SCANSTAT or STAT4 or ESTIMATED_ROWS */
/*
** Add a new name/number pair to a VList. This might require that the
diff --git a/src/vdbe.c b/src/vdbe.c
index 22cf433386..9cb44e96f5 100644
--- a/src/vdbe.c
+++ b/src/vdbe.c
@@ -241,7 +241,6 @@ static VdbeCursor *allocateCursor(
Vdbe *p, /* The virtual machine */
int iCur, /* Index of the new VdbeCursor */
int nField, /* Number of fields in the table or index */
- int iDb, /* Database the cursor belongs to, or -1 */
u8 eCurType /* Type of the new cursor */
){
/* Find the memory cell that will be used to store the blob of memory
@@ -298,7 +297,6 @@ static VdbeCursor *allocateCursor(
p->apCsr[iCur] = pCx = (VdbeCursor*)pMem->zMalloc;
memset(pCx, 0, offsetof(VdbeCursor,pAltCursor));
pCx->eCurType = eCurType;
- pCx->iDb = iDb;
pCx->nField = nField;
pCx->aOffset = &pCx->aType[nField];
if( eCurType==CURTYPE_BTREE ){
@@ -671,6 +669,30 @@ static Mem *out2Prerelease(Vdbe *p, VdbeOp *pOp){
}
}
+/*
+** Compute a bloom filter hash using pOp->p4.i registers from aMem[] beginning
+** with pOp->p3. Return the hash.
+*/
+static u64 filterHash(const Mem *aMem, const Op *pOp){
+ int i, mx;
+ u64 h = 0;
+
+ i = pOp->p3;
+ assert( pOp->p4type==P4_INT32 );
+ for(i=pOp->p3, mx=i+pOp->p4.i; iflags & (MEM_Int|MEM_IntReal) ){
+ h += p->u.i;
+ }else if( p->flags & MEM_Real ){
+ h += sqlite3VdbeIntValue(p);
+ }else if( p->flags & (MEM_Str|MEM_Blob) ){
+ h += p->n;
+ if( p->flags & MEM_Zero ) h += p->u.nZero;
+ }
+ }
+ return h;
+}
+
/*
** Return the symbolic name for the data type of a pMem
*/
@@ -1325,12 +1347,18 @@ case OP_SoftNull: {
** Synopsis: r[P2]=P4 (len=P1)
**
** P4 points to a blob of data P1 bytes long. Store this
-** blob in register P2.
+** blob in register P2. If P4 is a NULL pointer, then construct
+** a zero-filled blob that is P1 bytes long in P2.
*/
case OP_Blob: { /* out2 */
assert( pOp->p1 <= SQLITE_MAX_LENGTH );
pOut = out2Prerelease(p, pOp);
- sqlite3VdbeMemSetStr(pOut, pOp->p4.z, pOp->p1, 0, 0);
+ if( pOp->p4.z==0 ){
+ sqlite3VdbeMemSetZeroBlob(pOut, pOp->p1);
+ if( sqlite3VdbeMemExpandBlob(pOut) ) goto no_mem;
+ }else{
+ sqlite3VdbeMemSetStr(pOut, pOp->p4.z, pOp->p1, 0, 0);
+ }
pOut->enc = encoding;
UPDATE_MAX_BLOBSIZE(pOut);
break;
@@ -1479,24 +1507,22 @@ case OP_IntCopy: { /* out2 */
break;
}
-/* Opcode: ChngCntRow P1 P2 * * *
-** Synopsis: output=r[P1]
+/* Opcode: FkCheck * * * * *
**
-** Output value in register P1 as the chance count for a DML statement,
-** due to the "PRAGMA count_changes=ON" setting. Or, if there was a
-** foreign key error in the statement, trigger the error now.
+** Halt with an SQLITE_CONSTRAINT error if there are any unresolved
+** foreign key constraint violations. If there are no foreign key
+** constraint violations, this is a no-op.
**
-** This opcode is a variant of OP_ResultRow that checks the foreign key
-** immediate constraint count and throws an error if the count is
-** non-zero. The P2 opcode must be 1.
+** FK constraint violations are also checked when the prepared statement
+** exits. This opcode is used to raise foreign key constraint errors prior
+** to returning results such as a row change count or the result of a
+** RETURNING clause.
*/
-case OP_ChngCntRow: {
- assert( pOp->p2==1 );
+case OP_FkCheck: {
if( (rc = sqlite3VdbeCheckFk(p,0))!=SQLITE_OK ){
goto abort_due_to_error;
}
- /* Fall through to the next case, OP_ResultRow */
- /* no break */ deliberate_fall_through
+ break;
}
/* Opcode: ResultRow P1 P2 * * *
@@ -2134,7 +2160,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);
- if( NEVER(pIn1==pIn3) ) flags3 = flags1 | MEM_Str;
+ 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 );
@@ -2664,6 +2690,7 @@ case OP_Column: {
assert( pC!=0 );
assert( p2<(u32)pC->nField );
aOffset = pC->aOffset;
+ assert( aOffset==pC->aType+pC->nField );
assert( pC->eCurType!=CURTYPE_VTAB );
assert( pC->eCurType!=CURTYPE_PSEUDO || pC->nullRow );
assert( pC->eCurType!=CURTYPE_SORTER );
@@ -3343,7 +3370,7 @@ case OP_MakeRecord: {
break;
}
-/* Opcode: Count P1 P2 p3 * *
+/* Opcode: Count P1 P2 P3 * *
** Synopsis: r[P2]=count()
**
** Store the number of entries (an integer value) in the table or index
@@ -3844,6 +3871,7 @@ case OP_SetCookie: {
/* When the schema cookie changes, record the new cookie internally */
pDb->pSchema->schema_cookie = pOp->p3 - pOp->p5;
db->mDbFlags |= DBFLAG_SchemaChange;
+ sqlite3FkClearTriggerCache(db, pOp->p1);
}else if( pOp->p2==BTREE_FILE_FORMAT ){
/* Record changes in the file format */
pDb->pSchema->file_format = pOp->p3;
@@ -4026,8 +4054,9 @@ case OP_OpenWrite:
assert( pOp->p1>=0 );
assert( nField>=0 );
testcase( nField==0 ); /* Table with INTEGER PRIMARY KEY and nothing else */
- pCur = allocateCursor(p, pOp->p1, nField, iDb, CURTYPE_BTREE);
+ pCur = allocateCursor(p, pOp->p1, nField, CURTYPE_BTREE);
if( pCur==0 ) goto no_mem;
+ pCur->iDb = iDb;
pCur->nullRow = 1;
pCur->isOrdered = 1;
pCur->pgnoRoot = p2;
@@ -4069,7 +4098,7 @@ case OP_OpenDup: {
assert( pOrig );
assert( pOrig->isEphemeral ); /* Only ephemeral cursors can be duplicated */
- pCx = allocateCursor(p, pOp->p1, pOrig->nField, -1, CURTYPE_BTREE);
+ pCx = allocateCursor(p, pOp->p1, pOrig->nField, CURTYPE_BTREE);
if( pCx==0 ) goto no_mem;
pCx->nullRow = 1;
pCx->isEphemeral = 1;
@@ -4077,10 +4106,10 @@ case OP_OpenDup: {
pCx->isTable = pOrig->isTable;
pCx->pgnoRoot = pOrig->pgnoRoot;
pCx->isOrdered = pOrig->isOrdered;
- pCx->pBtx = pOrig->pBtx;
+ pCx->ub.pBtx = pOrig->ub.pBtx;
pCx->hasBeenDuped = 1;
pOrig->hasBeenDuped = 1;
- rc = sqlite3BtreeCursor(pCx->pBtx, pCx->pgnoRoot, BTREE_WRCSR,
+ rc = sqlite3BtreeCursor(pCx->ub.pBtx, pCx->pgnoRoot, BTREE_WRCSR,
pCx->pKeyInfo, pCx->uc.pCursor);
/* The sqlite3BtreeCursor() routine can only fail for the first cursor
** opened for a database. Since there is already an open cursor when this
@@ -4153,16 +4182,16 @@ case OP_OpenEphemeral: {
assert( pCx->isEphemeral );
pCx->seqCount = 0;
pCx->cacheStatus = CACHE_STALE;
- rc = sqlite3BtreeClearTable(pCx->pBtx, pCx->pgnoRoot, 0);
+ rc = sqlite3BtreeClearTable(pCx->ub.pBtx, pCx->pgnoRoot, 0);
}else{
- pCx = allocateCursor(p, pOp->p1, pOp->p2, -1, CURTYPE_BTREE);
+ pCx = allocateCursor(p, pOp->p1, pOp->p2, CURTYPE_BTREE);
if( pCx==0 ) goto no_mem;
pCx->isEphemeral = 1;
- rc = sqlite3BtreeOpen(db->pVfs, 0, db, &pCx->pBtx,
+ rc = sqlite3BtreeOpen(db->pVfs, 0, db, &pCx->ub.pBtx,
BTREE_OMIT_JOURNAL | BTREE_SINGLE | pOp->p5,
vfsFlags);
if( rc==SQLITE_OK ){
- rc = sqlite3BtreeBeginTrans(pCx->pBtx, 1, 0);
+ rc = sqlite3BtreeBeginTrans(pCx->ub.pBtx, 1, 0);
if( rc==SQLITE_OK ){
/* If a transient index is required, create it by calling
** sqlite3BtreeCreateTable() with the BTREE_BLOBKEY flag before
@@ -4171,26 +4200,26 @@ case OP_OpenEphemeral: {
*/
if( (pCx->pKeyInfo = pKeyInfo = pOp->p4.pKeyInfo)!=0 ){
assert( pOp->p4type==P4_KEYINFO );
- rc = sqlite3BtreeCreateTable(pCx->pBtx, &pCx->pgnoRoot,
+ rc = sqlite3BtreeCreateTable(pCx->ub.pBtx, &pCx->pgnoRoot,
BTREE_BLOBKEY | pOp->p5);
if( rc==SQLITE_OK ){
assert( pCx->pgnoRoot==SCHEMA_ROOT+1 );
assert( pKeyInfo->db==db );
assert( pKeyInfo->enc==ENC(db) );
- rc = sqlite3BtreeCursor(pCx->pBtx, pCx->pgnoRoot, BTREE_WRCSR,
+ rc = sqlite3BtreeCursor(pCx->ub.pBtx, pCx->pgnoRoot, BTREE_WRCSR,
pKeyInfo, pCx->uc.pCursor);
}
pCx->isTable = 0;
}else{
pCx->pgnoRoot = SCHEMA_ROOT;
- rc = sqlite3BtreeCursor(pCx->pBtx, SCHEMA_ROOT, BTREE_WRCSR,
+ rc = sqlite3BtreeCursor(pCx->ub.pBtx, SCHEMA_ROOT, BTREE_WRCSR,
0, pCx->uc.pCursor);
pCx->isTable = 1;
}
}
pCx->isOrdered = (pOp->p5!=BTREE_UNORDERED);
if( rc ){
- sqlite3BtreeClose(pCx->pBtx);
+ sqlite3BtreeClose(pCx->ub.pBtx);
}
}
}
@@ -4214,7 +4243,7 @@ case OP_SorterOpen: {
assert( pOp->p1>=0 );
assert( pOp->p2>=0 );
- pCx = allocateCursor(p, pOp->p1, pOp->p2, -1, CURTYPE_SORTER);
+ pCx = allocateCursor(p, pOp->p1, pOp->p2, CURTYPE_SORTER);
if( pCx==0 ) goto no_mem;
pCx->pKeyInfo = pOp->p4.pKeyInfo;
assert( pCx->pKeyInfo->db==db );
@@ -4263,7 +4292,7 @@ case OP_OpenPseudo: {
assert( pOp->p1>=0 );
assert( pOp->p3>=0 );
- pCx = allocateCursor(p, pOp->p1, pOp->p3, -1, CURTYPE_PSEUDO);
+ pCx = allocateCursor(p, pOp->p1, pOp->p3, CURTYPE_PSEUDO);
if( pCx==0 ) goto no_mem;
pCx->nullRow = 1;
pCx->seekResult = pOp->p2;
@@ -6203,9 +6232,9 @@ case OP_IdxRowid: { /* out2 */
pTabCur->movetoTarget = rowid;
pTabCur->deferredMoveto = 1;
assert( pOp->p4type==P4_INTARRAY || pOp->p4.ai==0 );
- pTabCur->aAltMap = pOp->p4.ai;
- assert( !pC->isEphemeral );
assert( !pTabCur->isEphemeral );
+ pTabCur->ub.aAltMap = pOp->p4.ai;
+ assert( !pC->isEphemeral );
pTabCur->pAltCursor = pC;
}else{
pOut = out2Prerelease(p, pOp);
@@ -7744,7 +7773,7 @@ case OP_VOpen: {
pVCur->pVtab = pVtab;
/* Initialize vdbe cursor object */
- pCur = allocateCursor(p, pOp->p1, 0, -1, CURTYPE_VTAB);
+ pCur = allocateCursor(p, pOp->p1, 0, CURTYPE_VTAB);
if( pCur ){
pCur->uc.pVCur = pVCur;
pVtab->nRef++;
@@ -8182,6 +8211,77 @@ case OP_Function: { /* group */
break;
}
+/* Opcode: FilterAdd P1 * P3 P4 *
+** Synopsis: filter(P1) += key(P3@P4)
+**
+** Compute a hash on the P4 registers starting with r[P3] and
+** add that hash to the bloom filter contained in r[P1].
+*/
+case OP_FilterAdd: {
+ u64 h;
+
+ assert( pOp->p1>0 && pOp->p1<=(p->nMem+1 - p->nCursor) );
+ pIn1 = &aMem[pOp->p1];
+ assert( pIn1->flags & MEM_Blob );
+ assert( pIn1->n>0 );
+ h = filterHash(aMem, pOp);
+#ifdef SQLITE_DEBUG
+ if( db->flags&SQLITE_VdbeTrace ){
+ int ii;
+ for(ii=pOp->p3; iip3+pOp->p4.i; ii++){
+ registerTrace(ii, &aMem[ii]);
+ }
+ printf("hash: %llu modulo %d -> %u\n", h, pIn1->n, (int)(h%pIn1->n));
+ }
+#endif
+ h %= pIn1->n;
+ pIn1->z[h/8] |= 1<<(h&7);
+ break;
+}
+
+/* Opcode: Filter P1 P2 P3 P4 *
+** Synopsis: if key(P3@P4) not in filter(P1) goto P2
+**
+** Compute a hash on the key contained in the P4 registers starting
+** with r[P3]. Check to see if that hash is found in the
+** bloom filter hosted by register P1. If it is not present then
+** maybe jump to P2. Otherwise fall through.
+**
+** False negatives are harmless. It is always safe to fall through,
+** even if the value is in the bloom filter. A false negative causes
+** more CPU cycles to be used, but it should still yield the correct
+** answer. However, an incorrect answer may well arise from a
+** false positive - if the jump is taken when it should fall through.
+*/
+case OP_Filter: { /* jump */
+ u64 h;
+
+ assert( pOp->p1>0 && pOp->p1<=(p->nMem+1 - p->nCursor) );
+ pIn1 = &aMem[pOp->p1];
+ assert( (pIn1->flags & MEM_Blob)!=0 );
+ assert( pIn1->n >= 1 );
+ h = filterHash(aMem, pOp);
+#ifdef SQLITE_DEBUG
+ if( db->flags&SQLITE_VdbeTrace ){
+ int ii;
+ for(ii=pOp->p3; iip3+pOp->p4.i; ii++){
+ registerTrace(ii, &aMem[ii]);
+ }
+ printf("hash: %llu modulo %d -> %u\n", h, pIn1->n, (int)(h%pIn1->n));
+ }
+#endif
+ h %= pIn1->n;
+ if( (pIn1->z[h/8] & (1<<(h&7)))==0 ){
+ VdbeBranchTaken(1, 2);
+ p->aCounter[SQLITE_STMTSTATUS_FILTER_HIT]++;
+ goto jump_to_p2;
+ }else{
+ p->aCounter[SQLITE_STMTSTATUS_FILTER_MISS]++;
+ VdbeBranchTaken(0, 2);
+ }
+ break;
+}
+
/* Opcode: Trace P1 P2 * P4 *
**
** Write P4 on the statement trace output if statement tracing is
diff --git a/src/vdbeInt.h b/src/vdbeInt.h
index 599d064165..376c9edac9 100644
--- a/src/vdbeInt.h
+++ b/src/vdbeInt.h
@@ -75,7 +75,7 @@ typedef struct AuxData AuxData;
typedef struct VdbeCursor VdbeCursor;
struct VdbeCursor {
u8 eCurType; /* One of the CURTYPE_* values above */
- i8 iDb; /* Index of cursor database in db->aDb[] (or -1) */
+ i8 iDb; /* Index of cursor database in db->aDb[] */
u8 nullRow; /* True if pointing to a row with no data */
u8 deferredMoveto; /* A call to sqlite3BtreeMoveto() is needed */
u8 isTable; /* True for rowid tables. False for indexes */
@@ -88,9 +88,11 @@ struct VdbeCursor {
Bool isOrdered:1; /* True if the table is not BTREE_UNORDERED */
Bool hasBeenDuped:1; /* This cursor was source or target of OP_OpenDup */
u16 seekHit; /* See the OP_SeekHit and OP_IfNoHope opcodes */
- Btree *pBtx; /* Separate file holding temporary table */
+ union { /* pBtx for isEphermeral. pAltMap otherwise */
+ Btree *pBtx; /* Separate file holding temporary table */
+ u32 *aAltMap; /* Mapping from table to index column numbers */
+ } ub;
i64 seqCount; /* Sequence counter */
- u32 *aAltMap; /* Mapping from table to index column numbers */
/* Cached OP_Column parse information is only valid if cacheStatus matches
** Vdbe.cacheCtr. Vdbe.cacheCtr will never take on the value of
@@ -430,7 +432,7 @@ struct Vdbe {
bft bIsReader:1; /* True for statements that read */
yDbMask btreeMask; /* Bitmask of db->aDb[] entries referenced */
yDbMask lockMask; /* Subset of btreeMask that requires a lock */
- u32 aCounter[7]; /* Counters used by sqlite3_stmt_status() */
+ u32 aCounter[9]; /* Counters used by sqlite3_stmt_status() */
char *zSql; /* Text of the SQL statement that generated this */
#ifdef SQLITE_ENABLE_NORMALIZE
char *zNormSql; /* Normalization of the associated SQL statement */
@@ -492,7 +494,7 @@ int sqlite3VdbeCursorRestore(VdbeCursor*);
u32 sqlite3VdbeSerialTypeLen(u32);
u8 sqlite3VdbeOneByteSerialTypeLen(u8);
u32 sqlite3VdbeSerialPut(unsigned char*, Mem*, u32);
-u32 sqlite3VdbeSerialGet(const unsigned char*, u32, Mem*);
+void sqlite3VdbeSerialGet(const unsigned char*, u32, Mem*);
void sqlite3VdbeDeleteAuxData(sqlite3*, AuxData**, int, int);
int sqlite2BtreeKeyCompare(BtCursor *, const void *, int, int, int *);
@@ -538,7 +540,7 @@ int sqlite3VdbeMemSetRowSet(Mem*);
int sqlite3VdbeMemMakeWriteable(Mem*);
int sqlite3VdbeMemStringify(Mem*, u8, u8);
int sqlite3IntFloatCompare(i64,double);
-i64 sqlite3VdbeIntValue(Mem*);
+i64 sqlite3VdbeIntValue(const Mem*);
int sqlite3VdbeMemIntegerify(Mem*);
double sqlite3VdbeRealValue(Mem*);
int sqlite3VdbeBooleanValue(Mem*, int ifNull);
diff --git a/src/vdbeaux.c b/src/vdbeaux.c
index abc73e6513..e2d13e0799 100644
--- a/src/vdbeaux.c
+++ b/src/vdbeaux.c
@@ -2470,8 +2470,6 @@ void sqlite3VdbeFreeCursor(Vdbe *p, VdbeCursor *pCx){
if( pCx==0 ){
return;
}
- assert( pCx->pBtx==0 || pCx->eCurType==CURTYPE_BTREE );
- assert( pCx->pBtx==0 || pCx->isEphemeral );
switch( pCx->eCurType ){
case CURTYPE_SORTER: {
sqlite3VdbeSorterClose(p->db, pCx);
@@ -3593,7 +3591,7 @@ int sqlite3VdbeCursorMoveto(VdbeCursor **pp, u32 *piCol){
if( p->deferredMoveto ){
u32 iMap;
assert( !p->isEphemeral );
- if( p->aAltMap && (iMap = p->aAltMap[1+*piCol])>0 && !p->nullRow ){
+ if( p->ub.aAltMap && (iMap = p->ub.aAltMap[1+*piCol])>0 && !p->nullRow ){
*pp = p->pAltCursor;
*piCol = iMap - 1;
return SQLITE_OK;
@@ -3871,14 +3869,14 @@ u32 sqlite3VdbeSerialPut(u8 *buf, Mem *pMem, u32 serial_type){
/*
** Deserialize the data blob pointed to by buf as serial type serial_type
-** and store the result in pMem. Return the number of bytes read.
+** and store the result in pMem.
**
** This function is implemented as two separate routines for performance.
** The few cases that require local variables are broken out into a separate
** routine so that in most cases the overhead of moving the stack pointer
** is avoided.
*/
-static u32 serialGet(
+static void serialGet(
const unsigned char *buf, /* Buffer to deserialize from */
u32 serial_type, /* Serial type to deserialize */
Mem *pMem /* Memory cell to write value into */
@@ -3912,9 +3910,8 @@ static u32 serialGet(
memcpy(&pMem->u.r, &x, sizeof(x));
pMem->flags = IsNaN(x) ? MEM_Null : MEM_Real;
}
- return 8;
}
-u32 sqlite3VdbeSerialGet(
+void sqlite3VdbeSerialGet(
const unsigned char *buf, /* Buffer to deserialize from */
u32 serial_type, /* Serial type to deserialize */
Mem *pMem /* Memory cell to write value into */
@@ -3925,13 +3922,13 @@ u32 sqlite3VdbeSerialGet(
pMem->flags = MEM_Null|MEM_Zero;
pMem->n = 0;
pMem->u.nZero = 0;
- break;
+ return;
}
case 11: /* Reserved for future use */
case 0: { /* Null */
/* EVIDENCE-OF: R-24078-09375 Value is a NULL. */
pMem->flags = MEM_Null;
- break;
+ return;
}
case 1: {
/* EVIDENCE-OF: R-44885-25196 Value is an 8-bit twos-complement
@@ -3939,7 +3936,7 @@ u32 sqlite3VdbeSerialGet(
pMem->u.i = ONE_BYTE_INT(buf);
pMem->flags = MEM_Int;
testcase( pMem->u.i<0 );
- return 1;
+ return;
}
case 2: { /* 2-byte signed integer */
/* EVIDENCE-OF: R-49794-35026 Value is a big-endian 16-bit
@@ -3947,7 +3944,7 @@ u32 sqlite3VdbeSerialGet(
pMem->u.i = TWO_BYTE_INT(buf);
pMem->flags = MEM_Int;
testcase( pMem->u.i<0 );
- return 2;
+ return;
}
case 3: { /* 3-byte signed integer */
/* EVIDENCE-OF: R-37839-54301 Value is a big-endian 24-bit
@@ -3955,7 +3952,7 @@ u32 sqlite3VdbeSerialGet(
pMem->u.i = THREE_BYTE_INT(buf);
pMem->flags = MEM_Int;
testcase( pMem->u.i<0 );
- return 3;
+ return;
}
case 4: { /* 4-byte signed integer */
/* EVIDENCE-OF: R-01849-26079 Value is a big-endian 32-bit
@@ -3967,7 +3964,7 @@ u32 sqlite3VdbeSerialGet(
#endif
pMem->flags = MEM_Int;
testcase( pMem->u.i<0 );
- return 4;
+ return;
}
case 5: { /* 6-byte signed integer */
/* EVIDENCE-OF: R-50385-09674 Value is a big-endian 48-bit
@@ -3975,13 +3972,14 @@ u32 sqlite3VdbeSerialGet(
pMem->u.i = FOUR_BYTE_UINT(buf+2) + (((i64)1)<<32)*TWO_BYTE_INT(buf);
pMem->flags = MEM_Int;
testcase( pMem->u.i<0 );
- return 6;
+ return;
}
case 6: /* 8-byte signed integer */
case 7: { /* IEEE floating point */
/* These use local variables, so do them in a separate routine
** to avoid having to move the frame pointer in the common case */
- return serialGet(buf,serial_type,pMem);
+ serialGet(buf,serial_type,pMem);
+ return;
}
case 8: /* Integer 0 */
case 9: { /* Integer 1 */
@@ -3989,7 +3987,7 @@ u32 sqlite3VdbeSerialGet(
/* EVIDENCE-OF: R-18143-12121 Value is the integer 1. */
pMem->u.i = serial_type-8;
pMem->flags = MEM_Int;
- return 0;
+ return;
}
default: {
/* EVIDENCE-OF: R-14606-31564 Value is a BLOB that is (N-12)/2 bytes in
@@ -4000,10 +3998,10 @@ u32 sqlite3VdbeSerialGet(
pMem->z = (char *)buf;
pMem->n = (serial_type-12)/2;
pMem->flags = aFlag[serial_type&1];
- return pMem->n;
+ return;
}
}
- return 0;
+ return;
}
/*
** This routine is used to allocate sufficient space for an UnpackedRecord
@@ -4066,7 +4064,8 @@ void sqlite3VdbeRecordUnpack(
/* pMem->flags = 0; // sqlite3VdbeSerialGet() will set this for us */
pMem->szMalloc = 0;
pMem->z = 0;
- d += sqlite3VdbeSerialGet(&aKey[d], serial_type, pMem);
+ sqlite3VdbeSerialGet(&aKey[d], serial_type, pMem);
+ d += sqlite3VdbeSerialTypeLen(serial_type);
pMem++;
if( (++u)>=p->nField ) break;
}
@@ -4150,7 +4149,8 @@ static int vdbeRecordCompareDebug(
/* Extract the values to be compared.
*/
- d1 += sqlite3VdbeSerialGet(&aKey1[d1], serial_type1, &mem1);
+ sqlite3VdbeSerialGet(&aKey1[d1], serial_type1, &mem1);
+ d1 += sqlite3VdbeSerialTypeLen(serial_type1);
/* Do the comparison
*/
@@ -4954,7 +4954,7 @@ int sqlite3VdbeIdxRowid(sqlite3 *db, BtCursor *pCur, i64 *rowid){
/* The index entry must begin with a header size */
getVarint32NR((u8*)m.z, szHdr);
testcase( szHdr==3 );
- testcase( szHdr==m.n );
+ testcase( szHdr==(u32)m.n );
testcase( szHdr>0x7fffffff );
assert( m.n>=0 );
if( unlikely(szHdr<3 || szHdr>(unsigned)m.n) ){
diff --git a/src/vdbemem.c b/src/vdbemem.c
index 570a2eb38c..5a9d15f465 100644
--- a/src/vdbemem.c
+++ b/src/vdbemem.c
@@ -596,12 +596,12 @@ static SQLITE_NOINLINE i64 doubleToInt64(double r){
**
** If pMem represents a string value, its encoding might be changed.
*/
-static SQLITE_NOINLINE i64 memIntValue(Mem *pMem){
+static SQLITE_NOINLINE i64 memIntValue(const Mem *pMem){
i64 value = 0;
sqlite3Atoi64(pMem->z, &value, pMem->n, pMem->enc);
return value;
}
-i64 sqlite3VdbeIntValue(Mem *pMem){
+i64 sqlite3VdbeIntValue(const Mem *pMem){
int flags;
assert( pMem!=0 );
assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
diff --git a/src/vdbesort.c b/src/vdbesort.c
index 8bf7b57173..3958662cc6 100644
--- a/src/vdbesort.c
+++ b/src/vdbesort.c
@@ -960,7 +960,8 @@ int sqlite3VdbeSorterInit(
}
#endif
- assert( pCsr->pKeyInfo && pCsr->pBtx==0 );
+ assert( pCsr->pKeyInfo );
+ assert( !pCsr->isEphemeral );
assert( pCsr->eCurType==CURTYPE_SORTER );
szKeyInfo = sizeof(KeyInfo) + (pCsr->pKeyInfo->nKeyField-1)*sizeof(CollSeq*);
sz = sizeof(VdbeSorter) + nWorker * sizeof(SortSubtask);
diff --git a/src/vtab.c b/src/vtab.c
index 2c787c6c44..ef86dd6bd4 100644
--- a/src/vtab.c
+++ b/src/vtab.c
@@ -807,7 +807,6 @@ int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
VtabCtx *pCtx;
int rc = SQLITE_OK;
Table *pTab;
- char *zErr = 0;
Parse sParse;
int initBusy;
@@ -836,11 +835,12 @@ int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
initBusy = db->init.busy;
db->init.busy = 0;
sParse.nQueryLoop = 1;
- if( SQLITE_OK==sqlite3RunParser(&sParse, zCreateTable, &zErr)
- && sParse.pNewTable
- && !db->mallocFailed
+ if( SQLITE_OK==sqlite3RunParser(&sParse, zCreateTable)
+ && ALWAYS(sParse.pNewTable!=0)
+ && ALWAYS(!db->mallocFailed)
&& IsOrdinaryTable(sParse.pNewTable)
){
+ assert( sParse.zErrMsg==0 );
if( !pTab->aCol ){
Table *pNew = sParse.pNewTable;
Index *pIdx;
@@ -870,8 +870,9 @@ int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
}
pCtx->bDeclared = 1;
}else{
- sqlite3ErrorWithMsg(db, SQLITE_ERROR, (zErr ? "%s" : 0), zErr);
- sqlite3DbFree(db, zErr);
+ sqlite3ErrorWithMsg(db, SQLITE_ERROR,
+ (sParse.zErrMsg ? "%s" : 0), sParse.zErrMsg);
+ sqlite3DbFree(db, sParse.zErrMsg);
rc = SQLITE_ERROR;
}
sParse.eParseMode = PARSE_MODE_NORMAL;
diff --git a/src/where.c b/src/where.c
index 7a8342675d..35bad3f696 100644
--- a/src/where.c
+++ b/src/where.c
@@ -234,7 +234,12 @@ whereOrInsert_done:
Bitmask sqlite3WhereGetMask(WhereMaskSet *pMaskSet, int iCursor){
int i;
assert( pMaskSet->n<=(int)sizeof(Bitmask)*8 );
- for(i=0; in; i++){
+ assert( pMaskSet->n>0 || pMaskSet->ix[0]<0 );
+ assert( iCursor>=-1 );
+ if( pMaskSet->ix[0]==iCursor ){
+ return 1;
+ }
+ for(i=1; in; i++){
if( pMaskSet->ix[i]==iCursor ){
return MASKBIT(i);
}
@@ -419,16 +424,16 @@ static WhereTerm *whereScanInit(
if( pIdx ){
int j = iColumn;
iColumn = pIdx->aiColumn[j];
- if( iColumn==XN_EXPR ){
- pScan->pIdxExpr = pIdx->aColExpr->a[j].pExpr;
- pScan->zCollName = pIdx->azColl[j];
- pScan->aiColumn[0] = XN_EXPR;
- return whereScanInitIndexExpr(pScan);
- }else if( iColumn==pIdx->pTable->iPKey ){
+ if( iColumn==pIdx->pTable->iPKey ){
iColumn = XN_ROWID;
}else if( iColumn>=0 ){
pScan->idxaff = pIdx->pTable->aCol[iColumn].affinity;
pScan->zCollName = pIdx->azColl[j];
+ }else if( iColumn==XN_EXPR ){
+ pScan->pIdxExpr = pIdx->aColExpr->a[j].pExpr;
+ pScan->zCollName = pIdx->azColl[j];
+ pScan->aiColumn[0] = XN_EXPR;
+ return whereScanInitIndexExpr(pScan);
}
}else if( iColumn==XN_EXPR ){
return 0;
@@ -671,12 +676,14 @@ static void whereTraceIndexInfoInputs(sqlite3_index_info *p){
int i;
if( !sqlite3WhereTrace ) return;
for(i=0; inConstraint; i++){
- sqlite3DebugPrintf(" constraint[%d]: col=%d termid=%d op=%d usabled=%d\n",
+ sqlite3DebugPrintf(
+ " constraint[%d]: col=%d termid=%d op=%d usabled=%d collseq=%s\n",
i,
p->aConstraint[i].iColumn,
p->aConstraint[i].iTermOffset,
p->aConstraint[i].op,
- p->aConstraint[i].usable);
+ p->aConstraint[i].usable,
+ sqlite3_vtab_collation(p,i));
}
for(i=0; inOrderBy; i++){
sqlite3DebugPrintf(" orderby[%d]: col=%d desc=%d\n",
@@ -712,9 +719,9 @@ static void whereTraceIndexInfoOutputs(sqlite3_index_info *p){
** index existed.
*/
static int termCanDriveIndex(
- WhereTerm *pTerm, /* WHERE clause term to check */
- SrcItem *pSrc, /* Table we are trying to access */
- Bitmask notReady /* Tables in outer loops of the join */
+ const WhereTerm *pTerm, /* WHERE clause term to check */
+ const SrcItem *pSrc, /* Table we are trying to access */
+ const Bitmask notReady /* Tables in outer loops of the join */
){
char aff;
if( pTerm->leftCursor!=pSrc->iCursor ) return 0;
@@ -745,11 +752,11 @@ static int termCanDriveIndex(
** and to set up the WhereLevel object pLevel so that the code generator
** makes use of the automatic index.
*/
-static void constructAutomaticIndex(
+static SQLITE_NOINLINE void constructAutomaticIndex(
Parse *pParse, /* The parsing context */
- WhereClause *pWC, /* The WHERE clause */
- SrcItem *pSrc, /* The FROM clause term to get the next index */
- Bitmask notReady, /* Mask of cursors that are not available */
+ const WhereClause *pWC, /* The WHERE clause */
+ const SrcItem *pSrc, /* The FROM clause term to get the next index */
+ const Bitmask notReady, /* Mask of cursors that are not available */
WhereLevel *pLevel /* Write new index here */
){
int nKeyCol; /* Number of columns in the constructed index */
@@ -791,13 +798,13 @@ static void constructAutomaticIndex(
idxCols = 0;
for(pTerm=pWC->a; pTermpExpr;
- assert( !ExprHasProperty(pExpr, EP_FromJoin) /* prereq always non-zero */
- || pExpr->iRightJoinTable!=pSrc->iCursor /* for the right-hand */
- || pLoop->prereq!=0 ); /* table of a LEFT JOIN */
- if( pLoop->prereq==0
- && (pTerm->wtFlags & TERM_VIRTUAL)==0
- && !ExprHasProperty(pExpr, EP_FromJoin)
- && sqlite3ExprIsTableConstant(pExpr, pSrc->iCursor) ){
+ /* Make the automatic index a partial index if there are terms in the
+ ** WHERE clause (or the ON clause of a LEFT join) that constrain which
+ ** rows of the target table (pSrc) that can be used. */
+ if( (pTerm->wtFlags & TERM_VIRTUAL)==0
+ && ((pSrc->fg.jointype&JT_LEFT)==0 || ExprHasProperty(pExpr,EP_FromJoin))
+ && sqlite3ExprIsTableConstant(pExpr, pSrc->iCursor)
+ ){
pPartial = sqlite3ExprAnd(pParse, pPartial,
sqlite3ExprDup(pParse->db, pExpr, 0));
}
@@ -904,6 +911,10 @@ static void constructAutomaticIndex(
sqlite3VdbeAddOp2(v, OP_OpenAutoindex, pLevel->iIdxCur, nKeyCol+1);
sqlite3VdbeSetP4KeyInfo(pParse, pIdx);
VdbeComment((v, "for %s", pTable->zName));
+ if( OptimizationEnabled(pParse->db, SQLITE_BloomFilter) ){
+ pLevel->regFilter = ++pParse->nMem;
+ sqlite3VdbeAddOp2(v, OP_Blob, 10000, pLevel->regFilter);
+ }
/* Fill the automatic index with content */
pTabItem = &pWC->pWInfo->pTabList->a[pLevel->iFrom];
@@ -926,6 +937,10 @@ static void constructAutomaticIndex(
regBase = sqlite3GenerateIndexKey(
pParse, pIdx, pLevel->iTabCur, regRecord, 0, 0, 0, 0
);
+ if( pLevel->regFilter ){
+ sqlite3VdbeAddOp4Int(v, OP_FilterAdd, pLevel->regFilter, 0,
+ regBase, pLoop->u.btree.nEq);
+ }
sqlite3VdbeAddOp2(v, OP_IdxInsert, pLevel->iIdxCur, regRecord);
sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT);
if( pPartial ) sqlite3VdbeResolveLabel(v, iContinue);
@@ -952,6 +967,130 @@ end_auto_index_create:
}
#endif /* SQLITE_OMIT_AUTOMATIC_INDEX */
+/*
+** Generate bytecode that will initialize a Bloom filter that is appropriate
+** for pLevel.
+**
+** If there are inner loops within pLevel that have the WHERE_BLOOMFILTER
+** flag set, initialize a Bloomfilter for them as well. Except don't do
+** this recursive initialization if the SQLITE_BloomPulldown optimization has
+** been turned off.
+**
+** When the Bloom filter is initialized, the WHERE_BLOOMFILTER flag is cleared
+** from the loop, but the regFilter value is set to a register that implements
+** the Bloom filter. When regFilter is positive, the
+** sqlite3WhereCodeOneLoopStart() will generate code to test the Bloom filter
+** and skip the subsequence B-Tree seek if the Bloom filter indicates that
+** no matching rows exist.
+**
+** This routine may only be called if it has previously been determined that
+** the loop would benefit from a Bloom filter, and the WHERE_BLOOMFILTER bit
+** is set.
+*/
+static SQLITE_NOINLINE void sqlite3ConstructBloomFilter(
+ WhereInfo *pWInfo, /* The WHERE clause */
+ int iLevel, /* Index in pWInfo->a[] that is pLevel */
+ WhereLevel *pLevel, /* Make a Bloom filter for this FROM term */
+ Bitmask notReady /* Loops that are not ready */
+){
+ int addrOnce; /* Address of opening OP_Once */
+ int addrTop; /* Address of OP_Rewind */
+ int addrCont; /* Jump here to skip a row */
+ const WhereTerm *pTerm; /* For looping over WHERE clause terms */
+ const WhereTerm *pWCEnd; /* Last WHERE clause term */
+ Parse *pParse = pWInfo->pParse; /* Parsing context */
+ Vdbe *v = pParse->pVdbe; /* VDBE under construction */
+ WhereLoop *pLoop = pLevel->pWLoop; /* The loop being coded */
+ int iCur; /* Cursor for table getting the filter */
+
+ assert( pLoop!=0 );
+ assert( v!=0 );
+ assert( pLoop->wsFlags & WHERE_BLOOMFILTER );
+
+ addrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
+ do{
+ const SrcItem *pItem;
+ const Table *pTab;
+ u64 sz;
+ sqlite3WhereExplainBloomFilter(pParse, pWInfo, pLevel);
+ addrCont = sqlite3VdbeMakeLabel(pParse);
+ iCur = pLevel->iTabCur;
+ pLevel->regFilter = ++pParse->nMem;
+
+ /* The Bloom filter is a Blob held in a register. Initialize it
+ ** to zero-filled blob of at least 80K bits, but maybe more if the
+ ** estimated size of the table is larger. We could actually
+ ** measure the size of the table at run-time using OP_Count with
+ ** P3==1 and use that value to initialize the blob. But that makes
+ ** testing complicated. By basing the blob size on the value in the
+ ** sqlite_stat1 table, testing is much easier.
+ */
+ pItem = &pWInfo->pTabList->a[pLevel->iFrom];
+ assert( pItem!=0 );
+ pTab = pItem->pTab;
+ assert( pTab!=0 );
+ sz = sqlite3LogEstToInt(pTab->nRowLogEst);
+ if( sz<10000 ){
+ sz = 10000;
+ }else if( sz>10000000 ){
+ sz = 10000000;
+ }
+ sqlite3VdbeAddOp2(v, OP_Blob, (int)sz, pLevel->regFilter);
+
+ addrTop = sqlite3VdbeAddOp1(v, OP_Rewind, iCur); VdbeCoverage(v);
+ pWCEnd = &pWInfo->sWC.a[pWInfo->sWC.nTerm];
+ for(pTerm=pWInfo->sWC.a; pTermpExpr;
+ if( (pTerm->wtFlags & TERM_VIRTUAL)==0
+ && sqlite3ExprIsTableConstant(pExpr, iCur)
+ ){
+ sqlite3ExprIfFalse(pParse, pTerm->pExpr, addrCont, SQLITE_JUMPIFNULL);
+ }
+ }
+ if( pLoop->wsFlags & WHERE_IPK ){
+ int r1 = sqlite3GetTempReg(pParse);
+ sqlite3VdbeAddOp2(v, OP_Rowid, iCur, r1);
+ sqlite3VdbeAddOp4Int(v, OP_FilterAdd, pLevel->regFilter, 0, r1, 1);
+ sqlite3ReleaseTempReg(pParse, r1);
+ }else{
+ Index *pIdx = pLoop->u.btree.pIndex;
+ int n = pLoop->u.btree.nEq;
+ int r1 = sqlite3GetTempRange(pParse, n);
+ int jj;
+ for(jj=0; jjaiColumn[jj];
+ assert( pIdx->pTable==pItem->pTab );
+ sqlite3ExprCodeGetColumnOfTable(v, pIdx->pTable, iCur, iCol,r1+jj);
+ }
+ sqlite3VdbeAddOp4Int(v, OP_FilterAdd, pLevel->regFilter, 0, r1, n);
+ sqlite3ReleaseTempRange(pParse, r1, n);
+ }
+ sqlite3VdbeResolveLabel(v, addrCont);
+ sqlite3VdbeAddOp2(v, OP_Next, pLevel->iTabCur, addrTop+1);
+ VdbeCoverage(v);
+ sqlite3VdbeJumpHere(v, addrTop);
+ pLoop->wsFlags &= ~WHERE_BLOOMFILTER;
+ if( OptimizationDisabled(pParse->db, SQLITE_BloomPulldown) ) break;
+ while( ++iLevel < pWInfo->nLevel ){
+ pLevel = &pWInfo->a[iLevel];
+ pLoop = pLevel->pWLoop;
+ if( NEVER(pLoop==0) ) continue;
+ if( pLoop->prereq & notReady ) continue;
+ if( (pLoop->wsFlags & (WHERE_BLOOMFILTER|WHERE_COLUMN_IN))
+ ==WHERE_BLOOMFILTER
+ ){
+ /* This is a candidate for bloom-filter pull-down (early evaluation).
+ ** The test that WHERE_COLUMN_IN is omitted is important, as we are
+ ** not able to do early evaluation of bloom filters that make use of
+ ** the IN operator */
+ break;
+ }
+ }
+ }while( iLevel < pWInfo->nLevel );
+ sqlite3VdbeJumpHere(v, addrOnce);
+}
+
+
#ifndef SQLITE_OMIT_VIRTUALTABLE
/*
** Allocate and populate an sqlite3_index_info structure. It is the
@@ -976,10 +1115,19 @@ static sqlite3_index_info *allocateIndexInfo(
int nOrderBy;
sqlite3_index_info *pIdxInfo;
u16 mNoOmit = 0;
+ const Table *pTab;
- /* Count the number of possible WHERE clause constraints referring
- ** to this virtual table */
+ assert( pSrc!=0 );
+ pTab = pSrc->pTab;
+ assert( pTab!=0 );
+ assert( IsVirtual(pTab) );
+
+ /* Find all WHERE clause constraints referring to this virtual table.
+ ** Mark each term with the TERM_OK flag. Set nTerm to the number of
+ ** terms found.
+ */
for(i=nTerm=0, pTerm=pWC->a; inTerm; i++, pTerm++){
+ pTerm->wtFlags &= ~TERM_OK;
if( pTerm->leftCursor != pSrc->iCursor ) continue;
if( pTerm->prereqRight & mUnusable ) continue;
assert( IsPowerOfTwo(pTerm->eOperator & ~WO_EQUIV) );
@@ -990,8 +1138,19 @@ static sqlite3_index_info *allocateIndexInfo(
if( (pTerm->eOperator & ~(WO_EQUIV))==0 ) continue;
if( pTerm->wtFlags & TERM_VNULL ) continue;
assert( (pTerm->eOperator & (WO_OR|WO_AND))==0 );
- assert( pTerm->u.x.leftColumn>=(-1) );
+ assert( pTerm->u.x.leftColumn>=XN_ROWID );
+ assert( pTerm->u.x.leftColumnnCol );
+
+ /* 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)
+ ){
+ continue;
+ }
nTerm++;
+ pTerm->wtFlags |= TERM_OK;
}
/* If the ORDER BY clause contains only columns in the current
@@ -1003,8 +1162,41 @@ static sqlite3_index_info *allocateIndexInfo(
int n = pOrderBy->nExpr;
for(i=0; ia[i].pExpr;
- if( pExpr->op!=TK_COLUMN || pExpr->iTable!=pSrc->iCursor ) break;
+ Expr *pE2;
+
+ /* Skip over constant terms in the ORDER BY clause */
+ if( sqlite3ExprIsConstant(pExpr) ){
+ continue;
+ }
+
+ /* Virtual tables are unable to deal with NULLS FIRST */
if( pOrderBy->a[i].sortFlags & KEYINFO_ORDER_BIGNULL ) break;
+
+ /* First case - a direct column references without a COLLATE operator */
+ if( pExpr->op==TK_COLUMN && pExpr->iTable==pSrc->iCursor ){
+ assert( pExpr->iColumn>=XN_ROWID && pExpr->iColumnnCol );
+ continue;
+ }
+
+ /* 2nd case - a column reference with a COLLATE operator. Only match
+ ** of the COLLATE operator matches the collation of the column. */
+ if( pExpr->op==TK_COLLATE
+ && (pE2 = pExpr->pLeft)->op==TK_COLUMN
+ && pE2->iTable==pSrc->iCursor
+ ){
+ const char *zColl; /* The collating sequence name */
+ assert( !ExprHasProperty(pExpr, EP_IntValue) );
+ assert( pExpr->u.zToken!=0 );
+ assert( pE2->iColumn>=XN_ROWID && pE2->iColumnnCol );
+ pExpr->iColumn = pE2->iColumn;
+ if( pE2->iColumn<0 ) continue; /* Collseq does not matter for rowid */
+ zColl = sqlite3ColumnColl(&pTab->aCol[pE2->iColumn]);
+ if( zColl==0 ) zColl = sqlite3StrBINARY;
+ if( sqlite3_stricmp(pExpr->u.zToken, zColl)==0 ) continue;
+ }
+
+ /* No matches cause a break out of the loop */
+ break;
}
if( i==n){
nOrderBy = n;
@@ -1024,7 +1216,6 @@ static sqlite3_index_info *allocateIndexInfo(
pIdxCons = (struct sqlite3_index_constraint*)&pHidden[1];
pIdxOrderBy = (struct sqlite3_index_orderby*)&pIdxCons[nTerm];
pUsage = (struct sqlite3_index_constraint_usage*)&pIdxOrderBy[nOrderBy];
- pIdxInfo->nOrderBy = nOrderBy;
pIdxInfo->aConstraint = pIdxCons;
pIdxInfo->aOrderBy = pIdxOrderBy;
pIdxInfo->aConstraintUsage = pUsage;
@@ -1032,26 +1223,7 @@ static sqlite3_index_info *allocateIndexInfo(
pHidden->pParse = pParse;
for(i=j=0, pTerm=pWC->a; inTerm; i++, pTerm++){
u16 op;
- if( pTerm->leftCursor != pSrc->iCursor ) continue;
- if( pTerm->prereqRight & mUnusable ) continue;
- assert( IsPowerOfTwo(pTerm->eOperator & ~WO_EQUIV) );
- testcase( pTerm->eOperator & WO_IN );
- testcase( pTerm->eOperator & WO_IS );
- testcase( pTerm->eOperator & WO_ISNULL );
- 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)
- ){
- continue;
- }
- assert( (pTerm->eOperator & (WO_OR|WO_AND))==0 );
- assert( pTerm->u.x.leftColumn>=(-1) );
+ if( (pTerm->wtFlags & TERM_OK)==0 ) continue;
pIdxCons[j].iColumn = pTerm->u.x.leftColumn;
pIdxCons[j].iTermOffset = i;
op = pTerm->eOperator & WO_ALL;
@@ -1088,12 +1260,19 @@ static sqlite3_index_info *allocateIndexInfo(
j++;
}
+ assert( j==nTerm );
pIdxInfo->nConstraint = j;
- for(i=0; ia[i].pExpr;
- pIdxOrderBy[i].iColumn = pExpr->iColumn;
- pIdxOrderBy[i].desc = pOrderBy->a[i].sortFlags & KEYINFO_ORDER_DESC;
+ if( sqlite3ExprIsConstant(pExpr) ) continue;
+ assert( pExpr->op==TK_COLUMN
+ || (pExpr->op==TK_COLLATE && pExpr->pLeft->op==TK_COLUMN
+ && pExpr->iColumn==pExpr->pLeft->iColumn) );
+ pIdxOrderBy[j].iColumn = pExpr->iColumn;
+ pIdxOrderBy[j].desc = pOrderBy->a[i].sortFlags & KEYINFO_ORDER_DESC;
+ j++;
}
+ pIdxInfo->nOrderBy = j;
*pmNoOmit = mNoOmit;
return pIdxInfo;
@@ -1894,9 +2073,9 @@ void sqlite3WhereLoopPrint(WhereLoop *p, WhereClause *pWC){
sqlite3_free(z);
}
if( p->wsFlags & WHERE_SKIPSCAN ){
- sqlite3DebugPrintf(" f %05x %d-%d", p->wsFlags, p->nLTerm,p->nSkip);
+ sqlite3DebugPrintf(" f %06x %d-%d", p->wsFlags, p->nLTerm,p->nSkip);
}else{
- sqlite3DebugPrintf(" f %05x N %d", p->wsFlags, p->nLTerm);
+ sqlite3DebugPrintf(" f %06x N %d", p->wsFlags, p->nLTerm);
}
sqlite3DebugPrintf(" cost %d,%d,%d\n", p->rSetup, p->rRun, p->nOut);
if( p->nLTerm && (sqlite3WhereTrace & 0x100)!=0 ){
@@ -2356,11 +2535,11 @@ static void whereLoopOutputAdjust(
LogEst iReduce = 0; /* pLoop->nOut should not exceed nRow-iReduce */
assert( (pLoop->wsFlags & WHERE_AUTO_INDEX)==0 );
- for(i=pWC->nTerm, pTerm=pWC->a; i>0; i--, pTerm++){
+ for(i=pWC->nBase, pTerm=pWC->a; i>0; i--, pTerm++){
assert( pTerm!=0 );
- if( (pTerm->wtFlags & TERM_VIRTUAL)!=0 ) break;
- if( (pTerm->prereqAll & pLoop->maskSelf)==0 ) continue;
if( (pTerm->prereqAll & notAllowed)!=0 ) continue;
+ if( (pTerm->prereqAll & pLoop->maskSelf)==0 ) continue;
+ if( (pTerm->wtFlags & TERM_VIRTUAL)!=0 ) continue;
for(j=pLoop->nLTerm-1; j>=0; j--){
pX = pLoop->aLTerm[j];
if( pX==0 ) continue;
@@ -2368,6 +2547,13 @@ static void whereLoopOutputAdjust(
if( pX->iParent>=0 && (&pWC->a[pX->iParent])==pTerm ) break;
}
if( j<0 ){
+ if( pLoop->maskSelf==pTerm->prereqAll ){
+ /* If there are extra terms in the WHERE clause not used by an index
+ ** that depend only on the table being scanned, and that will tend to
+ ** cause many rows to be omitted, then mark that table as
+ ** "self-culling". */
+ pLoop->wsFlags |= WHERE_SELFCULL;
+ }
if( pTerm->truthProb<=0 ){
/* If a truth probability is specified using the likelihood() hints,
** then use the probability provided by the application. */
@@ -2395,7 +2581,9 @@ static void whereLoopOutputAdjust(
}
}
}
- if( pLoop->nOut > nRow-iReduce ) pLoop->nOut = nRow - iReduce;
+ if( pLoop->nOut > nRow-iReduce ){
+ pLoop->nOut = nRow - iReduce;
+ }
}
/*
@@ -3416,11 +3604,19 @@ static int whereLoopAddVirtualOne(
}
/*
-** If this function is invoked from within an xBestIndex() callback, it
-** returns a pointer to a buffer containing the name of the collation
-** sequence associated with element iCons of the sqlite3_index_info.aConstraint
-** array. Or, if iCons is out of range or there is no active xBestIndex
-** call, return NULL.
+** Return the collating sequence for a constraint passed into xBestIndex.
+**
+** pIdxInfo must be an sqlite3_index_info structure passed into xBestIndex.
+** This routine depends on there being a HiddenIndexInfo structure immediately
+** following the sqlite3_index_info structure.
+**
+** Return a pointer to the collation name:
+**
+** 1. If there is an explicit COLLATE operator on the constaint, return it.
+**
+** 2. Else, if the column has an alternative collation, return that.
+**
+** 3. Otherwise, return "BINARY".
*/
const char *sqlite3_vtab_collation(sqlite3_index_info *pIdxInfo, int iCons){
HiddenIndexInfo *pHidden = (HiddenIndexInfo*)&pIdxInfo[1];
@@ -3631,6 +3827,7 @@ static int whereLoopAddOr(
tempWC.pOuter = pWC;
tempWC.op = TK_AND;
tempWC.nTerm = 1;
+ tempWC.nBase = 1;
tempWC.a = pOrTerm;
sSubBuild.pWC = &tempWC;
}else{
@@ -4738,6 +4935,150 @@ static void showAllWhereLoops(WhereInfo *pWInfo, WhereClause *pWC){
# define WHERETRACE_ALL_LOOPS(W,C)
#endif
+/* Attempt to omit tables from a join that do not affect the result.
+** For a table to not affect the result, the following must be true:
+**
+** 1) The query must not be an aggregate.
+** 2) The table must be the RHS of a LEFT JOIN.
+** 3) Either the query must be DISTINCT, or else the ON or USING clause
+** must contain a constraint that limits the scan of the table to
+** at most a single row.
+** 4) The table must not be referenced by any part of the query apart
+** from its own USING or ON clause.
+**
+** For example, given:
+**
+** CREATE TABLE t1(ipk INTEGER PRIMARY KEY, v1);
+** CREATE TABLE t2(ipk INTEGER PRIMARY KEY, v2);
+** CREATE TABLE t3(ipk INTEGER PRIMARY KEY, v3);
+**
+** then table t2 can be omitted from the following:
+**
+** SELECT v1, v3 FROM t1
+** LEFT JOIN t2 ON (t1.ipk=t2.ipk)
+** LEFT JOIN t3 ON (t1.ipk=t3.ipk)
+**
+** or from:
+**
+** SELECT DISTINCT v1, v3 FROM t1
+** LEFT JOIN t2
+** LEFT JOIN t3 ON (t1.ipk=t3.ipk)
+*/
+static SQLITE_NOINLINE Bitmask whereOmitNoopJoin(
+ WhereInfo *pWInfo,
+ Bitmask notReady
+){
+ int i;
+ Bitmask tabUsed;
+
+ /* Preconditions checked by the caller */
+ assert( pWInfo->nLevel>=2 );
+ assert( OptimizationEnabled(pWInfo->pParse->db, SQLITE_OmitNoopJoin) );
+
+ /* These two preconditions checked by the caller combine to guarantee
+ ** condition (1) of the header comment */
+ assert( pWInfo->pResultSet!=0 );
+ assert( 0==(pWInfo->wctrlFlags & WHERE_AGG_DISTINCT) );
+
+ tabUsed = sqlite3WhereExprListUsage(&pWInfo->sMaskSet, pWInfo->pResultSet);
+ if( pWInfo->pOrderBy ){
+ tabUsed |= sqlite3WhereExprListUsage(&pWInfo->sMaskSet, pWInfo->pOrderBy);
+ }
+ for(i=pWInfo->nLevel-1; i>=1; i--){
+ WhereTerm *pTerm, *pEnd;
+ SrcItem *pItem;
+ WhereLoop *pLoop;
+ pLoop = pWInfo->a[i].pWLoop;
+ pItem = &pWInfo->pTabList->a[pLoop->iTab];
+ if( (pItem->fg.jointype & JT_LEFT)==0 ) continue;
+ if( (pWInfo->wctrlFlags & WHERE_WANT_DISTINCT)==0
+ && (pLoop->wsFlags & WHERE_ONEROW)==0
+ ){
+ continue;
+ }
+ if( (tabUsed & pLoop->maskSelf)!=0 ) continue;
+ pEnd = pWInfo->sWC.a + pWInfo->sWC.nTerm;
+ for(pTerm=pWInfo->sWC.a; pTermprereqAll & pLoop->maskSelf)!=0 ){
+ if( !ExprHasProperty(pTerm->pExpr, EP_FromJoin)
+ || pTerm->pExpr->iRightJoinTable!=pItem->iCursor
+ ){
+ break;
+ }
+ }
+ }
+ if( pTerm drop loop %c not used\n", pLoop->cId));
+ notReady &= ~pLoop->maskSelf;
+ for(pTerm=pWInfo->sWC.a; pTermprereqAll & pLoop->maskSelf)!=0 ){
+ pTerm->wtFlags |= TERM_CODED;
+ }
+ }
+ if( i!=pWInfo->nLevel-1 ){
+ int nByte = (pWInfo->nLevel-1-i) * sizeof(WhereLevel);
+ memmove(&pWInfo->a[i], &pWInfo->a[i+1], nByte);
+ }
+ pWInfo->nLevel--;
+ assert( pWInfo->nLevel>0 );
+ }
+ return notReady;
+}
+
+/*
+** Check to see if there are any SEARCH loops that might benefit from
+** using a Bloom filter. Consider a Bloom filter if:
+**
+** (1) The SEARCH happens more than N times where N is the number
+** of rows in the table that is being considered for the Bloom
+** filter.
+** (2) Some searches are expected to find zero rows. (This is determined
+** by the WHERE_SELFCULL flag on the term.)
+** (3) Bloom-filter processing is not disabled. (Checked by the
+** caller.)
+** (4) The size of the table being searched is known by ANALYZE.
+**
+** This block of code merely checks to see if a Bloom filter would be
+** appropriate, and if so sets the WHERE_BLOOMFILTER flag on the
+** WhereLoop. The implementation of the Bloom filter comes further
+** down where the code for each WhereLoop is generated.
+*/
+static SQLITE_NOINLINE void whereCheckIfBloomFilterIsUseful(
+ const WhereInfo *pWInfo
+){
+ int i;
+ LogEst nSearch;
+
+ assert( pWInfo->nLevel>=2 );
+ assert( OptimizationEnabled(pWInfo->pParse->db, SQLITE_BloomFilter) );
+ nSearch = pWInfo->a[0].pWLoop->nOut;
+ for(i=1; inLevel; i++){
+ WhereLoop *pLoop = pWInfo->a[i].pWLoop;
+ const unsigned int reqFlags = (WHERE_SELFCULL|WHERE_COLUMN_EQ);
+ if( (pLoop->wsFlags & reqFlags)==reqFlags
+ /* vvvvvv--- Always the case if WHERE_COLUMN_EQ is defined */
+ && ALWAYS((pLoop->wsFlags & (WHERE_IPK|WHERE_INDEXED))!=0)
+ ){
+ SrcItem *pItem = &pWInfo->pTabList->a[pLoop->iTab];
+ Table *pTab = pItem->pTab;
+ pTab->tabFlags |= TF_StatsUsed;
+ if( nSearch > pTab->nRowLogEst
+ && (pTab->tabFlags & TF_HasStat1)!=0
+ ){
+ testcase( pItem->fg.jointype & JT_LEFT );
+ pLoop->wsFlags |= WHERE_BLOOMFILTER;
+ pLoop->wsFlags &= ~WHERE_IDX_ONLY;
+ WHERETRACE(0xffff, (
+ "-> use Bloom-filter on loop %c because there are ~%.1e "
+ "lookups into %s which has only ~%.1e rows\n",
+ pLoop->cId, (double)sqlite3LogEstToInt(nSearch), pTab->zName,
+ (double)sqlite3LogEstToInt(pTab->nRowLogEst)));
+ }
+ }
+ nSearch += pLoop->nOut;
+ }
+}
+
/*
** Generate the beginning of the loop used for WHERE clause processing.
** The return value is a pointer to an opaque structure that contains
@@ -4868,12 +5209,6 @@ WhereInfo *sqlite3WhereBegin(
if( pOrderBy && pOrderBy->nExpr>=BMS ) pOrderBy = 0;
sWLB.pOrderBy = pOrderBy;
- /* Disable the DISTINCT optimization if SQLITE_DistinctOpt is set via
- ** sqlite3_test_ctrl(SQLITE_TESTCTRL_OPTIMIZATIONS,...) */
- if( OptimizationDisabled(db, SQLITE_DistinctOpt) ){
- wctrlFlags &= ~WHERE_WANT_DISTINCT;
- }
-
/* The number of tables in the FROM clause is limited by the number of
** bits in a Bitmask
*/
@@ -4920,6 +5255,10 @@ WhereInfo *sqlite3WhereBegin(
memset(&pWInfo->a[0], 0, sizeof(WhereLoop)+nTabList*sizeof(WhereLevel));
assert( pWInfo->eOnePass==ONEPASS_OFF ); /* ONEPASS defaults to OFF */
pMaskSet = &pWInfo->sMaskSet;
+ pMaskSet->n = 0;
+ pMaskSet->ix[0] = -99; /* Initialize ix[0] to a value that can never be
+ ** a valid cursor number, to avoid an initial
+ ** test for pMaskSet->n==0 in sqlite3WhereGetMask() */
sWLB.pWInfo = pWInfo;
sWLB.pWC = &pWInfo->sWC;
sWLB.pNew = (WhereLoop*)(((char*)pWInfo)+nByteWInfo);
@@ -4932,7 +5271,6 @@ WhereInfo *sqlite3WhereBegin(
/* Split the WHERE clause into separate subexpressions where each
** subexpression is separated by an AND operator.
*/
- initMaskSet(pMaskSet);
sqlite3WhereClauseInit(&pWInfo->sWC, pWInfo);
sqlite3WhereSplit(&pWInfo->sWC, pWhere, TK_AND);
@@ -4940,7 +5278,9 @@ WhereInfo *sqlite3WhereBegin(
*/
if( nTabList==0 ){
if( pOrderBy ) pWInfo->nOBSat = pOrderBy->nExpr;
- if( wctrlFlags & WHERE_WANT_DISTINCT ){
+ if( (wctrlFlags & WHERE_WANT_DISTINCT)!=0
+ && OptimizationEnabled(db, SQLITE_DistinctOpt)
+ ){
pWInfo->eDistinct = WHERE_DISTINCT_UNIQUE;
}
ExplainQueryPlan((pParse, 0, "SCAN CONSTANT ROW"));
@@ -4991,7 +5331,7 @@ WhereInfo *sqlite3WhereBegin(
** FROM ... WHERE random()>0; -- eval random() once per row
** FROM ... WHERE (SELECT random())>0; -- eval random() once overall
*/
- for(ii=0; iinTerm; ii++){
+ for(ii=0; iinBase; ii++){
WhereTerm *pT = &sWLB.pWC->a[ii];
if( pT->wtFlags & TERM_VIRTUAL ) continue;
if( pT->prereqAll==0 && (nTabList==0 || exprIsDeterministic(pT->pExpr)) ){
@@ -5001,7 +5341,12 @@ WhereInfo *sqlite3WhereBegin(
}
if( wctrlFlags & WHERE_WANT_DISTINCT ){
- if( isDistinctRedundant(pParse, pTabList, &pWInfo->sWC, pResultSet) ){
+ if( OptimizationDisabled(db, SQLITE_DistinctOpt) ){
+ /* Disable the DISTINCT optimization if SQLITE_DistinctOpt is set via
+ ** sqlite3_test_ctrl(SQLITE_TESTCTRL_OPTIMIZATIONS,...) */
+ wctrlFlags &= ~WHERE_WANT_DISTINCT;
+ pWInfo->wctrlFlags &= ~WHERE_WANT_DISTINCT;
+ }else if( isDistinctRedundant(pParse, pTabList, &pWInfo->sWC, pResultSet) ){
/* The DISTINCT marking is pointless. Ignore it. */
pWInfo->eDistinct = WHERE_DISTINCT_UNIQUE;
}else if( pOrderBy==0 ){
@@ -5102,34 +5447,15 @@ WhereInfo *sqlite3WhereBegin(
}
#endif
- /* Attempt to omit tables from the join that do not affect the result.
- ** For a table to not affect the result, the following must be true:
+ /* Attempt to omit tables from a join that do not affect the result.
+ ** See the comment on whereOmitNoopJoin() for further information.
**
- ** 1) The query must not be an aggregate.
- ** 2) The table must be the RHS of a LEFT JOIN.
- ** 3) Either the query must be DISTINCT, or else the ON or USING clause
- ** must contain a constraint that limits the scan of the table to
- ** at most a single row.
- ** 4) The table must not be referenced by any part of the query apart
- ** from its own USING or ON clause.
- **
- ** For example, given:
- **
- ** CREATE TABLE t1(ipk INTEGER PRIMARY KEY, v1);
- ** CREATE TABLE t2(ipk INTEGER PRIMARY KEY, v2);
- ** CREATE TABLE t3(ipk INTEGER PRIMARY KEY, v3);
- **
- ** then table t2 can be omitted from the following:
- **
- ** SELECT v1, v3 FROM t1
- ** LEFT JOIN t2 ON (t1.ipk=t2.ipk)
- ** LEFT JOIN t3 ON (t1.ipk=t3.ipk)
- **
- ** or from:
- **
- ** SELECT DISTINCT v1, v3 FROM t1
- ** LEFT JOIN t2
- ** LEFT JOIN t3 ON (t1.ipk=t3.ipk)
+ ** This query optimization is factored out into a separate "no-inline"
+ ** procedure to keep the sqlite3WhereBegin() procedure from becoming
+ ** too large. If sqlite3WhereBegin() becomes too large, that prevents
+ ** some C-compiler optimizers from in-lining the
+ ** sqlite3WhereCodeOneLoopStart() procedure, and it is important to
+ ** in-line sqlite3WhereCodeOneLoopStart() for performance reasons.
*/
notReady = ~(Bitmask)0;
if( pWInfo->nLevel>=2
@@ -5137,49 +5463,20 @@ WhereInfo *sqlite3WhereBegin(
&& 0==(wctrlFlags & WHERE_AGG_DISTINCT) /* condition (1) above */
&& OptimizationEnabled(db, SQLITE_OmitNoopJoin)
){
- int i;
- Bitmask tabUsed = sqlite3WhereExprListUsage(pMaskSet, pResultSet);
- if( sWLB.pOrderBy ){
- tabUsed |= sqlite3WhereExprListUsage(pMaskSet, sWLB.pOrderBy);
- }
- for(i=pWInfo->nLevel-1; i>=1; i--){
- WhereTerm *pTerm, *pEnd;
- SrcItem *pItem;
- pLoop = pWInfo->a[i].pWLoop;
- pItem = &pWInfo->pTabList->a[pLoop->iTab];
- if( (pItem->fg.jointype & JT_LEFT)==0 ) continue;
- if( (wctrlFlags & WHERE_WANT_DISTINCT)==0
- && (pLoop->wsFlags & WHERE_ONEROW)==0
- ){
- continue;
- }
- if( (tabUsed & pLoop->maskSelf)!=0 ) continue;
- pEnd = sWLB.pWC->a + sWLB.pWC->nTerm;
- for(pTerm=sWLB.pWC->a; pTermprereqAll & pLoop->maskSelf)!=0 ){
- if( !ExprHasProperty(pTerm->pExpr, EP_FromJoin)
- || pTerm->pExpr->iRightJoinTable!=pItem->iCursor
- ){
- break;
- }
- }
- }
- if( pTerm drop loop %c not used\n", pLoop->cId));
- notReady &= ~pLoop->maskSelf;
- for(pTerm=sWLB.pWC->a; pTermprereqAll & pLoop->maskSelf)!=0 ){
- pTerm->wtFlags |= TERM_CODED;
- }
- }
- if( i!=pWInfo->nLevel-1 ){
- int nByte = (pWInfo->nLevel-1-i) * sizeof(WhereLevel);
- memmove(&pWInfo->a[i], &pWInfo->a[i+1], nByte);
- }
- pWInfo->nLevel--;
- nTabList--;
- }
+ notReady = whereOmitNoopJoin(pWInfo, notReady);
+ nTabList = pWInfo->nLevel;
+ assert( nTabList>0 );
}
+
+ /* Check to see if there are any SEARCH loops that might benefit from
+ ** using a Bloom filter.
+ */
+ if( pWInfo->nLevel>=2
+ && OptimizationEnabled(db, SQLITE_BloomFilter)
+ ){
+ whereCheckIfBloomFilterIsUseful(pWInfo);
+ }
+
#if defined(WHERETRACE_ENABLED)
if( sqlite3WhereTrace & 0x100 ){ /* Display all terms of the WHERE clause */
sqlite3DebugPrintf("---- WHERE clause at end of analysis:\n");
@@ -5368,13 +5665,17 @@ WhereInfo *sqlite3WhereBegin(
if( pParse->nErr ) goto whereBeginError;
pLevel = &pWInfo->a[ii];
wsFlags = pLevel->pWLoop->wsFlags;
+ if( (wsFlags & (WHERE_AUTO_INDEX|WHERE_BLOOMFILTER))!=0 ){
+ if( (wsFlags & WHERE_AUTO_INDEX)!=0 ){
#ifndef SQLITE_OMIT_AUTOMATIC_INDEX
- if( (pLevel->pWLoop->wsFlags & WHERE_AUTO_INDEX)!=0 ){
- constructAutomaticIndex(pParse, &pWInfo->sWC,
- &pTabList->a[pLevel->iFrom], notReady, pLevel);
+ constructAutomaticIndex(pParse, &pWInfo->sWC,
+ &pTabList->a[pLevel->iFrom], notReady, pLevel);
+#endif
+ }else{
+ sqlite3ConstructBloomFilter(pWInfo, ii, pLevel, notReady);
+ }
if( db->mallocFailed ) goto whereBeginError;
}
-#endif
addrExplain = sqlite3WhereExplainOneScan(
pParse, pTabList, pLevel, wctrlFlags
);
diff --git a/src/whereInt.h b/src/whereInt.h
index f651e790cc..a97b4afc69 100644
--- a/src/whereInt.h
+++ b/src/whereInt.h
@@ -64,6 +64,7 @@ struct WhereLevel {
u32 iLikeRepCntr; /* LIKE range processing counter register (times 2) */
int addrLikeRep; /* LIKE range processing address */
#endif
+ int regFilter; /* Bloom filter */
u8 iFrom; /* Which entry in the FROM clause */
u8 op, p3, p5; /* Opcode, P3 & P5 of the opcode that ends the loop */
int p1, p2; /* Operands of the opcode used to end the loop */
@@ -269,7 +270,7 @@ struct WhereTerm {
#define TERM_COPIED 0x0008 /* Has a child */
#define TERM_ORINFO 0x0010 /* Need to free the WhereTerm.u.pOrInfo object */
#define TERM_ANDINFO 0x0020 /* Need to free the WhereTerm.u.pAndInfo obj */
-#define TERM_OR_OK 0x0040 /* Used during OR-clause processing */
+#define TERM_OK 0x0040 /* Used during OR-clause processing */
#define TERM_VNULL 0x0080 /* Manufactured x>NULL or x<=NULL term */
#define TERM_LIKEOPT 0x0100 /* Virtual terms from the LIKE optimization */
#define TERM_LIKECOND 0x0200 /* Conditionally this LIKE operator term */
@@ -292,11 +293,11 @@ struct WhereScan {
WhereClause *pWC; /* WhereClause currently being scanned */
const char *zCollName; /* Required collating sequence, if not NULL */
Expr *pIdxExpr; /* Search for this index expression */
- char idxaff; /* Must match this affinity, if zCollName!=NULL */
- unsigned char nEquiv; /* Number of entries in aiCur[] and aiColumn[] */
- unsigned char iEquiv; /* Next unused slot in aiCur[] and aiColumn[] */
- u32 opMask; /* Acceptable operators */
int k; /* Resume scanning at this->pWC->a[this->k] */
+ u32 opMask; /* Acceptable operators */
+ char idxaff; /* Must match this affinity, if zCollName!=NULL */
+ unsigned char iEquiv; /* Current slot in aiCur[] and aiColumn[] */
+ unsigned char nEquiv; /* Number of entries in aiCur[] and aiColumn[] */
int aiCur[11]; /* Cursors in the equivalence class */
i16 aiColumn[11]; /* Corresponding column number in the eq-class */
};
@@ -320,6 +321,7 @@ struct WhereClause {
u8 hasOr; /* True if any a[].eOperator is WO_OR */
int nTerm; /* Number of terms */
int nSlot; /* Number of entries in a[] */
+ int nBase; /* Number of terms through the last non-Virtual */
WhereTerm *a; /* Each a[] describes a term of the WHERE cluase */
#if defined(SQLITE_SMALL_STACK)
WhereTerm aStatic[1]; /* Initial static space for a[] */
@@ -377,11 +379,6 @@ struct WhereMaskSet {
int ix[BMS]; /* Cursor assigned to each bit */
};
-/*
-** Initialize a WhereMaskSet object
-*/
-#define initMaskSet(P) (P)->n=0
-
/*
** This object is a convenience wrapper holding all information needed
** to construct WhereLoop objects for a particular query.
@@ -510,8 +507,14 @@ int sqlite3WhereExplainOneScan(
WhereLevel *pLevel, /* Scan to write OP_Explain opcode for */
u16 wctrlFlags /* Flags passed to sqlite3WhereBegin() */
);
+int sqlite3WhereExplainBloomFilter(
+ const Parse *pParse, /* Parse context */
+ const WhereInfo *pWInfo, /* WHERE clause */
+ const WhereLevel *pLevel /* Bloom filter on this level */
+);
#else
# define sqlite3WhereExplainOneScan(u,v,w,x) 0
+# define sqlite3WhereExplainBloomFilter(u,v,w) 0
#endif /* SQLITE_OMIT_EXPLAIN */
#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
void sqlite3WhereAddScanStatus(
@@ -604,5 +607,7 @@ void sqlite3WhereTabFuncArgs(Parse*, SrcItem*, WhereClause*);
#define WHERE_BIGNULL_SORT 0x00080000 /* Column nEq of index is BIGNULL */
#define WHERE_IN_SEEKSCAN 0x00100000 /* Seek-scan optimization for IN */
#define WHERE_TRANSCONS 0x00200000 /* Uses a transitive constraint */
+#define WHERE_BLOOMFILTER 0x00400000 /* Consider using a Bloom-filter */
+#define WHERE_SELFCULL 0x00800000 /* nOut reduced by extra WHERE terms */
#endif /* !defined(SQLITE_WHEREINT_H) */
diff --git a/src/wherecode.c b/src/wherecode.c
index 460ac4fe30..a08ff84d28 100644
--- a/src/wherecode.c
+++ b/src/wherecode.c
@@ -176,19 +176,27 @@ int sqlite3WhereExplainOneScan(
explainIndexRange(&str, pLoop);
}
}else if( (flags & WHERE_IPK)!=0 && (flags & WHERE_CONSTRAINT)!=0 ){
- const char *zRangeOp;
+ char cRangeOp;
+#if 0 /* Better output, but breaks many tests */
+ const Table *pTab = pItem->pTab;
+ const char *zRowid = pTab->iPKey>=0 ? pTab->aCol[pTab->iPKey].zCnName:
+ "rowid";
+#else
+ const char *zRowid = "rowid";
+#endif
+ sqlite3_str_appendf(&str, " USING INTEGER PRIMARY KEY (%s", zRowid);
if( flags&(WHERE_COLUMN_EQ|WHERE_COLUMN_IN) ){
- zRangeOp = "=";
+ cRangeOp = '=';
}else if( (flags&WHERE_BOTH_LIMIT)==WHERE_BOTH_LIMIT ){
- zRangeOp = ">? AND rowid<";
+ sqlite3_str_appendf(&str, ">? AND %s", zRowid);
+ cRangeOp = '<';
}else if( flags&WHERE_BTM_LIMIT ){
- zRangeOp = ">";
+ cRangeOp = '>';
}else{
assert( flags&WHERE_TOP_LIMIT);
- zRangeOp = "<";
+ cRangeOp = '<';
}
- sqlite3_str_appendf(&str,
- " USING INTEGER PRIMARY KEY (rowid%s?)",zRangeOp);
+ sqlite3_str_appendf(&str, "%c?)", cRangeOp);
}
#ifndef SQLITE_OMIT_VIRTUALTABLE
else if( (flags & WHERE_VIRTUALTABLE)!=0 ){
@@ -211,6 +219,56 @@ int sqlite3WhereExplainOneScan(
}
return ret;
}
+
+/*
+** Add a single OP_Explain opcode that describes a Bloom filter.
+**
+** Or if not processing EXPLAIN QUERY PLAN and not in a SQLITE_DEBUG and/or
+** SQLITE_ENABLE_STMT_SCANSTATUS build, then OP_Explain opcodes are not
+** required and this routine is a no-op.
+**
+** If an OP_Explain opcode is added to the VM, its address is returned.
+** Otherwise, if no OP_Explain is coded, zero is returned.
+*/
+int sqlite3WhereExplainBloomFilter(
+ const Parse *pParse, /* Parse context */
+ const WhereInfo *pWInfo, /* WHERE clause */
+ const WhereLevel *pLevel /* Bloom filter on this level */
+){
+ int ret = 0;
+ SrcItem *pItem = &pWInfo->pTabList->a[pLevel->iFrom];
+ Vdbe *v = pParse->pVdbe; /* VM being constructed */
+ sqlite3 *db = pParse->db; /* Database handle */
+ char *zMsg; /* Text to add to EQP output */
+ int i; /* Loop counter */
+ WhereLoop *pLoop; /* The where loop */
+ StrAccum str; /* EQP output string */
+ char zBuf[100]; /* Initial space for EQP output string */
+
+ sqlite3StrAccumInit(&str, db, zBuf, sizeof(zBuf), SQLITE_MAX_LENGTH);
+ str.printfFlags = SQLITE_PRINTF_INTERNAL;
+ sqlite3_str_appendf(&str, "BLOOM FILTER ON %S (", pItem);
+ pLoop = pLevel->pWLoop;
+ if( pLoop->wsFlags & WHERE_IPK ){
+ const Table *pTab = pItem->pTab;
+ if( pTab->iPKey>=0 ){
+ sqlite3_str_appendf(&str, "%s=?", pTab->aCol[pTab->iPKey].zCnName);
+ }else{
+ sqlite3_str_appendf(&str, "rowid=?");
+ }
+ }else{
+ for(i=pLoop->nSkip; iu.btree.nEq; i++){
+ const char *z = explainIndexColumnName(pLoop->u.btree.pIndex, i);
+ if( i>pLoop->nSkip ) sqlite3_str_append(&str, " AND ", 5);
+ sqlite3_str_appendf(&str, "%s=?", z);
+ }
+ }
+ sqlite3_str_append(&str, ")", 1);
+ zMsg = sqlite3StrAccumFinish(&str);
+ ret = sqlite3VdbeAddOp4(v, OP_Explain, sqlite3VdbeCurrentAddr(v),
+ pParse->addrExplain, 0, zMsg,P4_DYNAMIC);
+ return ret;
+}
#endif /* SQLITE_OMIT_EXPLAIN */
#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
@@ -970,7 +1028,7 @@ static void codeCursorHint(
sWalker.pParse = pParse;
sWalker.u.pCCurHint = &sHint;
pWC = &pWInfo->sWC;
- for(i=0; inTerm; i++){
+ for(i=0; inBase; i++){
pTerm = &pWC->a[i];
if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue;
if( pTerm->prereqAll & pLevel->notReady ) continue;
@@ -1301,6 +1359,64 @@ static void whereApplyPartialIndexConstraints(
}
}
+/*
+** This routine is called right after An OP_Filter has been generated and
+** before the corresponding index search has been performed. This routine
+** checks to see if there are additional Bloom filters in inner loops that
+** can be checked prior to doing the index lookup. If there are available
+** inner-loop Bloom filters, then evaluate those filters now, before the
+** index lookup. The idea is that a Bloom filter check is way faster than
+** an index lookup, and the Bloom filter might return false, meaning that
+** the index lookup can be skipped.
+**
+** We know that an inner loop uses a Bloom filter because it has the
+** WhereLevel.regFilter set. If an inner-loop Bloom filter is checked,
+** then clear the WhereLevel.regFilter value to prevent the Bloom filter
+** from being checked a second time when the inner loop is evaluated.
+*/
+static SQLITE_NOINLINE void filterPullDown(
+ Parse *pParse, /* Parsing context */
+ WhereInfo *pWInfo, /* Complete information about the WHERE clause */
+ int iLevel, /* Which level of pWInfo->a[] should be coded */
+ int addrNxt, /* Jump here to bypass inner loops */
+ Bitmask notReady /* Loops that are not ready */
+){
+ while( ++iLevel < pWInfo->nLevel ){
+ WhereLevel *pLevel = &pWInfo->a[iLevel];
+ WhereLoop *pLoop = pLevel->pWLoop;
+ if( pLevel->regFilter==0 ) continue;
+ /* ,--- Because sqlite3ConstructBloomFilter() has will not have set
+ ** vvvvv--' pLevel->regFilter if this were true. */
+ if( NEVER(pLoop->prereq & notReady) ) continue;
+ if( pLoop->wsFlags & WHERE_IPK ){
+ WhereTerm *pTerm = pLoop->aLTerm[0];
+ int regRowid;
+ assert( pTerm!=0 );
+ assert( pTerm->pExpr!=0 );
+ testcase( pTerm->wtFlags & TERM_VIRTUAL );
+ regRowid = sqlite3GetTempReg(pParse);
+ regRowid = codeEqualityTerm(pParse, pTerm, pLevel, 0, 0, regRowid);
+ sqlite3VdbeAddOp4Int(pParse->pVdbe, OP_Filter, pLevel->regFilter,
+ addrNxt, regRowid, 1);
+ VdbeCoverage(pParse->pVdbe);
+ }else{
+ u16 nEq = pLoop->u.btree.nEq;
+ int r1;
+ char *zStartAff;
+
+ assert( pLoop->wsFlags & WHERE_INDEXED );
+ assert( (pLoop->wsFlags & WHERE_COLUMN_IN)==0 );
+ r1 = codeAllEqualityTerms(pParse,pLevel,0,0,&zStartAff);
+ codeApplyAffinity(pParse, r1, nEq, zStartAff);
+ sqlite3DbFree(pParse->db, zStartAff);
+ sqlite3VdbeAddOp4Int(pParse->pVdbe, OP_Filter, pLevel->regFilter,
+ addrNxt, r1, nEq);
+ VdbeCoverage(pParse->pVdbe);
+ }
+ pLevel->regFilter = 0;
+ }
+}
+
/*
** Generate code for the start of the iLevel-th loop in the WHERE clause
** implementation described by pWInfo.
@@ -1511,6 +1627,12 @@ Bitmask sqlite3WhereCodeOneLoopStart(
iRowidReg = codeEqualityTerm(pParse, pTerm, pLevel, 0, bRev, iReleaseReg);
if( iRowidReg!=iReleaseReg ) sqlite3ReleaseTempReg(pParse, iReleaseReg);
addrNxt = pLevel->addrNxt;
+ if( pLevel->regFilter ){
+ sqlite3VdbeAddOp4Int(v, OP_Filter, pLevel->regFilter, addrNxt,
+ iRowidReg, 1);
+ VdbeCoverage(v);
+ filterPullDown(pParse, pWInfo, iLevel, addrNxt, notReady);
+ }
sqlite3VdbeAddOp3(v, OP_SeekRowid, iCur, addrNxt, iRowidReg);
VdbeCoverage(v);
pLevel->op = OP_Noop;
@@ -1836,6 +1958,12 @@ Bitmask sqlite3WhereCodeOneLoopStart(
sqlite3VdbeAddOp2(v, OP_Integer, 1, regBignull);
VdbeComment((v, "NULL-scan pass ctr"));
}
+ if( pLevel->regFilter ){
+ sqlite3VdbeAddOp4Int(v, OP_Filter, pLevel->regFilter, addrNxt,
+ regBase, nEq);
+ VdbeCoverage(v);
+ filterPullDown(pParse, pWInfo, iLevel, addrNxt, notReady);
+ }
op = aStartOp[(start_constraints<<2) + (startEq<<1) + bRev];
assert( op!=0 );
@@ -2467,7 +2595,7 @@ Bitmask sqlite3WhereCodeOneLoopStart(
** then we cannot use the "t1.a=t2.b" constraint, but we can code
** the implied "t1.a=123" constraint.
*/
- for(pTerm=pWC->a, j=pWC->nTerm; j>0; j--, pTerm++){
+ for(pTerm=pWC->a, j=pWC->nBase; j>0; j--, pTerm++){
Expr *pE, sEAlt;
WhereTerm *pAlt;
if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue;
@@ -2512,7 +2640,7 @@ Bitmask sqlite3WhereCodeOneLoopStart(
pLevel->addrFirst = sqlite3VdbeCurrentAddr(v);
sqlite3VdbeAddOp2(v, OP_Integer, 1, pLevel->iLeftJoin);
VdbeComment((v, "record LEFT JOIN hit"));
- for(pTerm=pWC->a, j=0; jnTerm; j++, pTerm++){
+ for(pTerm=pWC->a, j=0; jnBase; j++, pTerm++){
testcase( pTerm->wtFlags & TERM_VIRTUAL );
testcase( pTerm->wtFlags & TERM_CODED );
if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue;
diff --git a/src/whereexpr.c b/src/whereexpr.c
index 53dd14031c..f0660a990e 100644
--- a/src/whereexpr.c
+++ b/src/whereexpr.c
@@ -79,6 +79,7 @@ static int whereClauseInsert(WhereClause *pWC, Expr *p, u16 wtFlags){
pWC->nSlot = sqlite3DbMallocSize(db, pWC->a)/sizeof(pWC->a[0]);
}
pTerm = &pWC->a[idx = pWC->nTerm++];
+ if( (wtFlags & TERM_VIRTUAL)==0 ) pWC->nBase = pWC->nTerm;
if( p && ExprHasProperty(p, EP_Unlikely) ){
pTerm->truthProb = sqlite3LogEst(p->iTable) - 270;
}else{
@@ -795,7 +796,7 @@ static void exprAnalyzeOrTerm(
pOrTerm = pOrWc->a;
for(i=pOrWc->nTerm-1; i>=0; i--, pOrTerm++){
assert( pOrTerm->eOperator & WO_EQ );
- pOrTerm->wtFlags &= ~TERM_OR_OK;
+ pOrTerm->wtFlags &= ~TERM_OK;
if( pOrTerm->leftCursor==iCursor ){
/* This is the 2-bit case and we are on the second iteration and
** current term is from the first iteration. So skip this term. */
@@ -836,7 +837,7 @@ static void exprAnalyzeOrTerm(
assert( pOrTerm->eOperator & WO_EQ );
assert( (pOrTerm->eOperator & (WO_OR|WO_AND))==0 );
if( pOrTerm->leftCursor!=iCursor ){
- pOrTerm->wtFlags &= ~TERM_OR_OK;
+ pOrTerm->wtFlags &= ~TERM_OK;
}else if( pOrTerm->u.x.leftColumn!=iColumn || (iColumn==XN_EXPR
&& sqlite3ExprCompare(pParse, pOrTerm->pExpr->pLeft, pLeft, -1)
)){
@@ -852,7 +853,7 @@ static void exprAnalyzeOrTerm(
if( affRight!=0 && affRight!=affLeft ){
okToChngToIN = 0;
}else{
- pOrTerm->wtFlags |= TERM_OR_OK;
+ pOrTerm->wtFlags |= TERM_OK;
}
}
}
@@ -869,7 +870,7 @@ static void exprAnalyzeOrTerm(
Expr *pNew; /* The complete IN operator */
for(i=pOrWc->nTerm-1, pOrTerm=pOrWc->a; i>=0; i--, pOrTerm++){
- if( (pOrTerm->wtFlags & TERM_OR_OK)==0 ) continue;
+ if( (pOrTerm->wtFlags & TERM_OK)==0 ) continue;
assert( pOrTerm->eOperator & WO_EQ );
assert( (pOrTerm->eOperator & (WO_OR|WO_AND))==0 );
assert( pOrTerm->leftCursor==iCursor );
@@ -1070,10 +1071,13 @@ static void exprAnalyze(
if( db->mallocFailed ){
return;
}
+ assert( pWC->nTerm > idxTerm );
pTerm = &pWC->a[idxTerm];
pMaskSet = &pWInfo->sMaskSet;
pExpr = pTerm->pExpr;
+ assert( pExpr!=0 ); /* Because malloc() has not failed */
assert( pExpr->op!=TK_AS && pExpr->op!=TK_COLLATE );
+ pMaskSet->bVarSelect = 0;
prereqLeft = sqlite3WhereExprUsage(pMaskSet, pExpr->pLeft);
op = pExpr->op;
if( op==TK_IN ){
@@ -1084,14 +1088,28 @@ static void exprAnalyze(
}else{
pTerm->prereqRight = sqlite3WhereExprListUsage(pMaskSet, pExpr->x.pList);
}
- }else if( op==TK_ISNULL ){
- pTerm->prereqRight = 0;
+ prereqAll = prereqLeft | pTerm->prereqRight;
}else{
pTerm->prereqRight = sqlite3WhereExprUsage(pMaskSet, pExpr->pRight);
+ if( pExpr->pLeft==0
+ || ExprHasProperty(pExpr, EP_xIsSelect|EP_IfNullRow)
+ || pExpr->x.pList!=0
+ ){
+ prereqAll = sqlite3WhereExprUsageNN(pMaskSet, pExpr);
+ }else{
+ prereqAll = prereqLeft | pTerm->prereqRight;
+ }
}
- pMaskSet->bVarSelect = 0;
- prereqAll = sqlite3WhereExprUsageNN(pMaskSet, pExpr);
if( pMaskSet->bVarSelect ) pTerm->wtFlags |= TERM_VARSELECT;
+
+#ifdef SQLITE_DEBUG
+ if( prereqAll!=sqlite3WhereExprUsageNN(pMaskSet, pExpr) ){
+ printf("\n*** Incorrect prereqAll computed for:\n");
+ sqlite3TreeViewExpr(0,pExpr,0);
+ abort();
+ }
+#endif
+
if( ExprHasProperty(pExpr, EP_FromJoin) ){
Bitmask x = sqlite3WhereGetMask(pMaskSet, pExpr->iRightJoinTable);
prereqAll |= x;
@@ -1515,6 +1533,7 @@ void sqlite3WhereClauseInit(
pWC->hasOr = 0;
pWC->pOuter = 0;
pWC->nTerm = 0;
+ pWC->nBase = 0;
pWC->nSlot = ArraySize(pWC->aStatic);
pWC->a = pWC->aStatic;
}
@@ -1525,17 +1544,33 @@ void sqlite3WhereClauseInit(
** sqlite3WhereClauseInit().
*/
void sqlite3WhereClauseClear(WhereClause *pWC){
- int i;
- WhereTerm *a;
sqlite3 *db = pWC->pWInfo->pParse->db;
- for(i=pWC->nTerm-1, a=pWC->a; i>=0; i--, a++){
- if( a->wtFlags & TERM_DYNAMIC ){
- sqlite3ExprDelete(db, a->pExpr);
+ assert( pWC->nTerm>=pWC->nBase );
+ if( pWC->nTerm>0 ){
+ WhereTerm *a = pWC->a;
+ WhereTerm *aLast = &pWC->a[pWC->nTerm-1];
+#ifdef SQLITE_DEBUG
+ int i;
+ /* Verify that every term past pWC->nBase is virtual */
+ for(i=pWC->nBase; inTerm; i++){
+ assert( (pWC->a[i].wtFlags & TERM_VIRTUAL)!=0 );
}
- if( a->wtFlags & TERM_ORINFO ){
- whereOrInfoDelete(db, a->u.pOrInfo);
- }else if( a->wtFlags & TERM_ANDINFO ){
- whereAndInfoDelete(db, a->u.pAndInfo);
+#endif
+ while(1){
+ if( a->wtFlags & TERM_DYNAMIC ){
+ sqlite3ExprDelete(db, a->pExpr);
+ }
+ if( a->wtFlags & (TERM_ORINFO|TERM_ANDINFO) ){
+ if( a->wtFlags & TERM_ORINFO ){
+ assert( (a->wtFlags & TERM_ANDINFO)==0 );
+ whereOrInfoDelete(db, a->u.pOrInfo);
+ }else{
+ assert( (a->wtFlags & TERM_ANDINFO)!=0 );
+ whereAndInfoDelete(db, a->u.pAndInfo);
+ }
+ }
+ if( a==aLast ) break;
+ a++;
}
}
if( pWC->a!=pWC->aStatic ){
@@ -1548,15 +1583,38 @@ void sqlite3WhereClauseClear(WhereClause *pWC){
** These routines walk (recursively) an expression tree and generate
** a bitmask indicating which tables are used in that expression
** tree.
+**
+** sqlite3WhereExprUsage(MaskSet, Expr) ->
+**
+** Return a Bitmask of all tables referenced by Expr. Expr can be
+** be NULL, in which case 0 is returned.
+**
+** sqlite3WhereExprUsageNN(MaskSet, Expr) ->
+**
+** Same as sqlite3WhereExprUsage() except that Expr must not be
+** NULL. The "NN" suffix on the name stands for "Not Null".
+**
+** sqlite3WhereExprListUsage(MaskSet, ExprList) ->
+**
+** Return a Bitmask of all tables referenced by every expression
+** in the expression list ExprList. ExprList can be NULL, in which
+** case 0 is returned.
+**
+** sqlite3WhereExprUsageFull(MaskSet, ExprList) ->
+**
+** Internal use only. Called only by sqlite3WhereExprUsageNN() for
+** complex expressions that require pushing register values onto
+** the stack. Many calls to sqlite3WhereExprUsageNN() do not need
+** the more complex analysis done by this routine. Hence, the
+** computations done by this routine are broken out into a separate
+** "no-inline" function to avoid the stack push overhead in the
+** common case where it is not needed.
*/
-Bitmask sqlite3WhereExprUsageNN(WhereMaskSet *pMaskSet, Expr *p){
+static SQLITE_NOINLINE Bitmask sqlite3WhereExprUsageFull(
+ WhereMaskSet *pMaskSet,
+ Expr *p
+){
Bitmask mask;
- if( p->op==TK_COLUMN && !ExprHasProperty(p, EP_FixedCol) ){
- return sqlite3WhereGetMask(pMaskSet, p->iTable);
- }else if( ExprHasProperty(p, EP_TokenOnly|EP_Leaf) ){
- assert( p->op!=TK_IF_NULL_ROW );
- return 0;
- }
mask = (p->op==TK_IF_NULL_ROW) ? sqlite3WhereGetMask(pMaskSet, p->iTable) : 0;
if( p->pLeft ) mask |= sqlite3WhereExprUsageNN(pMaskSet, p->pLeft);
if( p->pRight ){
@@ -1578,6 +1636,15 @@ Bitmask sqlite3WhereExprUsageNN(WhereMaskSet *pMaskSet, Expr *p){
#endif
return mask;
}
+Bitmask sqlite3WhereExprUsageNN(WhereMaskSet *pMaskSet, Expr *p){
+ if( p->op==TK_COLUMN && !ExprHasProperty(p, EP_FixedCol) ){
+ return sqlite3WhereGetMask(pMaskSet, p->iTable);
+ }else if( ExprHasProperty(p, EP_TokenOnly|EP_Leaf) ){
+ assert( p->op!=TK_IF_NULL_ROW );
+ return 0;
+ }
+ return sqlite3WhereExprUsageFull(pMaskSet, p);
+}
Bitmask sqlite3WhereExprUsage(WhereMaskSet *pMaskSet, Expr *p){
return p ? sqlite3WhereExprUsageNN(pMaskSet,p) : 0;
}
diff --git a/test/altercol.test b/test/altercol.test
index d0c5c40ea6..10ff9e773f 100644
--- a/test/altercol.test
+++ b/test/altercol.test
@@ -838,6 +838,8 @@ do_execsql_test 22.0 {
#-------------------------------------------------------------------------
#
reset_db
+sqlite3_db_config db SQLITE_DBCONFIG_DQS_DDL 1
+sqlite3_db_config db SQLITE_DBCONFIG_DQS_DML 1
do_execsql_test 22.0 {
CREATE TABLE t1(a, b);
CREATE INDEX x1 on t1("c"=b);
diff --git a/test/alterqf.test b/test/alterqf.test
index 6a89641865..400c4b6e79 100644
--- a/test/alterqf.test
+++ b/test/alterqf.test
@@ -25,6 +25,8 @@ ifcapable !altertable {
sqlite3_test_control SQLITE_TESTCTRL_INTERNAL_FUNCTIONS db
+sqlite3_db_config db SQLITE_DBCONFIG_DQS_DDL 1
+sqlite3_db_config db SQLITE_DBCONFIG_DQS_DML 1
do_execsql_test 1.0 {
CREATE TABLE t1(a, b, c);
@@ -89,6 +91,8 @@ foreach {tn before after} {
#-------------------------------------------------------------------------
reset_db
+sqlite3_db_config db SQLITE_DBCONFIG_DQS_DDL 1
+sqlite3_db_config db SQLITE_DBCONFIG_DQS_DML 1
do_execsql_test 2.0 {
CREATE TABLE x1(
one, two, three, PRIMARY KEY(one),
diff --git a/test/autoindex4.test b/test/autoindex4.test
index 0e7a80df21..24604af588 100644
--- a/test/autoindex4.test
+++ b/test/autoindex4.test
@@ -79,5 +79,98 @@ do_execsql_test autoindex4-3.1 {
ORDER BY Items.ItemName;
} {Item1 Item2}
+# 2021-11-30 - Enhancement to help the automatic index mechanism to
+# create a partial index more often.
+#
+unset -nocomplain id data1 data2 jointype onclause whereclause answer
+foreach {id data1 data2 jointype onclause whereclause answer} {
+ 1
+ VALUES(1,2),(3,4)
+ VALUES(1,2),(3,4)
+ {LEFT JOIN}
+ a=x
+ {y=4 OR y IS NULL}
+ {3 4 3 4}
+
+ 2
+ VALUES(1,2),(3,4)
+ VALUES(1,2),(3,4)
+ {LEFT JOIN}
+ {a=x AND y=4}
+ {coalesce(y,4)==4}
+ {1 2 {} {} 3 4 3 4}
+
+ 3
+ VALUES(1,2),(3,4)
+ VALUES(1,2),(3,4)
+ {JOIN}
+ {a=x}
+ {y=4 OR y IS NULL}
+ {3 4 3 4}
+
+ 4
+ VALUES(1,2),(3,4)
+ VALUES(1,2),(3,4)
+ {JOIN}
+ {a=x AND y=4}
+ {coalesce(y,4)==4}
+ {3 4 3 4}
+
+ 5
+ VALUES(1,2),(3,4),(NULL,4)
+ VALUES(1,2),(3,4)
+ {LEFT JOIN}
+ a=x
+ {y=4 OR y IS NULL}
+ {3 4 3 4 {} 4 {} {}}
+
+ 6
+ VALUES(1,2),(3,4)
+ VALUES(1,2),(3,4),(NULL,4)
+ {LEFT JOIN}
+ {a=x AND y=4}
+ {coalesce(y,4)==4}
+ {1 2 {} {} 3 4 3 4}
+
+ 7
+ VALUES(1,2),(3,4),(NULL,4)
+ VALUES(1,2),(3,4),(NULL,4)
+ {JOIN}
+ {a=x}
+ {y=4 OR y IS NULL}
+ {3 4 3 4}
+
+ 8
+ VALUES(1,2),(3,4)
+ VALUES(1,2),(3,4)
+ {JOIN}
+ {a=x AND y=4}
+ {coalesce(y,4)==4}
+ {3 4 3 4}
+} {
+ do_test autoindex4-4.$id.0 {
+ db eval {
+ DROP TABLE IF EXISTS t1;
+ CREATE TABLE t1(a INT, b INT);
+ DROP TABLE IF EXISTS t2;
+ CREATE TABLE t2(x INT, y INT);
+ }
+ db eval "INSERT INTO t1(a,b) $data1;"
+ db eval "INSERT INTO t2(x,y) $data2;"
+ } {}
+ set sql "SELECT * FROM t1 $jointype t2 ON $onclause WHERE $whereclause"
+ # puts "sql = $sql"
+ do_test autoindex4-4.$id.1 {
+ db eval {PRAGMA automatic_index=ON;}
+ db eval $sql
+ } $answer
+ do_test autoindex4-4.$id.2 {
+ db eval {PRAGMA automatic_index=OFF;}
+ db eval $sql
+ } $answer
+}
+
+
+
finish_test
diff --git a/test/check.test b/test/check.test
index 94fe1d14e4..10d1cf4be6 100644
--- a/test/check.test
+++ b/test/check.test
@@ -21,6 +21,8 @@ ifcapable !check {
finish_test
return
}
+sqlite3_db_config db SQLITE_DBCONFIG_DQS_DDL 1
+sqlite3_db_config db SQLITE_DBCONFIG_DQS_DML 1
do_test check-1.1 {
execsql {
@@ -138,6 +140,8 @@ do_test check-2.2 {
} {1 2.2 three}
db close
sqlite3 db test.db
+sqlite3_db_config db SQLITE_DBCONFIG_DQS_DDL 1
+sqlite3_db_config db SQLITE_DBCONFIG_DQS_DML 1
do_test check-2.3 {
execsql {
INSERT INTO t2 VALUES(NULL, NULL, NULL);
diff --git a/test/collate1.test b/test/collate1.test
index 007dd7c370..b65b850474 100644
--- a/test/collate1.test
+++ b/test/collate1.test
@@ -338,6 +338,7 @@ do_test collate1-5.3 {
#-------------------------------------------------------------------------
# Fix problems with handling collation sequences named '"""'.
#
+sqlite3_db_config db SQLITE_DBCONFIG_DQS_DML 1
do_execsql_test 6.1 {
SELECT """""""";
} {\"\"\"}
diff --git a/test/ctime.test b/test/ctime.test
index 1f07c1a947..26b2fa2ee2 100644
--- a/test/ctime.test
+++ b/test/ctime.test
@@ -81,6 +81,7 @@ ifcapable threadsafe2 {
# SQLITE_THREADSAFE should pretty much always be defined
# one way or the other, and it must have a value of 0 or 1.
+sqlite3_db_config db SQLITE_DBCONFIG_DQS_DML 1
do_test ctime-1.4.1 {
catchsql {
SELECT sqlite_compileoption_used('SQLITE_THREADSAFE');
diff --git a/test/eval.test b/test/eval.test
index 360d158f3c..159e8754dc 100644
--- a/test/eval.test
+++ b/test/eval.test
@@ -81,7 +81,7 @@ do_test eval-3.1 {
} {1 {} 102 2 {} 103 3 {} 104 4 {} 105}
do_test eval-4.1 {
- execsql { SELECT test_eval('SELECT "abcdefghij"') }
+ execsql { SELECT test_eval('SELECT ''abcdefghij''') }
} {abcdefghij}
finish_test
diff --git a/test/expr.test b/test/expr.test
index ec5c55c2e4..c64b6cb706 100644
--- a/test/expr.test
+++ b/test/expr.test
@@ -970,6 +970,7 @@ do_realnum_test expr-13.7 {
}
} {9.22337203685478e+18}
+sqlite3_db_config db SQLITE_DBCONFIG_DQS_DML 1
do_execsql_test expr-13.8 {
SELECT "" <= '';
} {1}
diff --git a/test/fkey1.test b/test/fkey1.test
index 13635db987..db93be501d 100644
--- a/test/fkey1.test
+++ b/test/fkey1.test
@@ -241,5 +241,35 @@ do_execsql_test 7.2 {
PRAGMA foreign_key_check;
} {}
+# 2021-12-31 forum https://sqlite.org/forum/forumpost/24bd1fef7e9323ef
+# Memory leak caused by sqlite3NestedParse() running on a corrupt system
+# table. Discovered by Jingzhou Fu.
+#
+reset_db
+do_execsql_test 8.1 {
+ PRAGMA writable_schema=ON;
+ PRAGMA foreign_keys = ON;
+ CREATE TABLE sqlite_stat1 (tbl INTEGER PRIMARY KEY DESC, idx UNIQUE DEFAULT NULL) WITHOUT ROWID;
+ PRAGMA writable_schema=OFF;
+ CREATE TABLE sqlsim4(stat PRIMARY KEY);;
+ CREATE TABLE t1(sqlsim7 REFERENCES sqlite_stat1 ON DELETE CASCADE);
+ DROP table "sqlsim4";
+} {}
+# 2022-01-01 dbsqlfuzz 1c57440219f6f0aedf5e8f72a8ddd75f15aea381
+# Follow-up case to the above. Assertion is not true if the schema
+# is corrupt.
+reset_db
+database_may_be_corrupt
+do_execsql_test 8.2 {
+ CREATE TABLE t1(a REFERENCES sqlite_stat1 ON DELETE CASCADE);
+ CREATE TABLE t2(a TEXT PRIMARY KEY);
+ PRAGMA writable_schema=ON;
+ CREATE TABLE sqlite_stat1(tbl INTEGER PRIMARY KEY DESC, idx UNIQUE DEFAULT NULL) WITHOUT ROWID;
+ UPDATE sqlite_schema SET name='sqlite_autoindex_sqlite_stat1_1' WHERE name='sqlite_autoindex_sqlite_stat1_2';
+ PRAGMA writable_schema=RESET;
+} {}
+do_catchsql_test 8.3 {
+ REINDEX;
+} {1 {database disk image is malformed}}
finish_test
diff --git a/test/fts3aj.test b/test/fts3aj.test
index f3d46f2ad8..0c89691162 100644
--- a/test/fts3aj.test
+++ b/test/fts3aj.test
@@ -6,8 +6,6 @@
# This file implements regression tests for SQLite library. This
# tests creating fts3 tables in an attached database.
#
-# $Id: fts3aj.test,v 1.1 2007/08/20 17:38:42 shess Exp $
-#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
@@ -25,14 +23,14 @@ sqlite3 db2 test2.db
db eval {
CREATE VIRTUAL TABLE t3 USING fts3(content);
- INSERT INTO t3 (rowid, content) VALUES(1, "hello world");
+ INSERT INTO t3 (rowid, content) VALUES(1, 'hello world');
}
db2 eval {
CREATE VIRTUAL TABLE t1 USING fts3(content);
- INSERT INTO t1 (rowid, content) VALUES(1, "hello world");
- INSERT INTO t1 (rowid, content) VALUES(2, "hello there");
- INSERT INTO t1 (rowid, content) VALUES(3, "cruel world");
+ INSERT INTO t1 (rowid, content) VALUES(1, 'hello world');
+ INSERT INTO t1 (rowid, content) VALUES(2, 'hello there');
+ INSERT INTO t1 (rowid, content) VALUES(3, 'cruel world');
}
# This has always worked because the t1_* tables used by fts3 will be
@@ -56,9 +54,9 @@ do_test fts3aj-1.2 {
execsql {
ATTACH DATABASE 'test2.db' AS two;
CREATE VIRTUAL TABLE two.t2 USING fts3(content);
- INSERT INTO t2 (rowid, content) VALUES(1, "hello world");
- INSERT INTO t2 (rowid, content) VALUES(2, "hello there");
- INSERT INTO t2 (rowid, content) VALUES(3, "cruel world");
+ INSERT INTO t2 (rowid, content) VALUES(1, 'hello world');
+ INSERT INTO t2 (rowid, content) VALUES(2, 'hello there');
+ INSERT INTO t2 (rowid, content) VALUES(3, 'cruel world');
SELECT rowid FROM t2 WHERE t2 MATCH 'hello';
DETACH DATABASE two;
}
@@ -74,8 +72,8 @@ do_test fts3aj-1.3 {
ATTACH DATABASE 'test2.db' AS two;
CREATE VIRTUAL TABLE two.t3 USING fts3(content);
- INSERT INTO two.t3 (rowid, content) VALUES(2, "hello there");
- INSERT INTO two.t3 (rowid, content) VALUES(3, "cruel world");
+ INSERT INTO two.t3 (rowid, content) VALUES(2, 'hello there');
+ INSERT INTO two.t3 (rowid, content) VALUES(3, 'cruel world');
SELECT rowid FROM two.t3 WHERE t3 MATCH 'hello';
DETACH DATABASE two;
diff --git a/test/fts3ak.test b/test/fts3ak.test
index a263f0b740..080efe52b5 100644
--- a/test/fts3ak.test
+++ b/test/fts3ak.test
@@ -21,17 +21,17 @@ ifcapable !fts3 {
db eval {
CREATE VIRTUAL TABLE t1 USING fts3(content);
- INSERT INTO t1 (rowid, content) VALUES(1, "hello world");
- INSERT INTO t1 (rowid, content) VALUES(2, "hello there");
- INSERT INTO t1 (rowid, content) VALUES(3, "cruel world");
+ INSERT INTO t1 (rowid, content) VALUES(1, 'hello world');
+ INSERT INTO t1 (rowid, content) VALUES(2, 'hello there');
+ INSERT INTO t1 (rowid, content) VALUES(3, 'cruel world');
}
# Test that possibly-buffered inserts went through after commit.
do_test fts3ak-1.1 {
execsql {
BEGIN TRANSACTION;
- INSERT INTO t1 (rowid, content) VALUES(4, "false world");
- INSERT INTO t1 (rowid, content) VALUES(5, "false door");
+ INSERT INTO t1 (rowid, content) VALUES(4, 'false world');
+ INSERT INTO t1 (rowid, content) VALUES(5, 'false door');
COMMIT TRANSACTION;
SELECT rowid FROM t1 WHERE t1 MATCH 'world';
}
@@ -42,8 +42,8 @@ do_test fts3ak-1.1 {
do_test fts3ak-1.2 {
execsql {
BEGIN TRANSACTION;
- INSERT INTO t1 (rowid, content) VALUES(6, "another world");
- INSERT INTO t1 (rowid, content) VALUES(7, "another test");
+ INSERT INTO t1 (rowid, content) VALUES(6, 'another world');
+ INSERT INTO t1 (rowid, content) VALUES(7, 'another test');
SELECT rowid FROM t1 WHERE t1 MATCH 'world';
COMMIT TRANSACTION;
}
@@ -54,8 +54,8 @@ do_test fts3ak-1.2 {
do_test fts3ak-1.3 {
execsql {
BEGIN TRANSACTION;
- INSERT INTO t1 (rowid, content) VALUES(8, "second world");
- INSERT INTO t1 (rowid, content) VALUES(9, "second sight");
+ INSERT INTO t1 (rowid, content) VALUES(8, 'second world');
+ INSERT INTO t1 (rowid, content) VALUES(9, 'second sight');
SELECT rowid FROM t1 WHERE t1 MATCH 'world';
ROLLBACK TRANSACTION;
}
@@ -73,8 +73,8 @@ do_test fts3ak-1.4 {
do_test fts3ak-1.5 {
execsql {
BEGIN TRANSACTION;
- INSERT INTO t1 (rowid, content) VALUES(10, "second world");
- INSERT INTO t1 (rowid, content) VALUES(11, "second sight");
+ INSERT INTO t1 (rowid, content) VALUES(10, 'second world');
+ INSERT INTO t1 (rowid, content) VALUES(11, 'second sight');
ROLLBACK TRANSACTION;
SELECT rowid FROM t1 WHERE t1 MATCH 'world';
}
@@ -84,7 +84,7 @@ do_test fts3ak-1.5 {
do_test fts3ak-1.6 {
execsql {
BEGIN;
- INSERT INTO t1 (rowid, content) VALUES(12, "third world");
+ INSERT INTO t1 (rowid, content) VALUES(12, 'third world');
COMMIT;
SELECT rowid FROM t1 WHERE t1 MATCH 'third';
}
@@ -95,7 +95,7 @@ do_test fts3ak-1.6 {
do_test fts3ak-1.7 {
execsql {
BEGIN;
- INSERT INTO t1 (rowid, content) VALUES(13, "third dimension");
+ INSERT INTO t1 (rowid, content) VALUES(13, 'third dimension');
CREATE TABLE x (c);
COMMIT;
SELECT rowid FROM t1 WHERE t1 MATCH 'dimension';
diff --git a/test/fts3corrupt.test b/test/fts3corrupt.test
index 828964b1bc..8b958db5fa 100644
--- a/test/fts3corrupt.test
+++ b/test/fts3corrupt.test
@@ -178,7 +178,7 @@ do_catchsql_test 6.10 {
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");
+ INSERT INTO f(f) VALUES ('merge=1');
} {1 {database disk image is malformed}}
# 2020-03-02 https://bugs.chromium.org/p/chromium/issues/detail?id=1057441
diff --git a/test/fts3dropmod.test b/test/fts3dropmod.test
new file mode 100644
index 0000000000..d6b1677ac2
--- /dev/null
+++ b/test/fts3dropmod.test
@@ -0,0 +1,44 @@
+# 2021 December 16
+#
+# The author disclaims copyright to this source code. In place of
+# a legal notice, here is a blessing:
+#
+# May you do good and not evil.
+# May you find forgiveness for yourself and forgive others.
+# May you share freely, never taking more than you give.
+#
+#*************************************************************************
+# This file implements regression tests for SQLite library. The
+# focus of this script is testing the FTS3 module.
+#
+# $Id: fts3aa.test,v 1.1 2007/08/20 17:38:42 shess Exp $
+#
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+set testprefix fts3dropmod
+
+# If SQLITE_ENABLE_FTS3 is defined, omit this file.
+ifcapable !fts3 {
+ finish_test
+ return
+}
+
+sqlite3_drop_modules db fts3
+do_execsql_test 1.0 {
+ CREATE VIRTUAL TABLE t1 USING fts3(x);
+}
+do_catchsql_test 1.1 {
+ CREATE VIRTUAL TABLE t2 USING fts4(x);
+} {1 {no such module: fts4}}
+
+reset_db
+sqlite3_drop_modules db fts4
+do_execsql_test 2.0 {
+ CREATE VIRTUAL TABLE t1 USING fts4(x);
+}
+do_catchsql_test 2.1 {
+ CREATE VIRTUAL TABLE t2 USING fts3(x);
+} {1 {no such module: fts3}}
+
+finish_test
diff --git a/test/fts4noti.test b/test/fts4noti.test
index 6707203970..87a05714bf 100644
--- a/test/fts4noti.test
+++ b/test/fts4noti.test
@@ -173,7 +173,7 @@ do_execsql_test 6.1.1 {
CREATE VIRTUAL TABLE t1 USING fts4(
poiCategory, poiCategoryId, notindexed=poiCategoryId
);
- INSERT INTO t1(poiCategory, poiCategoryId) values ("Restaurant", 6021);
+ INSERT INTO t1(poiCategory, poiCategoryId) values ('Restaurant', 6021);
}
do_execsql_test 6.1.2 {
@@ -194,7 +194,7 @@ do_execsql_test 6.2.1 {
CREATE VIRTUAL TABLE t1 USING fts4(
poiCategory, poiCategoryId, notindexed=poiCategory
);
- INSERT INTO t1(poiCategory, poiCategoryId) values ("Restaurant", 6021);
+ INSERT INTO t1(poiCategory, poiCategoryId) values ('Restaurant', 6021);
}
do_execsql_test 6.2.2 {
diff --git a/test/func.test b/test/func.test
index ca1027f508..df9d4dacfa 100644
--- a/test/func.test
+++ b/test/func.test
@@ -1007,32 +1007,32 @@ do_test func-21.2 {
} {1 {wrong number of arguments to function replace()}}
do_test func-21.3 {
execsql {
- SELECT typeof(replace("This is the main test string", NULL, "ALT"));
+ SELECT typeof(replace('This is the main test string', NULL, 'ALT'));
}
} {null}
do_test func-21.4 {
execsql {
- SELECT typeof(replace(NULL, "main", "ALT"));
+ SELECT typeof(replace(NULL, 'main', 'ALT'));
}
} {null}
do_test func-21.5 {
execsql {
- SELECT typeof(replace("This is the main test string", "main", NULL));
+ SELECT typeof(replace('This is the main test string', 'main', NULL));
}
} {null}
do_test func-21.6 {
execsql {
- SELECT replace("This is the main test string", "main", "ALT");
+ SELECT replace('This is the main test string', 'main', 'ALT');
}
} {{This is the ALT test string}}
do_test func-21.7 {
execsql {
- SELECT replace("This is the main test string", "main", "larger-main");
+ SELECT replace('This is the main test string', 'main', 'larger-main');
}
} {{This is the larger-main test string}}
do_test func-21.8 {
execsql {
- SELECT replace("aaaaaaa", "a", "0123456789");
+ SELECT replace('aaaaaaa', 'a', '0123456789');
}
} {0123456789012345678901234567890123456789012345678901234567890123456789}
@@ -1315,7 +1315,7 @@ do_test func-29.1 {
CREATE TABLE t29(id INTEGER PRIMARY KEY, x, y);
INSERT INTO t29 VALUES(1, 2, 3), (2, NULL, 4), (3, 4.5, 5);
INSERT INTO t29 VALUES(4, randomblob(1000000), 6);
- INSERT INTO t29 VALUES(5, "hello", 7);
+ INSERT INTO t29 VALUES(5, 'hello', 7);
}
db close
sqlite3 db test.db
@@ -1507,4 +1507,19 @@ do_execsql_test func-35.200 {
PRAGMA integrity_check;
} {ok}
+# 2021-01-07: The -> and ->> operators.
+#
+proc ptr1 {a b} { return "$a->$b" }
+db func -> ptr1
+proc ptr2 {a b} { return "$a->>$b" }
+db func ->> ptr2
+do_execsql_test func-36.100 {
+ SELECT 123 -> 456
+} {123->456}
+do_execsql_test func-36.110 {
+ SELECT 123 ->> 456
+} {123->>456}
+
+
+
finish_test
diff --git a/test/fuzz-oss1.test b/test/fuzz-oss1.test
index e77b7ed0f8..46feeb62eb 100644
--- a/test/fuzz-oss1.test
+++ b/test/fuzz-oss1.test
@@ -329,6 +329,8 @@ ifcapable !fts3 {
db close
forcedelete test.db
sqlite3 db test.db
+sqlite3_db_config db SQLITE_DBCONFIG_DQS_DDL 1
+sqlite3_db_config db SQLITE_DBCONFIG_DQS_DML 1
do_test fuzz-oss1-gnomeshell {
db eval {
CREATE TABLE Resource (ID INTEGER NOT NULL PRIMARY KEY, Uri TEXT NOT
diff --git a/test/fuzzdata8.db b/test/fuzzdata8.db
index 966b73730c..960b157625 100644
Binary files a/test/fuzzdata8.db and b/test/fuzzdata8.db differ
diff --git a/test/in.test b/test/in.test
index efbfbd0379..b0eb371cb7 100644
--- a/test/in.test
+++ b/test/in.test
@@ -281,12 +281,13 @@ do_test in-7.8.2 {
db status step
} {0}
-do_test in-8.1 {
+do_test in-8.3 {
execsql {
SELECT b FROM t1 WHERE a IN ('hello','there')
}
} {world}
-do_test in-8.2 {
+do_test in-8.4 {
+ sqlite3_db_config db SQLITE_DBCONFIG_DQS_DML 1
execsql {
SELECT b FROM t1 WHERE a IN ("hello",'there')
}
diff --git a/test/index.test b/test/index.test
index 15120a40c9..11d3d7191c 100644
--- a/test/index.test
+++ b/test/index.test
@@ -428,7 +428,7 @@ do_test index-13.1 {
} {1 2.0 3}
do_test index-13.2 {
set ::idxlist [execsql {
- SELECT name FROM sqlite_master WHERE type="index" AND tbl_name="t5";
+ SELECT name FROM sqlite_master WHERE type='index' AND tbl_name='t5';
}]
llength $::idxlist
} {3}
diff --git a/test/join.test b/test/join.test
index cb3ccc65d5..221dbdd098 100644
--- a/test/join.test
+++ b/test/join.test
@@ -439,6 +439,7 @@ do_test join-5.1 {
# A test for ticket #247.
#
do_test join-7.1 {
+ sqlite3_db_config db SQLITE_DBCONFIG_DQS_DML 1
execsql {
CREATE TABLE t7 (x, y);
INSERT INTO t7 VALUES ("pa1", 1);
diff --git a/test/join5.test b/test/join5.test
index e2ff2f6c27..0ae4ca1127 100644
--- a/test/join5.test
+++ b/test/join5.test
@@ -303,6 +303,7 @@ do_eqp_test 7.4 {
} {
QUERY PLAN
|--SCAN t3
+ |--BLOOM FILTER ON t4 (x=?)
`--SEARCH t4 USING INDEX t4xz (x=?)
}
diff --git a/test/json102.test b/test/json102.test
index 18a6bbf5cc..9f8f482b85 100644
--- a/test/json102.test
+++ b/test/json102.test
@@ -337,4 +337,60 @@ do_execsql_test json102-1501 {
SELECT sum(json_valid(json_quote('a'||char(x)||'z'))) FROM c ORDER BY x;
} {31}
+# 2022-01-10 tests for -> and ->> operators
+#
+reset_db
+do_execsql_test json102-1600 {
+ CREATE TABLE t1(id INTEGER PRIMARY KEY, x JSON);
+ INSERT INTO t1(id,x) VALUES
+ (1, '{"a":null}'),
+ (2, '{"a":123}'),
+ (3, '{"a":4.5}'),
+ (4, '{"a":"six"}'),
+ (5, '{"a":[7,8]}'),
+ (6, '{"a":{"b":9}}'),
+ (7, '{"b":999}');
+ SELECT
+ id,
+ x->'a' AS '->',
+ CASE WHEN subtype(x->'a') THEN 'json' ELSE typeof(x->'a') END AS 'type',
+ x->>'a' AS '->>',
+ CASE WHEN subtype(x->>'a') THEN 'json' ELSE typeof(x->>'a') END AS 'type',
+ json_extract(x,'$.a') AS 'json_extract',
+ CASE WHEN subtype(json_extract(x,'$.a'))
+ THEN 'json' ELSE typeof(json_extract(x,'$.a')) END AS 'type'
+ FROM t1 ORDER BY id;
+} [list \
+ 1 null json {} null {} null \
+ 2 123 json 123 integer 123 integer \
+ 3 4.5 json 4.5 real 4.5 real \
+ 4 {"six"} json six text six text \
+ 5 {[7,8]} json {[7,8]} text {[7,8]} json \
+ 6 {{"b":9}} json {{"b":9}} text {{"b":9}} json \
+ 7 {} null {} null {} null
+]
+do_execsql_test json102-1610 {
+ DELETE FROM t1;
+ INSERT INTO t1(x) VALUES('[null,123,4.5,"six",[7,8],{"b":9}]');
+ WITH c(y) AS (VALUES(0),(1),(2),(3),(4),(5),(6))
+ SELECT
+ y,
+ x->y AS '->',
+ CASE WHEN subtype(x->y) THEN 'json' ELSE typeof(x->y) END AS 'type',
+ x->>y AS '->>',
+ CASE WHEN subtype(x->>y) THEN 'json' ELSE typeof(x->>y) END AS 'type',
+ json_extract(x,format('$[%d]',y)) AS 'json_extract',
+ CASE WHEN subtype(json_extract(x,format('$[%d]',y)))
+ THEN 'json' ELSE typeof(json_extract(x,format('$[%d]',y))) END AS 'type'
+ FROM c, t1 ORDER BY y;
+} [list \
+ 0 null json {} null {} null \
+ 1 123 json 123 integer 123 integer \
+ 2 4.5 json 4.5 real 4.5 real \
+ 3 {"six"} json six text six text \
+ 4 {[7,8]} json {[7,8]} text {[7,8]} json \
+ 5 {{"b":9}} json {{"b":9}} text {{"b":9}} json \
+ 6 {} null {} null {} null
+]
+
finish_test
diff --git a/test/memjournal2.test b/test/memjournal2.test
new file mode 100644
index 0000000000..97d35a98d1
--- /dev/null
+++ b/test/memjournal2.test
@@ -0,0 +1,62 @@
+# 2022 Jan 01
+#
+# 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.
+#
+#***********************************************************************
+# Tests focused on the in-memory journal.
+#
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+source $testdir/malloc_common.tcl
+set testprefix memjournal2
+
+do_execsql_test 1.0 {
+ PRAGMA journal_mode = memory;
+ CREATE TABLE t1(a INTEGER PRIMARY KEY, b UNIQUE);
+} {memory}
+
+set nRow [expr 2000]
+
+do_execsql_test 1.1 {
+ BEGIN;
+ WITH s(i) AS (
+ SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<$nRow
+ )
+ INSERT INTO t1 SELECT NULL, randomblob(700) FROM s;
+}
+
+for {set jj 200} {$jj <= 300} {incr jj} {
+ do_execsql_test 1.2.$jj.1 {
+ SAVEPOINT one;
+ UPDATE t1 SET b=randomblob(700) WHERE a<=$jj;
+ }
+ do_execsql_test 1.2.$jj.2 {
+ SAVEPOINT two;
+ UPDATE t1 SET b=randomblob(700) WHERE a==1;
+ ROLLBACK TO two;
+ RELEASE two;
+ }
+ do_execsql_test 1.2.$jj.3 {
+ SAVEPOINT two;
+ UPDATE t1 SET b=randomblob(700) WHERE a==1;
+ ROLLBACK TO two;
+ RELEASE two;
+ }
+
+ do_execsql_test 1.2.$jj.4 {
+ PRAGMA integrity_check;
+ ROLLBACK TO one;
+ RELEASE one;
+ } {ok}
+}
+
+
+finish_test
+
+
diff --git a/test/merge1.test b/test/merge1.test
new file mode 100644
index 0000000000..e4a7d657b3
--- /dev/null
+++ b/test/merge1.test
@@ -0,0 +1,138 @@
+# 2021-12-29
+#
+# 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.
+#
+#***********************************************************************
+#
+# Testing the compound-SELECT merge algorithm to ensure that it works
+# when it tries to balance the merge tree.
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+set testprefix merge1
+
+load_static_extension db series
+
+
+optimization_control db all on
+do_execsql_test 100 {
+ WITH data(v) AS (
+ SELECT value FROM generate_series(1,35,3)
+ UNION ALL
+ SELECT value FROM generate_series(10,30,4)
+ UNION ALL
+ SELECT value FROM generate_series(20,50,5)
+ UNION ALL
+ SELECT value FROM generate_series(30,60,6)
+ UNION ALL
+ SELECT value FROM generate_series(1,50,7)
+ UNION ALL
+ SELECT value FROM generate_series(10,80,8)
+ )
+ SELECT v FROM data ORDER BY v;
+} {1 1 4 7 8 10 10 10 13 14 15 16 18 18 19 20 22 22 22 25 25 26 26 28 29 30 30 30 31 34 34 35 36 36 40 42 42 43 45 48 50 50 50 54 58 60 66 74}
+do_eqp_test 101 {
+ WITH data(v) AS (
+ SELECT value FROM generate_series(1,35,3)
+ UNION ALL
+ SELECT value FROM generate_series(10,30,4)
+ UNION ALL
+ SELECT value FROM generate_series(20,50,5)
+ UNION ALL
+ SELECT value FROM generate_series(30,60,6)
+ UNION ALL
+ SELECT value FROM generate_series(1,50,7)
+ UNION ALL
+ SELECT value FROM generate_series(10,80,8)
+ )
+ SELECT v FROM data ORDER BY v;
+} {
+ QUERY PLAN
+ `--MERGE (UNION ALL)
+ |--LEFT
+ | `--MERGE (UNION ALL)
+ | |--LEFT
+ | | `--MERGE (UNION ALL)
+ | | |--LEFT
+ | | | `--SCAN generate_series VIRTUAL TABLE INDEX 23:
+ | | `--RIGHT
+ | | `--SCAN generate_series VIRTUAL TABLE INDEX 23:
+ | `--RIGHT
+ | `--SCAN generate_series VIRTUAL TABLE INDEX 23:
+ `--RIGHT
+ `--MERGE (UNION ALL)
+ |--LEFT
+ | `--MERGE (UNION ALL)
+ | |--LEFT
+ | | `--SCAN generate_series VIRTUAL TABLE INDEX 23:
+ | `--RIGHT
+ | `--SCAN generate_series VIRTUAL TABLE INDEX 23:
+ `--RIGHT
+ `--SCAN generate_series VIRTUAL TABLE INDEX 23:
+}
+
+# Same test with the blanced-merge optimization
+# disabled. Should give the exact same answer.
+#
+optimization_control db balanced-merge off
+db cache flush
+do_execsql_test 110 {
+ WITH data(v) AS (
+ SELECT value FROM generate_series(1,35,3)
+ UNION ALL
+ SELECT value FROM generate_series(10,30,4)
+ UNION ALL
+ SELECT value FROM generate_series(20,50,5)
+ UNION ALL
+ SELECT value FROM generate_series(30,60,6)
+ UNION ALL
+ SELECT value FROM generate_series(1,50,7)
+ UNION ALL
+ SELECT value FROM generate_series(10,80,8)
+ )
+ SELECT v FROM data ORDER BY v;
+} {1 1 4 7 8 10 10 10 13 14 15 16 18 18 19 20 22 22 22 25 25 26 26 28 29 30 30 30 31 34 34 35 36 36 40 42 42 43 45 48 50 50 50 54 58 60 66 74}
+do_eqp_test 111 {
+ WITH data(v) AS (
+ SELECT value FROM generate_series(1,35,3)
+ UNION ALL
+ SELECT value FROM generate_series(10,30,4)
+ UNION ALL
+ SELECT value FROM generate_series(20,50,5)
+ UNION ALL
+ SELECT value FROM generate_series(30,60,6)
+ UNION ALL
+ SELECT value FROM generate_series(1,50,7)
+ UNION ALL
+ SELECT value FROM generate_series(10,80,8)
+ )
+ SELECT v FROM data ORDER BY v;
+} {
+ QUERY PLAN
+ `--MERGE (UNION ALL)
+ |--LEFT
+ | `--MERGE (UNION ALL)
+ | |--LEFT
+ | | `--MERGE (UNION ALL)
+ | | |--LEFT
+ | | | `--MERGE (UNION ALL)
+ | | | |--LEFT
+ | | | | `--MERGE (UNION ALL)
+ | | | | |--LEFT
+ | | | | | `--SCAN generate_series VIRTUAL TABLE INDEX 23:
+ | | | | `--RIGHT
+ | | | | `--SCAN generate_series VIRTUAL TABLE INDEX 23:
+ | | | `--RIGHT
+ | | | `--SCAN generate_series VIRTUAL TABLE INDEX 23:
+ | | `--RIGHT
+ | | `--SCAN generate_series VIRTUAL TABLE INDEX 23:
+ | `--RIGHT
+ | `--SCAN generate_series VIRTUAL TABLE INDEX 23:
+ `--RIGHT
+ `--SCAN generate_series VIRTUAL TABLE INDEX 23:
+}
diff --git a/test/misc1.test b/test/misc1.test
index 758d4082e0..b1b1b083c3 100644
--- a/test/misc1.test
+++ b/test/misc1.test
@@ -652,7 +652,7 @@ do_catchsql_test misc1-21.2 {
# 2015-04-15
do_execsql_test misc1-22.1 {
- SELECT ""+3 FROM (SELECT ""+5);
+ SELECT ''+3 FROM (SELECT ''+5);
} {3}
# 2015-04-19: NULL pointer dereference on a corrupt schema
diff --git a/test/quote.test b/test/quote.test
index 9810a3ca03..6d7b317ea1 100644
--- a/test/quote.test
+++ b/test/quote.test
@@ -173,6 +173,7 @@ ifcapable altertable {
INSERT INTO t1 VALUES(1,2,3),(1,4,5);
ALTER TABLE t1 DROP COLUMN b;
} {1 {error in index x1 after drop column: no such column: b}}
+ sqlite3_db_config db SQLITE_DBCONFIG_DQS_DDL 1
do_catchsql_test 3.5 {
DROP TABLE t1;
CREATE TABLE t1(a, b, c);
diff --git a/test/returning1.test b/test/returning1.test
index c64e72f723..2b97b42348 100644
--- a/test/returning1.test
+++ b/test/returning1.test
@@ -333,4 +333,33 @@ do_execsql_test 13.1 {
} {{}}
} ;# end ifcapable rtree
+# 2021-12-01 Forum post https://sqlite.org/forum/forumpost/793beaf322
+# Need to report foreign key constraint errors prior to RETURNING
+#
+reset_db
+do_execsql_test 14.0 {
+ PRAGMA foreign_keys(1);
+ CREATE TABLE Parent(id INTEGER PRIMARY KEY);
+ CREATE TABLE Child(id INTEGER PRIMARY KEY, parent_id INTEGER REFERENCES Parent(id));
+} {}
+do_catchsql_test 14.1 {
+ INSERT INTO child(parent_id) VALUES(123) RETURNING id;
+} {1 {FOREIGN KEY constraint failed}}
+
+# 2021-12-28 Forum post https://sqlite.org/forum/forumpost/e0c7574ab2
+# Incorrect affinity for REAL values that can be represented as integers.
+#
+reset_db
+sqlite3_test_control SQLITE_TESTCTRL_INTERNAL_FUNCTIONS db
+do_execsql_test 15.0 {
+ CREATE TABLE t1(x REAL);
+ INSERT INTO t1(x) VALUES(5.0) RETURNING x, affinity(x);
+} {5.0 real}
+do_execsql_test 15.1 {
+ UPDATE t1 SET x=x+1 RETURNING x, affinity(x);
+} {6.0 real}
+do_execsql_test 15.2 {
+ DELETE FROM t1 RETURNING x, affinity(x);
+} {6.0 real}
+
finish_test
diff --git a/test/returningfault.test b/test/returningfault.test
new file mode 100644
index 0000000000..8bf6fbfe06
--- /dev/null
+++ b/test/returningfault.test
@@ -0,0 +1,36 @@
+# 2022 January 5
+#
+# The author disclaims copyright to this source code. In place of
+# a legal notice, here is a blessing:
+#
+# May you do good and not evil.
+# May you find forgiveness for yourself and forgive others.
+# May you share freely, never taking more than you give.
+#
+#***********************************************************************
+#
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+source $testdir/malloc_common.tcl
+
+
+do_execsql_test 1.0 {
+ CREATE TABLE t1 (b);
+} {}
+faultsim_save_and_close
+
+do_faultsim_test pagerfault-1 -faults oom-t* -prep {
+ faultsim_restore_and_reopen
+} -body {
+ execsql {
+ INSERT INTO t1(b) VALUES(65) RETURNING (
+ SELECT * FROM sqlite_temp_schema
+ ) AS aaa;
+ }
+} -test {
+ faultsim_test_result {1 {sub-select returns 5 columns - expected 1}}
+}
+
+
+finish_test
diff --git a/test/select6.test b/test/select6.test
index ef5c5b2f07..612afefa6f 100644
--- a/test/select6.test
+++ b/test/select6.test
@@ -169,7 +169,6 @@ do_test select6-3.2 {
FROM (SELECT count(*) as p , b as q FROM t2 GROUP BY q) AS a,
(SELECT max(a) as r, b as s FROM t2 GROUP BY s) as b
WHERE a.q=b.s ORDER BY a.q)
- ORDER BY "a.q"
}
} {1 1 1 2 2 3 3 4 7 4 8 15 5 5 20}
do_test select6-3.3 {
diff --git a/test/shell1.test b/test/shell1.test
index c4e2ceb88b..75118b9419 100644
--- a/test/shell1.test
+++ b/test/shell1.test
@@ -53,7 +53,7 @@ do_test shell1-1.1.2 {
# error on extra options
do_test shell1-1.1.3 {
catchcmd "test.db FOO test.db BAD" ".quit"
-} {1 {Error: in prepare, near "FOO": syntax error (1)}}
+} {/1 .Error: in prepare, near "FOO": syntax error (1)*/}
# -help
do_test shell1-1.2.1 {
@@ -78,7 +78,7 @@ do_test shell1-1.3.2 {
} {0 {}}
do_test shell1-1.3.3 {
catchcmd "-init FOO test.db BAD .quit" ""
-} {1 {Error: in prepare, near "BAD": syntax error (1)}}
+} {/1 .Error: in prepare, near "BAD": syntax error (1)*/}
# -echo print commands before execution
do_test shell1-1.4.1 {
@@ -1024,6 +1024,12 @@ do_test shell1-4.6 {
";"
"$"} 7}
+# Test the output of ".mode quote"
+#
+do_test shell1-4.7 {
+ catchcmd test.db ".mode quote\nselect x'0123456789ABCDEF';"
+} {0 X'0123456789abcdef'}
+
# Test using arbitrary byte data with the shell via standard input/output.
#
do_test shell1-5.0 {
diff --git a/test/shell5.test b/test/shell5.test
index dc99a7acea..1e0038d9d5 100644
--- a/test/shell5.test
+++ b/test/shell5.test
@@ -88,8 +88,9 @@ do_test shell5-1.4.2 {
forcedelete shell5.csv
set in [open shell5.csv w]
close $in
- set res [catchcmd "test.db" {.import shell5.csv t1
-SELECT COUNT(*) FROM t1;}]
+ set res [catchcmd ":memory:" {ATTACH 'test.db' AS test;
+.import -schema test shell5.csv t1
+SELECT COUNT(*) FROM test.t1;}]
} {0 0}
# import file with 1 row, 1 column (expecting 2 cols)
@@ -97,7 +98,8 @@ do_test shell5-1.4.3 {
set in [open shell5.csv w]
puts $in "1"
close $in
- set res [catchcmd "test.db" {.import shell5.csv t1}]
+ set res [catchcmd ":memory:" {ATTACH 'test.db' AS test;
+.import -schema test shell5.csv t1}]
} {1 {shell5.csv:1: expected 2 columns but found 1 - filling the rest with NULL}}
# import file with 1 row, 3 columns (expecting 2 cols)
@@ -105,7 +107,8 @@ do_test shell5-1.4.4 {
set in [open shell5.csv w]
puts $in "1|2|3"
close $in
- set res [catchcmd "test.db" {.import shell5.csv t1}]
+ set res [catchcmd ":memory:" {ATTACH 'test.db' AS test;
+.import --schema test shell5.csv t1}]
} {1 {shell5.csv:1: expected 2 columns but found 3 - extras ignored}}
# import file with 1 row, 2 columns
@@ -126,8 +129,9 @@ do_test shell5-1.4.6 {
puts $in "2|3"
puts $in "3|4"
close $in
- set res [catchcmd "test.db" {.import shell5.csv t1
-SELECT COUNT(*) FROM t1;}]
+ set res [catchcmd ":memory:" {ATTACH 'test.db' AS test;
+.import -schema test shell5.csv t1
+SELECT COUNT(*) FROM test.t1;}]
} {0 3}
# import file with 1 row, 2 columns, using a comma
@@ -135,9 +139,10 @@ do_test shell5-1.4.7 {
set in [open shell5.csv w]
puts $in "4,5"
close $in
- set res [catchcmd "test.db" {.separator ,
-.import shell5.csv t1
-SELECT COUNT(*) FROM t1;}]
+ set res [catchcmd ":memory:" {ATTACH 'test.db' AS test;
+.separator ,
+.import --schema test shell5.csv t1
+SELECT COUNT(*) FROM test.t1;}]
} {0 4}
# import file with 1 row, 2 columns, text data
diff --git a/test/subquery.test b/test/subquery.test
index 06facbbae0..a048f9ed4e 100644
--- a/test/subquery.test
+++ b/test/subquery.test
@@ -477,7 +477,7 @@ do_test subquery-5.1 {
INSERT INTO t5 VALUES(3,33);
INSERT INTO t5 VALUES(4,44);
SELECT b FROM t5 WHERE a IN
- (SELECT callcnt(y)+0 FROM t4 WHERE x="two")
+ (SELECT callcnt(y)+0 FROM t4 WHERE x='two')
}
} {22}
do_test subquery-5.2 {
@@ -594,4 +594,23 @@ do_execsql_test subquery-8.1 {
SELECT (SELECT 0 FROM (SELECT * FROM (SELECT 0))) AS x WHERE x;
} {}
+# 2022-01-12 https://sqlite.org/forum/forumpost/0ec80f12d02acb3f
+#
+reset_db
+do_execsql_test subquery-9.1 {
+ CREATE TABLE t1(x);
+ INSERT INTO t1 VALUES(1),(1),(1);
+ SELECT (SELECT DISTINCT x FROM t1 ORDER BY +x LIMIT 1 OFFSET 100) FROM t1;
+} {{} {} {}}
+do_execsql_test subquery-9.2 {
+ SELECT (SELECT DISTINCT x FROM t1 ORDER BY +x LIMIT 1 OFFSET 0) FROM t1;
+} {1 1 1}
+do_execsql_test subquery-9.3 {
+ INSERT INTO t1 VALUES(2);
+ SELECT (SELECT DISTINCT x FROM t1 ORDER BY +x LIMIT 1 OFFSET 1) FROM t1;
+} {2 2 2 2}
+do_execsql_test subquery-9.4 {
+ SELECT (SELECT DISTINCT x FROM t1 ORDER BY +x LIMIT 1 OFFSET 2) FROM t1;
+} {{} {} {} {}}
+
finish_test
diff --git a/test/swarmvtab.test b/test/swarmvtab.test
index 9d2919bee1..b4b94487ac 100644
--- a/test/swarmvtab.test
+++ b/test/swarmvtab.test
@@ -209,8 +209,8 @@ db func fetch_db fetch_db
do_catchsql_test 3.1 {
CREATE VIRTUAL TABLE temp.xyz USING swarmvtab(
'VALUES
- ("test.db1", "t1", 1, 10),
- ("test.db2", "t1", 11, 20)
+ (''test.db1'', ''t1'', 1, 10),
+ (''test.db2'', ''t1'', 11, 20)
', 'fetch_db_no_such_function'
);
} {1 {sql error: no such function: fetch_db_no_such_function}}
@@ -218,8 +218,8 @@ do_catchsql_test 3.1 {
do_catchsql_test 3.2 {
CREATE VIRTUAL TABLE temp.xyz USING swarmvtab(
'VALUES
- ("test.db1", "t1", 1, 10),
- ("test.db2", "t1", 11, 20)
+ (''test.db1'', ''t1'', 1, 10),
+ (''test.db2'', ''t1'', 11, 20)
', 'fetch_db'
);
} {1 {fetch_db error!}}
@@ -233,8 +233,8 @@ do_execsql_test 3.3.1 {
DETACH aux;
CREATE VIRTUAL TABLE temp.xyz USING swarmvtab(
'VALUES
- ("test.db1", "t1", 1, 10),
- ("test.db2", "t1", 11, 20)
+ (''test.db1'', ''t1'', 1, 10),
+ (''test.db2'', ''t1'', 11, 20)
', 'fetch_db'
);
} {}
diff --git a/test/tabfunc01.test b/test/tabfunc01.test
index d3d93792da..0a7e3bc245 100644
--- a/test/tabfunc01.test
+++ b/test/tabfunc01.test
@@ -117,6 +117,51 @@ do_execsql_test tabfunc01-3.1 {
SELECT DISTINCT value FROM generate_series(1,x), t1 ORDER BY 1;
} {1 2 3}
+do_eqp_test tabfunc01-3.10 {
+ SELECT value FROM generate_series(1,10) ORDER BY value;
+} {
+ QUERY PLAN
+ `--SCAN generate_series VIRTUAL TABLE INDEX 19:
+}
+do_eqp_test tabfunc01-3.11 {
+ SELECT value FROM generate_series(1,10) ORDER BY +value;
+} {
+ QUERY PLAN
+ |--SCAN generate_series VIRTUAL TABLE INDEX 3:
+ `--USE TEMP B-TREE FOR ORDER BY
+}
+do_eqp_test tabfunc01-3.12 {
+ SELECT value FROM generate_series(1,10) ORDER BY value, stop;
+} {
+ QUERY PLAN
+ `--SCAN generate_series VIRTUAL TABLE INDEX 19:
+}
+do_eqp_test tabfunc01-3.13 {
+ SELECT value FROM generate_series(1,10) ORDER BY stop, value;
+} {
+ QUERY PLAN
+ |--SCAN generate_series VIRTUAL TABLE INDEX 3:
+ `--USE TEMP B-TREE FOR ORDER BY
+}
+
+
+do_eqp_test tabfunc01-3.20 {
+ WITH t1(a) AS (
+ SELECT value FROM generate_series(0,10,2)
+ UNION ALL
+ SELECT value FROM generate_series(9,18,3)
+ )
+ SELECT * FROM t1 ORDER BY a;
+} {
+ QUERY PLAN
+ `--MERGE (UNION ALL)
+ |--LEFT
+ | `--SCAN generate_series VIRTUAL TABLE INDEX 23:
+ `--RIGHT
+ `--SCAN generate_series VIRTUAL TABLE INDEX 23:
+}
+
+
# Eponymous virtual table exists in all schemas.
#
do_execsql_test tabfunc01-4.1 {
diff --git a/test/tkt-7bbfb7d442.test b/test/tkt-7bbfb7d442.test
index 56d4caeb3e..c020b515e2 100644
--- a/test/tkt-7bbfb7d442.test
+++ b/test/tkt-7bbfb7d442.test
@@ -146,7 +146,7 @@ do_execsql_test 2.2 {
} {31 10}
do_execsql_test 2.3 {
- SELECT CASE WHEN DeliveredQty=10 THEN "TEST PASSED!" ELSE "TEST FAILED!" END
+ SELECT CASE WHEN DeliveredQty=10 THEN 'TEST PASSED!' ELSE 'TEST FAILED!' END
FROM InventoryControl WHERE SKU=31;
} {{TEST PASSED!}}
diff --git a/test/tkt3442.test b/test/tkt3442.test
index 13d29a1b05..aaf2662398 100644
--- a/test/tkt3442.test
+++ b/test/tkt3442.test
@@ -38,6 +38,7 @@ do_test tkt3442-1.1 {
# SELECT referenced in ticket #3442 (both '5000' and "5000")
# and verify that the query plan is the same.
#
+sqlite3_db_config db SQLITE_DBCONFIG_DQS_DML 1
do_eqp_test tkt3442-1.2 {
SELECT node FROM listhash WHERE id='5000' LIMIT 1;
} {SEARCH listhash USING INDEX ididx (id=?)}
diff --git a/test/tkt3841.test b/test/tkt3841.test
index df6de5c2f3..542c1bb5e7 100644
--- a/test/tkt3841.test
+++ b/test/tkt3841.test
@@ -22,6 +22,7 @@ ifcapable !subquery {
return
}
+sqlite3_db_config db SQLITE_DBCONFIG_DQS_DML 1
do_test tkt3841.1 {
execsql {
CREATE TABLE table2 (key TEXT, x TEXT);
diff --git a/test/update.test b/test/update.test
index 7be360726f..66efd10ec8 100644
--- a/test/update.test
+++ b/test/update.test
@@ -627,7 +627,7 @@ ifcapable altertable {
CREATE INDEX t15c ON t15(c);
INSERT INTO t15(a,b)
VALUES(5,'zyx'),(15,'wvu'),(25,'tsr'),(35,'qpo');
- UPDATE t15 SET c=printf("y%d",a) WHERE c IS NULL;
+ UPDATE t15 SET c=printf('y%d',a) WHERE c IS NULL;
SELECT a,b,c,'|' FROM t15 ORDER BY a;
} {5 zyx y5 | 10 abc y10 | 15 wvu y15 | 20 def y20 | 25 tsr y25 | 30 ghi y30 | 35 qpo y35 |}
}
diff --git a/test/upsert1.test b/test/upsert1.test
index 5250a5d2f5..a321d6171d 100644
--- a/test/upsert1.test
+++ b/test/upsert1.test
@@ -241,4 +241,18 @@ do_catchsql_test upsert1-1000 {
ON CONFLICT(c2) DO UPDATE SET c1 = c0;
} {1 {NOT NULL constraint failed: t0.c0}}
+# 2021-12-29 forum post https://sqlite.org/forum/forumpost/06b16b8b29f8c8c3
+# By Jingzhou Fu. When there is both an INTEGER PRIMARY KEY ON CONFLICT REPLACE
+# and an upsert on a constraint other than the INTEGER PRIMARY KEY, the
+# constraint checking logic generates invalid bytecode which might result
+# in a NULL pointer dereference.
+#
+reset_db
+do_execsql_test upsert1-1100 {
+ CREATE TABLE t1(a INTEGER PRIMARY KEY ON CONFLICT REPLACE, b UNIQUE);
+ INSERT INTO t1(b) VALUES(22);
+ INSERT INTO t1 VALUES(2,22) ON CONFLICT (b) DO NOTHING;
+ SELECT * FROM t1;
+} {1 22}
+
finish_test
diff --git a/test/upsert2.test b/test/upsert2.test
index 1aa499e606..5cbc4656a4 100644
--- a/test/upsert2.test
+++ b/test/upsert2.test
@@ -72,7 +72,7 @@ do_execsql_test upsert2-300 {
CREATE TABLE record(x TEXT, y TEXT);
CREATE TRIGGER r1 BEFORE INSERT ON t1 BEGIN
INSERT INTO record(x,y)
- VALUES('before-insert',printf('%d,%d,%d',new.a,new.b,new.c));
+ VALUES('before-insert',format('%d,%d,%d',new.a,new.b,new.c));
END;
CREATE TRIGGER r2 AFTER INSERT ON t1 BEGIN
INSERT INTO record(x,y)
@@ -80,7 +80,7 @@ do_execsql_test upsert2-300 {
END;
CREATE TRIGGER r3 BEFORE UPDATE ON t1 BEGIN
INSERT INTO record(x,y)
- VALUES('before-update',printf('%d,%d,%d/%d,%d,%d',
+ VALUES('before-update',format('%d,%d,%d/%d,%d,%d',
old.a,old.b,old.c,new.a,new.b,new.c));
END;
CREATE TRIGGER r4 AFTER UPDATE ON t1 BEGIN
@@ -123,7 +123,7 @@ do_execsql_test upsert2-400 {
CREATE TABLE t1(a INT PRIMARY KEY, b int, c DEFAULT 0) WITHOUT ROWID;
CREATE TRIGGER r1 BEFORE INSERT ON t1 BEGIN
INSERT INTO record(x,y)
- VALUES('before-insert',printf('%d,%d,%d',new.a,new.b,new.c));
+ VALUES('before-insert',format('%d,%d,%d',new.a,new.b,new.c));
END;
CREATE TRIGGER r2 AFTER INSERT ON t1 BEGIN
INSERT INTO record(x,y)
@@ -131,7 +131,7 @@ do_execsql_test upsert2-400 {
END;
CREATE TRIGGER r3 BEFORE UPDATE ON t1 BEGIN
INSERT INTO record(x,y)
- VALUES('before-update',printf('%d,%d,%d/%d,%d,%d',
+ VALUES('before-update',format('%d,%d,%d/%d,%d,%d',
old.a,old.b,old.c,new.a,new.b,new.c));
END;
CREATE TRIGGER r4 AFTER UPDATE ON t1 BEGIN
diff --git a/test/utf16align.test b/test/utf16align.test
index f026d9575d..ef10bc659d 100644
--- a/test/utf16align.test
+++ b/test/utf16align.test
@@ -32,6 +32,7 @@ ifcapable !utf16 {
do_test utf16align-1.0 {
set unaligned_string_counter 0
add_alignment_test_collations [sqlite3_connection_pointer db]
+ sqlite3_db_config db SQLITE_DBCONFIG_DQS_DML 1
execsql {
PRAGMA encoding=UTF16;
CREATE TABLE t1(
diff --git a/test/vtab6.test b/test/vtab6.test
index f4504b017d..ffbe430c6e 100644
--- a/test/vtab6.test
+++ b/test/vtab6.test
@@ -351,6 +351,7 @@ do_test vtab6-4.10 {
# A test for ticket #247.
#
do_test vtab6-7.1 {
+ sqlite3_db_config db SQLITE_DBCONFIG_DQS_DML 1
execsql {
INSERT INTO t7 VALUES ("pa1", 1);
INSERT INTO t7 VALUES ("pa2", NULL);
diff --git a/test/window6.test b/test/window6.test
index c6889c72ac..b5e677208f 100644
--- a/test/window6.test
+++ b/test/window6.test
@@ -148,6 +148,7 @@ do_execsql_test 5.5 {
#
ifcapable !icu {
+ sqlite3_db_config db SQLITE_DBCONFIG_DQS_DML 1
do_execsql_test 6.0 {
SELECT LIKE('!', '', '!') x WHERE x;
} {}
diff --git a/test/windowC.test b/test/windowC.test
index 499c2f50fd..013876f9b3 100644
--- a/test/windowC.test
+++ b/test/windowC.test
@@ -13,7 +13,7 @@
set testdir [file dirname $argv0]
source $testdir/tester.tcl
-set testprefix windowB
+set testprefix windowC
ifcapable !windowfunc {
finish_test
@@ -67,11 +67,19 @@ foreach {tn bBlob seps} {
#
reset_db
do_execsql_test 2.0 {
- PRAGMA encoding=UTF16;
+ PRAGMA encoding=UTF16le;
WITH separator(x) AS (VALUES(',a,'),(',bc,')),
value(y) AS (VALUES(1),(x'5585d09013455178cd11ce4a'))
SELECT group_concat(y,x) OVER (ORDER BY x ROWS BETWEEN 1 PRECEDING AND 1 PRECEDING)
FROM separator, value;
} {{} 1 蕕郐䔓硑ᇍ䫎 1}
+reset_db
+do_execsql_test 2.1 {
+ PRAGMA encoding=UTF16be;
+ WITH separator(x) AS (VALUES(',a,'),(',bc,')),
+ value(y) AS (VALUES(1),(x'5585d09013455178cd11ce4a'))
+ SELECT group_concat(y,x) OVER (ORDER BY x ROWS BETWEEN 1 PRECEDING AND 1 PRECEDING)
+ FROM separator, value;
+} {{} 1 喅킐ፅ典촑칊 1}
finish_test
diff --git a/test/without_rowid1.test b/test/without_rowid1.test
index c712392688..1191115527 100644
--- a/test/without_rowid1.test
+++ b/test/without_rowid1.test
@@ -470,5 +470,20 @@ ifcapable altertable {
EXPLAIN QUERY PLAN SELECT * FROM dual, t1 WHERE a=10 AND b=10;
} {~/b=/}
}
-
+
+# 2022-01-01 https://sqlite.org/forum/forumpost/b03d86f951 PoC #1
+# Omit an assert() from 2013 that no longer serves any purpose and
+# is no longer always true.
+#
+reset_db
+do_execsql_test 15.1 {
+ PRAGMA writable_schema=ON;
+ CREATE TABLE sqlite_sequence (name PRIMARY KEY) WITHOUT ROWID;
+ PRAGMA writable_schema=OFF;
+ CREATE TABLE c1(x);
+ INSERT INTO sqlite_sequence(name) VALUES('c0'),('c1'),('c2');
+ ALTER TABLE c1 RENAME TO a;
+ SELECT name FROM sqlite_sequence ORDER BY +name;
+} {a c0 c2}
+
finish_test
diff --git a/tool/lemon.c b/tool/lemon.c
index d4e157a1cd..11e25c8a1c 100644
--- a/tool/lemon.c
+++ b/tool/lemon.c
@@ -4290,7 +4290,6 @@ void ReportTable(
int sqlFlag /* Generate the *.sql file too */
){
FILE *out, *in, *sql;
- char line[LINESIZE];
int lineno;
struct state *stp;
struct action *ap;
@@ -4765,7 +4764,6 @@ void ReportTable(
/* Generate a table containing the symbolic name of every symbol
*/
for(i=0; insymbol; i++){
- lemon_sprintf(line,"\"%s\",",lemp->symbols[i]->name);
fprintf(out," /* %4d */ \"%s\",\n",i, lemp->symbols[i]->name); lineno++;
}
tplt_xfer(lemp->name,in,out,&lineno);
diff --git a/tool/logest.c b/tool/logest.c
index e936e02cbe..d916b43d39 100644
--- a/tool/logest.c
+++ b/tool/logest.c
@@ -75,6 +75,7 @@ static sqlite3_uint64 logEstToInt(LogEst x){
x /= 10;
if( n>=5 ) n -= 2;
else if( n>=1 ) n -= 1;
+ if( x>60 ) return (((sqlite3_uint64)0xffffffff)<<32)+(sqlite3_uint64)0xffffffff;
if( x>=3 ) return (n+8)<<(x-3);
return (n+8)>>(3-x);
}
@@ -149,7 +150,7 @@ int main(int argc, char **argv){
}else if( z[0]=='^' ){
a[n++] = (LogEst)atoi(z+1);
}else if( isInteger(z) ){
- a[n++] = logEstFromInteger(atoi(z));
+ a[n++] = logEstFromInteger(atoll(z));
}else if( isFloat(z) && z[0]!='-' ){
a[n++] = logEstFromDouble(atof(z));
}else{
@@ -161,6 +162,8 @@ int main(int argc, char **argv){
printf("%5d (%f)\n", a[i], 1.0/(double)logEstToInt(-a[i]));
}else if( a[i]<10 ){
printf("%5d (%f)\n", a[i], logEstToInt(a[i]+100)/1024.0);
+ }else if( a[i]>100 ){
+ printf("%5d (%lld)\n", a[i], logEstToInt(a[i]));
}else{
sqlite3_uint64 x = logEstToInt(a[i]+100)*100/1024;
printf("%5d (%lld.%02lld)\n", a[i], x/100, x%100);
diff --git a/tool/mkctimec.tcl b/tool/mkctimec.tcl
old mode 100644
new mode 100755
index 6294609451..745a59a229
--- a/tool/mkctimec.tcl
+++ b/tool/mkctimec.tcl
@@ -5,9 +5,82 @@
# const char **azCompileOpt[]
#
# definition used in src/ctime.c, run this script from
-# the checkout root. It alters src/ctime.c in-place.
+# the checkout root. It generates src/ctime.c .
#
+
+set ::headWarning {/* DO NOT EDIT!
+** This file is automatically generated by the script in the canonical
+** SQLite source tree at tool/mkctimec.tcl.
+**
+** To modify this header, edit any of the various lists in that script
+** which specify categories of generated conditionals in this file.
+*/}
+
+# Make { and } easier to put into literals (even on EBCDIC machines.)
+regexp {(\{)(\})} "{}" ma ::lb ::rb
+
+set ::headCode "
+/*
+** 2010 February 23
+**
+** The author disclaims copyright to this source code. In place of
+** a legal notice, here is a blessing:
+**
+** May you do good and not evil.
+** May you find forgiveness for yourself and forgive others.
+** May you share freely, never taking more than you give.
+**
+*************************************************************************
+**
+** This file implements routines used to report what compile-time options
+** SQLite was built with.
+*/
+#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS /* IMP: R-16824-07538 */
+
+/*
+** Include the configuration header output by 'configure' if we're using the
+** autoconf-based build
+*/
+#if defined(_HAVE_SQLITE_CONFIG_H) && !defined(SQLITECONFIG_H)
+#include \"config.h\"
+#define SQLITECONFIG_H 1
+#endif
+
+/* These macros are provided to \"stringify\" the value of the define
+** for those options in which the value is meaningful. */
+#define CTIMEOPT_VAL_(opt) #opt
+#define CTIMEOPT_VAL(opt) CTIMEOPT_VAL_(opt)
+
+/* Like CTIMEOPT_VAL, but especially for SQLITE_DEFAULT_LOOKASIDE. This
+** option requires a separate macro because legal values contain a single
+** comma. e.g. (-DSQLITE_DEFAULT_LOOKASIDE=\"100,100\") */
+#define CTIMEOPT_VAL2_(opt1,opt2) #opt1 \",\" #opt2
+#define CTIMEOPT_VAL2(opt) CTIMEOPT_VAL2_(opt)
+#include \"sqliteInt.h\"
+
+/*
+** An array of names of all compile-time options. This array should
+** be sorted A-Z.
+**
+** This array looks large, but in a typical installation actually uses
+** only a handful of compile-time options, so most times this array is usually
+** rather short and uses little memory space.
+*/
+static const char * const sqlite3azCompileOpt\[\] = $::lb
+"
+
+set ::tailCode "
+$::rb ;
+
+const char **sqlite3CompileOptions(int *pnOpt){
+ *pnOpt = sizeof(sqlite3azCompileOpt) / sizeof(sqlite3azCompileOpt\[0\]);
+ return (const char**)sqlite3azCompileOpt;
+}
+
+#endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */
+"
+
# All Boolean compile time options which default to something
# other than 0 or empty. The default is paired with the PP
# symbol so that a differing define can be detected.
@@ -70,7 +143,6 @@ set boolean_defnil_options {
SQLITE_ENABLE_HIDDEN_COLUMNS
SQLITE_ENABLE_ICU
SQLITE_ENABLE_IOTRACE
- SQLITE_ENABLE_JSON1
SQLITE_ENABLE_LOAD_EXTENSION
SQLITE_ENABLE_LOCKING_STYLE
SQLITE_ENABLE_MATH_FUNCTIONS
@@ -151,6 +223,7 @@ set boolean_defnil_options {
SQLITE_OMIT_INCRBLOB
SQLITE_OMIT_INTEGRITY_CHECK
SQLITE_OMIT_INTROSPECTION_PRAGMAS
+ SQLITE_OMIT_JSON
SQLITE_OMIT_LIKE_OPTIMIZATION
SQLITE_OMIT_LOAD_EXTENSION
SQLITE_OMIT_LOCALTIME
@@ -354,60 +427,18 @@ foreach v $value2_options {
}]
}
-# Split a string on a regex, return all parts in order.
-# Any elements with an even index may be empty.
-# Elements with odd indices will match the regex.
-proc split_on_re {re str {nrepps 1}} {
- set chunks {}
- set cix 0
- set resm [regexp -all -inline -indices $re $str]
- if {[llength $resm]==0} {
- return $str
- }
- set rix 0
- while {$rix < [llength $resm]} {
- set mre [lindex $resm $rix]
- incr rix $nrepps
- set mbx [lindex $mre 0]
- set mex [lindex $mre 1]
- lappend chunks [string range $str $cix [expr $mbx - 1]]
- lappend chunks [string range $str $mbx $mex]
- set cix [expr $mex + 1]
- }
- lappend chunks [string range $str $cix end]
- return $chunks
-}
-
-
set ctime_c "src/ctime.c"
-if {[catch {set cfd [open $ctime_c r]}]!=0} {
- puts stderr "File '$ctime_c' unreadable. Run this script from checkout root."
- exit 1;
-}
-
-set ctfc [read $cfd]
-close $cfd
-
-set re {/\*\s+\*+\s*((BEGIN)|(END)) CODE GENERATED BY (\S+)\s+\*/\s+}
-set renpp 5
-
-set ctfcChunks [split_on_re $re $ctfc $renpp]
-if {[llength $ctfcChunks] != 5} {
- puts stderr "File '$ctime_c' has too few generated code markers."
- exit 1;
-}
if {[catch {set cfd [open $ctime_c w]}]!=0} {
puts stderr "File '$ctime_c' unwritable."
exit 1;
}
-puts -nonewline $cfd [lindex $ctfcChunks 0]
-puts -nonewline $cfd [lindex $ctfcChunks 1]
+puts $cfd $::headWarning;
+puts $cfd $::headCode;
foreach o [lsort [array names options]] {
puts $cfd [string trim $options($o)]
}
-puts -nonewline $cfd [lindex $ctfcChunks 3]
-puts -nonewline $cfd [lindex $ctfcChunks 4]
+puts -nonewline $cfd $::tailCode;
close $cfd
diff --git a/tool/mksqlite3c.tcl b/tool/mksqlite3c.tcl
index 9d59e17b16..1a35fc0ea3 100644
--- a/tool/mksqlite3c.tcl
+++ b/tool/mksqlite3c.tcl
@@ -429,7 +429,7 @@ foreach file {
fts3_unicode.c
fts3_unicode2.c
- json1.c
+ json.c
rtree.c
icu.c
fts3_icu.c
diff --git a/tool/showdb.c b/tool/showdb.c
index 3c91967ed1..611e603fe9 100644
--- a/tool/showdb.c
+++ b/tool/showdb.c
@@ -726,7 +726,7 @@ static void decode_btree_page(
}
if( showMap ){
printf("Page map: (H=header P=cell-index 1=page-1-header .=free-space)\n");
- for(i=0; i0 && pgno<=g.mxPage && (cnt++)0 && pgno<=g.mxPage && (u32)(cnt++)