Compare commits
132 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f380c3f13c | |||
| 7b88f54914 | |||
| a2560ce934 | |||
| d6665c51e2 | |||
| f3ebea8114 | |||
| abc6b67aff | |||
| 06afa291cf | |||
| 9fcc8c69bb | |||
| 9ffa258a01 | |||
| 4be8bdccd4 | |||
| 2a3be742ca | |||
| 1e2896ec6e | |||
| f7588d4072 | |||
| a828d565b6 | |||
| e8f7fcf6f4 | |||
| 9d326d6793 | |||
| 19ef211d85 | |||
| 10c9ef65fa | |||
| 19f9cd73ff | |||
| 76cac6ef06 | |||
| 41d01407ea | |||
| 6bfc167a67 | |||
| 5870dc80f9 | |||
| 5e5683ae46 | |||
| af7b76534b | |||
| d193057ad1 | |||
| aa556b0fa7 | |||
| b9366f8e32 | |||
| b782e05c64 | |||
| 21d4f5b53a | |||
| d9cc532a1e | |||
| ef36ccd1a4 | |||
| cf3c078f93 | |||
| a6e6cf2c8f | |||
| 4ee492f176 | |||
| 1242c0ccf4 | |||
| 3a5e975947 | |||
| 5cb960b7af | |||
| c2dbf35f49 | |||
| 31afee9372 | |||
| e81f879f51 | |||
| c8af879e5f | |||
| 630fc34c1a | |||
| 37114fbfcc | |||
| 3e992d1ab7 | |||
| 266f0f4585 | |||
| 88efc796c2 | |||
| e2b0a12d58 | |||
| 69e856ae66 | |||
| 33e1ec224e | |||
| 4fd4a7a1e9 | |||
| 85d31b9f37 | |||
| c4403ca61a | |||
| a06eafc8fc | |||
| 277a30d9ce | |||
| 0cb735b9fb | |||
| 7225bfef16 | |||
| 9a60e716f7 | |||
| f39168e468 | |||
| 06ddb08f3f | |||
| 961a72601b | |||
| a3d33ebe4a | |||
| 6d5f928d22 | |||
| 237f41ab8d | |||
| 8e2b9c2a89 | |||
| 5763f3d582 | |||
| e69ba68363 | |||
| d131b51cbd | |||
| 964fa26e0c | |||
| 9353beaff1 | |||
| 8daf5ae2ed | |||
| 18a4bbdf63 | |||
| 13dd0228d3 | |||
| 0a8b6a9f8f | |||
| de9ed6293d | |||
| e5baf5c283 | |||
| 9463d79353 | |||
| 7f60706691 | |||
| 0bf333467c | |||
| 84b168ffa7 | |||
| 9f023ce539 | |||
| 59964b4010 | |||
| 1c19848386 | |||
| 250af6e0fb | |||
| 255c1c159b | |||
| 58b18a47df | |||
| 855aed19e2 | |||
| d3e21a1098 | |||
| ed4c54699d | |||
| 7710878333 | |||
| d0a0538229 | |||
| 69871baa15 | |||
| 61e280ad8a | |||
| daf2761c62 | |||
| 9257ddbf87 | |||
| a64804b5e1 | |||
| d2ffc9721e | |||
| 46a6b1a1be | |||
| 7aae73588a | |||
| 70f3eda5be | |||
| 91f2717f22 | |||
| d97a4c008d | |||
| cd1b2d0b54 | |||
| e84ad92f17 | |||
| 1418b9daf6 | |||
| ebbf36878c | |||
| 5602777e8f | |||
| 20b86324a1 | |||
| 036e0675e6 | |||
| 2549e4cc2f | |||
| 0dffe465f7 | |||
| e2ce8c446f | |||
| 63f8f98a63 | |||
| f6e904bd92 | |||
| aeb6bc5628 | |||
| 0a2fb7960c | |||
| b9ceb833f7 | |||
| ee8221859b | |||
| 7b0ab21016 | |||
| 0a3e80b051 | |||
| 3190b88e75 | |||
| 1de03abb03 | |||
| 0b1e70c4ce | |||
| 4338000d47 | |||
| 64f1ef6abd | |||
| f30bbcec90 | |||
| 0fa433b40c | |||
| bb497fe36d | |||
| 636f505864 | |||
| c52a1e9f35 | |||
| f461bab265 | |||
| d1032f952c |
@@ -1378,6 +1378,9 @@ wordcount$(TEXE): $(TOP)/test/wordcount.c sqlite3.lo
|
||||
speedtest1$(TEXE): $(TOP)/test/speedtest1.c sqlite3.c
|
||||
$(LTLINK) $(ST_OPT) -o $@ $(TOP)/test/speedtest1.c sqlite3.c $(TLIBS)
|
||||
|
||||
startup$(TEXE): $(TOP)/test/startup.c sqlite3.c
|
||||
$(CC) -Os -g -DSQLITE_THREADSAFE=0 -o $@ $(TOP)/test/startup.c sqlite3.c $(TLIBS)
|
||||
|
||||
KV_OPT += -DSQLITE_DIRECT_OVERFLOW_READ
|
||||
|
||||
kvtest$(TEXE): $(TOP)/test/kvtest.c sqlite3.c
|
||||
|
||||
@@ -380,6 +380,9 @@ OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_SESSION=1
|
||||
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_PREUPDATE_HOOK=1
|
||||
!ENDIF
|
||||
|
||||
# Always enable math functions on Windows
|
||||
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_MATH_FUNCTIONS
|
||||
|
||||
# Should the rbu extension be enabled? If so, add compilation options
|
||||
# to enable it.
|
||||
#
|
||||
|
||||
@@ -87,7 +87,9 @@ AC_SUBST(READLINE_LIBS)
|
||||
AC_ARG_ENABLE(threadsafe, [AS_HELP_STRING(
|
||||
[--enable-threadsafe], [build a thread-safe library [default=yes]])],
|
||||
[], [enable_threadsafe=yes])
|
||||
if test x"$enable_threadsafe" != "xno"; then
|
||||
if test x"$enable_threadsafe" == "xno"; then
|
||||
BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_THREADSAFE=0"
|
||||
else
|
||||
BUILD_CFLAGS="$BUILD_CFLAGS -D_REENTRANT=1 -DSQLITE_THREADSAFE=1"
|
||||
AC_SEARCH_LIBS(pthread_create, pthread)
|
||||
AC_SEARCH_LIBS(pthread_mutexattr_init, pthread)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#! /bin/sh
|
||||
# Guess values for system-dependent variables and create Makefiles.
|
||||
# Generated by GNU Autoconf 2.69 for sqlite 3.34.0.
|
||||
# Generated by GNU Autoconf 2.69 for sqlite 3.35.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.34.0'
|
||||
PACKAGE_STRING='sqlite 3.34.0'
|
||||
PACKAGE_VERSION='3.35.0'
|
||||
PACKAGE_STRING='sqlite 3.35.0'
|
||||
PACKAGE_BUGREPORT=''
|
||||
PACKAGE_URL=''
|
||||
|
||||
@@ -903,6 +903,7 @@ with_readline_inc
|
||||
enable_debug
|
||||
enable_amalgamation
|
||||
enable_load_extension
|
||||
enable_math
|
||||
enable_memsys5
|
||||
enable_memsys3
|
||||
enable_all
|
||||
@@ -1466,7 +1467,7 @@ if test "$ac_init_help" = "long"; then
|
||||
# Omit some internal or obsolete options to make the list less imposing.
|
||||
# This message is too long to be a string in the A/UX 3.1 sh.
|
||||
cat <<_ACEOF
|
||||
\`configure' configures sqlite 3.34.0 to adapt to many kinds of systems.
|
||||
\`configure' configures sqlite 3.35.0 to adapt to many kinds of systems.
|
||||
|
||||
Usage: $0 [OPTION]... [VAR=VALUE]...
|
||||
|
||||
@@ -1531,7 +1532,7 @@ fi
|
||||
|
||||
if test -n "$ac_init_help"; then
|
||||
case $ac_init_help in
|
||||
short | recursive ) echo "Configuration of sqlite 3.34.0:";;
|
||||
short | recursive ) echo "Configuration of sqlite 3.35.0:";;
|
||||
esac
|
||||
cat <<\_ACEOF
|
||||
|
||||
@@ -1557,6 +1558,7 @@ Optional Features:
|
||||
separately
|
||||
--disable-load-extension
|
||||
Disable loading of external extensions
|
||||
--disable-math Disable math functions
|
||||
--enable-memsys5 Enable MEMSYS5
|
||||
--enable-memsys3 Enable MEMSYS3
|
||||
--enable-all Enable FTS4, FTS5, Geopoly, JSON, RTree, Sessions
|
||||
@@ -1658,7 +1660,7 @@ fi
|
||||
test -n "$ac_init_help" && exit $ac_status
|
||||
if $ac_init_version; then
|
||||
cat <<\_ACEOF
|
||||
sqlite configure 3.34.0
|
||||
sqlite configure 3.35.0
|
||||
generated by GNU Autoconf 2.69
|
||||
|
||||
Copyright (C) 2012 Free Software Foundation, Inc.
|
||||
@@ -2077,7 +2079,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.34.0, which was
|
||||
It was created by sqlite $as_me 3.35.0, which was
|
||||
generated by GNU Autoconf 2.69. Invocation command line was
|
||||
|
||||
$ $0 $@
|
||||
@@ -3935,13 +3937,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:3938: $ac_compile\"" >&5)
|
||||
(eval echo "\"\$as_me:3940: $ac_compile\"" >&5)
|
||||
(eval "$ac_compile" 2>conftest.err)
|
||||
cat conftest.err >&5
|
||||
(eval echo "\"\$as_me:3941: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
|
||||
(eval echo "\"\$as_me:3943: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
|
||||
(eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
|
||||
cat conftest.err >&5
|
||||
(eval echo "\"\$as_me:3944: output\"" >&5)
|
||||
(eval echo "\"\$as_me:3946: output\"" >&5)
|
||||
cat conftest.out >&5
|
||||
if $GREP 'External.*some_variable' conftest.out > /dev/null; then
|
||||
lt_cv_nm_interface="MS dumpbin"
|
||||
@@ -5147,7 +5149,7 @@ ia64-*-hpux*)
|
||||
;;
|
||||
*-*-irix6*)
|
||||
# Find out which ABI we are using.
|
||||
echo '#line 5150 "configure"' > conftest.$ac_ext
|
||||
echo '#line 5152 "configure"' > conftest.$ac_ext
|
||||
if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
|
||||
(eval $ac_compile) 2>&5
|
||||
ac_status=$?
|
||||
@@ -6672,11 +6674,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:6675: $lt_compile\"" >&5)
|
||||
(eval echo "\"\$as_me:6677: $lt_compile\"" >&5)
|
||||
(eval "$lt_compile" 2>conftest.err)
|
||||
ac_status=$?
|
||||
cat conftest.err >&5
|
||||
echo "$as_me:6679: \$? = $ac_status" >&5
|
||||
echo "$as_me:6681: \$? = $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.
|
||||
@@ -7011,11 +7013,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:7014: $lt_compile\"" >&5)
|
||||
(eval echo "\"\$as_me:7016: $lt_compile\"" >&5)
|
||||
(eval "$lt_compile" 2>conftest.err)
|
||||
ac_status=$?
|
||||
cat conftest.err >&5
|
||||
echo "$as_me:7018: \$? = $ac_status" >&5
|
||||
echo "$as_me:7020: \$? = $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.
|
||||
@@ -7116,11 +7118,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:7119: $lt_compile\"" >&5)
|
||||
(eval echo "\"\$as_me:7121: $lt_compile\"" >&5)
|
||||
(eval "$lt_compile" 2>out/conftest.err)
|
||||
ac_status=$?
|
||||
cat out/conftest.err >&5
|
||||
echo "$as_me:7123: \$? = $ac_status" >&5
|
||||
echo "$as_me:7125: \$? = $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
|
||||
@@ -7171,11 +7173,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:7174: $lt_compile\"" >&5)
|
||||
(eval echo "\"\$as_me:7176: $lt_compile\"" >&5)
|
||||
(eval "$lt_compile" 2>out/conftest.err)
|
||||
ac_status=$?
|
||||
cat out/conftest.err >&5
|
||||
echo "$as_me:7178: \$? = $ac_status" >&5
|
||||
echo "$as_me:7180: \$? = $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
|
||||
@@ -9551,7 +9553,7 @@ else
|
||||
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
|
||||
lt_status=$lt_dlunknown
|
||||
cat > conftest.$ac_ext <<_LT_EOF
|
||||
#line 9554 "configure"
|
||||
#line 9556 "configure"
|
||||
#include "confdefs.h"
|
||||
|
||||
#if HAVE_DLFCN_H
|
||||
@@ -9647,7 +9649,7 @@ else
|
||||
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
|
||||
lt_status=$lt_dlunknown
|
||||
cat > conftest.$ac_ext <<_LT_EOF
|
||||
#line 9650 "configure"
|
||||
#line 9652 "configure"
|
||||
#include "confdefs.h"
|
||||
|
||||
#if HAVE_DLFCN_H
|
||||
@@ -10364,8 +10366,10 @@ fi
|
||||
if test "x${TCLLIBDIR+set}" != "xset" ; then
|
||||
TCLLIBDIR='$(libdir)'
|
||||
for i in `echo 'puts stdout $auto_path' | ${TCLSH_CMD}` ; do
|
||||
TCLLIBDIR=$i
|
||||
break
|
||||
if test -d $i ; then
|
||||
TCLLIBDIR=$i
|
||||
break
|
||||
fi
|
||||
done
|
||||
TCLLIBDIR="${TCLLIBDIR}/sqlite3"
|
||||
fi
|
||||
@@ -11411,6 +11415,81 @@ else
|
||||
OPT_FEATURE_FLAGS="-DSQLITE_OMIT_LOAD_EXTENSION=1"
|
||||
fi
|
||||
|
||||
##########
|
||||
# Do we want to support math functions
|
||||
#
|
||||
# Check whether --enable-math was given.
|
||||
if test "${enable_math+set}" = set; then :
|
||||
enableval=$enable_math;
|
||||
fi
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to support math functions" >&5
|
||||
$as_echo_n "checking whether to support math functions... " >&6; }
|
||||
if test "$enable_math" = "no"; then
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
|
||||
$as_echo "no" >&6; }
|
||||
else
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
|
||||
$as_echo "yes" >&6; }
|
||||
OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_MATH_FUNCTIONS"
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing ceil" >&5
|
||||
$as_echo_n "checking for library containing ceil... " >&6; }
|
||||
if ${ac_cv_search_ceil+:} false; then :
|
||||
$as_echo_n "(cached) " >&6
|
||||
else
|
||||
ac_func_search_save_LIBS=$LIBS
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
|
||||
/* Override any GCC internal prototype to avoid an error.
|
||||
Use char because int might match the return type of a GCC
|
||||
builtin and then its argument prototype would still apply. */
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
#endif
|
||||
char ceil ();
|
||||
int
|
||||
main ()
|
||||
{
|
||||
return ceil ();
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
_ACEOF
|
||||
for ac_lib in '' m; do
|
||||
if test -z "$ac_lib"; then
|
||||
ac_res="none required"
|
||||
else
|
||||
ac_res=-l$ac_lib
|
||||
LIBS="-l$ac_lib $ac_func_search_save_LIBS"
|
||||
fi
|
||||
if ac_fn_c_try_link "$LINENO"; then :
|
||||
ac_cv_search_ceil=$ac_res
|
||||
fi
|
||||
rm -f core conftest.err conftest.$ac_objext \
|
||||
conftest$ac_exeext
|
||||
if ${ac_cv_search_ceil+:} false; then :
|
||||
break
|
||||
fi
|
||||
done
|
||||
if ${ac_cv_search_ceil+:} false; then :
|
||||
|
||||
else
|
||||
ac_cv_search_ceil=no
|
||||
fi
|
||||
rm conftest.$ac_ext
|
||||
LIBS=$ac_func_search_save_LIBS
|
||||
fi
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_ceil" >&5
|
||||
$as_echo "$ac_cv_search_ceil" >&6; }
|
||||
ac_res=$ac_cv_search_ceil
|
||||
if test "$ac_res" != no; then :
|
||||
test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
|
||||
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
##########
|
||||
# Do we want to support memsys3 and/or memsys5
|
||||
#
|
||||
@@ -12236,7 +12315,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.34.0, which was
|
||||
This file was extended by sqlite $as_me 3.35.0, which was
|
||||
generated by GNU Autoconf 2.69. Invocation command line was
|
||||
|
||||
CONFIG_FILES = $CONFIG_FILES
|
||||
@@ -12302,7 +12381,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.34.0
|
||||
sqlite config.status 3.35.0
|
||||
configured by $0, generated by GNU Autoconf 2.69,
|
||||
with options \\"\$ac_cs_config\\"
|
||||
|
||||
|
||||
+18
-2
@@ -134,8 +134,10 @@ AC_ARG_VAR([TCLLIBDIR], [Where to install tcl plugin])
|
||||
if test "x${TCLLIBDIR+set}" != "xset" ; then
|
||||
TCLLIBDIR='$(libdir)'
|
||||
for i in `echo 'puts stdout $auto_path' | ${TCLSH_CMD}` ; do
|
||||
TCLLIBDIR=$i
|
||||
break
|
||||
if test -d $i ; then
|
||||
TCLLIBDIR=$i
|
||||
break
|
||||
fi
|
||||
done
|
||||
TCLLIBDIR="${TCLLIBDIR}/sqlite3"
|
||||
fi
|
||||
@@ -586,6 +588,20 @@ else
|
||||
OPT_FEATURE_FLAGS="-DSQLITE_OMIT_LOAD_EXTENSION=1"
|
||||
fi
|
||||
|
||||
##########
|
||||
# Do we want to support math functions
|
||||
#
|
||||
AC_ARG_ENABLE(math,
|
||||
AC_HELP_STRING([--disable-math],[Disable math functions]))
|
||||
AC_MSG_CHECKING([whether to support math functions])
|
||||
if test "$enable_math" = "no"; then
|
||||
AC_MSG_RESULT([no])
|
||||
else
|
||||
AC_MSG_RESULT([yes])
|
||||
OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_MATH_FUNCTIONS"
|
||||
AC_SEARCH_LIBS(ceil, m)
|
||||
fi
|
||||
|
||||
##########
|
||||
# Do we want to support memsys3 and/or memsys5
|
||||
#
|
||||
|
||||
+2
-2
@@ -1077,7 +1077,7 @@ can choose a different start symbol using the
|
||||
<a id='syntax_error'></a>
|
||||
<h4>4.4.19 The <tt>%syntax_error</tt> directive</h4>
|
||||
|
||||
<p>See <a href='#error_processing'>Error Processing</a>.</p>
|
||||
<p>See <a href='#errors'>Error Processing</a>.</p>
|
||||
|
||||
<a id='token_class'></a>
|
||||
<h4>4.4.20 The <tt>%token_class</tt> directive</h4>
|
||||
@@ -1176,7 +1176,7 @@ match any input token.</p>
|
||||
the wildcard token and some other token, the other token is always used.
|
||||
The wildcard token is only matched if there are no alternatives.</p>
|
||||
|
||||
<a id='error_processing'></a>
|
||||
<a id='errors'></a>
|
||||
<h2>5.0 Error Processing</h2>
|
||||
|
||||
<p>After extensive experimentation over several years, it has been
|
||||
|
||||
+25
-1
@@ -28,6 +28,7 @@ if {[info commands sqlite3_expert_new]==""} {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
set CLI [test_binary_name sqlite3]
|
||||
set CMD [test_binary_name sqlite3_expert]
|
||||
|
||||
@@ -367,6 +368,29 @@ do_setup_rec_test $tn.17.5 {
|
||||
SEARCH TABLE example USING INDEX example_idx_0000cb3f (B=? AND A>?)
|
||||
}
|
||||
|
||||
do_setup_rec_test $tn.18.0 {
|
||||
CREATE TABLE SomeObject (
|
||||
a INTEGER PRIMARY KEY,
|
||||
x TEXT GENERATED ALWAYS AS(HEX(a)) VIRTUAL
|
||||
);
|
||||
} {
|
||||
SELECT x FROM SomeObject;
|
||||
} {
|
||||
(no new indexes)
|
||||
SCAN TABLE SomeObject
|
||||
}
|
||||
do_setup_rec_test $tn.18.1 {
|
||||
CREATE TABLE SomeObject (
|
||||
a INTEGER PRIMARY KEY,
|
||||
x TEXT GENERATED ALWAYS AS(HEX(a)) VIRTUAL
|
||||
);
|
||||
} {
|
||||
SELECT * FROM SomeObject WHERE x=?;
|
||||
} {
|
||||
CREATE INDEX SomeObject_idx_00000078 ON SomeObject(x);
|
||||
SEARCH TABLE SomeObject USING COVERING INDEX SomeObject_idx_00000078 (x=?)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
proc do_candidates_test {tn sql res} {
|
||||
@@ -430,5 +454,5 @@ do_execsql_test 5.3 {
|
||||
t2 t2_idx_0001295b {100 20 5}
|
||||
}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
@@ -687,7 +687,7 @@ static int idxGetTableInfo(
|
||||
char *pCsr = 0;
|
||||
int nPk = 0;
|
||||
|
||||
rc = idxPrintfPrepareStmt(db, &p1, pzErrmsg, "PRAGMA table_info=%Q", zTab);
|
||||
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);
|
||||
nByte += 1 + STRLEN(zCol);
|
||||
@@ -1721,10 +1721,12 @@ static int idxPopulateStat1(sqlite3expert *p, char **pzErr){
|
||||
idxFinalize(&rc, pIndexXInfo);
|
||||
idxFinalize(&rc, pWrite);
|
||||
|
||||
for(i=0; i<pCtx->nSlot; i++){
|
||||
sqlite3_free(pCtx->aSlot[i].z);
|
||||
if( pCtx ){
|
||||
for(i=0; i<pCtx->nSlot; i++){
|
||||
sqlite3_free(pCtx->aSlot[i].z);
|
||||
}
|
||||
sqlite3_free(pCtx);
|
||||
}
|
||||
sqlite3_free(pCtx);
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3_exec(p->dbm, "ANALYZE sqlite_schema", 0, 0, 0);
|
||||
|
||||
@@ -1500,8 +1500,8 @@ int sqlite3Fts5ExprFirst(Fts5Expr *p, Fts5Index *pIdx, i64 iFirst, int bDesc){
|
||||
}
|
||||
|
||||
/* If the iterator is not at a real match, skip forward until it is. */
|
||||
while( pRoot->bNomatch ){
|
||||
assert( pRoot->bEof==0 && rc==SQLITE_OK );
|
||||
while( pRoot->bNomatch && rc==SQLITE_OK ){
|
||||
assert( pRoot->bEof==0 );
|
||||
rc = fts5ExprNodeNext(p, pRoot, 0, 0);
|
||||
}
|
||||
return rc;
|
||||
|
||||
+302
-232
@@ -2070,14 +2070,10 @@ static void fts5SegIterNext(
|
||||
}else{
|
||||
/* The following could be done by calling fts5SegIterLoadNPos(). But
|
||||
** this block is particularly performance critical, so equivalent
|
||||
** code is inlined.
|
||||
**
|
||||
** Later: Switched back to fts5SegIterLoadNPos() because it supports
|
||||
** detail=none mode. Not ideal.
|
||||
*/
|
||||
** code is inlined. */
|
||||
int nSz;
|
||||
assert( p->rc==SQLITE_OK );
|
||||
assert( pIter->iLeafOffset<=pIter->pLeaf->nn );
|
||||
assert_nc( pIter->iLeafOffset<=pIter->pLeaf->nn );
|
||||
fts5FastGetVarint32(pIter->pLeaf->p, pIter->iLeafOffset, nSz);
|
||||
pIter->bDel = (nSz & 0x0001);
|
||||
pIter->nPos = nSz>>1;
|
||||
@@ -3069,7 +3065,7 @@ static void fts5ChunkIterate(
|
||||
int pgno = pSeg->iLeafPgno;
|
||||
int pgnoSave = 0;
|
||||
|
||||
/* This function does notmwork with detail=none databases. */
|
||||
/* This function does not work with detail=none databases. */
|
||||
assert( p->pConfig->eDetail!=FTS5_DETAIL_NONE );
|
||||
|
||||
if( (pSeg->flags & FTS5_SEGITER_REVERSE)==0 ){
|
||||
@@ -3082,6 +3078,9 @@ static void fts5ChunkIterate(
|
||||
fts5DataRelease(pData);
|
||||
if( nRem<=0 ){
|
||||
break;
|
||||
}else if( pSeg->pSeg==0 ){
|
||||
p->rc = FTS5_CORRUPT;
|
||||
return;
|
||||
}else{
|
||||
pgno++;
|
||||
pData = fts5LeafRead(p, FTS5_SEGMENT_ROWID(pSeg->pSeg->iSegid, pgno));
|
||||
@@ -3133,66 +3132,72 @@ static void fts5SegiterPoslist(
|
||||
}
|
||||
|
||||
/*
|
||||
** IN/OUT parameter (*pa) points to a position list n bytes in size. If
|
||||
** the position list contains entries for column iCol, then (*pa) is set
|
||||
** to point to the sub-position-list for that column and the number of
|
||||
** bytes in it returned. Or, if the argument position list does not
|
||||
** contain any entries for column iCol, return 0.
|
||||
** Parameter pPos points to a buffer containing a position list, size nPos.
|
||||
** This function filters it according to pColset (which must be non-NULL)
|
||||
** and sets pIter->base.pData/nData to point to the new position list.
|
||||
** If memory is required for the new position list, use buffer pIter->poslist.
|
||||
** Or, if the new position list is a contiguous subset of the input, set
|
||||
** pIter->base.pData/nData to point directly to it.
|
||||
**
|
||||
** This function is a no-op if *pRc is other than SQLITE_OK when it is
|
||||
** called. If an OOM error is encountered, *pRc is set to SQLITE_NOMEM
|
||||
** before returning.
|
||||
*/
|
||||
static int fts5IndexExtractCol(
|
||||
const u8 **pa, /* IN/OUT: Pointer to poslist */
|
||||
int n, /* IN: Size of poslist in bytes */
|
||||
int iCol /* Column to extract from poslist */
|
||||
){
|
||||
int iCurrent = 0; /* Anything before the first 0x01 is col 0 */
|
||||
const u8 *p = *pa;
|
||||
const u8 *pEnd = &p[n]; /* One byte past end of position list */
|
||||
|
||||
while( iCol>iCurrent ){
|
||||
/* Advance pointer p until it points to pEnd or an 0x01 byte that is
|
||||
** not part of a varint. Note that it is not possible for a negative
|
||||
** or extremely large varint to occur within an uncorrupted position
|
||||
** list. So the last byte of each varint may be assumed to have a clear
|
||||
** 0x80 bit. */
|
||||
while( *p!=0x01 ){
|
||||
while( *p++ & 0x80 );
|
||||
if( p>=pEnd ) return 0;
|
||||
}
|
||||
*pa = p++;
|
||||
iCurrent = *p++;
|
||||
if( iCurrent & 0x80 ){
|
||||
p--;
|
||||
p += fts5GetVarint32(p, iCurrent);
|
||||
}
|
||||
}
|
||||
if( iCol!=iCurrent ) return 0;
|
||||
|
||||
/* Advance pointer p until it points to pEnd or an 0x01 byte that is
|
||||
** not part of a varint */
|
||||
while( p<pEnd && *p!=0x01 ){
|
||||
while( *p++ & 0x80 );
|
||||
}
|
||||
|
||||
return p - (*pa);
|
||||
}
|
||||
|
||||
static void fts5IndexExtractColset(
|
||||
int *pRc,
|
||||
Fts5Colset *pColset, /* Colset to filter on */
|
||||
const u8 *pPos, int nPos, /* Position list */
|
||||
Fts5Buffer *pBuf /* Output buffer */
|
||||
Fts5Iter *pIter
|
||||
){
|
||||
if( *pRc==SQLITE_OK ){
|
||||
int i;
|
||||
fts5BufferZero(pBuf);
|
||||
for(i=0; i<pColset->nCol; i++){
|
||||
const u8 *pSub = pPos;
|
||||
int nSub = fts5IndexExtractCol(&pSub, nPos, pColset->aiCol[i]);
|
||||
if( nSub ){
|
||||
fts5BufferAppendBlob(pRc, pBuf, nSub, pSub);
|
||||
const u8 *p = pPos;
|
||||
const u8 *aCopy = p;
|
||||
const u8 *pEnd = &p[nPos]; /* One byte past end of position list */
|
||||
int i = 0;
|
||||
int iCurrent = 0;
|
||||
|
||||
if( pColset->nCol>1 && sqlite3Fts5BufferSize(pRc, &pIter->poslist, nPos) ){
|
||||
return;
|
||||
}
|
||||
|
||||
while( 1 ){
|
||||
while( pColset->aiCol[i]<iCurrent ){
|
||||
i++;
|
||||
if( i==pColset->nCol ){
|
||||
pIter->base.pData = pIter->poslist.p;
|
||||
pIter->base.nData = pIter->poslist.n;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Advance pointer p until it points to pEnd or an 0x01 byte that is
|
||||
** not part of a varint */
|
||||
while( p<pEnd && *p!=0x01 ){
|
||||
while( *p++ & 0x80 );
|
||||
}
|
||||
|
||||
if( pColset->aiCol[i]==iCurrent ){
|
||||
if( pColset->nCol==1 ){
|
||||
pIter->base.pData = aCopy;
|
||||
pIter->base.nData = p-aCopy;
|
||||
return;
|
||||
}
|
||||
fts5BufferSafeAppendBlob(&pIter->poslist, aCopy, p-aCopy);
|
||||
}
|
||||
if( p==pEnd ){
|
||||
pIter->base.pData = pIter->poslist.p;
|
||||
pIter->base.nData = pIter->poslist.n;
|
||||
return;
|
||||
}
|
||||
aCopy = p++;
|
||||
iCurrent = *p++;
|
||||
if( iCurrent & 0x80 ){
|
||||
p--;
|
||||
p += fts5GetVarint32(p, iCurrent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -3312,16 +3317,9 @@ static void fts5IterSetOutputs_Full(Fts5Iter *pIter, Fts5SegIter *pSeg){
|
||||
/* All data is stored on the current page. Populate the output
|
||||
** variables to point into the body of the page object. */
|
||||
const u8 *a = &pSeg->pLeaf->p[pSeg->iLeafOffset];
|
||||
if( pColset->nCol==1 ){
|
||||
pIter->base.nData = fts5IndexExtractCol(&a, pSeg->nPos,pColset->aiCol[0]);
|
||||
pIter->base.pData = a;
|
||||
}else{
|
||||
int *pRc = &pIter->pIndex->rc;
|
||||
fts5BufferZero(&pIter->poslist);
|
||||
fts5IndexExtractColset(pRc, pColset, a, pSeg->nPos, &pIter->poslist);
|
||||
pIter->base.pData = pIter->poslist.p;
|
||||
pIter->base.nData = pIter->poslist.n;
|
||||
}
|
||||
int *pRc = &pIter->pIndex->rc;
|
||||
fts5BufferZero(&pIter->poslist);
|
||||
fts5IndexExtractColset(pRc, pColset, a, pSeg->nPos, pIter);
|
||||
}else{
|
||||
/* The data is distributed over two or more pages. Copy it into the
|
||||
** Fts5Iter.poslist buffer and then set the output pointer to point
|
||||
@@ -4804,7 +4802,7 @@ static void fts5AppendPoslist(
|
||||
static void fts5DoclistIterNext(Fts5DoclistIter *pIter){
|
||||
u8 *p = pIter->aPoslist + pIter->nSize + pIter->nPoslist;
|
||||
|
||||
assert( pIter->aPoslist );
|
||||
assert( pIter->aPoslist || (p==0 && pIter->aPoslist==0) );
|
||||
if( p>=pIter->aEof ){
|
||||
pIter->aPoslist = 0;
|
||||
}else{
|
||||
@@ -4888,16 +4886,20 @@ static void fts5NextRowid(Fts5Buffer *pBuf, int *piOff, i64 *piRowid){
|
||||
static void fts5MergeRowidLists(
|
||||
Fts5Index *p, /* FTS5 backend object */
|
||||
Fts5Buffer *p1, /* First list to merge */
|
||||
Fts5Buffer *p2 /* Second list to merge */
|
||||
int nBuf, /* Number of entries in apBuf[] */
|
||||
Fts5Buffer *aBuf /* Array of other lists to merge into p1 */
|
||||
){
|
||||
int i1 = 0;
|
||||
int i2 = 0;
|
||||
i64 iRowid1 = 0;
|
||||
i64 iRowid2 = 0;
|
||||
i64 iOut = 0;
|
||||
|
||||
Fts5Buffer *p2 = &aBuf[0];
|
||||
Fts5Buffer out;
|
||||
|
||||
(void)nBuf;
|
||||
memset(&out, 0, sizeof(out));
|
||||
assert( nBuf==1 );
|
||||
sqlite3Fts5BufferSize(&p->rc, &out, p1->n + p2->n);
|
||||
if( p->rc ) return;
|
||||
|
||||
@@ -4924,180 +4926,213 @@ static void fts5MergeRowidLists(
|
||||
fts5BufferFree(&out);
|
||||
}
|
||||
|
||||
typedef struct PrefixMerger PrefixMerger;
|
||||
struct PrefixMerger {
|
||||
Fts5DoclistIter iter; /* Doclist iterator */
|
||||
i64 iPos; /* For iterating through a position list */
|
||||
int iOff;
|
||||
u8 *aPos;
|
||||
PrefixMerger *pNext; /* Next in docid/poslist order */
|
||||
};
|
||||
|
||||
static void fts5PrefixMergerInsertByRowid(
|
||||
PrefixMerger **ppHead,
|
||||
PrefixMerger *p
|
||||
){
|
||||
if( p->iter.aPoslist ){
|
||||
PrefixMerger **pp = ppHead;
|
||||
while( *pp && p->iter.iRowid>(*pp)->iter.iRowid ){
|
||||
pp = &(*pp)->pNext;
|
||||
}
|
||||
p->pNext = *pp;
|
||||
*pp = p;
|
||||
}
|
||||
}
|
||||
|
||||
static void fts5PrefixMergerInsertByPosition(
|
||||
PrefixMerger **ppHead,
|
||||
PrefixMerger *p
|
||||
){
|
||||
if( p->iPos>=0 ){
|
||||
PrefixMerger **pp = ppHead;
|
||||
while( *pp && p->iPos>(*pp)->iPos ){
|
||||
pp = &(*pp)->pNext;
|
||||
}
|
||||
p->pNext = *pp;
|
||||
*pp = p;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Buffers p1 and p2 contain doclists. This function merges the content
|
||||
** of the two doclists together and sets buffer p1 to the result before
|
||||
** returning.
|
||||
**
|
||||
** If an error occurs, an error code is left in p->rc. If an error has
|
||||
** already occurred, this function is a no-op.
|
||||
** Array aBuf[] contains nBuf doclists. These are all merged in with the
|
||||
** doclist in buffer p1.
|
||||
*/
|
||||
static void fts5MergePrefixLists(
|
||||
Fts5Index *p, /* FTS5 backend object */
|
||||
Fts5Buffer *p1, /* First list to merge */
|
||||
Fts5Buffer *p2 /* Second list to merge */
|
||||
int nBuf, /* Number of buffers in array aBuf[] */
|
||||
Fts5Buffer *aBuf /* Other lists to merge in */
|
||||
){
|
||||
if( p2->n ){
|
||||
i64 iLastRowid = 0;
|
||||
Fts5DoclistIter i1;
|
||||
Fts5DoclistIter i2;
|
||||
Fts5Buffer out = {0, 0, 0};
|
||||
Fts5Buffer tmp = {0, 0, 0};
|
||||
#define fts5PrefixMergerNextPosition(p) \
|
||||
sqlite3Fts5PoslistNext64((p)->aPos,(p)->iter.nPoslist,&(p)->iOff,&(p)->iPos);
|
||||
#define FTS5_MERGE_NLIST 16
|
||||
PrefixMerger aMerger[FTS5_MERGE_NLIST];
|
||||
PrefixMerger *pHead = 0;
|
||||
int i;
|
||||
int nOut = 0;
|
||||
Fts5Buffer out = {0, 0, 0};
|
||||
Fts5Buffer tmp = {0, 0, 0};
|
||||
i64 iLastRowid = 0;
|
||||
|
||||
/* The maximum size of the output is equal to the sum of the two
|
||||
** input sizes + 1 varint (9 bytes). The extra varint is because if the
|
||||
** first rowid in one input is a large negative number, and the first in
|
||||
** the other a non-negative number, the delta for the non-negative
|
||||
** number will be larger on disk than the literal integer value
|
||||
** was.
|
||||
**
|
||||
** Or, if the input position-lists are corrupt, then the output might
|
||||
** include up to 2 extra 10-byte positions created by interpreting -1
|
||||
** (the value PoslistNext64() uses for EOF) as a position and appending
|
||||
** it to the output. This can happen at most once for each input
|
||||
** position-list, hence two 10 byte paddings. */
|
||||
if( sqlite3Fts5BufferSize(&p->rc, &out, p1->n + p2->n + 9+10+10) ) return;
|
||||
fts5DoclistIterInit(p1, &i1);
|
||||
fts5DoclistIterInit(p2, &i2);
|
||||
|
||||
while( 1 ){
|
||||
if( i1.iRowid<i2.iRowid ){
|
||||
/* Copy entry from i1 */
|
||||
fts5MergeAppendDocid(&out, iLastRowid, i1.iRowid);
|
||||
fts5BufferSafeAppendBlob(&out, i1.aPoslist, i1.nPoslist+i1.nSize);
|
||||
fts5DoclistIterNext(&i1);
|
||||
if( i1.aPoslist==0 ) break;
|
||||
assert( out.n<=((i1.aPoslist-p1->p) + (i2.aPoslist-p2->p)+9+10+10) );
|
||||
}
|
||||
else if( i2.iRowid!=i1.iRowid ){
|
||||
/* Copy entry from i2 */
|
||||
fts5MergeAppendDocid(&out, iLastRowid, i2.iRowid);
|
||||
fts5BufferSafeAppendBlob(&out, i2.aPoslist, i2.nPoslist+i2.nSize);
|
||||
fts5DoclistIterNext(&i2);
|
||||
if( i2.aPoslist==0 ) break;
|
||||
assert( out.n<=((i1.aPoslist-p1->p) + (i2.aPoslist-p2->p)+9+10+10) );
|
||||
}
|
||||
else{
|
||||
/* Merge the two position lists. */
|
||||
i64 iPos1 = 0;
|
||||
i64 iPos2 = 0;
|
||||
int iOff1 = 0;
|
||||
int iOff2 = 0;
|
||||
u8 *a1 = &i1.aPoslist[i1.nSize];
|
||||
u8 *a2 = &i2.aPoslist[i2.nSize];
|
||||
int nCopy;
|
||||
u8 *aCopy;
|
||||
|
||||
i64 iPrev = 0;
|
||||
Fts5PoslistWriter writer;
|
||||
memset(&writer, 0, sizeof(writer));
|
||||
|
||||
/* See the earlier comment in this function for an explanation of why
|
||||
** corrupt input position lists might cause the output to consume
|
||||
** at most 20 bytes of unexpected space. */
|
||||
fts5MergeAppendDocid(&out, iLastRowid, i2.iRowid);
|
||||
fts5BufferZero(&tmp);
|
||||
sqlite3Fts5BufferSize(&p->rc, &tmp,
|
||||
i1.nPoslist + i2.nPoslist + 10 + 10 + FTS5_DATA_ZERO_PADDING
|
||||
);
|
||||
if( p->rc ) break;
|
||||
|
||||
sqlite3Fts5PoslistNext64(a1, i1.nPoslist, &iOff1, &iPos1);
|
||||
sqlite3Fts5PoslistNext64(a2, i2.nPoslist, &iOff2, &iPos2);
|
||||
assert_nc( iPos1>=0 && iPos2>=0 );
|
||||
|
||||
if( iPos1<iPos2 ){
|
||||
sqlite3Fts5PoslistSafeAppend(&tmp, &iPrev, iPos1);
|
||||
sqlite3Fts5PoslistNext64(a1, i1.nPoslist, &iOff1, &iPos1);
|
||||
}else{
|
||||
sqlite3Fts5PoslistSafeAppend(&tmp, &iPrev, iPos2);
|
||||
sqlite3Fts5PoslistNext64(a2, i2.nPoslist, &iOff2, &iPos2);
|
||||
}
|
||||
if( iPos1>=0 && iPos2>=0 ){
|
||||
while( 1 ){
|
||||
if( iPos1<iPos2 ){
|
||||
if( iPos1!=iPrev ){
|
||||
sqlite3Fts5PoslistSafeAppend(&tmp, &iPrev, iPos1);
|
||||
}
|
||||
sqlite3Fts5PoslistNext64(a1, i1.nPoslist, &iOff1, &iPos1);
|
||||
if( iPos1<0 ) break;
|
||||
}else{
|
||||
assert_nc( iPos2!=iPrev );
|
||||
sqlite3Fts5PoslistSafeAppend(&tmp, &iPrev, iPos2);
|
||||
sqlite3Fts5PoslistNext64(a2, i2.nPoslist, &iOff2, &iPos2);
|
||||
if( iPos2<0 ) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( iPos1>=0 ){
|
||||
if( iPos1!=iPrev ){
|
||||
sqlite3Fts5PoslistSafeAppend(&tmp, &iPrev, iPos1);
|
||||
}
|
||||
aCopy = &a1[iOff1];
|
||||
nCopy = i1.nPoslist - iOff1;
|
||||
}else{
|
||||
assert_nc( iPos2>=0 && iPos2!=iPrev );
|
||||
sqlite3Fts5PoslistSafeAppend(&tmp, &iPrev, iPos2);
|
||||
aCopy = &a2[iOff2];
|
||||
nCopy = i2.nPoslist - iOff2;
|
||||
}
|
||||
if( nCopy>0 ){
|
||||
fts5BufferSafeAppendBlob(&tmp, aCopy, nCopy);
|
||||
}
|
||||
|
||||
/* WRITEPOSLISTSIZE */
|
||||
assert_nc( tmp.n<=i1.nPoslist+i2.nPoslist );
|
||||
assert( tmp.n<=i1.nPoslist+i2.nPoslist+10+10 );
|
||||
if( tmp.n>i1.nPoslist+i2.nPoslist ){
|
||||
if( p->rc==SQLITE_OK ) p->rc = FTS5_CORRUPT;
|
||||
break;
|
||||
}
|
||||
fts5BufferSafeAppendVarint(&out, tmp.n * 2);
|
||||
fts5BufferSafeAppendBlob(&out, tmp.p, tmp.n);
|
||||
fts5DoclistIterNext(&i1);
|
||||
fts5DoclistIterNext(&i2);
|
||||
assert_nc( out.n<=(p1->n+p2->n+9) );
|
||||
if( i1.aPoslist==0 || i2.aPoslist==0 ) break;
|
||||
assert( out.n<=((i1.aPoslist-p1->p) + (i2.aPoslist-p2->p)+9+10+10) );
|
||||
}
|
||||
}
|
||||
|
||||
if( i1.aPoslist ){
|
||||
fts5MergeAppendDocid(&out, iLastRowid, i1.iRowid);
|
||||
fts5BufferSafeAppendBlob(&out, i1.aPoslist, i1.aEof - i1.aPoslist);
|
||||
}
|
||||
else if( i2.aPoslist ){
|
||||
fts5MergeAppendDocid(&out, iLastRowid, i2.iRowid);
|
||||
fts5BufferSafeAppendBlob(&out, i2.aPoslist, i2.aEof - i2.aPoslist);
|
||||
}
|
||||
assert_nc( out.n<=(p1->n+p2->n+9) );
|
||||
|
||||
fts5BufferFree(p1);
|
||||
fts5BufferFree(&tmp);
|
||||
memset(&out.p[out.n], 0, FTS5_DATA_ZERO_PADDING);
|
||||
*p1 = out;
|
||||
/* Initialize a doclist-iterator for each input buffer. Arrange them in
|
||||
** a linked-list starting at pHead in ascending order of rowid. Avoid
|
||||
** linking any iterators already at EOF into the linked list at all. */
|
||||
assert( nBuf+1<=sizeof(aMerger)/sizeof(aMerger[0]) );
|
||||
memset(aMerger, 0, sizeof(PrefixMerger)*(nBuf+1));
|
||||
pHead = &aMerger[nBuf];
|
||||
fts5DoclistIterInit(p1, &pHead->iter);
|
||||
for(i=0; i<nBuf; i++){
|
||||
fts5DoclistIterInit(&aBuf[i], &aMerger[i].iter);
|
||||
fts5PrefixMergerInsertByRowid(&pHead, &aMerger[i]);
|
||||
nOut += aBuf[i].n;
|
||||
}
|
||||
if( nOut==0 ) return;
|
||||
nOut += p1->n + 9 + 10*nBuf;
|
||||
|
||||
/* The maximum size of the output is equal to the sum of the
|
||||
** input sizes + 1 varint (9 bytes). The extra varint is because if the
|
||||
** first rowid in one input is a large negative number, and the first in
|
||||
** the other a non-negative number, the delta for the non-negative
|
||||
** number will be larger on disk than the literal integer value
|
||||
** was.
|
||||
**
|
||||
** Or, if the input position-lists are corrupt, then the output might
|
||||
** include up to (nBuf+1) extra 10-byte positions created by interpreting -1
|
||||
** (the value PoslistNext64() uses for EOF) as a position and appending
|
||||
** it to the output. This can happen at most once for each input
|
||||
** position-list, hence (nBuf+1) 10 byte paddings. */
|
||||
if( sqlite3Fts5BufferSize(&p->rc, &out, nOut) ) return;
|
||||
|
||||
while( pHead ){
|
||||
fts5MergeAppendDocid(&out, iLastRowid, pHead->iter.iRowid);
|
||||
|
||||
if( pHead->pNext && iLastRowid==pHead->pNext->iter.iRowid ){
|
||||
/* Merge data from two or more poslists */
|
||||
i64 iPrev = 0;
|
||||
int nTmp = FTS5_DATA_ZERO_PADDING;
|
||||
int nMerge = 0;
|
||||
PrefixMerger *pSave = pHead;
|
||||
PrefixMerger *pThis = 0;
|
||||
int nTail = 0;
|
||||
|
||||
pHead = 0;
|
||||
while( pSave && pSave->iter.iRowid==iLastRowid ){
|
||||
PrefixMerger *pNext = pSave->pNext;
|
||||
pSave->iOff = 0;
|
||||
pSave->iPos = 0;
|
||||
pSave->aPos = &pSave->iter.aPoslist[pSave->iter.nSize];
|
||||
fts5PrefixMergerNextPosition(pSave);
|
||||
nTmp += pSave->iter.nPoslist + 10;
|
||||
nMerge++;
|
||||
fts5PrefixMergerInsertByPosition(&pHead, pSave);
|
||||
pSave = pNext;
|
||||
}
|
||||
|
||||
if( pHead==0 || pHead->pNext==0 ){
|
||||
p->rc = FTS5_CORRUPT;
|
||||
break;
|
||||
}
|
||||
|
||||
/* See the earlier comment in this function for an explanation of why
|
||||
** corrupt input position lists might cause the output to consume
|
||||
** at most nMerge*10 bytes of unexpected space. */
|
||||
if( sqlite3Fts5BufferSize(&p->rc, &tmp, nTmp+nMerge*10) ){
|
||||
break;
|
||||
}
|
||||
fts5BufferZero(&tmp);
|
||||
|
||||
pThis = pHead;
|
||||
pHead = pThis->pNext;
|
||||
sqlite3Fts5PoslistSafeAppend(&tmp, &iPrev, pThis->iPos);
|
||||
fts5PrefixMergerNextPosition(pThis);
|
||||
fts5PrefixMergerInsertByPosition(&pHead, pThis);
|
||||
|
||||
while( pHead->pNext ){
|
||||
pThis = pHead;
|
||||
if( pThis->iPos!=iPrev ){
|
||||
sqlite3Fts5PoslistSafeAppend(&tmp, &iPrev, pThis->iPos);
|
||||
}
|
||||
fts5PrefixMergerNextPosition(pThis);
|
||||
pHead = pThis->pNext;
|
||||
fts5PrefixMergerInsertByPosition(&pHead, pThis);
|
||||
}
|
||||
|
||||
if( pHead->iPos!=iPrev ){
|
||||
sqlite3Fts5PoslistSafeAppend(&tmp, &iPrev, pHead->iPos);
|
||||
}
|
||||
nTail = pHead->iter.nPoslist - pHead->iOff;
|
||||
|
||||
/* WRITEPOSLISTSIZE */
|
||||
assert( tmp.n+nTail<=nTmp );
|
||||
if( tmp.n+nTail>nTmp-FTS5_DATA_ZERO_PADDING ){
|
||||
if( p->rc==SQLITE_OK ) p->rc = FTS5_CORRUPT;
|
||||
break;
|
||||
}
|
||||
fts5BufferSafeAppendVarint(&out, (tmp.n+nTail) * 2);
|
||||
fts5BufferSafeAppendBlob(&out, tmp.p, tmp.n);
|
||||
if( nTail>0 ){
|
||||
fts5BufferSafeAppendBlob(&out, &pHead->aPos[pHead->iOff], nTail);
|
||||
}
|
||||
|
||||
pHead = pSave;
|
||||
for(i=0; i<nBuf+1; i++){
|
||||
PrefixMerger *pX = &aMerger[i];
|
||||
if( pX->iter.aPoslist && pX->iter.iRowid==iLastRowid ){
|
||||
fts5DoclistIterNext(&pX->iter);
|
||||
fts5PrefixMergerInsertByRowid(&pHead, pX);
|
||||
}
|
||||
}
|
||||
|
||||
}else{
|
||||
/* Copy poslist from pHead to output */
|
||||
PrefixMerger *pThis = pHead;
|
||||
Fts5DoclistIter *pI = &pThis->iter;
|
||||
fts5BufferSafeAppendBlob(&out, pI->aPoslist, pI->nPoslist+pI->nSize);
|
||||
fts5DoclistIterNext(pI);
|
||||
pHead = pThis->pNext;
|
||||
fts5PrefixMergerInsertByRowid(&pHead, pThis);
|
||||
}
|
||||
}
|
||||
|
||||
fts5BufferFree(p1);
|
||||
fts5BufferFree(&tmp);
|
||||
memset(&out.p[out.n], 0, FTS5_DATA_ZERO_PADDING);
|
||||
*p1 = out;
|
||||
}
|
||||
|
||||
static void fts5SetupPrefixIter(
|
||||
Fts5Index *p, /* Index to read from */
|
||||
int bDesc, /* True for "ORDER BY rowid DESC" */
|
||||
const u8 *pToken, /* Buffer containing prefix to match */
|
||||
int iIdx, /* Index to scan for data */
|
||||
u8 *pToken, /* Buffer containing prefix to match */
|
||||
int nToken, /* Size of buffer pToken in bytes */
|
||||
Fts5Colset *pColset, /* Restrict matches to these columns */
|
||||
Fts5Iter **ppIter /* OUT: New iterator */
|
||||
){
|
||||
Fts5Structure *pStruct;
|
||||
Fts5Buffer *aBuf;
|
||||
const int nBuf = 32;
|
||||
int nBuf = 32;
|
||||
int nMerge = 1;
|
||||
|
||||
void (*xMerge)(Fts5Index*, Fts5Buffer*, Fts5Buffer*);
|
||||
void (*xMerge)(Fts5Index*, Fts5Buffer*, int, Fts5Buffer*);
|
||||
void (*xAppend)(Fts5Index*, i64, Fts5Iter*, Fts5Buffer*);
|
||||
if( p->pConfig->eDetail==FTS5_DETAIL_NONE ){
|
||||
xMerge = fts5MergeRowidLists;
|
||||
xAppend = fts5AppendRowid;
|
||||
}else{
|
||||
nMerge = FTS5_MERGE_NLIST-1;
|
||||
nBuf = nMerge*8; /* Sufficient to merge (16^8)==(2^32) lists */
|
||||
xMerge = fts5MergePrefixLists;
|
||||
xAppend = fts5AppendPoslist;
|
||||
}
|
||||
@@ -5117,6 +5152,27 @@ static void fts5SetupPrefixIter(
|
||||
int bNewTerm = 1;
|
||||
|
||||
memset(&doclist, 0, sizeof(doclist));
|
||||
if( iIdx!=0 ){
|
||||
int dummy = 0;
|
||||
const int f2 = FTS5INDEX_QUERY_SKIPEMPTY|FTS5INDEX_QUERY_NOOUTPUT;
|
||||
pToken[0] = FTS5_MAIN_PREFIX;
|
||||
fts5MultiIterNew(p, pStruct, f2, pColset, pToken, nToken, -1, 0, &p1);
|
||||
fts5IterSetOutputCb(&p->rc, p1);
|
||||
for(;
|
||||
fts5MultiIterEof(p, p1)==0;
|
||||
fts5MultiIterNext2(p, p1, &dummy)
|
||||
){
|
||||
Fts5SegIter *pSeg = &p1->aSeg[ p1->aFirst[1].iFirst ];
|
||||
p1->xSetOutputs(p1, pSeg);
|
||||
if( p1->base.nData ){
|
||||
xAppend(p, p1->base.iRowid-iLastRowid, p1, &doclist);
|
||||
iLastRowid = p1->base.iRowid;
|
||||
}
|
||||
}
|
||||
fts5MultiIterFree(p1);
|
||||
}
|
||||
|
||||
pToken[0] = FTS5_MAIN_PREFIX + iIdx;
|
||||
fts5MultiIterNew(p, pStruct, flags, pColset, pToken, nToken, -1, 0, &p1);
|
||||
fts5IterSetOutputCb(&p->rc, p1);
|
||||
for( /* no-op */ ;
|
||||
@@ -5137,13 +5193,21 @@ static void fts5SetupPrefixIter(
|
||||
|
||||
if( p1->base.iRowid<=iLastRowid && doclist.n>0 ){
|
||||
for(i=0; p->rc==SQLITE_OK && doclist.n; i++){
|
||||
assert( i<nBuf );
|
||||
if( aBuf[i].n==0 ){
|
||||
fts5BufferSwap(&doclist, &aBuf[i]);
|
||||
fts5BufferZero(&doclist);
|
||||
}else{
|
||||
xMerge(p, &doclist, &aBuf[i]);
|
||||
fts5BufferZero(&aBuf[i]);
|
||||
int i1 = i*nMerge;
|
||||
int iStore;
|
||||
assert( i1+nMerge<=nBuf );
|
||||
for(iStore=i1; iStore<i1+nMerge; iStore++){
|
||||
if( aBuf[iStore].n==0 ){
|
||||
fts5BufferSwap(&doclist, &aBuf[iStore]);
|
||||
fts5BufferZero(&doclist);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( iStore==i1+nMerge ){
|
||||
xMerge(p, &doclist, nMerge, &aBuf[i1]);
|
||||
for(iStore=i1; iStore<i1+nMerge; iStore++){
|
||||
fts5BufferZero(&aBuf[iStore]);
|
||||
}
|
||||
}
|
||||
}
|
||||
iLastRowid = 0;
|
||||
@@ -5153,11 +5217,15 @@ static void fts5SetupPrefixIter(
|
||||
iLastRowid = p1->base.iRowid;
|
||||
}
|
||||
|
||||
for(i=0; i<nBuf; i++){
|
||||
assert( (nBuf%nMerge)==0 );
|
||||
for(i=0; i<nBuf; i+=nMerge){
|
||||
int iFree;
|
||||
if( p->rc==SQLITE_OK ){
|
||||
xMerge(p, &doclist, &aBuf[i]);
|
||||
xMerge(p, &doclist, nMerge, &aBuf[i]);
|
||||
}
|
||||
for(iFree=i; iFree<i+nMerge; iFree++){
|
||||
fts5BufferFree(&aBuf[iFree]);
|
||||
}
|
||||
fts5BufferFree(&aBuf[i]);
|
||||
}
|
||||
fts5MultiIterFree(p1);
|
||||
|
||||
@@ -5412,6 +5480,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);
|
||||
|
||||
/* Figure out which index to search and set iIdx accordingly. If this
|
||||
@@ -5433,7 +5502,9 @@ int sqlite3Fts5IndexQuery(
|
||||
if( flags & FTS5INDEX_QUERY_PREFIX ){
|
||||
int nChar = fts5IndexCharlen(pToken, nToken);
|
||||
for(iIdx=1; iIdx<=pConfig->nPrefix; iIdx++){
|
||||
if( pConfig->aPrefix[iIdx-1]==nChar ) break;
|
||||
int nIdxChar = pConfig->aPrefix[iIdx-1];
|
||||
if( nIdxChar==nChar ) break;
|
||||
if( nIdxChar==nChar+1 ) iPrefixIdx = iIdx;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5450,8 +5521,7 @@ int sqlite3Fts5IndexQuery(
|
||||
}else{
|
||||
/* Scan multiple terms in the main index */
|
||||
int bDesc = (flags & FTS5INDEX_QUERY_DESC)!=0;
|
||||
buf.p[0] = FTS5_MAIN_PREFIX;
|
||||
fts5SetupPrefixIter(p, bDesc, buf.p, nToken+1, pColset, &pRet);
|
||||
fts5SetupPrefixIter(p, bDesc, iPrefixIdx, buf.p, nToken+1, pColset,&pRet);
|
||||
assert( p->rc!=SQLITE_OK || pRet->pColset==0 );
|
||||
fts5IterSetOutputCb(&p->rc, pRet);
|
||||
if( p->rc==SQLITE_OK ){
|
||||
|
||||
@@ -8346,6 +8346,7 @@ do_catchsql_test 58.1 {
|
||||
#-------------------------------------------------------------------------
|
||||
do_test 59.0 {
|
||||
sqlite3 db {}
|
||||
sqlite3_fts5_register_matchinfo db
|
||||
db deserialize [decode_hexdb {
|
||||
.open --hexdb
|
||||
| size 32768 pagesize 4096 filename crash-96b136358d01ec.db
|
||||
@@ -8544,11 +8545,12 @@ do_test 59.0 {
|
||||
|
||||
do_catchsql_test 59.1 {
|
||||
SELECT (matchinfo(591,t1)) FROM t1 WHERE t1 MATCH 'e*e'
|
||||
} {1 {database disk image is malformed}}
|
||||
} {0 {}}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
do_test 60.0 {
|
||||
sqlite3 db {}
|
||||
sqlite3_fts5_register_matchinfo db
|
||||
db deserialize [decode_hexdb {
|
||||
.open --hexdb
|
||||
| size 32768 pagesize 4096 filename crash-c77b90b929dc92.db
|
||||
@@ -10507,6 +10509,260 @@ do_catchsql_test 71.2 {
|
||||
INSERT INTO t1(t1) VALUES('integrity-check');
|
||||
} {1 {database disk image is malformed}}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_test 72.0 {
|
||||
sqlite3 db {}
|
||||
db deserialize [decode_hexdb {
|
||||
.open --hexdb
|
||||
| size 24576 pagesize 4096 filename crash-77b86d070d0ac6.db
|
||||
| page 1 offset 0
|
||||
| 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3.
|
||||
| 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 06 .....@ ........
|
||||
| 32: 00 00 00 00 00 00 00 00 00 00 00 06 00 00 00 04 ................
|
||||
| 96: 00 00 00 00 0d 00 00 00 06 0d e2 00 0f c4 0f 6a ...............j
|
||||
| 112: 0e fc 0e 9d 0e 3d 0d e2 00 00 00 00 00 00 00 00 .....=..........
|
||||
| 3552: 00 00 59 06 06 17 21 21 01 7f 74 61 62 6c 65 74 ..Y...!!..tablet
|
||||
| 3568: 74 74 5f 63 6f 6e 66 69 67 74 74 74 5f 63 6f 6e tt_configttt_con
|
||||
| 3584: 66 69 67 06 43 52 45 41 54 45 20 54 41 42 4c 45 fig.CREATE TABLE
|
||||
| 3600: 20 27 74 74 74 5f 63 6f 6e 66 69 67 27 28 6b 20 'ttt_config'(k
|
||||
| 3616: 50 52 49 4d 41 52 59 20 4b 45 59 2c 20 76 29 20 PRIMARY KEY, v)
|
||||
| 3632: 57 49 54 48 4f 55 54 20 52 4f 57 49 44 5e 05 07 WITHOUT ROWID^..
|
||||
| 3648: 17 23 23 01 81 03 74 61 62 6c 65 74 74 74 5f 64 .##...tablettt_d
|
||||
| 3664: 6f 63 73 69 7a 65 74 74 74 5f 64 6f 63 73 69 7a ocsizettt_docsiz
|
||||
| 3680: 65 05 43 52 45 41 54 45 20 54 41 42 4c 45 20 27 e.CREATE TABLE '
|
||||
| 3696: 74 74 74 5f 64 6f 63 73 69 7a 65 27 28 69 64 20 ttt_docsize'(id
|
||||
| 3712: 49 4e 54 45 47 45 52 20 50 52 49 4d 41 52 59 20 INTEGER PRIMARY
|
||||
| 3728: 4b 45 59 2c 20 73 7a 20 42 4c 4f 42 29 5d 04 07 KEY, sz BLOB)]..
|
||||
| 3744: 17 23 23 01 81 01 74 61 62 6c 65 74 74 74 5f 63 .##...tablettt_c
|
||||
| 3760: 6f 6e 74 65 6e 74 74 74 74 5f 63 6f 6e 74 65 6e ontentttt_conten
|
||||
| 3776: 74 04 43 52 45 41 54 45 20 54 41 42 4c 45 20 27 t.CREATE TABLE '
|
||||
| 3792: 74 74 74 5f 63 6f 6e 74 65 6e 74 27 28 69 64 20 ttt_content'(id
|
||||
| 3808: 49 4e 54 45 47 45 52 20 50 52 49 4d 41 52 59 20 INTEGER PRIMARY
|
||||
| 3824: 4b 45 59 2c 20 63 30 2c 20 63 31 29 6c 03 07 17 KEY, c0, c1)l...
|
||||
| 3840: 1b 1b 01 81 2f 74 61 62 6c 65 74 74 74 5f 69 64 ..../tablettt_id
|
||||
| 3856: 78 74 74 74 5f 69 64 78 03 43 52 45 41 54 45 20 xttt_idx.CREATE
|
||||
| 3872: 54 41 42 4c 45 20 27 74 74 74 5f 69 64 78 27 28 TABLE 'ttt_idx'(
|
||||
| 3888: 73 65 67 69 64 2c 20 74 65 72 6d 2c 20 70 67 6e segid, term, pgn
|
||||
| 3904: 6f 2c 20 50 52 49 4d 41 52 59 20 4b 45 59 28 73 o, PRIMARY KEY(s
|
||||
| 3920: 65 67 69 64 2c 20 74 65 72 6d 29 29 20 57 49 54 egid, term)) WIT
|
||||
| 3936: 48 4f 55 54 20 52 4f 57 49 44 58 02 07 17 1d 1d HOUT ROWIDX.....
|
||||
| 3952: 01 81 03 74 61 62 6c 65 74 74 74 5f 64 61 74 61 ...tablettt_data
|
||||
| 3968: 74 74 74 5f 64 61 74 61 02 43 52 45 41 54 45 20 ttt_data.CREATE
|
||||
| 3984: 54 41 42 4c 45 20 27 74 74 74 5f 64 61 74 61 27 TABLE 'ttt_data'
|
||||
| 4000: 28 69 64 20 49 4e 54 45 47 45 52 20 50 52 49 4d (id INTEGER PRIM
|
||||
| 4016: 41 52 59 20 4b 45 59 2c 20 62 6c 6f 63 6b 20 42 ARY KEY, block B
|
||||
| 4032: 4c 4f 42 29 3a 01 06 17 13 13 08 5f 74 61 62 6c LOB):......_tabl
|
||||
| 4048: 65 74 74 74 74 74 74 43 52 45 41 54 45 20 56 49 ettttttCREATE VI
|
||||
| 4064: 52 54 55 41 4c 20 54 41 42 4c 45 20 74 74 74 20 RTUAL TABLE ttt
|
||||
| 4080: 55 53 49 4e 47 20 66 74 73 35 28 61 2c 20 62 29 USING fts5(a, b)
|
||||
| page 2 offset 4096
|
||||
| 0: 0d 0f 44 00 05 0e 81 00 0f e7 0e 81 0f af 0f 58 ..D............X
|
||||
| 16: 0e 98 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
| 3712: 00 15 0a 03 00 30 00 00 00 00 01 03 03 00 03 01 .....0..........
|
||||
| 3728: 01 01 02 01 01 03 01 01 81 24 8c 80 80 80 80 01 .........$......
|
||||
| 3744: 04 00 82 4c 00 00 00 9b 02 30 65 03 1a 02 05 05 ...L.....0e.....
|
||||
| 3760: 07 05 01 01 04 03 03 08 03 03 01 2e 02 05 05 07 ................
|
||||
| 3776: 05 07 05 07 05 01 01 04 03 03 08 03 03 08 03 03 ................
|
||||
| 3792: 08 03 03 02 01 65 03 1e 03 05 05 04 05 05 01 01 .....e..........
|
||||
| 3808: 03 06 04 04 06 04 03 01 36 03 05 05 04 05 05 04 ........6.......
|
||||
| 3824: 05 05 04 05 05 01 01 03 06 04 04 06 04 04 06 04 ................
|
||||
| 3840: 04 06 04 03 03 01 65 03 14 04 05 07 05 05 01 01 ......e.........
|
||||
| 3856: 02 08 0a 01 20 04 05 07 05 07 05 07 05 05 01 01 .... ...........
|
||||
| 3872: 02 08 0a 09 fa 04 01 65 03 02 0a 01 06 0a 1a 0a .......e........
|
||||
| 3888: 05 01 65 03 06 01 01 0a 01 0a 01 01 0a 0a 0a 04 ..e.............
|
||||
| 3904: 2b 31 21 0b 0f ef 00 14 2a 00 00 00 00 01 02 02 +1!.....*.......
|
||||
| 3920: 00 02 01 01 01 02 01 01 50 88 80 80 80 80 01 04 ........P.......
|
||||
| 3936: 00 81 24 00 00 00 47 02 30 65 02 1a 02 05 05 07 ..$...G.0e......
|
||||
| 3952: 05 01 01 04 03 03 08 03 03 02 01 65 02 1e 03 05 ...........e....
|
||||
| 3968: 05 04 05 05 01 01 03 06 04 04 06 04 03 03 01 65 ...............e
|
||||
| 3984: 02 14 04 05 07 05 05 01 01 02 08 0a 04 01 65 02 ..............e.
|
||||
| 4000: 02 0a 05 01 65 02 06 01 01 0a 04 12 14 0f 06 31 ....e..........1
|
||||
| 4016: 84 80 80 80 80 01 03 00 68 00 00 00 2b 02 30 65 ........h...+.0e
|
||||
| 4032: 01 10 02 05 05 01 01 04 03 9f 02 01 65 01 12 03 ............e...
|
||||
| 4048: 05 05 01 01 03 06 04 03 03 01 65 01 0e 14 05 05 ..........e.....
|
||||
| 4064: 01 01 02 08 04 0d 0e 06 01 03 00 12 04 4c 4c 00 .............LL.
|
||||
| 4080: 00 00 11 24 00 00 00 00 01 01 01 00 01 01 01 01 ...$............
|
||||
| page 3 offset 8192
|
||||
| 0: 0a 00 00 00 03 0f 00 00 00 00 00 00 00 00 00 00 ................
|
||||
| 4064: 00 00 00 00 00 00 00 00 00 00 00 00 06 04 01 0c ................
|
||||
| 4080: 01 03 02 06 04 01 0c 01 02 02 05 04 09 0c 01 02 ................
|
||||
| page 4 offset 12288
|
||||
| 0: 0d 00 00 00 04 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
| 3600: 00 00 00 00 00 00 00 00 00 00 81 52 04 06 00 81 ...........R....
|
||||
| 3616: 5d 81 55 65 20 65 65 20 65 65 65 20 65 20 65 65 ].Ue ee eee e ee
|
||||
| 3632: 20 65 65 65 20 65 20 65 65 20 65 65 65 65 20 65 eee e ee eeee e
|
||||
| 3648: 65 20 65 65 65 20 65 20 65 65 20 65 65 65 20 65 e eee e ee eee e
|
||||
| 3664: 20 65 65 20 65 65 55 65 20 65 65 20 65 65 65 20 ee eeUe ee eee
|
||||
| 3680: 65 20 65 65 20 65 65 65 20 65 20 65 65 20 65 65 e ee eee e ee ee
|
||||
| 3696: 65 65 20 65 65 20 65 65 65 20 65 20 65 65 20 65 ee ee eee e ee e
|
||||
| 3712: 65 65 20 65 20 65 65 20 65 65 65 65 65 65 20 65 ee e ee eeeeee e
|
||||
| 3728: 65 20 65 20 65 20 65 20 65 65 20 65 85 65 20 65 e e e e ee e.e e
|
||||
| 3744: 65 20 65 65 65 65 65 20 65 65 20 65 20 65 20 65 e eeeee ee e e e
|
||||
| 3760: 20 65 65 20 65 65 65 20 65 65 20 65 65 65 65 65 ee eee ee eeeee
|
||||
| 3776: 20 65 65 20 65 20 65 20 65 20 65 65 20 65 65 65 ee e e e ee eee
|
||||
| 3792: 20 65 65 20 65 65 65 65 65 20 65 65 20 65 20 65 ee eeeee ee e e
|
||||
| 3808: 20 65 20 65 65 20 65 65 65 20 65 65 20 65 65 6a e ee eee ee eej
|
||||
| 3824: 03 04 00 75 71 65 20 65 65 20 65 65 65 20 65 20 ...uqe ee eee e
|
||||
| 3840: 65 65 20 65 65 65 20 65 20 65 65 20 65 65 65 65 ee eee e ee eeee
|
||||
| 3856: 20 65 65 20 65 65 65 20 65 20 65 65 20 65 65 65 ee eee e ee eee
|
||||
| 3872: 20 65 20 65 65 20 65 65 65 65 65 65 20 65 65 20 e ee eeeeee ee
|
||||
| 3888: 65 20 65 20 65 20 65 64 20 65 65 65 20 65 65 20 e e e ed eee ee
|
||||
| 3904: 65 65 65 65 65 20 65 65 20 65 20 65 20 65 10 65 eeeee ee e e e.e
|
||||
| 3920: 65 20 65 65 65 10 65 65 20 65 65 6a 02 04 00 75 e eee.ee eej...u
|
||||
| 3936: 71 65 20 65 65 20 65 65 65 20 65 20 65 65 20 65 qe ee eee e ee e
|
||||
| 3952: 65 65 20 65 20 65 65 20 65 65 65 65 20 65 65 20 ee e ee eeee ee
|
||||
| 3968: 65 65 65 20 65 20 65 65 20 65 65 65 20 65 20 65 eee e ee eee e e
|
||||
| 3984: 65 20 65 65 65 66 65 65 20 65 65 20 65 20 65 20 e eeefee ee e e
|
||||
| 4000: 65 88 65 65 20 65 65 65 30 65 65 20 65 65 65 65 e.ee eee0ee eeee
|
||||
| 4016: 65 20 65 65 20 65 20 65 20 65 20 65 65 20 65 65 e ee e e e ee ee
|
||||
| 4032: 65 20 65 65 20 65 65 37 01 04 00 41 3f 65 20 65 e ee ee7...A?e e
|
||||
| 4048: 65 20 65 65 65 20 65 20 65 65 20 65 65 65 20 65 e eee e ee eee e
|
||||
| 4064: 20 65 65 20 65 65 65 65 65 65 20 65 65 20 65 20 ee eeeeee ee e
|
||||
| 4080: 65 20 65 20 65 65 20 65 65 65 20 65 65 20 65 65 e e ee eee ee ee
|
||||
| page 5 offset 16384
|
||||
| 0: 0d 00 00 00 04 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
| 4064: 00 00 00 00 05 04 03 00 10 21 21 05 03 03 00 10 .........!!.....
|
||||
| 4080: 11 11 05 02 03 00 10 11 11 05 01 03 00 10 09 09 ................
|
||||
| page 6 offset 20480
|
||||
| 0: 0a 00 00 00 01 0f f4 00 0f f4 00 00 00 00 00 00 ................
|
||||
| 4080: 00 00 00 00 0b 03 1b 01 76 65 72 73 69 6f 6e 04 ........version.
|
||||
| end crash-77b86d070d0ac6.db
|
||||
}]} {}
|
||||
|
||||
do_catchsql_test 72.1 {
|
||||
INSERT INTO ttt(ttt) VALUES('integrity-check');
|
||||
} {1 {database disk image is malformed}}
|
||||
|
||||
do_catchsql_test 72.1 {
|
||||
SELECT 1 FROM ttt('e* NOT ee*');
|
||||
} {1 {database disk image is malformed}}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_test 73.0 {
|
||||
sqlite3 db {}
|
||||
db deserialize [decode_hexdb {
|
||||
.open --hexdb
|
||||
| size 24576 pagesize 4096 filename crash-b02ca2cc4d7dda.db
|
||||
| page 1 offset 0
|
||||
| 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3.
|
||||
| 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 06 .....@ ........
|
||||
| 32: 00 00 00 00 00 00 00 00 00 00 00 06 00 00 00 04 ................
|
||||
| 96: 00 00 00 00 0d 00 00 00 06 0d e2 00 0f c4 0f 6a ...............j
|
||||
| 112: 0e fc 0e 9d 0e 3d 0d e2 00 00 00 00 00 00 00 00 .....=..........
|
||||
| 3552: 00 00 59 06 06 17 21 21 01 7f 74 61 62 6c 65 74 ..Y...!!..tablet
|
||||
| 3568: 74 74 5f 63 6f 6e 66 69 67 74 74 74 5f 63 6f 6e tt_configttt_con
|
||||
| 3584: 66 69 67 06 43 52 45 41 54 45 20 54 41 42 4c 45 fig.CREATE TABLE
|
||||
| 3600: 20 27 74 74 74 5f 63 6f 6e 66 69 67 27 28 6b 20 'ttt_config'(k
|
||||
| 3616: 50 52 49 4d 41 52 59 20 4b 45 59 2c 20 76 29 20 PRIMARY KEY, v)
|
||||
| 3632: 57 49 54 48 4f 55 54 20 52 4f 57 49 44 5e 05 07 WITHOUT ROWID^..
|
||||
| 3648: 17 23 23 01 81 03 74 61 62 6c 65 74 74 74 5f 64 .##...tablettt_d
|
||||
| 3664: 6f 63 73 69 7a 65 74 74 74 5f 64 6f 63 73 69 7a ocsizettt_docsiz
|
||||
| 3680: 65 05 43 52 45 41 54 45 20 54 41 42 4c 45 20 27 e.CREATE TABLE '
|
||||
| 3696: 74 74 74 5f 64 6f 63 73 69 7a 65 27 28 69 64 20 ttt_docsize'(id
|
||||
| 3712: 49 4e 54 45 47 45 52 20 50 52 49 4d 41 52 59 20 INTEGER PRIMARY
|
||||
| 3728: 4b 45 59 2c 20 73 7a 20 42 4c 4f 42 29 5d 04 07 KEY, sz BLOB)]..
|
||||
| 3744: 17 23 23 01 81 01 74 61 62 6c 65 74 74 74 5f 63 .##...tablettt_c
|
||||
| 3760: 6f 6e 74 65 6e 74 74 74 74 5f 63 6f 6e 74 65 6e ontentttt_conten
|
||||
| 3776: 74 04 43 52 45 41 54 45 20 54 41 42 4c 45 20 27 t.CREATE TABLE '
|
||||
| 3792: 74 74 74 5f 63 6f 6e 74 65 6e 74 27 28 69 64 20 ttt_content'(id
|
||||
| 3808: 49 4e 54 45 47 45 52 20 50 52 49 4d 41 52 59 20 INTEGER PRIMARY
|
||||
| 3824: 4b 45 59 2c 20 63 30 2c 20 63 31 29 6c 03 07 17 KEY, c0, c1)l...
|
||||
| 3840: 1b 1b 01 81 2f 74 61 62 6c 65 74 74 74 5f 69 64 ..../tablettt_id
|
||||
| 3856: 78 74 74 74 5f 69 64 78 03 43 52 45 41 54 45 20 xttt_idx.CREATE
|
||||
| 3872: 54 41 42 4c 45 20 27 74 74 74 5f 69 64 78 27 28 TABLE 'ttt_idx'(
|
||||
| 3888: 73 65 67 69 64 2c 20 74 65 72 6d 2c 20 70 67 6e segid, term, pgn
|
||||
| 3904: 6f 2c 20 50 52 49 4d 41 52 59 20 4b 45 59 28 73 o, PRIMARY KEY(s
|
||||
| 3920: 65 67 69 64 2c 20 74 65 72 6d 29 29 20 57 49 54 egid, term)) WIT
|
||||
| 3936: 48 4f 55 54 20 52 4f 57 49 44 58 02 07 17 1d 1d HOUT ROWIDX.....
|
||||
| 3952: 01 81 03 74 61 62 6c 65 74 74 74 5f 64 61 74 61 ...tablettt_data
|
||||
| 3968: 74 74 74 5f 64 61 74 61 02 43 52 45 41 54 45 20 ttt_data.CREATE
|
||||
| 3984: 54 41 42 4c 45 20 27 74 74 74 5f 64 61 74 61 27 TABLE 'ttt_data'
|
||||
| 4000: 28 69 65 20 49 4e 54 45 47 45 52 20 50 52 49 4d (ie INTEGER PRIM
|
||||
| 4016: 41 52 59 20 4b 45 59 2c 20 62 6c 6f 63 6b 20 42 ARY KEY, block B
|
||||
| 4032: 4c 4f 42 29 3a 01 06 17 13 13 08 5f 74 61 62 6c LOB):......_tabl
|
||||
| 4048: 65 74 74 74 74 74 74 43 52 45 41 54 45 20 56 49 ettttttCREATE VI
|
||||
| 4064: 52 54 55 41 4c 20 54 41 42 4c 45 20 74 74 74 20 RTUAL TABLE ttt
|
||||
| 4080: 55 53 49 4e 47 20 66 74 73 35 28 61 2c 20 62 29 USING fts5(a, b)
|
||||
| page 2 offset 4096
|
||||
| 0: 0d 0f 44 00 05 0e 81 00 0f e7 0e 81 0f af 0f 58 ..D............X
|
||||
| 16: 0e 98 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
| 3712: 00 15 0a 03 00 30 00 00 00 00 01 03 03 00 03 01 .....0..........
|
||||
| 3728: 01 01 02 01 01 03 01 01 81 24 8c 80 80 80 80 01 .........$......
|
||||
| 3744: 04 00 82 4c 00 00 00 9b 02 30 65 03 1a 02 05 05 ...L.....0e.....
|
||||
| 3760: 07 05 01 01 04 03 03 08 03 03 01 2e 02 05 05 07 ................
|
||||
| 3776: 05 07 05 07 05 01 01 04 03 03 08 03 03 08 03 03 ................
|
||||
| 3792: 08 03 03 02 01 65 03 1e 03 05 05 04 05 05 01 01 .....e..........
|
||||
| 3808: 03 06 04 04 06 04 03 01 36 03 05 05 04 05 05 04 ........6.......
|
||||
| 3824: 05 04 f4 04 05 01 01 03 06 04 04 06 04 04 06 04 ................
|
||||
| 3840: 04 06 04 db 03 01 65 03 14 04 05 07 05 05 01 01 ......e.........
|
||||
| 3856: 02 08 0a 01 20 04 05 07 05 07 05 07 05 05 01 01 .... ...........
|
||||
| 3872: 02 08 0a 0a 0a 04 01 65 03 02 0a 01 06 0a 0a 0a .......e........
|
||||
| 3888: 05 01 65 03 06 01 01 0a 01 0a 01 01 0a 0a 0a 04 ..e.............
|
||||
| 3904: 2b 31 21 0b 0f ef 00 14 2a 00 00 00 00 01 02 02 +1!.....*.......
|
||||
| 3920: 00 02 01 01 01 02 01 01 50 88 80 80 80 80 01 04 ........P.......
|
||||
| 3936: 00 81 24 00 00 00 47 02 30 65 02 1a 02 05 05 07 ..$...G.0e......
|
||||
| 3952: 05 01 01 04 03 03 08 03 03 02 01 65 02 1e 03 05 ...........e....
|
||||
| 3968: 05 04 05 05 01 01 03 06 09 14 06 04 03 03 01 65 ...............e
|
||||
| 3984: 02 14 04 05 07 05 05 01 01 02 08 ed 04 01 65 02 ..............e.
|
||||
| 4000: 02 0a 05 01 65 02 06 01 01 0a 04 12 14 0f 06 31 ....e..........1
|
||||
| 4016: 84 80 80 80 80 01 03 00 68 00 00 00 2b 02 30 65 ........h...+.0e
|
||||
| 4032: 01 10 02 05 05 01 01 04 03 03 02 01 55 01 12 03 ............U...
|
||||
| 4048: 05 05 01 01 03 06 05 03 03 01 65 01 0e 04 05 05 ..........e.....
|
||||
| 4064: 01 01 02 08 04 0d 0e 06 01 03 00 12 04 4c 4c 00 .............LL.
|
||||
| 4080: 00 00 11 24 00 00 00 00 01 0f c1 00 01 01 01 01 ...$............
|
||||
| page 3 offset 8192
|
||||
| 0: 0a 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
| 4064: 00 00 00 00 00 00 00 00 00 00 00 00 06 04 01 0c ................
|
||||
| 4080: 01 03 02 06 04 01 0c 01 02 02 05 04 09 0c 01 02 ................
|
||||
| page 4 offset 12288
|
||||
| 0: 0d 00 00 00 04 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
| 3600: 00 00 00 00 00 00 00 00 00 00 81 52 04 06 00 81 ...........R....
|
||||
| 3616: 5d 81 55 65 20 65 65 20 65 65 65 20 65 20 65 65 ].Ue ee eee e ee
|
||||
| 3632: 20 65 65 65 20 65 20 65 65 20 65 65 65 65 20 65 eee e ee eeee e
|
||||
| 3648: 65 20 65 65 65 20 65 20 65 65 20 65 65 65 20 65 e eee e ee eee e
|
||||
| 3664: 20 65 65 20 65 65 65 65 20 65 65 20 65 65 65 20 ee eeee ee eee
|
||||
| 3680: 65 20 65 65 20 65 65 65 20 65 20 65 65 20 65 65 e ee eee e ee ee
|
||||
| 3696: 65 65 20 65 65 20 65 65 65 20 65 20 65 65 20 65 ee ee eee e ee e
|
||||
| 3712: 65 65 20 65 20 65 65 20 65 65 65 65 65 65 20 65 ee e ee eeeeee e
|
||||
| 3728: 65 20 65 20 65 20 65 20 65 65 20 65 65 65 20 65 e e e e ee eee e
|
||||
| 3744: 65 20 65 65 65 65 65 20 65 65 20 65 20 65 20 65 e eeeee ee e e e
|
||||
| 3760: 20 65 65 20 65 62 d5 20 65 65 20 65 65 65 65 65 ee eb. ee eeeee
|
||||
| 3776: 20 65 65 20 65 20 65 20 65 20 65 65 20 65 65 65 ee e e e ee eee
|
||||
| 3792: 20 65 65 20 65 65 65 65 65 20 65 65 20 65 21 65 ee eeeee ee e!e
|
||||
| 3808: 20 65 20 65 65 20 65 65 65 20 65 65 20 65 65 6a e ee eee ee eej
|
||||
| 3824: 03 04 00 75 71 65 20 65 65 10 65 65 65 20 65 20 ...uqe ee.eee e
|
||||
| 3840: 65 65 20 65 65 65 20 65 20 65 65 20 65 65 65 65 ee eee e ee eeee
|
||||
| 3856: 20 65 65 20 65 65 65 20 65 20 65 65 20 65 65 65 ee eee e ee eee
|
||||
| 3872: 20 65 20 65 65 20 65 65 65 65 65 65 20 65 65 20 e ee eeeeee ee
|
||||
| 3888: 65 20 65 20 65 20 65 65 20 65 65 65 20 62 55 20 e e e ee eee bU
|
||||
| 3904: 65 65 65 65 65 20 65 65 20 65 20 65 20 65 20 65 eeeee ee e e e e
|
||||
| 3920: 65 20 65 65 65 20 55 65 20 65 65 6a 02 04 00 75 e eee Ue eej...u
|
||||
| 3936: 71 65 20 65 65 20 65 65 65 20 65 10 65 65 20 65 qe ee eee e.ee e
|
||||
| 3952: 65 65 20 65 20 65 65 20 65 65 65 65 20 65 65 20 ee e ee eeee ee
|
||||
| 3968: 65 65 65 20 65 20 65 65 20 65 65 65 20 65 20 65 eee e ee eee e e
|
||||
| 3984: 65 20 65 65 65 65 65 65 20 65 65 20 65 20 65 20 e eeeeee ee e e
|
||||
| 4000: 65 20 65 65 20 65 65 65 20 65 65 20 65 65 65 65 e ee eee ee eeee
|
||||
| 4016: 65 20 65 65 20 65 20 65 20 65 20 65 65 20 65 65 e ee e e e ee ee
|
||||
| 4032: 65 20 65 65 21 65 65 37 0a 04 00 41 3f 65 20 65 e ee!ee7...A?e e
|
||||
| 4048: 65 20 65 65 65 20 65 20 65 65 20 65 65 65 20 65 e eee e ee eee e
|
||||
| 4064: 20 65 65 20 65 65 65 65 65 65 20 65 65 20 65 20 ee eeeeee ee e
|
||||
| 4080: 65 20 65 20 65 65 20 65 65 65 20 65 65 20 65 65 e e ee eee ee ee
|
||||
| page 5 offset 16384
|
||||
| 0: 0d 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
| 4064: 00 00 00 00 05 04 03 00 10 21 21 05 13 03 00 10 .........!!.....
|
||||
| 4080: 11 11 05 02 03 00 10 11 11 05 01 03 00 10 09 09 ................
|
||||
| page 6 offset 20480
|
||||
| 0: 0a 00 00 00 01 0f f4 00 0f f4 00 00 00 00 00 00 ................
|
||||
| 4080: 00 00 00 00 0b 03 1b 01 76 65 72 73 69 6f 6e 04 ........version.
|
||||
| end crash-b02ca2cc4d7dda.db
|
||||
}]} {}
|
||||
|
||||
do_catchsql_test 73.1 {
|
||||
SELECT snippet(ttt,ttt, NOT 54 ),
|
||||
* FROM ttt('e* NOT ee*e* NOT ee* NOT ee*e* NOT e*') ;
|
||||
} {1 {database disk image is malformed}}
|
||||
|
||||
sqlite3_fts5_may_be_corrupt 0
|
||||
finish_test
|
||||
|
||||
@@ -29,6 +29,8 @@ do_execsql_test 1.0 {
|
||||
INSERT INTO ttt SELECT a||a, b||b FROM ttt;
|
||||
}
|
||||
|
||||
expr srand(1)
|
||||
|
||||
proc mutate {blob i} {
|
||||
set o [expr {$i % [string length $blob]}]
|
||||
set a [string range $blob 0 $o-1]
|
||||
|
||||
@@ -91,6 +91,27 @@ do_catchsql_test 2.4 {
|
||||
SELECT rowid FROM test_idx WHERE test_idx MATCH 'two' ORDER BY rank;
|
||||
} {1 {database disk image is malformed}}
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_execsql_test 3.0 {
|
||||
CREATE VIRTUAL TABLE tx USING fts5(a, b, c, d, content=);
|
||||
INSERT INTO tx(rowid, a, c) VALUES(1, 'abc def', 'a b c');
|
||||
INSERT INTO tx(rowid, a, c) VALUES(5, 'a b c', 'a b d def');
|
||||
}
|
||||
do_execsql_test 3.1 {
|
||||
INSERT INTO tx(tx, rowid, a, b, c, d)
|
||||
VALUES('delete', 5, 'a b c', NULL, 'a b d def', NULL);
|
||||
}
|
||||
do_execsql_test 3.2 {
|
||||
INSERT INTO tx(tx) VALUES('integrity-check');
|
||||
}
|
||||
do_execsql_test 3.3 {
|
||||
INSERT INTO tx(tx, rowid, a, b, c, d)
|
||||
VALUES('delete', 1, 'abc def', NULL, 'a b c', NULL);
|
||||
}
|
||||
do_execsql_test 3.4 {
|
||||
INSERT INTO tx(tx) VALUES('integrity-check');
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
# 2020 Dec 3
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
# This file contains tests focused on prefix indexes.
|
||||
#
|
||||
|
||||
source [file join [file dirname [info script]] fts5_common.tcl]
|
||||
set testprefix fts5prefix2
|
||||
|
||||
# If SQLITE_ENABLE_FTS5 is defined, omit this file.
|
||||
ifcapable !fts5 {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
foreach p {3 2 1} {
|
||||
reset_db
|
||||
do_execsql_test 1.$p.0 "
|
||||
CREATE VIRTUAL TABLE t1 USING fts5(xyz, prefix=$p);
|
||||
"
|
||||
do_execsql_test 1.$p.1 {
|
||||
INSERT INTO t1 VALUES
|
||||
('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 f.');
|
||||
}
|
||||
|
||||
do_execsql_test 1.$p.2 {
|
||||
SELECT highlight(t1, 0, '[', ']') FROM t1('f*');
|
||||
} {
|
||||
{May you [find] [forgiveness] [for] yourself and [forgive] others.}
|
||||
{May you share [freely], never taking more than you give [f].}
|
||||
}
|
||||
}
|
||||
|
||||
do_execsql_test 2.0 {
|
||||
CREATE VIRTUAL TABLE t2 USING fts5(one, prefix=3);
|
||||
INSERT INTO t2 VALUES('top');
|
||||
INSERT INTO t2 VALUES('to');
|
||||
INSERT INTO t2 VALUES('tommy');
|
||||
}
|
||||
|
||||
do_execsql_test 2.1 {
|
||||
SELECT * FROM t2('to*');
|
||||
} {top to tommy}
|
||||
|
||||
|
||||
|
||||
finish_test
|
||||
+51
-1
@@ -356,6 +356,41 @@ static void cksmVerifyFunc(
|
||||
sqlite3_result_int(context, memcmp(data+nByte-8,cksum,8)==0);
|
||||
}
|
||||
|
||||
#ifdef SQLITE_CKSUMVFS_INIT_FUNCNAME
|
||||
/*
|
||||
** SQL function: initialize_cksumvfs(SCHEMANAME)
|
||||
**
|
||||
** This SQL functions (whose name is actually determined at compile-time
|
||||
** by the value of the SQLITE_CKSUMVFS_INIT_FUNCNAME macro) invokes:
|
||||
**
|
||||
** sqlite3_file_control(db, SCHEMANAME, SQLITE_FCNTL_RESERVE_BYTE, &n);
|
||||
**
|
||||
** In order to set the reserve bytes value to 8, so that cksumvfs will
|
||||
** operation. This feature is provided (if and only if the
|
||||
** SQLITE_CKSUMVFS_INIT_FUNCNAME compile-time option is set to a string
|
||||
** which is the name of the SQL function) so as to provide the ability
|
||||
** to invoke the file-control in programming languages that lack
|
||||
** direct access to the sqlite3_file_control() interface (ex: Java).
|
||||
**
|
||||
** This interface is undocumented, apart from this comment. Usage
|
||||
** example:
|
||||
**
|
||||
** 1. Compile with -DSQLITE_CKSUMVFS_INIT_FUNCNAME="ckvfs_init"
|
||||
** 2. Run: "SELECT cksum_init('main'); VACUUM;"
|
||||
*/
|
||||
static void cksmInitFunc(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
int nByte = 8;
|
||||
const char *zSchemaName = (const char*)sqlite3_value_text(argv[0]);
|
||||
sqlite3 *db = sqlite3_context_db_handle(context);
|
||||
sqlite3_file_control(db, zSchemaName, SQLITE_FCNTL_RESERVE_BYTES, &nByte);
|
||||
/* Return NULL */
|
||||
}
|
||||
#endif /* SQLITE_CKSUMBFS_INIT_FUNCNAME */
|
||||
|
||||
/*
|
||||
** Close a cksm-file.
|
||||
*/
|
||||
@@ -715,7 +750,17 @@ static int cksmGetLastError(sqlite3_vfs *pVfs, int a, char *b){
|
||||
return ORIGVFS(pVfs)->xGetLastError(ORIGVFS(pVfs), a, b);
|
||||
}
|
||||
static int cksmCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *p){
|
||||
return ORIGVFS(pVfs)->xCurrentTimeInt64(ORIGVFS(pVfs), p);
|
||||
sqlite3_vfs *pOrig = ORIGVFS(pVfs);
|
||||
int rc;
|
||||
assert( pOrig->iVersion>=2 );
|
||||
if( pOrig->xCurrentTimeInt64 ){
|
||||
rc = pOrig->xCurrentTimeInt64(pOrig, p);
|
||||
}else{
|
||||
double r;
|
||||
rc = pOrig->xCurrentTime(pOrig, &r);
|
||||
*p = (sqlite3_int64)(r*86400000.0);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
static int cksmSetSystemCall(
|
||||
sqlite3_vfs *pVfs,
|
||||
@@ -746,6 +791,11 @@ static int cksmRegisterFunc(
|
||||
rc = sqlite3_create_function(db, "verify_checksum", 1,
|
||||
SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_DETERMINISTIC,
|
||||
0, cksmVerifyFunc, 0, 0);
|
||||
#ifdef SQLITE_CKSUMVFS_INIT_FUNCNAME
|
||||
(void)sqlite3_create_function(db, SQLITE_CKSUMVFS_INIT_FUNCNAME, 1,
|
||||
SQLITE_UTF8|SQLITE_DIRECTONLY,
|
||||
0, cksmInitFunc, 0, 0);
|
||||
#endif
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
+13
-3
@@ -247,7 +247,8 @@ static int seriesEof(sqlite3_vtab_cursor *cur){
|
||||
** 4: step=VALUE
|
||||
**
|
||||
** Also, if bit 8 is set, that means that the series should be output
|
||||
** in descending order rather than in ascending order.
|
||||
** in descending order rather than in ascending order. If bit 16 is
|
||||
** set, then output must appear in ascending order.
|
||||
**
|
||||
** This routine should initialize the cursor and position it so that it
|
||||
** is pointing at the first row, or pointing off the end of the table
|
||||
@@ -273,7 +274,12 @@ static int seriesFilter(
|
||||
}
|
||||
if( idxNum & 4 ){
|
||||
pCur->iStep = sqlite3_value_int64(argv[i++]);
|
||||
if( pCur->iStep<1 ) pCur->iStep = 1;
|
||||
if( pCur->iStep==0 ){
|
||||
pCur->iStep = 1;
|
||||
}else if( pCur->iStep<0 ){
|
||||
pCur->iStep = -pCur->iStep;
|
||||
if( (idxNum & 16)==0 ) idxNum |= 8;
|
||||
}
|
||||
}else{
|
||||
pCur->iStep = 1;
|
||||
}
|
||||
@@ -367,7 +373,11 @@ static int seriesBestIndex(
|
||||
pIdxInfo->estimatedCost = (double)(2 - ((idxNum&4)!=0));
|
||||
pIdxInfo->estimatedRows = 1000;
|
||||
if( pIdxInfo->nOrderBy==1 ){
|
||||
if( pIdxInfo->aOrderBy[0].desc ) idxNum |= 8;
|
||||
if( pIdxInfo->aOrderBy[0].desc ){
|
||||
idxNum |= 8;
|
||||
}else{
|
||||
idxNum |= 16;
|
||||
}
|
||||
pIdxInfo->orderByConsumed = 1;
|
||||
}
|
||||
}else{
|
||||
|
||||
+8
-3
@@ -31,7 +31,10 @@ SQLITE_EXTENSION_INIT1
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#ifndef SQLITE_AMALGAMATION
|
||||
typedef sqlite3_uint64 u64;
|
||||
#endif /* SQLITE_AMALGAMATION */
|
||||
|
||||
/******************************************************************************
|
||||
** The Hash Engine
|
||||
@@ -621,9 +624,11 @@ static void sha3QueryFunc(
|
||||
}
|
||||
nCol = sqlite3_column_count(pStmt);
|
||||
z = sqlite3_sql(pStmt);
|
||||
n = (int)strlen(z);
|
||||
hash_step_vformat(&cx,"S%d:",n);
|
||||
SHA3Update(&cx,(unsigned char*)z,n);
|
||||
if( z ){
|
||||
n = (int)strlen(z);
|
||||
hash_step_vformat(&cx,"S%d:",n);
|
||||
SHA3Update(&cx,(unsigned char*)z,n);
|
||||
}
|
||||
|
||||
/* Compute a hash over the result of the query */
|
||||
while( SQLITE_ROW==sqlite3_step(pStmt) ){
|
||||
|
||||
@@ -183,6 +183,13 @@ int main(int argc, char **argv){
|
||||
break;
|
||||
}
|
||||
|
||||
if( nStatStep>0 ){
|
||||
sqlite3_int64 nUsed;
|
||||
sqlite3_int64 nHighwater;
|
||||
sqlite3_status64(SQLITE_STATUS_MEMORY_USED, &nUsed, &nHighwater, 0);
|
||||
fprintf(stdout, "memory used=%lld highwater=%lld\n", nUsed, nHighwater);
|
||||
}
|
||||
|
||||
sqlite3_free(zErrmsg);
|
||||
return (rc==SQLITE_OK || rc==SQLITE_DONE) ? 0 : 1;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
# 2020 December 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 regression tests for the SQLite sessions module
|
||||
# Specifically, for the sqlite3session_memory_used() API.
|
||||
#
|
||||
|
||||
if {![info exists testdir]} {
|
||||
set testdir [file join [file dirname [info script]] .. .. test]
|
||||
}
|
||||
source [file join [file dirname [info script]] session_common.tcl]
|
||||
source $testdir/tester.tcl
|
||||
ifcapable !session {finish_test; return}
|
||||
|
||||
set testprefix sessionmem
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE TABLE t1(i INTEGER PRIMARY KEY, x, y);
|
||||
CREATE TABLE t2(i INTEGER, x, y, PRIMARY KEY(x, y));
|
||||
}
|
||||
|
||||
do_test 1.1 {
|
||||
sqlite3session S db main
|
||||
S attach *
|
||||
} {}
|
||||
|
||||
foreach {tn sql eRes} {
|
||||
1 { INSERT INTO t1 VALUES(1, 2, 3) } 1
|
||||
2 { UPDATE t1 SET x=5 } 0
|
||||
3 { UPDATE t1 SET i=5 } 1
|
||||
4 { DELETE FROM t1 } 0
|
||||
5 { INSERT INTO t1 VALUES(1, 2, 3) } 0
|
||||
6 { INSERT INTO t1 VALUES(5, 2, 3) } 0
|
||||
7 { INSERT INTO t2 VALUES('a', 'b', 'c') } 1
|
||||
8 { INSERT INTO t2 VALUES('d', 'e', 'f') } 1
|
||||
9 { UPDATE t2 SET i='e' } 0
|
||||
} {
|
||||
set mem1 [S memory_used]
|
||||
do_test 1.2.$tn.(mu=$mem1) {
|
||||
execsql $sql
|
||||
set mem2 [S memory_used]
|
||||
expr {$mem2 > $mem1}
|
||||
} $eRes
|
||||
}
|
||||
|
||||
do_test 1.3 {
|
||||
S delete
|
||||
} {}
|
||||
|
||||
finish_test
|
||||
@@ -48,6 +48,7 @@ struct sqlite3_session {
|
||||
int rc; /* Non-zero if an error has occurred */
|
||||
void *pFilterCtx; /* First argument to pass to xTableFilter */
|
||||
int (*xTableFilter)(void *pCtx, const char *zTab);
|
||||
i64 nMalloc; /* Number of bytes of data allocated */
|
||||
sqlite3_value *pZeroBlob; /* Value containing X'' */
|
||||
sqlite3_session *pNext; /* Next session object on same db. */
|
||||
SessionTable *pTable; /* List of attached tables */
|
||||
@@ -431,6 +432,26 @@ static int sessionSerializeValue(
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Allocate and return a pointer to a buffer nByte bytes in size. If
|
||||
** pSession is not NULL, increase the sqlite3_session.nMalloc variable
|
||||
** by the number of bytes allocated.
|
||||
*/
|
||||
static void *sessionMalloc64(sqlite3_session *pSession, i64 nByte){
|
||||
void *pRet = sqlite3_malloc64(nByte);
|
||||
if( pSession ) pSession->nMalloc += sqlite3_msize(pRet);
|
||||
return pRet;
|
||||
}
|
||||
|
||||
/*
|
||||
** Free buffer pFree, which must have been allocated by an earlier
|
||||
** call to sessionMalloc64(). If pSession is not NULL, decrease the
|
||||
** sqlite3_session.nMalloc counter by the number of bytes freed.
|
||||
*/
|
||||
static void sessionFree(sqlite3_session *pSession, void *pFree){
|
||||
if( pSession ) pSession->nMalloc -= sqlite3_msize(pFree);
|
||||
sqlite3_free(pFree);
|
||||
}
|
||||
|
||||
/*
|
||||
** This macro is used to calculate hash key values for data structures. In
|
||||
@@ -898,13 +919,19 @@ static int sessionPreupdateEqual(
|
||||
** Growing the hash table in this case is a performance optimization only,
|
||||
** it is not required for correct operation.
|
||||
*/
|
||||
static int sessionGrowHash(int bPatchset, SessionTable *pTab){
|
||||
static int sessionGrowHash(
|
||||
sqlite3_session *pSession, /* For memory accounting. May be NULL */
|
||||
int bPatchset,
|
||||
SessionTable *pTab
|
||||
){
|
||||
if( pTab->nChange==0 || pTab->nEntry>=(pTab->nChange/2) ){
|
||||
int i;
|
||||
SessionChange **apNew;
|
||||
sqlite3_int64 nNew = 2*(sqlite3_int64)(pTab->nChange ? pTab->nChange : 128);
|
||||
|
||||
apNew = (SessionChange **)sqlite3_malloc64(sizeof(SessionChange *) * nNew);
|
||||
apNew = (SessionChange**)sessionMalloc64(
|
||||
pSession, sizeof(SessionChange*) * nNew
|
||||
);
|
||||
if( apNew==0 ){
|
||||
if( pTab->nChange==0 ){
|
||||
return SQLITE_ERROR;
|
||||
@@ -925,7 +952,7 @@ static int sessionGrowHash(int bPatchset, SessionTable *pTab){
|
||||
}
|
||||
}
|
||||
|
||||
sqlite3_free(pTab->apChange);
|
||||
sessionFree(pSession, pTab->apChange);
|
||||
pTab->nChange = nNew;
|
||||
pTab->apChange = apNew;
|
||||
}
|
||||
@@ -959,6 +986,7 @@ static int sessionGrowHash(int bPatchset, SessionTable *pTab){
|
||||
** be freed using sqlite3_free() by the caller
|
||||
*/
|
||||
static int sessionTableInfo(
|
||||
sqlite3_session *pSession, /* For memory accounting. May be NULL */
|
||||
sqlite3 *db, /* Database connection */
|
||||
const char *zDb, /* Name of attached database (e.g. "main") */
|
||||
const char *zThis, /* Table name */
|
||||
@@ -1013,7 +1041,7 @@ static int sessionTableInfo(
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
nByte += nDbCol * (sizeof(const char *) + sizeof(u8) + 1);
|
||||
pAlloc = sqlite3_malloc64(nByte);
|
||||
pAlloc = sessionMalloc64(pSession, nByte);
|
||||
if( pAlloc==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}
|
||||
@@ -1056,7 +1084,7 @@ static int sessionTableInfo(
|
||||
*pabPK = 0;
|
||||
*pnCol = 0;
|
||||
if( pzTab ) *pzTab = 0;
|
||||
sqlite3_free(azCol);
|
||||
sessionFree(pSession, azCol);
|
||||
}
|
||||
sqlite3_finalize(pStmt);
|
||||
return rc;
|
||||
@@ -1078,7 +1106,7 @@ static int sessionInitTable(sqlite3_session *pSession, SessionTable *pTab){
|
||||
if( pTab->nCol==0 ){
|
||||
u8 *abPK;
|
||||
assert( pTab->azCol==0 || pTab->abPK==0 );
|
||||
pSession->rc = sessionTableInfo(pSession->db, pSession->zDb,
|
||||
pSession->rc = sessionTableInfo(pSession, pSession->db, pSession->zDb,
|
||||
pTab->zName, &pTab->nCol, 0, &pTab->azCol, &abPK
|
||||
);
|
||||
if( pSession->rc==SQLITE_OK ){
|
||||
@@ -1169,7 +1197,7 @@ static void sessionPreupdateOneChange(
|
||||
}
|
||||
|
||||
/* Grow the hash table if required */
|
||||
if( sessionGrowHash(0, pTab) ){
|
||||
if( sessionGrowHash(pSession, 0, pTab) ){
|
||||
pSession->rc = SQLITE_NOMEM;
|
||||
return;
|
||||
}
|
||||
@@ -1236,7 +1264,7 @@ static void sessionPreupdateOneChange(
|
||||
}
|
||||
|
||||
/* Allocate the change object */
|
||||
pChange = (SessionChange *)sqlite3_malloc64(nByte);
|
||||
pChange = (SessionChange *)sessionMalloc64(pSession, nByte);
|
||||
if( !pChange ){
|
||||
rc = SQLITE_NOMEM;
|
||||
goto error_out;
|
||||
@@ -1609,7 +1637,7 @@ int sqlite3session_diff(
|
||||
int nCol; /* Columns in zFrom.zTbl */
|
||||
u8 *abPK;
|
||||
const char **azCol = 0;
|
||||
rc = sessionTableInfo(db, zFrom, zTbl, &nCol, 0, &azCol, &abPK);
|
||||
rc = sessionTableInfo(0, db, zFrom, zTbl, &nCol, 0, &azCol, &abPK);
|
||||
if( rc==SQLITE_OK ){
|
||||
if( pTo->nCol!=nCol ){
|
||||
bMismatch = 1;
|
||||
@@ -1707,7 +1735,7 @@ int sqlite3session_create(
|
||||
** Free the list of table objects passed as the first argument. The contents
|
||||
** of the changed-rows hash tables are also deleted.
|
||||
*/
|
||||
static void sessionDeleteTable(SessionTable *pList){
|
||||
static void sessionDeleteTable(sqlite3_session *pSession, SessionTable *pList){
|
||||
SessionTable *pNext;
|
||||
SessionTable *pTab;
|
||||
|
||||
@@ -1719,12 +1747,12 @@ static void sessionDeleteTable(SessionTable *pList){
|
||||
SessionChange *pNextChange;
|
||||
for(p=pTab->apChange[i]; p; p=pNextChange){
|
||||
pNextChange = p->pNext;
|
||||
sqlite3_free(p);
|
||||
sessionFree(pSession, p);
|
||||
}
|
||||
}
|
||||
sqlite3_free((char*)pTab->azCol); /* cast works around VC++ bug */
|
||||
sqlite3_free(pTab->apChange);
|
||||
sqlite3_free(pTab);
|
||||
sessionFree(pSession, (char*)pTab->azCol); /* cast works around VC++ bug */
|
||||
sessionFree(pSession, pTab->apChange);
|
||||
sessionFree(pSession, pTab);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1752,9 +1780,11 @@ void sqlite3session_delete(sqlite3_session *pSession){
|
||||
|
||||
/* Delete all attached table objects. And the contents of their
|
||||
** associated hash-tables. */
|
||||
sessionDeleteTable(pSession->pTable);
|
||||
sessionDeleteTable(pSession, pSession->pTable);
|
||||
|
||||
/* Free the session object itself. */
|
||||
/* Assert that all allocations have been freed and then free the
|
||||
** session object itself. */
|
||||
assert( pSession->nMalloc==0 );
|
||||
sqlite3_free(pSession);
|
||||
}
|
||||
|
||||
@@ -1801,7 +1831,8 @@ int sqlite3session_attach(
|
||||
|
||||
if( !pTab ){
|
||||
/* Allocate new SessionTable object. */
|
||||
pTab = (SessionTable *)sqlite3_malloc64(sizeof(SessionTable) + nName + 1);
|
||||
int nByte = sizeof(SessionTable) + nName + 1;
|
||||
pTab = (SessionTable*)sessionMalloc64(pSession, nByte);
|
||||
if( !pTab ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
@@ -2398,7 +2429,7 @@ static int sessionGenerateChangeset(
|
||||
int nNoop; /* Size of buffer after writing tbl header */
|
||||
|
||||
/* Check the table schema is still Ok. */
|
||||
rc = sessionTableInfo(db, pSession->zDb, zName, &nCol, 0, &azCol, &abPK);
|
||||
rc = sessionTableInfo(0, db, pSession->zDb, zName, &nCol, 0,&azCol,&abPK);
|
||||
if( !rc && (pTab->nCol!=nCol || memcmp(abPK, pTab->abPK, nCol)) ){
|
||||
rc = SQLITE_SCHEMA;
|
||||
}
|
||||
@@ -2573,6 +2604,13 @@ int sqlite3session_isempty(sqlite3_session *pSession){
|
||||
return (ret==0);
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the amount of heap memory in use.
|
||||
*/
|
||||
sqlite3_int64 sqlite3session_memory_used(sqlite3_session *pSession){
|
||||
return pSession->nMalloc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Do the work for either sqlite3changeset_start() or start_strm().
|
||||
*/
|
||||
@@ -4384,7 +4422,7 @@ static int sessionChangesetApply(
|
||||
int i;
|
||||
|
||||
sqlite3changeset_pk(pIter, &abPK, 0);
|
||||
rc = sessionTableInfo(
|
||||
rc = sessionTableInfo(0,
|
||||
db, "main", zNew, &sApply.nCol, &zTab, &sApply.azCol, &sApply.abPK
|
||||
);
|
||||
if( rc!=SQLITE_OK ) break;
|
||||
@@ -4863,7 +4901,7 @@ static int sessionChangesetToHash(
|
||||
}
|
||||
}
|
||||
|
||||
if( sessionGrowHash(pIter->bPatchset, pTab) ){
|
||||
if( sessionGrowHash(0, pIter->bPatchset, pTab) ){
|
||||
rc = SQLITE_NOMEM;
|
||||
break;
|
||||
}
|
||||
@@ -5049,7 +5087,7 @@ int sqlite3changegroup_output_strm(
|
||||
*/
|
||||
void sqlite3changegroup_delete(sqlite3_changegroup *pGrp){
|
||||
if( pGrp ){
|
||||
sessionDeleteTable(pGrp->pList);
|
||||
sessionDeleteTable(0, pGrp->pList);
|
||||
sqlite3_free(pGrp);
|
||||
}
|
||||
}
|
||||
@@ -5450,7 +5488,7 @@ int sqlite3rebaser_rebase_strm(
|
||||
*/
|
||||
void sqlite3rebaser_delete(sqlite3_rebaser *p){
|
||||
if( p ){
|
||||
sessionDeleteTable(p->grp.pList);
|
||||
sessionDeleteTable(0, p->grp.pList);
|
||||
sqlite3_free(p);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -440,6 +440,14 @@ int sqlite3session_patchset(
|
||||
*/
|
||||
int sqlite3session_isempty(sqlite3_session *pSession);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Query for the amount of heap memory used by a session object.
|
||||
**
|
||||
** This API returns the total amount of heap memory in bytes currently
|
||||
** used by the session object passed as the only argument.
|
||||
*/
|
||||
sqlite3_int64 sqlite3session_memory_used(sqlite3_session *pSession);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Create An Iterator To Traverse A Changeset
|
||||
** CONSTRUCTOR: sqlite3_changeset_iter
|
||||
|
||||
@@ -242,6 +242,7 @@ static int SQLITE_TCLAPI test_session_cmd(
|
||||
{ "table_filter", 1, "SCRIPT", }, /* 6 */
|
||||
{ "patchset", 0, "", }, /* 7 */
|
||||
{ "diff", 2, "FROMDB TBL", }, /* 8 */
|
||||
{ "memory_used", 0, "", }, /* 9 */
|
||||
{ 0 }
|
||||
};
|
||||
int iSub;
|
||||
@@ -347,6 +348,12 @@ static int SQLITE_TCLAPI test_session_cmd(
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 9: { /* memory_used */
|
||||
sqlite3_int64 nMalloc = sqlite3session_memory_used(pSession);
|
||||
Tcl_SetObjResult(interp, Tcl_NewWideIntObj(nMalloc));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return TCL_OK;
|
||||
|
||||
@@ -550,13 +550,13 @@ ST_OPT = -DSQLITE_THREADSAFE=0
|
||||
# This is the default Makefile target. The objects listed here
|
||||
# are what get build when you type just "make" with no arguments.
|
||||
#
|
||||
all: sqlite3.h libsqlite3.a sqlite3$(EXE)
|
||||
all: sqlite3.h sqlite3ext.h libsqlite3.a sqlite3$(EXE)
|
||||
|
||||
libsqlite3.a: $(LIBOBJ)
|
||||
libsqlite3.a: sqlite3.h $(LIBOBJ)
|
||||
$(AR) libsqlite3.a $(LIBOBJ)
|
||||
$(RANLIB) libsqlite3.a
|
||||
|
||||
sqlite3$(EXE): shell.c libsqlite3.a sqlite3.h
|
||||
sqlite3$(EXE): sqlite3.h libsqlite3.a shell.c
|
||||
$(TCCX) $(READLINE_FLAGS) -o sqlite3$(EXE) $(SHELL_OPT) \
|
||||
shell.c libsqlite3.a $(LIBREADLINE) $(TLIBS) $(THREADLIB)
|
||||
|
||||
@@ -824,13 +824,13 @@ fts3_unicode2.o: $(TOP)/ext/fts3/fts3_unicode2.c $(HDR) $(EXTHDR)
|
||||
fts3_write.o: $(TOP)/ext/fts3/fts3_write.c $(HDR) $(EXTHDR)
|
||||
$(TCCX) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3_write.c
|
||||
|
||||
fts5.o: fts5.c
|
||||
fts5.o: fts5.c sqlite3ext.h sqlite3.h
|
||||
$(TCCX) -DSQLITE_CORE -c fts5.c
|
||||
|
||||
json1.o: $(TOP)/ext/misc/json1.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
|
||||
stmt.o: $(TOP)/ext/misc/stmt.c sqlite3ext.h sqlite3.h
|
||||
$(TCCX) -DSQLITE_CORE -c $(TOP)/ext/misc/stmt.c
|
||||
|
||||
rtree.o: $(TOP)/ext/rtree/rtree.c $(HDR) $(EXTHDR)
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
C Further\schanges\sto\sthe\strace\svariables\sto\stry\sto\seliminate\s(harmless)\scompiler\nwarnings\sin\sall\sconfigurations.
|
||||
D 2020-12-04T16:04:45.699
|
||||
C Fix\sa\sproblem\scaused\sby\susing\san\sSQL\svariable\sin\san\sOVER\sclause\swithin\sa\strigger\sprogram.
|
||||
D 2021-01-21T15:40:52.172
|
||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
|
||||
F Makefile.in 0e88f5d095213a9ccd45c5bbd871c8ead498f886dff4493471fbf48b1f867f9d
|
||||
F Makefile.in 9cae1bffe5cb811216bf7425395e7fc0594daa2ce31f625835a9d0c3fb25315f
|
||||
F Makefile.linux-gcc f609543700659711fbd230eced1f01353117621dccae7b9fb70daa64236c5241
|
||||
F Makefile.msc dd10dbf63b2f8ac3e2f0542963a21bc69058976ac4355165f212a31c83d17f44
|
||||
F Makefile.msc ad07bbd645132533e1fd7164a03acfa9afecda378b3787c10f62ab4c7c45e6ea
|
||||
F README.md 1514a365ffca3c138e00c5cc839906108a01011a6b082bad19b09781e3aa498a
|
||||
F VERSION 4027b9aea92d64385570778ebd14388c0b23e92aafda15e7b89c45886c9b920a
|
||||
F VERSION 92f3e4c5cdee6f0779aef1eae857dfc21d0eabb1f2af169dc90e63cd76b15bb2
|
||||
F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50
|
||||
F art/sqlite370.eps aa97a671332b432a54e1d74ff5e8775be34200c2
|
||||
F art/sqlite370.ico af56c1d00fee7cd4753e8631ed60703ed0fc6e90
|
||||
@@ -18,7 +18,7 @@ F autoconf/Makefile.fallback 22fe523eb36dfce31e0f6349f782eb084e86a5620b2b0b4f84a
|
||||
F autoconf/Makefile.msc e0f1dafc48d000fd6ddfdb01815271528db55cbc7299ca888df5b93367f0d5a4
|
||||
F autoconf/README.first 6c4f34fe115ff55d4e8dbfa3cecf04a0188292f7
|
||||
F autoconf/README.txt 4f04b0819303aabaa35fff5f7b257fb0c1ef95f1
|
||||
F autoconf/configure.ac 3cd933b959fe514eebd1ca1717dfddbf2c9b825b6bc2c5f744deaf5d63af9288
|
||||
F autoconf/configure.ac 55be6fc04a5b030b367fe317b72dc8c0eafc4713991fe6182cf647b02fb782cb
|
||||
F autoconf/tea/Makefile.in b438a7020446c8a8156e8d97c8914a04833da6fd
|
||||
F autoconf/tea/README 3e9a3c060f29a44344ab50aec506f4db903fb873
|
||||
F autoconf/tea/aclocal.m4 52c47aac44ce0ddb1f918b6993e8beb8eee88f43
|
||||
@@ -34,11 +34,11 @@ F autoconf/tea/win/rules.vc c511f222b80064096b705dbeb97060ee1d6b6d63
|
||||
F config.guess 883205ddf25b46f10c181818bf42c09da9888884af96f79e1719264345053bd6
|
||||
F config.h.in 6376abec766e9a0785178b1823b5a587e9f1ccbc
|
||||
F config.sub c2d0260f17f3e4bc0b6808fccf1b291cb5e9126c14fc5890efc77b9fd0175559
|
||||
F configure e7df2824b6e60d482d919fb3e7d823faf08467093b096ad47a4fe2eec3f0ba99 x
|
||||
F configure.ac 73545c21eebcef9398d85c982c7be260f07708256778221b541f83ae8c6f61eb
|
||||
F configure 91893a81f698778dda4d8fb24bfca606ded31ef02bcfbc2ab072d30fb67138d6 x
|
||||
F configure.ac 412b65c6107e41c098ad7f5f2e6a3f74ac02ffc6e92b9a6264b9f1060c235a04
|
||||
F contrib/sqlitecon.tcl 210a913ad63f9f991070821e599d600bd913e0ad
|
||||
F doc/F2FS.txt c1d4a0ae9711cfe0e1d8b019d154f1c29e0d3abfe820787ba1e9ed7691160fcd
|
||||
F doc/lemon.html c5d8ba85ac1daef7be8c2d389899480eb62451ff5c09b0c28ff8157bb8770746
|
||||
F doc/lemon.html 1bb72ece6271df0d901d233551dd985f2c6ba30d09382cf2d321ed951ab57491
|
||||
F doc/pager-invariants.txt 27fed9a70ddad2088750c4a2b493b63853da2710
|
||||
F doc/trusted-schema.md 33625008620e879c7bcfbbfa079587612c434fa094d338b08242288d358c3e8a
|
||||
F doc/vdbesort-memory.md 4da2639c14cd24a31e0af694b1a8dd37eaf277aff3867e9a8cc14046bc49df56
|
||||
@@ -50,8 +50,8 @@ F ext/async/sqlite3async.c 6f247666b495c477628dd19364d279c78ea48cd90c72d9f9b98ad
|
||||
F ext/async/sqlite3async.h 46b47c79357b97ad85d20d2795942c0020dc20c532114a49808287f04aa5309a
|
||||
F ext/expert/README.md b321c2762bb93c18ea102d5a5f7753a4b8bac646cb392b3b437f633caf2020c3
|
||||
F ext/expert/expert.c d548d603a4cc9e61f446cc179c120c6713511c413f82a4a32b1e1e69d3f086a4
|
||||
F ext/expert/expert1.test dba6e752cc701621771f925f3872b183fa688f7b4a9f4822631fc02bdbffc45a
|
||||
F ext/expert/sqlite3expert.c 2778d9f06b3a8bfa859cb6b75b82f004477bf5dd78edd17d954319750ca963f3
|
||||
F ext/expert/expert1.test 63d778d964e55ef2d1a723043d91c59e7dc6ef1649d91c78c0bef00f9c6f1427
|
||||
F ext/expert/sqlite3expert.c de51b187c629a4c4264d5de0b77862641e11426f7a963a92abf2d4077085fc8c
|
||||
F ext/expert/sqlite3expert.h ca81efc2679a92373a13a3e76a6138d0310e32be53d6c3bfaedabd158ea8969b
|
||||
F ext/expert/test_expert.c d56c194b769bdc90cf829a14c9ecbc1edca9c850b837a4d0b13be14095c32a72
|
||||
F ext/fts1/README.txt 20ac73b006a70bcfd80069bdaf59214b6cf1db5e
|
||||
@@ -117,9 +117,9 @@ F ext/fts5/fts5Int.h 26c74dd5776f798436fbf604a0bf0e8de263b35b5060b05c15f9085845d
|
||||
F ext/fts5/fts5_aux.c f558e1fb9f0f86a4f7489e258c162e1f947de5ff2709087fbb465fddb7092f98
|
||||
F ext/fts5/fts5_buffer.c 5a5fe0159752c0fb0a5a93c722e9db2662822709490769d482b76a6dc8aaca70
|
||||
F ext/fts5/fts5_config.c be54f44fca491e96c6923a4b9a736f2da2b13811600eb6e38d1bcc91c4ea2e61
|
||||
F ext/fts5/fts5_expr.c e527e3a7410393075598cec544e3831798a8c88b3e8878e2cfb7cb147113e925
|
||||
F ext/fts5/fts5_expr.c 016bd06030679bd31b0f07ef87d62c42031e5da25cb3174a84e5b0f6ef4b47b0
|
||||
F ext/fts5/fts5_hash.c 1aa93c9b5f461afba66701ee226297dc78402b3bdde81e90a10de5fe3df14959
|
||||
F ext/fts5/fts5_index.c 9f152a596df3a2227ddd59adb82549c2b6858ab36bc1d26fd8933f43d3d63d36
|
||||
F ext/fts5/fts5_index.c acbe3ccd36f5a7373009dfff02a11c4a817af73bc3ef8c340f2105d7d073f8b4
|
||||
F ext/fts5/fts5_main.c b4e4931c7fcc9acfa0c3b8b5e5e80b5b424b8d9207aae3a22b674bd35ccf149d
|
||||
F ext/fts5/fts5_storage.c 58ba71e6cd3d43a5735815e7956ee167babb4d2cbfe206905174792af4d09d75
|
||||
F ext/fts5/fts5_tcl.c 39bcbae507f594aad778172fa914cad0f585bf92fd3b078c686e249282db0d95
|
||||
@@ -160,9 +160,9 @@ F ext/fts5/test/fts5connect.test 08030168fc96fc278fa81f28654fb7e90566f33aff269c0
|
||||
F ext/fts5/test/fts5content.test 213506436fb2c87567b8e31f6d43ab30aab99354cec74ed679f22aad0cdbf283
|
||||
F ext/fts5/test/fts5corrupt.test 77ae6f41a7eba10620efb921cf7dbe218b0ef232b04519deb43581cb17a57ebe
|
||||
F ext/fts5/test/fts5corrupt2.test 7453752ba12ce91690c469a6449d412561cc604b1dec994e16ab132952e7805f
|
||||
F ext/fts5/test/fts5corrupt3.test dd5435659d5363fc3b3ac32175e2fc793fdc17980b47e3d598695d867eaa77a2
|
||||
F ext/fts5/test/fts5corrupt4.test ea805c4d7c68b5f185b9db5d2060a7ae5875339738dd48203c92162f41e7ca91
|
||||
F ext/fts5/test/fts5delete.test 4a15fb03b6c7eac62ac807a3a32b7f0dc74f0d479c410e3e3568ae96b9469290
|
||||
F ext/fts5/test/fts5corrupt3.test 5df97f353102f0078d0bb418d620652d03460ee1cceb2992a3b5ee6fb619b24e
|
||||
F ext/fts5/test/fts5corrupt4.test f4c08e2182a48d8b70975fd869ee5391855c06d8a0ff87b6a2529e7c5a88a1d3
|
||||
F ext/fts5/test/fts5delete.test 619295b20dbc1d840b403ee07c878f52378849c3c02e44f2ee143b3e978a0aa7
|
||||
F ext/fts5/test/fts5detail.test 31b240dbf6d44ac3507e2f8b65f29fdc12465ffd531212378c7ce1066766f54e
|
||||
F ext/fts5/test/fts5determin.test 1b77879b2ae818b5b71c859e534ee334dac088b7cf3ff3bf76a2c82b1c788d11
|
||||
F ext/fts5/test/fts5dlidx.test b90852c55881b29dbac6380b274de27beae623ac4b6d567c6c8fb9cdc315a86e
|
||||
@@ -204,6 +204,7 @@ F ext/fts5/test/fts5plan.test 79d35b5e83bbdcba48d946a7f008df161f6b0ede1a966892d0
|
||||
F ext/fts5/test/fts5porter.test 8d08010c28527db66bc3feebd2b8767504aaeb9b101a986342fa7833d49d0d15
|
||||
F ext/fts5/test/fts5porter2.test 0d251a673f02fa13ca7f011654873b3add20745f7402f108600a23e52d8c7457
|
||||
F ext/fts5/test/fts5prefix.test a0fa67b06650f2deaa7bf27745899d94e0fb547ad9ecbd08bfad98c04912c056
|
||||
F ext/fts5/test/fts5prefix2.test 3847ce46f70b82d61c6095103a9d7c53f2952c40a4704157bc079c04d9c8b18b
|
||||
F ext/fts5/test/fts5query.test ac363b17a442620bb0780e93c24f16a5f963dfe2f23dc85647b869efcfada728
|
||||
F ext/fts5/test/fts5rank.test c9fd4a1e36b4fa92d572ec13d846469b97da249d1c2f7fd3ee7e017ce46f2416
|
||||
F ext/fts5/test/fts5rebuild.test 55d6f17715cddbf825680dd6551efbc72ed916d8cf1cde40a46fc5d785b451e7
|
||||
@@ -290,7 +291,7 @@ F ext/misc/blobio.c a867c4c4617f6ec223a307ebfe0eabb45e0992f74dd47722b96f3e631c0e
|
||||
F ext/misc/btreeinfo.c d28ce349b40054eaa9473e835837bad7a71deec33ba13e39f963d50933bfa0f9
|
||||
F ext/misc/carray.c b75a0f207391038bf1540d3372f482a95c3613511c7c474db51ede1196321c7c
|
||||
F ext/misc/carray.h de74ac70b2338f416723f7d538026e8ec0b7f1d388319f8f140c9a4d7677f02e
|
||||
F ext/misc/cksumvfs.c c4e7ebeae5aa578df98f23bddb63ecbcbe913ee3c32b8b769525af100d752061
|
||||
F ext/misc/cksumvfs.c 8dc4e1b718e374bed3a9b5c0a08da2922438002e33267311697768e06217b983
|
||||
F ext/misc/closure.c dbfd8543b2a017ae6b1a5843986b22ddf99ff126ec9634a2f4047cd14c85c243
|
||||
F ext/misc/completion.c 6dafd7f4348eecc7be9e920d4b419d1fb2af75d938cd9c59a20cfe8beb2f22b9
|
||||
F ext/misc/compress.c 3354c77a7c8e86e07d849916000cdac451ed96500bfb5bd83b20eb61eee012c9
|
||||
@@ -318,9 +319,9 @@ F ext/misc/regexp.c 246244c714267f303df76acf73dcf110cf2eaf076896aaaba8db6d6d21a1
|
||||
F ext/misc/remember.c add730f0f7e7436cd15ea3fd6a90fd83c3f706ab44169f7f048438b7d6baa69c
|
||||
F ext/misc/rot13.c 51ac5f51e9d5fd811db58a9c23c628ad5f333c173f1fc53c8491a3603d38556c
|
||||
F ext/misc/scrub.c 2a44b0d44c69584c0580ad2553f6290a307a49df4668941d2812135bfb96a946
|
||||
F ext/misc/series.c fbb8e6be97b54d10d2f235e163fa2f53a8f4421c66ebd532a233fd1c69c3f522
|
||||
F ext/misc/series.c c6bd5d249e5199a1b55aeee4d0e6576ff3a68702fc475dbd64503a32903516c7
|
||||
F ext/misc/sha1.c c8f2253c8792ffab9517695ea7d88c079f0395a5505eefef5c8198fe184ed5ac
|
||||
F ext/misc/shathree.c 135b7c145db4a09b1650c3e7aff9cb538763a9a361e834c015dd1aaf8d5c9a00
|
||||
F ext/misc/shathree.c e984f31731de4cf302a0386be5fe664580f63d8204c47b9b41cc4b997745f9ec
|
||||
F ext/misc/showauth.c 732578f0fe4ce42d577e1c86dc89dd14a006ab52
|
||||
F ext/misc/spellfix.c 94df9bbfa514a563c1484f684a2df3d128a2f7209a84ca3ca100c68a0163e29f
|
||||
F ext/misc/sqlar.c 0ace5d3c10fe736dc584bf1159a36b8e2e60fab309d310cd8a0eecd9036621b6
|
||||
@@ -338,7 +339,7 @@ F ext/misc/vtshim.c 1976e6dd68dd0d64508c91a6dfab8e75f8aaf6cd
|
||||
F ext/misc/wholenumber.c 520f34c3099e5b7d546f13708607dc2fa173c46b68952eecf0d19cd675fec85e
|
||||
F ext/misc/zipfile.c e35e035bc2765b1ccdcb15f9815c2112843fcbc8f36aa071f0e5935df7072228
|
||||
F ext/misc/zorder.c b0ff58fa643afa1d846786d51ea8d5c4b6b35aa0254ab5a82617db92f3adda64
|
||||
F ext/rbu/rbu.c 8681f6157db6adc82c34af24b14ea8a3be0146ad2a3b6c1d5da6cb8a5796c8ce
|
||||
F ext/rbu/rbu.c b880ca5cb857d6d6f52e72eb7397813058ef48c78c5402cd04ff2b6b5437f622
|
||||
F ext/rbu/rbu1.test 221d9c18a5e600ac9ac6b1810d99d9f99163a7909ba61597876ab6e4d4beb3d6
|
||||
F ext/rbu/rbu10.test 0a201c32202143f23c81c0144503da339786fc20acb7a2fda11601b65659f314
|
||||
F ext/rbu/rbu11.test 5c834cf491086b45e071eabf71f708febc143e86a384a92de69e0b1a4cace144
|
||||
@@ -449,19 +450,20 @@ F ext/session/sessiondiff.test ad13dd65664bae26744e1f18eb3cbd5588349b7e9118851d8
|
||||
F ext/session/sessionfault.test da273f2712b6411e85e71465a1733b8501dbf6f7
|
||||
F ext/session/sessionfault2.test dd593f80b6b4786f7adfe83c5939620bc505559770cc181332da26f29cddd7bb
|
||||
F ext/session/sessioninvert.test 04075517a9497a80d39c495ba6b44f3982c7371129b89e2c52219819bc105a25
|
||||
F ext/session/sessionmem.test f2a735db84a3e9e19f571033b725b0b2daf847f3f28b1da55a0c1a4e74f1de09
|
||||
F ext/session/sessionrebase.test ccfa716b23bd1d3b03217ee58cfd90c78d4b99f53e6a9a2f05e82363b9142810
|
||||
F ext/session/sessionstat1.test 218d351cf9fcd6648f125a26b607b140310160184723c2666091b54450a68fb5
|
||||
F ext/session/sessionwor.test 67b5ab91d4f93ce65ff1f58240ac5ddf73f8670facc1ffa49cef56293d52818d
|
||||
F ext/session/sqlite3session.c 2c76b8c3a5d6dab736686f8a48833b8bdac0871ecc6f447f9839d28bd4a63d6c
|
||||
F ext/session/sqlite3session.h a2db5b72b938d12c727b4b4ec632254ca493670a9c0de597af3271a7f774fc57
|
||||
F ext/session/test_session.c 24286d958dc6f4ca4d7e710f09bc0fa9d50956a40dd99fd8223e7488024c71fe
|
||||
F ext/session/sqlite3session.c d2aaaf05241ac7d23a1b1eaa8b1f165c90f7ff0fe57ff1932a87c6b89b886117
|
||||
F ext/session/sqlite3session.h f53c99731882bf59c7362855cdeba176ce1fe8eeba089e38a8cce0172f8473aa
|
||||
F ext/session/test_session.c 93ca965112d2b4d9d669c9c0be6b1e52942a268796050a145612df1eee175ce0
|
||||
F ext/userauth/sqlite3userauth.h 7f3ea8c4686db8e40b0a0e7a8e0b00fac13aa7a3
|
||||
F ext/userauth/user-auth.txt e6641021a9210364665fe625d067617d03f27b04
|
||||
F ext/userauth/userauth.c 7f00cded7dcaa5d47f54539b290a43d2e59f4b1eb5f447545fa865f002fc80cb
|
||||
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
|
||||
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
|
||||
F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60
|
||||
F main.mk 57451ea5b3d5cd86e9c5324b10c9de184b12e8dcccc31c65d24fbcb55ccd9c53
|
||||
F main.mk 443a4ec1ca89ad267cbde45dadc68861154b99c7bd26e7b7dc74303a664002b8
|
||||
F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83
|
||||
F mptest/config01.test 3c6adcbc50b991866855f1977ff172eb6d901271
|
||||
F mptest/config02.test 4415dfe36c48785f751e16e32c20b077c28ae504
|
||||
@@ -473,37 +475,37 @@ F spec.template 86a4a43b99ebb3e75e6b9a735d5fd293a24e90ca
|
||||
F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
|
||||
F sqlite3.1 fc7ad8990fc8409983309bb80de8c811a7506786
|
||||
F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a
|
||||
F src/alter.c b6de60d59419e34f5b48ff2b21fe0f9bb66fc714e5545a6ac790ac7a0c46548c
|
||||
F src/alter.c 36cae0d6e3e91a1996e1a472f8c7242c31a4e38ba4295e3056da198c04fd2a87
|
||||
F src/analyze.c 01c6c6765cb4d40b473b71d85535093730770bb186f2f473abac25f07fcdee5c
|
||||
F src/attach.c 0f497c15c4cfe3bdcb214f0dbdbbb6c5ed7e8a9308ac445c7959f5e5780437a9
|
||||
F src/auth.c a3d5bfdba83d25abed1013a8c7a5f204e2e29b0c25242a56bc02bb0c07bf1e06
|
||||
F src/attach.c 87102aba5ddac8ef3a8a033ab657e4cae9cc8e846efe93b14029cfffaaf8831e
|
||||
F src/auth.c 8d1df0e2ef8bafbedd4f1fe4baff03eb27507da4bf6e449df3613d383c4018b2
|
||||
F src/backup.c 3014889fa06e20e6adfa0d07b60097eec1f6e5b06671625f476a714d2356513d
|
||||
F src/bitvec.c 17ea48eff8ba979f1f5b04cc484c7bb2be632f33
|
||||
F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6
|
||||
F src/btree.c ee14224322b9e4172d01e691e2f289f6c630ae39b7906f84b72dc780b9e42a76
|
||||
F src/btree.h dcdff4037d75b3f032a5de0d922fcfaf35d48589417f634fa8627362709315f9
|
||||
F src/btreeInt.h ffd66480520d9d70222171b3a026d78b80833b5cea49c89867949f3e023d5f43
|
||||
F src/build.c f6449d4e85e998e14d3f537e8ea898dca2fcb83c277db3e60945af9b9177db81
|
||||
F src/btree.c 0f9cb686871ae668817673f0823b55d1bcadbc86ea28bd22c590b064a8322d5a
|
||||
F src/btree.h 285f8377aa1353185a32bf455faafa9ff9a0d40d074d60509534d14990c7829e
|
||||
F src/btreeInt.h 7614cae30f95b6aed0c7cac7718276a55cfe2c77058cbfd8bef5b75329757331
|
||||
F src/build.c d4c06261b0e532523ede58dc511381a7a9c155132e4b65a6bb2ff76fe657793a
|
||||
F src/callback.c d0b853dd413255d2e337b34545e54d888ea02f20da5ad0e63585b389624c4a6c
|
||||
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
|
||||
F src/ctime.c e98518d2d3d4029a13c805e07313fb60c877be56db76e90dd5f3af73085d0ce6
|
||||
F src/ctime.c 2a322b9a3d75771fb4d99e0702851f4f68dda982507a0f798eefb0712969a410
|
||||
F src/date.c dace306a10d9b02ee553d454c8e1cf8d3c9b932e137738a6b15b90253a9bfc10
|
||||
F src/dbpage.c 8a01e865bf8bc6d7b1844b4314443a6436c07c3efe1d488ed89e81719047833a
|
||||
F src/dbstat.c 3aa79fc3aed7ce906e4ea6c10e85d657299e304f6049861fe300053ac57de36c
|
||||
F src/delete.c 927cf8f900583e79aca8f1a321979e0a8f053babd9a690b44b38f79de2cc09fe
|
||||
F src/expr.c 0d196ed5a2ebf96be7e8df88add4fabfad0dce16c0fed81a4b8f6a26e259797f
|
||||
F src/expr.c 47c85263e6d179424e6b09e2c79db5704ab5b8cbc2fae2ee3285faa2566f2e74
|
||||
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
|
||||
F src/fkey.c 83372403298e6a7dd989a47aaacdbaa5b4307b5199dbd56e07d4896066b3de72
|
||||
F src/func.c 574f7e5a67e4b7a7855cf3478037717c8f44686c0cd727e1d7f7773414165c03
|
||||
F src/func.c 251b5953cecd0ce3e282213c5e623134415793d3569d7804d13460559d7e45ff
|
||||
F src/global.c ed55af196a9b66e198aaeda3f5454c3aa7d7d050c6c938181fd044b70d180a81
|
||||
F src/hash.c 8d7dda241d0ebdafb6ffdeda3149a412d7df75102cecfc1021c98d6219823b19
|
||||
F src/hash.h 9d56a9079d523b648774c1784b74b89bd93fac7b365210157482e4319a468f38
|
||||
F src/hwtime.h cb1d7e3e1ed94b7aa6fde95ae2c2daccc3df826be26fc9ed7fd90d1750ae6144
|
||||
F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
|
||||
F src/insert.c 7e081d33aab4a9d761c39dccf3c3872c35501565d2ed9db66301918d23bc7901
|
||||
F src/insert.c 9b970eff058a858fbd9f2db71425ef195942c2610855daa66ae23024432d52f5
|
||||
F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa
|
||||
F src/loadext.c 8c9c8cd2bd8eecdb06d9b6e89de7e9e65bae45cc8fc33609cc74023a5c296067
|
||||
F src/main.c 97e9f137354bc1f76dc9bb60a0a24f8c45cf73b33e80d3ee4c64155336fb820d
|
||||
F src/main.c 1c5de7b3fabcdf05f4fe563aab5d81d175b89c67a8678a12ba86629356afa356
|
||||
F src/malloc.c c1af4ac5a463648cd2953fd4ac679b3ba9022ce5ec794a60806150ad69dfd33a
|
||||
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
|
||||
F src/mem1.c c12a42539b1ba105e3707d0e628ad70e611040d8f5e38cf942cee30c867083de
|
||||
@@ -519,7 +521,7 @@ F src/mutex_noop.c 9d4309c075ba9cc7249e19412d3d62f7f94839c4
|
||||
F src/mutex_unix.c dd2b3f1cc1863079bc1349ac0fec395a500090c4fe4e11ab775310a49f2f956d
|
||||
F src/mutex_w32.c caa50e1c0258ac4443f52e00fe8aaea73b6d0728bd8856bedfff822cae418541
|
||||
F src/notify.c 89a97dc854c3aa62ad5f384ef50c5a4a11d70fcc69f86de3e991573421130ed6
|
||||
F src/os.c 80e4cf3e5da06be03ca641661e331ce60eeeeabf0d7354dbb1c0e166d0eedbbe
|
||||
F src/os.c 2d6e646370b1aa78942c68d7edf124e518963adf4a90bce87f365a5a5495529a
|
||||
F src/os.h 48388821692e87da174ea198bf96b1b2d9d83be5dfc908f673ee21fafbe0d432
|
||||
F src/os_common.h b2f4707a603e36811d9b1a13278bffd757857b85
|
||||
F src/os_setup.h 0dbaea40a7d36bf311613d31342e0b99e2536586
|
||||
@@ -528,28 +530,28 @@ F src/os_win.c 77d39873836f1831a9b0b91894fec45ab0e9ca8e067dc8c549e1d1eca1566fe9
|
||||
F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
|
||||
F src/pager.c c49952ac5e9cc536778eff528091d79d38b3e45cbeeed4695dc05e207dc6547d
|
||||
F src/pager.h 4bf9b3213a4b2bebbced5eaa8b219cf25d4a82f385d093cd64b7e93e5285f66f
|
||||
F src/parse.y 9ce4dfb772608ed5bd3c32f33e943e021e3b06cfd2c01932d4280888fdd2ebed
|
||||
F src/parse.y 6c8aa09a7fa6e0867c3a3d67ef61b911aa392c9b084a61dc632cd93732aef8ad
|
||||
F src/pcache.c 385ff064bca69789d199a98e2169445dc16e4291fa807babd61d4890c3b34177
|
||||
F src/pcache.h 4f87acd914cef5016fae3030343540d75f5b85a1877eed1a2a19b9f284248586
|
||||
F src/pcache1.c 6596e10baf3d8f84cc1585d226cf1ab26564a5f5caf85a15757a281ff977d51a
|
||||
F src/pragma.c 6daaaecc26a4b09481d21722525b079ce756751a43a79cc1d8f122d686806193
|
||||
F src/pragma.h 8dc78ab7e9ec6ce3ded8332810a2066f1ef6267e2e03cd7356ee00276125c6cf
|
||||
F src/prepare.c 270170a239c0f66bd3c228f373afe24447c2614a6829ae22080babc64f241931
|
||||
F src/prepare.c f288cbc35f79eb32e162de7e80a63ebe00d80e639dcfac071bee11570cbdb16f
|
||||
F src/printf.c 30e92b638fac71dcd85cdea1d12ecfae354c9adee2c71e8e1ae4727cde7c91ed
|
||||
F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384
|
||||
F src/resolve.c 1948a92ca9eab776632816b97e57c61d933474a78aad4f4ef835c916a83dbb1c
|
||||
F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92
|
||||
F src/select.c c9b68506e5d8cc8d0e4b307b97a9800b050ac37dada80ae9c66f680f8fac3e09
|
||||
F src/shell.c.in 3568822723cea63b4a6c6ce0704c606d2ea207d4fe024c67729a105230d4b148
|
||||
F src/sqlite.h.in 0e2b4259e49a0eda54d9118eb18a04fcd60e0727a2fd2c81aade0bf57520e706
|
||||
F src/select.c 738cb746189f721f59972993c13085fa2975c4cbfd04ba26445f3b42c81237dc
|
||||
F src/shell.c.in 9ebc74e4f05cfbd0f4a36060fdaeff1da4e9af4458358722bc08c5a1ab9a0879
|
||||
F src/sqlite.h.in 0af968a1fa3c717261e1df0ed105fa7bddb4d82de7e0adb3eab49e6aa81b4de7
|
||||
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
|
||||
F src/sqlite3ext.h 61b38c073d5e1e96a3d45271b257aef27d0d13da2bea5347692ae579475cd95e
|
||||
F src/sqliteInt.h c897ea47eb7dfc1b337e2c5681dbf00eb43c2a1af2f0045a19adc1052aadc03d
|
||||
F src/sqliteInt.h 3e5bc0446611e272b93754265e3265f36249d0458da25e32991fce241d69dbcf
|
||||
F src/sqliteLimit.h d7323ffea5208c6af2734574bae933ca8ed2ab728083caa117c9738581a31657
|
||||
F src/status.c 4b8bc2a6905163a38b739854a35b826c737333fab5b1f8e03fa7eb9a4799c4c1
|
||||
F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
|
||||
F src/tclsqlite.c 986b6391f02cd9b53c1d688be55899f6ffddeb8e8014cd83c1b73ff912579a71
|
||||
F src/test1.c 3543dcebd67dbe8eb35114d7ea1d4306e9aa6ac1dcc1f6bd40aa701ae20fc8ee
|
||||
F src/test1.c 2197966d2f7211ef9eefaa6c3c7dd2c7d786d1f33f2aadef2f08c8c79eceec26
|
||||
F src/test2.c 3efb99ab7f1fc8d154933e02ae1378bac9637da5
|
||||
F src/test3.c 61798bb0d38b915067a8c8e03f5a534b431181f802659a6616f9b4ff7d872644
|
||||
F src/test4.c 7c4420e01c577b5c4add2cb03119743b1a357543d347773b9e717195ea967159
|
||||
@@ -564,7 +566,7 @@ F src/test_backup.c bf5da90c9926df0a4b941f2d92825a01bbe090a0
|
||||
F src/test_bestindex.c 78809f11026f18a93fcfd798d9479cba37e1201c830260bf1edc674b2fa9b857
|
||||
F src/test_blob.c ae4a0620b478548afb67963095a7417cd06a4ec0a56adb453542203bfdcb31ce
|
||||
F src/test_btree.c 8b2dc8b8848cf3a4db93f11578f075e82252a274
|
||||
F src/test_config.c 5ea19bf0972a9d91728518b4d30e91477acce80496003ecbef3a7fb18d0bd081
|
||||
F src/test_config.c 98698f5242be88af75eaac54adde573471d5ed2f6484e0dac034cb1e763a551a
|
||||
F src/test_delete.c e2fe07646dff6300b48d49b2fee2fe192ed389e834dd635e3b3bac0ce0bf9f8f
|
||||
F src/test_demovfs.c 86142ba864d4297d54c5b2e972e74f3141ae4b30f05b3a95824184ed2d3d7f91
|
||||
F src/test_devsym.c aff2255ea290d7718da08af30cdf18e470ff7325a5eff63e0057b1496ed66593
|
||||
@@ -603,33 +605,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 4dc01b267593537e2a0d0efe9f80dabe24c5b6f7627bc6971c487fa6a1dacbbf
|
||||
F src/tokenize.c c64c49d7c2ec4490c2fef1f24350167ba16b03b0c6cee58ad1a1d70a4325d4e9
|
||||
F src/treeview.c 4b92992176fb2caefbe06ba5bd06e0e0ebcde3d5564758da672631f17aa51cda
|
||||
F src/trigger.c 515e79206d40d1d4149129318582e79a6e9db590a7b74e226fdb5b2a6c7e1b10
|
||||
F src/trigger.c 29680c54c1aa088fa1b4d50137d75669a40d5ef814394e321fab1e547868e3d3
|
||||
F src/update.c 9f126204a6acb96bbe47391ae48e0fc579105d8e76a6d9c4fab3271367476580
|
||||
F src/upsert.c 2920de71b20f04fe25eb00b655d086f0ba60ea133c59d7fa3325c49838818e78
|
||||
F src/upsert.c df8f1727d62b5987c4fd302cd4d7c0c84ae57cd65683c5a34a740dfe24039235
|
||||
F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0
|
||||
F src/util.c c0c7977de7ef9b8cb10f6c85f2d0557889a658f817b0455909a49179ba4c8002
|
||||
F src/util.c 41c7a72da1df47864faa378a1c720b38adb288c6838cb6be5594511b6287a048
|
||||
F src/vacuum.c 492422c1463c076473bae1858799c7a0a5fe87a133d1223239447c422cd26286
|
||||
F src/vdbe.c d24a43b6b1ed2dba893636a14f5e56001444ab3fd5465e3bca8ab01799840acd
|
||||
F src/vdbe.c fd3ae827dea9da118d22c172ad183888120070d4c709bd0a5a97af7749246783
|
||||
F src/vdbe.h 83603854bfa5851af601fc0947671eb260f4363e62e960e8a994fb9bbcd2aaa1
|
||||
F src/vdbeInt.h 3ca5e9fd6e095a8b6cf6bc3587a46fc93499503b2fe48951e1034ba9e2ce2f6e
|
||||
F src/vdbeapi.c c5e7cb2ab89a24d7f723e87b508f21bfb1359a04db5277d8a99fd1e015c12eb9
|
||||
F src/vdbeaux.c c76b7e96e189f5056d1de914d33d07bd03d3b88741f75375c8e18c9b11ffd379
|
||||
F src/vdbeaux.c e91d74e24babcf61969279b193e228cf4f8bc724a9cc59ed287db064326876f8
|
||||
F src/vdbeblob.c 253ed82894924c362a7fa3079551d3554cd1cdace39aa833da77d3bc67e7c1b1
|
||||
F src/vdbemem.c 947f2a65910edb4014dc981d33e414a68c51f169f9df8c4c493a0ba840b6eb1f
|
||||
F src/vdbesort.c f5b5e473a7cee44e47a94817b042fd7172cf3aa2c0a7928a8339d612bcfdec5a
|
||||
F src/vdbetrace.c fa3bf238002f0bbbdfb66cc8afb0cea284ff9f148d6439bc1f6f2b4c3b7143f0
|
||||
F src/vdbetrace.c 666c6fd9f1b62be6999e072a45b913e3c2c3518bc60dfd4d54fe304130acb724
|
||||
F src/vdbevtab.c f99b275366c5fc5e2d99f734729880994ab9500bdafde7fae3b02d562b9d323c
|
||||
F src/vtab.c 5f5fc793092f53bbdfde296c50f563fb7bda58cf48e9cf6a8bdfbc5abd409845
|
||||
F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
|
||||
F src/wal.c 69e770e96fd56cc21608992bf2c6f1f3dc5cf2572d0495c6a643b06c3a679f14
|
||||
F src/wal.h c3aa7825bfa2fe0d85bef2db94655f99870a285778baa36307c0a16da32b226a
|
||||
F src/walker.c 3df26a33dc4f54e8771600fb7fdebe1ece0896c2ad68c30ab40b017aa4395049
|
||||
F src/where.c 2d593bfc6fa24e53dfe7c99bd327af687f8502e5f0e0299dd2c0f503b133f0bb
|
||||
F src/walker.c d9c4e454ebb9499e908aa62d55b8994c375cf5355ac78f60d45af17f7890701c
|
||||
F src/where.c 0e6abb22a2323fec80b450825593c26a2ad8f4815d1ee3af9969d8f6144bf681
|
||||
F src/whereInt.h 9a3f577619f07700d16d89eeb2f3d94d6b7ed7f109c2dacf0ce8844921549506
|
||||
F src/wherecode.c a3a1aff30fe99a818d8e7c607980f033f40c68d890e03ed25838b9dbb7908bee
|
||||
F src/whereexpr.c 3a463e156ea388083c501502229c2c7f4f5c6b5330ea59bdf40d6eb6e155a25f
|
||||
F src/whereexpr.c a022b4f447c0fb0674e172a9a303537ea5055df60d579f99cec7ead18e8c453f
|
||||
F src/window.c edd6f5e25a1e8f2b6f5305b7f5f7da7bb35f07f0d432b255b1d4c2fcab4205aa
|
||||
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
|
||||
F test/affinity2.test ce1aafc86e110685b324e9a763eab4f2a73f737842ec3b687bd965867de90627
|
||||
@@ -650,7 +652,7 @@ F test/altermalloc.test 167a47de41b5c638f5f5c6efb59784002b196fff70f98d9b4ed3cd74
|
||||
F test/altermalloc2.test fa7b1c1139ea39b8dec407cf1feb032ca8e0076bd429574969b619175ad0174b
|
||||
F test/altertab.test 6d7bbac2c4a6ef71b775094a3298fa3a92274d95034ee23157ffba92768e47e6
|
||||
F test/altertab2.test b0d62f323ca5dab42b0bc028c52e310ebdd13e655e8fac070fe622bad7852c2b
|
||||
F test/altertab3.test 1db384eb85b4a30b0b332842f5c596b0dc0126f7c61959be3f85ae8b1c271d9a
|
||||
F test/altertab3.test 2b82fa2236a3a91553d53ae5555d8e723c7eec174c41f1fa62ff497355398479
|
||||
F test/amatch1.test b5ae7065f042b7f4c1c922933f4700add50cdb9f
|
||||
F test/analyze.test 547bb700f903107b38611b014ca645d6b5bb819f5210d7bf39c40802aafeb7d7
|
||||
F test/analyze3.test fca2a9de0017becfdcc201647f03b1cfd5ba0e7b5b5c852936e4ec62780cde49
|
||||
@@ -790,6 +792,7 @@ F test/corruptJ.test 4d5ccc4bf959464229a836d60142831ef76a5aa4
|
||||
F test/corruptK.test 5b4212fe346699831c5ad559a62c54e11c0611bdde1ea8423a091f9c01aa32af
|
||||
F test/corruptL.test 22589f503602cc5984e80f27f46c4de2134f24f1515ba2440513c377cb692258
|
||||
F test/corruptM.test 7d574320e08c1b36caa3e47262061f186367d593a7e305d35f15289cc2c3e067
|
||||
F test/corruptN.test 781c5f26a2d8918f03d45ac4968a738031eeb113a4b153c7588756d9b09c7b04
|
||||
F test/cost.test 1d156ce9858780a966c062694687afe0343a0ed12d081d071fb57027e726bafc
|
||||
F test/count.test e0699a15712bc2a4679d60e408921c2cce7f6365a30340e790c98e0f334a9c77
|
||||
F test/countofview.test e17d6e6688cf74f22783c9ec6e788c0790ee4fbbaee713affd00b1ac0bb39b86
|
||||
@@ -798,7 +801,7 @@ F test/crash.test fb9dc4a02dcba30d4aa5c2c226f98b220b2b959f
|
||||
F test/crash2.test 5b14d4eb58b880e231361d3b609b216acda86651
|
||||
F test/crash3.test 8f5de9d32ab9ab95475a9efe7f47a940aa889418
|
||||
F test/crash4.test fe2821baf37168dc59dd733dcf7dba2a401487bc
|
||||
F test/crash5.test f14ff37eddc41991be4eb63568f86caa306fd9962a0ae3750db8836777bb7aae
|
||||
F test/crash5.test 4aa55e7ac3c4bc511873e457aa65d2827d52da9b51e061511899dadcfe22b1e8
|
||||
F test/crash6.test 4c56f1e40d0291e1110790a99807aa875b1647ba
|
||||
F test/crash7.test 1a194c4900a255258cf94b7fcbfd29536db572df
|
||||
F test/crash8.test 64366e459c28dd62edfb7ad87253a409c7533b92d16fcc479a6a8131bdcc3100
|
||||
@@ -817,7 +820,7 @@ F test/dbdata.test 042f49acff3438f940eeba5868d3af080ae64ddf26ae78f80c92bec3ca7d8
|
||||
F test/dbfuzz.c 73047c920d6210e5912c87cdffd9a1c281d4252e
|
||||
F test/dbfuzz001.test 55e1a3504f8dea84155e09912fe3b1c3ad77e0b1a938ec42ca03b8e51b321e30
|
||||
F test/dbfuzz2-seed1.db e6225c6f3d7b63f9c5b6867146a5f329d997ab105bee64644dc2b3a2f2aebaee
|
||||
F test/dbfuzz2.c 40cc4600947f30600f0ab365a2714ec76a899c9adb2c0ccd63ba583b2f71390e
|
||||
F test/dbfuzz2.c db2a1710c0d30d38e1352ee1b52b717fcb224c8caacc6f10909ef540f73cc9e8
|
||||
F test/dbpage.test 650234ba683b9d82b899c6c51439819787e7609f17a0cc40e0080a7b6443bc38
|
||||
F test/dbstatus.test 4a4221a883025ffd39696b3d1b3910b928fb097d77e671351acb35f3aed42759
|
||||
F test/dbstatus2.test f5fe0afed3fa45e57cfa70d1147606c20d2ba23feac78e9a172f2fe8ab5b78ef
|
||||
@@ -872,6 +875,8 @@ F test/exclusive.test 7ff63be7503990921838d5c9f77f6e33e68e48ed1a9d48cd28745bf650
|
||||
F test/exclusive2.test 984090e8e9d1b331d2e8111daf6e5d61dda0bef7
|
||||
F test/exec.test e949714dc127eaa5ecc7d723efec1ec27118fdd7
|
||||
F test/exists.test 79a75323c78f02bbe9c251ea502a092f9ef63dac
|
||||
F test/exists2.test 3e5726d6a67ebd4bd3466db58be424c09156c1f276c7594abb260cbf6ad494d3
|
||||
F test/existsfault.test 74f7edc713f5a335e7ff47adf503067bf05c6f8630f88b2a19c24f0fa5486ab8
|
||||
F test/expr.test 26cd01e8485bc48c8aa6a1add598e9ce1e706b4eb4f3f554e0b0223022e8c2cf
|
||||
F test/expr2.test c27327ae9c017a7ff6280123f67aff496f912da74d78c888926d68b46ec75fd8
|
||||
F test/extension01.test 00d13cec817f331a687a243e0e5a2d87b0e358c9
|
||||
@@ -1016,7 +1021,7 @@ F test/fts4opt.test 0fd0cc84000743ff2a883b9b84b4a5be07249f0ba790c8848a757164cdd4
|
||||
F test/fts4record.test a48508f69a84c9287c8019d3a1ae712f5730d8335ffaf8e2101e691d078950bb
|
||||
F test/fts4rename.test 15fd9985c2bce6dea20da2245b22029ec89bd4710ed317c4c53abbe3cfd0c880
|
||||
F test/fts4umlaut.test fcaca4471de7e78c9d1f7e8976e3e8704d7d8ad979d57a739d00f3f757380429
|
||||
F test/fts4unicode.test ceca76422abc251818cb25dabe33d3c3970da5f7c90e1540f190824e6b3a7c95
|
||||
F test/fts4unicode.test 82a9c16b68ba2f358a856226bb2ee02f81583797bc4744061c54401bf1a0f4c9
|
||||
F test/fts4upfrom.test 8df5acb6e10ad73f393d1add082b042ab1db72567888847d098152121e507b34
|
||||
F test/full.test 6b3c8fb43c6beab6b95438c1675374b95fab245d
|
||||
F test/func.test f673822636fb8ed618dd2b80230d16e495d19c8f2e2e7d6c22e93e2b3de097ad
|
||||
@@ -1025,6 +1030,7 @@ F test/func3.test 2bb0f31ab7baaed690b962a88544d7be6b34fa389364bc36a44e441ed3e3f1
|
||||
F test/func4.test 2285fb5792d593fef442358763f0fd9de806eda47dbc7a5934df57ffdc484c31
|
||||
F test/func5.test 863e6d1bd0013d09c17236f8a13ea34008dd857d87d85a13a673960e4c25d82a
|
||||
F test/func6.test 90e42b64c4f9fb6f04f44cb8a1da586c8542502e926b19c76504fe74ff2a9b7c
|
||||
F test/func7.test bb05a77daedf0e3f8764f323a49bc3b8d98f280a0bc6a370387117f4596bde05
|
||||
F test/fuzz-oss1.test e58330d01cbbd8215ee636b17a03fe220b37dbfa
|
||||
F test/fuzz.test 96083052bf5765e4518c1ba686ce2bab785670d1
|
||||
F test/fuzz2.test 76dc35b32b6d6f965259508508abce75a6c4d7e1
|
||||
@@ -1032,7 +1038,7 @@ F test/fuzz3.test 9c813e6613b837cb7a277b0383cd66bfa07042b4cf0317157c35852f30043c
|
||||
F test/fuzz4.test c229bcdb45518a89e1d208a21343e061503460ac69fae1539320a89f572eb634
|
||||
F test/fuzz_common.tcl b7197de6ed1ee8250a4f82d67876f4561b42ee8cbbfc6160dcb66331bad3f830
|
||||
F test/fuzz_malloc.test f348276e732e814802e39f042b1f6da6362a610af73a528d8f76898fde6b22f2
|
||||
F test/fuzzcheck.c 5f81f2cc65f13068620245f2e2c6059657d3b26be476df379ae2da539f17676d
|
||||
F test/fuzzcheck.c 95427205d6cedb8fdb95bf7738e95785c790febf782d9c1e6067baaa1adc871d
|
||||
F test/fuzzdata1.db d36e88741b4f23bcbaaf55b006290669d03c6c891cf13c7b3a53bc1b097b693f
|
||||
F test/fuzzdata2.db 128b3feeb78918d075c9b14b48610145a0dd4c8d6f1ca7c2870c7e425f5bf31f
|
||||
F test/fuzzdata3.db c6586d3e3cef0fbc18108f9bb649aa77bfc38aba
|
||||
@@ -1040,14 +1046,14 @@ F test/fuzzdata4.db b502c7d5498261715812dd8b3c2005bad08b3a26e6489414bd13926cd3e4
|
||||
F test/fuzzdata5.db e35f64af17ec48926481cfaf3b3855e436bd40d1cfe2d59a9474cb4b748a52a5
|
||||
F test/fuzzdata6.db 92a80e4afc172c24f662a10a612d188fb272de4a9bd19e017927c95f737de6d7
|
||||
F test/fuzzdata7.db 0166b56fd7a6b9636a1d60ef0a060f86ddaecf99400a666bb6e5bbd7199ad1f2
|
||||
F test/fuzzdata8.db f8451a1fd38efbea8c1a7cdf5d02259c4702446a9fabf566becd306b64a50236
|
||||
F test/fuzzdata8.db 7f6c5443d67ba040f760b4d28da54cc9f68174fa212ae34ccb86c645de761ec4
|
||||
F test/fuzzer1.test 3d4c4b7e547aba5e5511a2991e3e3d07166cfbb8
|
||||
F test/fuzzer2.test a85ef814ce071293bce1ad8dffa217cbbaad4c14
|
||||
F test/fuzzerfault.test 8792cd77fd5bce765b05d0c8e01b9edcf8af8536
|
||||
F test/gcfault.test dd28c228a38976d6336a3fc42d7e5f1ad060cb8c
|
||||
F test/gencol1.test b05e6c5edb9b10d48efb634ed07342441bddc89d225043e17095c36e567521a0
|
||||
F test/genesis.tcl 1e2e2e8e5cc4058549a154ff1892fe5c9de19f98
|
||||
F test/having.test e4098a4b8962f9596035c3b87a8928a10648acc509f1bb8d6f96413bbf79a1b3
|
||||
F test/having.test a89236dd8d55aa50c4805f82ac9daf64d477a44d712d8209c118978d0ca21ec9
|
||||
F test/hexlit.test 4a6a5f46e3c65c4bf1fa06f5dd5a9507a5627751
|
||||
F test/hidden.test 23c1393a79e846d68fd902d72c85d5e5dcf98711
|
||||
F test/hook.test e97382e68e4379838e888756d653afd159f5f14780315ff97b70360d3d8485bc
|
||||
@@ -1328,7 +1334,7 @@ F test/select8.test 8c8f5ae43894c891efc5755ed905467d1d67ad5d
|
||||
F test/select9.test aebc2bb0c3bc44606125033cbcaac2c8d1f33a95
|
||||
F test/selectA.test 68de52409e45a3313d00b8461b48bef4fb729faf36ade9067a994eae55cc86f4
|
||||
F test/selectB.test 954e4e49cf1f896d61794e440669e03a27ceea25
|
||||
F test/selectC.test e25243f8ca503e06f252eb0218976d07cfeceac3
|
||||
F test/selectC.test fec14c9015ed4ec941508bbc144f30b42e40ac34a4bb33001450369865dd0b75
|
||||
F test/selectD.test fc20452847a01775710090383cfb4423275d2f745fed61f34fbf37573ac0d214
|
||||
F test/selectE.test a8730ca330fcf40ace158f134f4fe0eb00c7edbf
|
||||
F test/selectF.test 21c94e6438f76537b72532fa9fd4710cdd455fc3
|
||||
@@ -1349,10 +1355,10 @@ 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 0ba53c72545de142e1b76fa793ee33293134aa02abb9b50b35398670481ea661
|
||||
F test/shell1.test 56a7358a2a05e850e9e4aa24629db9c8975e8038dbe8debd2d95be22a5f03612
|
||||
F test/shell2.test e242a9912f44f4c23c3d1d802a83e934e84c853b
|
||||
F test/shell3.test ac8c2b744014c3e9a0e26bfd829ab65f00923dc1a91ffd044863e9423cc91494
|
||||
F test/shell4.test 1c6aef11daaa2d6830acaba3ac9cbec93fbc1c3d5530743a637f39b3987d08ce
|
||||
F test/shell4.test 3ed6c4b42fd695efcbc25d69ef759dbb15855ca8e52ba6c5ee076f8b435f48be
|
||||
F test/shell5.test 84a30b55722a95a5b72989e691c469a999ca7591e7aa00b7fabc783ea5c9a6fe
|
||||
F test/shell6.test 1ceb51b2678c472ba6cf1e5da96679ce8347889fe2c3bf93a0e0fa73f00b00d3
|
||||
F test/shell7.test 115132f66d0463417f408562cc2cf534f6bbc6d83a6d50f0072a9eb171bae97f
|
||||
@@ -1390,7 +1396,7 @@ F test/speed3.test 694affeb9100526007436334cf7d08f3d74b85ef
|
||||
F test/speed4.test abc0ad3399dcf9703abed2fff8705e4f8e416715
|
||||
F test/speed4p.explain 6b5f104ebeb34a038b2f714150f51d01143e59aa
|
||||
F test/speed4p.test 377a0c48e5a92e0b11c1c5ebb1bc9d83a7312c922bc0cb05970ef5d6a96d1f0c
|
||||
F test/speedtest1.c 849dbcb0bded9f966e43f28e8ce824b2915cb5dd0031a2e85996f7e3de36c2b1
|
||||
F test/speedtest1.c 5e5b805f24cc939656058f6a498f5a2160f9142e4815c54faf758ec798d4cdad
|
||||
F test/spellfix.test 951a6405d49d1a23d6b78027d3877b4a33eeb8221dcab5704b499755bb4f552e
|
||||
F test/spellfix2.test dfc8f519a3fc204cb2dfa8b4f29821ae90f6f8c3
|
||||
F test/spellfix3.test 0f9efaaa502a0e0a09848028518a6fb096c8ad33
|
||||
@@ -1398,6 +1404,7 @@ F test/spellfix4.test 51c7c26514ade169855c66bcf130bd5acfb4d7fd090cc624645ab275ae
|
||||
F test/sqldiff1.test 28cd737cf1b0078b1ec1bbf425e674c47785835e
|
||||
F test/sqllimits1.test 264f4b0f941800ba139d25e33ee919c5d95fea06dfbe8ac291d6811a30984ca5
|
||||
F test/sqllog.test 6af6cb0b09f4e44e1917e06ce85be7670302517a
|
||||
F test/startup.c 1beb5ca66fcc0fce95c3444db9d1674f90fc605499a574ae2434dcfc10d22805
|
||||
F test/stat.test 15a3106eddedfc882f64bc09f237b4169be4b92dd57c93031b8ff8b13af3e7c5
|
||||
F test/statfault.test f525a7bf633e50afd027700e9a486090684b1ac1
|
||||
F test/stmt.test 54ed2cc0764bf3e48a058331813c3dbd19fc1d0827c3d8369914a5d8f564ec75
|
||||
@@ -1431,7 +1438,7 @@ F test/temptable.test d2c9b87a54147161bcd1822e30c1d1cd891e5b30
|
||||
F test/temptable2.test d2940417496e2b9548e01d09990763fbe88c316504033256d51493e1f1a5ce6a
|
||||
F test/temptable3.test d11a0974e52b347e45ee54ef1923c91ed91e4637
|
||||
F test/temptrigger.test 38f0ca479b1822d3117069e014daabcaacefffcc
|
||||
F test/tester.tcl 754521f0db534d51ab504b2d14fe0bdca1f1c15de731ceb8ee5bfd78372a2a5f
|
||||
F test/tester.tcl e5e4f5707fbf791ff8e06438fd0d4d71fe4c1d48753b7dd415efe72e853ef877
|
||||
F test/thread001.test b61a29dd87cf669f5f6ac96124a7c97d71b0c80d9012746072055877055cf9ef
|
||||
F test/thread002.test e630504f8a06c00bf8bbe68528774dd96aeb2e58
|
||||
F test/thread003.test ee4c9efc3b86a6a2767516a37bd64251272560a7
|
||||
@@ -1592,7 +1599,7 @@ F test/tokenize.test ce430a7aed48fc98301611429595883fdfcab5d7
|
||||
F test/tpch01.test 7c4eb8cdd79c568f46d344b3e789c9fdb8a766d112871352704861f3fca32a2a
|
||||
F test/trace.test a659a9862957f4789e37a92b3bf6d2caf5c86b02cdeefc41e850ae53acf6992a
|
||||
F test/trace2.test f5cb67ad3bc09e0c58e8cca78dfd0b5639259983
|
||||
F test/trace3.test 1dff966888773ff1bfea01c080caf15417892b3f998408fe920c4791f7337144
|
||||
F test/trace3.test ae2004df24b585fed9046cc0bae4601762bc6fc4aa321d475f1350bba5047f31
|
||||
F test/trans.test 45f6f9ab6f66a7b5744f1caac06b558f95da62501916906cf55586a896f9f439
|
||||
F test/trans2.test 62bd045bfc7a1c14c5ba83ba64d21ade31583f76
|
||||
F test/trans3.test 91a100e5412b488e22a655fe423a14c26403ab94
|
||||
@@ -1610,7 +1617,7 @@ F test/triggerA.test 837be862d8721f903dba3f3ceff05b32e0bee5214cf6ea3da5fadf12d36
|
||||
F test/triggerB.test 56780c031b454abac2340dbb3b71ac5c56c3d7fe
|
||||
F test/triggerC.test 29f5a28d0fe39e6e2c01f6e1f53f08c0955170ae10a63ad023e33cb0a1682a51
|
||||
F test/triggerD.test 8e7f3921a92a5797d472732108109e44575fa650
|
||||
F test/triggerE.test ede2e4bce4ba802337bd69d39447fa04a938e06d84a8bfc53c76850fc36ed86d
|
||||
F test/triggerE.test 612969cb57a4ef792059ad6d01af0117e1ae862c283753ffcc9a6428642b22ee
|
||||
F test/triggerF.test 5d76f0a8c428ff87a4d5ed52da06f6096a2c787a1e21b846111dfac4123de3ad
|
||||
F test/triggerG.test 2b816093c91ba73c733cfa8aedcc210ad819d72a98b1da30768a3c56505233e9
|
||||
F test/triggerupfrom.test d25961fa70a99b6736193da7b49a36d8c1d28d56188f0be6406d4366315cd6e4
|
||||
@@ -1624,6 +1631,9 @@ F test/tt3_vacuum.c 1753f45917699c9c1f66b64c717a717c9379f776
|
||||
F test/types.test bf816ce73c7dfcfe26b700c19f97ef4050d194ff
|
||||
F test/types2.test 1aeb81976841a91eef292723649b5c4fe3bc3cac
|
||||
F test/types3.test 99e009491a54f4dc02c06bdbc0c5eea56ae3e25a
|
||||
F test/unionall.test ca6f612930c79e30f41f804dff4cce949b61347930847642e333ecd5d79f5964
|
||||
F test/unionall2.test c9a62db63350bcbce3a7bec50dd8c5410f08be33f8af435473756286d4657215
|
||||
F test/unionallfault.test 652bfbb630e6c43135965dc1e8f0a9a791da83aec885d626a632fe1909c56f73
|
||||
F test/unionvtab.test e1704ab1b4c1bb3ffc9da4681f8e85a0b909fd80b937984fc94b27415ac8e5a4
|
||||
F test/unionvtabfault.test e8759f3d14fb938ce9657e2342db34aeac0fb9bc1692b0d1ebb0069630151d06
|
||||
F test/unique.test 93f8b2ef5ea51b9495f8d6493429b1fd0f465264
|
||||
@@ -1641,6 +1651,7 @@ F test/upsert1.test 88f9e258c6a0eeeb85937b08831e8daad440ba41f125af48439e9d33f266
|
||||
F test/upsert2.test 9c3cdbb1a890227f6504ce4b0e3de68f4cdfa16bb21d8641208a9239896c5a09
|
||||
F test/upsert3.test 88d7d590a1948a9cb6eac1b54b0642f67a9f35a1fc0f19b200e97d5d39e3179c
|
||||
F test/upsert4.test 25d2a1da92f149331ae0c51ca6e3eee78189577585eab92de149900d62994fa5
|
||||
F test/upsert5.test f49faf5f15b5c3641c6f5d7c7cc531ef5ac997567b2b6bb7bc96f7c88753ca0b
|
||||
F test/upsertfault.test f21ca47740841fdb4d61acfa7b17646d773e67724fe8c185b71c018db8a94b35
|
||||
F test/uri.test 3481026f00ade6dfe8adb7acb6e1e47b04369568
|
||||
F test/uri2.test 9d3ba7a53ee167572d53a298ee4a5d38ec4a8fb7
|
||||
@@ -1648,10 +1659,11 @@ F test/userauth01.test e740a2697a7b40d7c5003a7d7edaee16acd349a9
|
||||
F test/utf16align.test 54cd35a27c005a9b6e7815d887718780b6a462ae
|
||||
F test/vacuum-into.test 48f4cec354fb6f27c98ef58d2fe49a11b71ff131af0cd9140efacc9858b9f670
|
||||
F test/vacuum.test ce91c39f7f91a4273bf620efad21086b5aa6ef1d
|
||||
F test/vacuum2.test aa048abee196c16c9ba308465494009057b79f9b
|
||||
F test/vacuum2.test 9fd45ce6ce29f5614c249e03938d3567c06a9e772d4f155949f8eafe2d8af520
|
||||
F test/vacuum3.test 77ecdd54592b45a0bcb133339f99f1ae0ae94d0d
|
||||
F test/vacuum4.test 7ea76b769fffeb41f925303b04cbcf5a5bbeabe55e4c60ae754ff24eeeb7c010
|
||||
F test/vacuum5.test 263b144d537e92ad8e9ca8a73cc6e1583f41cfd0dda9432b87f7806174a2f48c
|
||||
F test/vacuum6.test d3173a54edc81d13d99e4cf4972232b3cbb52f1d56ed48c3a939ef4e751c1ee8
|
||||
F test/vacuummem.test 7b42abb3208bd82dd23a7536588396f295a314f2
|
||||
F test/varint.test bbce22cda8fc4d135bcc2b589574be8410614e62
|
||||
F test/veryquick.test 57ab846bacf7b90cf4e9a672721ea5c5b669b661
|
||||
@@ -1713,7 +1725,7 @@ F test/walsetlk.test 11f7fe792fdce54cf09874dab824e0627f2eedecfb9f7983e325606ec51
|
||||
F test/walshared.test 0befc811dcf0b287efae21612304d15576e35417
|
||||
F test/walslow.test c05c68d4dc2700a982f89133ce103a1a84cc285f
|
||||
F test/walthread.test 14b20fcfa6ae152f5d8e12f5dc8a8a724b7ef189f5d8ef1e2ceab79f2af51747
|
||||
F test/walvfs.test a2913001a83b19c1d20220e556cee14d87d47ecb6949b5e0a2e9e2590abecf1e
|
||||
F test/walvfs.test bccb3e0d235ef85e276f491d34db32c9ada1ea67be8d9f10aabe7b30319ec656
|
||||
F test/wapp.tcl b440cd8cf57953d3a49e7ee81e6a18f18efdaf113b69f7d8482b0710a64566ec
|
||||
F test/wapptest.tcl 899594e25684861d5b0c0880fb012364def50ef8097041b8ddf74be5ba7fa270 x
|
||||
F test/where.test e713c0c64e3e6b062235e39a2f7e5508c517df16b63d69fd786e26bc7330b1c6
|
||||
@@ -1736,7 +1748,7 @@ F test/whereH.test e4b07f7a3c2f5d31195cd33710054c78667573b2
|
||||
F test/whereI.test a2874062140ed4aba9ffae76e6190a3df6fc73d1373fdfa8fd632945082a5364
|
||||
F test/whereJ.test 88287550f6ee604422403b053455b1ad894eeaa5c35d348532dfa1439286cb9a
|
||||
F test/whereK.test f8e3cf26a8513ecc7f514f54df9f0572c046c42b
|
||||
F test/whereL.test e05cedc9389c6f09ad55bd5999a3fddccebec90672fb989433c145dcdaf26996
|
||||
F test/whereL.test 1afe47227f093dc0547236491fb37529b7be9724b8575925a321001b80e6a23a
|
||||
F test/wherefault.test 1374c3aa198388925246475f84ad4cd5f9528864
|
||||
F test/wherelfault.test 9012e4ef5259058b771606616bd007af5d154e64cc25fa9fd4170f6411db44e3
|
||||
F test/wherelimit.test 592081800806d297dd7449b1030c863d2883d6d42901837ccd2e5a9bd962edb0
|
||||
@@ -1805,8 +1817,8 @@ 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 70eedc31614a58fe31a71025c17ebd1502a6ce9cfef0ed5e33acb0b5b737b291
|
||||
F tool/lempar.c 0e1d5eeb9736108d3dba782a9dd56f4e7cb69006b6ee181308b7ebfb15313a12
|
||||
F tool/lemon.c d44ba4f03427c9bd34b601f315fe77c2b6d4bd215801a0259aeedbcc4c94a95c
|
||||
F tool/lempar.c 1d3d075da18681c67ecc66c1f171e7094e18cd2cfba6a8a1bd4f3f639d6656e1
|
||||
F tool/libvers.c caafc3b689638a1d88d44bc5f526c2278760d9b9
|
||||
F tool/loadfts.c c3c64e4d5e90e8ba41159232c2189dba4be7b862
|
||||
F tool/logest.c 11346aa019e2e77a00902aa7d0cabd27bd2e8cca
|
||||
@@ -1814,7 +1826,7 @@ F tool/max-limits.c cbb635fbb37ae4d05f240bfb5b5270bb63c54439
|
||||
F tool/mkautoconfamal.sh f62353eb6c06ab264da027fd4507d09914433dbdcab9cb011cdc18016f1ab3b8
|
||||
F tool/mkccode.tcl 86463e68ce9c15d3041610fedd285ce32a5cf7a58fc88b3202b8b76837650dbe x
|
||||
F tool/mkctimec.tcl dd183b73ae1c28249669741c250525f0407e579a70482371668fd5f130d9feb3
|
||||
F tool/mkkeywordhash.c 11a3f3af8e787d0c5ca459ed66fe80fd09e661876506e7b978ec08c19477bdc2
|
||||
F tool/mkkeywordhash.c 24e4396ae665d985fed9e040e8b748129c1a12d77eeeae7ad4609821c41ba7bf
|
||||
F tool/mkmsvcmin.tcl 6ecab9fe22c2c8de4d82d4c46797bda3d2deac8e763885f5a38d0c44a895ab33
|
||||
F tool/mkopcodec.tcl d1b6362bd3aa80d5520d4d6f3765badf01f6c43c
|
||||
F tool/mkopcodeh.tcl 352a4319c0ad869eb26442bf7c3b015aa15594c21f1cce5a6420dbe999367c21
|
||||
@@ -1886,7 +1898,10 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||
P d36d6f2923a2393c751c0ac7634433453be20df7567fd914e57cbb1ae15f68b2
|
||||
R ef71c1d96862a5ef1769c7803a088f57
|
||||
U drh
|
||||
Z 7ead96ffcfc794dcb28dd96880ba576c
|
||||
P d1873054d8e1006a370ea7891dbb9a62e7d36ce98cb92b58dcb0daf271265de3
|
||||
R 56f323b51c91a7109bc328027a56f7a2
|
||||
T *branch * fix-over-trigger
|
||||
T *sym-fix-over-trigger *
|
||||
T -sym-trunk *
|
||||
U dan
|
||||
Z c7d4efd5b6b0d32bc23a7887ed998edc
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
3a4c98b989964e3e366fe9519e9b5ed935e893d5b69d92bc0388a14c7e7938e6
|
||||
4f676466e60ee2a420b7b2deace76f3a733ce1af278347428285715d9c67f022
|
||||
+5
-2
@@ -381,11 +381,14 @@ void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
|
||||
*zEnd-- = '\0';
|
||||
}
|
||||
db->mDbFlags |= DBFLAG_PreferBuiltin;
|
||||
/* substr() operations on characters, but addColOffset is in bytes. So we
|
||||
** have to use printf() to translate between these units: */
|
||||
sqlite3NestedParse(pParse,
|
||||
"UPDATE \"%w\"." DFLT_SCHEMA_TABLE " SET "
|
||||
"sql = substr(sql,1,%d) || ', ' || %Q || substr(sql,%d) "
|
||||
"sql = printf('%%.%ds, ',sql) || %Q"
|
||||
" || substr(sql,1+length(printf('%%.%ds',sql))) "
|
||||
"WHERE type = 'table' AND name = %Q",
|
||||
zDb, pNew->addColOffset, zCol, pNew->addColOffset+1,
|
||||
zDb, pNew->addColOffset, zCol, pNew->addColOffset,
|
||||
zTab
|
||||
);
|
||||
sqlite3DbFree(db, zCol);
|
||||
|
||||
+84
-114
@@ -433,6 +433,63 @@ void sqlite3Attach(Parse *pParse, Expr *p, Expr *pDbname, Expr *pKey){
|
||||
}
|
||||
#endif /* SQLITE_OMIT_ATTACH */
|
||||
|
||||
/*
|
||||
** Expression callback used by sqlite3FixAAAA() routines.
|
||||
*/
|
||||
static int fixExprCb(Walker *p, Expr *pExpr){
|
||||
DbFixer *pFix = p->u.pFix;
|
||||
if( !pFix->bTemp ) ExprSetProperty(pExpr, EP_FromDDL);
|
||||
if( pExpr->op==TK_VARIABLE ){
|
||||
if( pFix->pParse->db->init.busy ){
|
||||
pExpr->op = TK_NULL;
|
||||
}else{
|
||||
sqlite3ErrorMsg(pFix->pParse, "%s cannot use variables", pFix->zType);
|
||||
return WRC_Abort;
|
||||
}
|
||||
}
|
||||
return WRC_Continue;
|
||||
}
|
||||
|
||||
/*
|
||||
** Select callback used by sqlite3FixAAAA() routines.
|
||||
*/
|
||||
static int fixSelectCb(Walker *p, Select *pSelect){
|
||||
DbFixer *pFix = p->u.pFix;
|
||||
int i;
|
||||
struct SrcList_item *pItem;
|
||||
sqlite3 *db = pFix->pParse->db;
|
||||
int iDb = sqlite3FindDbName(db, pFix->zDb);
|
||||
SrcList *pList = pSelect->pSrc;
|
||||
|
||||
if( NEVER(pList==0) ) return WRC_Continue;
|
||||
for(i=0, pItem=pList->a; i<pList->nSrc; i++, pItem++){
|
||||
if( pFix->bTemp==0 ){
|
||||
if( pItem->zDatabase && iDb!=sqlite3FindDbName(db, pItem->zDatabase) ){
|
||||
sqlite3ErrorMsg(pFix->pParse,
|
||||
"%s %T cannot reference objects in database %s",
|
||||
pFix->zType, pFix->pName, pItem->zDatabase);
|
||||
return WRC_Abort;
|
||||
}
|
||||
sqlite3DbFree(db, pItem->zDatabase);
|
||||
pItem->zDatabase = 0;
|
||||
pItem->pSchema = pFix->pSchema;
|
||||
pItem->fg.fromDDL = 1;
|
||||
}
|
||||
#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER)
|
||||
if( sqlite3WalkExpr(&pFix->w, pList->a[i].pOn) ) return WRC_Abort;
|
||||
#endif
|
||||
}
|
||||
if( pSelect->pWith ){
|
||||
int i;
|
||||
for(i=0; i<pSelect->pWith->nCte; i++){
|
||||
if( sqlite3WalkSelect(p, pSelect->pWith->a[i].pSelect) ){
|
||||
return WRC_Abort;
|
||||
}
|
||||
}
|
||||
}
|
||||
return WRC_Continue;
|
||||
}
|
||||
|
||||
/*
|
||||
** Initialize a DbFixer structure. This routine must be called prior
|
||||
** to passing the structure to one of the sqliteFixAAAA() routines below.
|
||||
@@ -444,9 +501,7 @@ void sqlite3FixInit(
|
||||
const char *zType, /* "view", "trigger", or "index" */
|
||||
const Token *pName /* Name of the view, trigger, or index */
|
||||
){
|
||||
sqlite3 *db;
|
||||
|
||||
db = pParse->db;
|
||||
sqlite3 *db = pParse->db;
|
||||
assert( db->nDb>iDb );
|
||||
pFix->pParse = pParse;
|
||||
pFix->zDb = db->aDb[iDb].zDbSName;
|
||||
@@ -454,6 +509,13 @@ void sqlite3FixInit(
|
||||
pFix->zType = zType;
|
||||
pFix->pName = pName;
|
||||
pFix->bTemp = (iDb==1);
|
||||
pFix->w.pParse = pParse;
|
||||
pFix->w.xExprCallback = fixExprCb;
|
||||
pFix->w.xSelectCallback = fixSelectCb;
|
||||
pFix->w.xSelectCallback2 = 0;
|
||||
pFix->w.walkerDepth = 0;
|
||||
pFix->w.eCode = 0;
|
||||
pFix->w.u.pFix = pFix;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -474,115 +536,27 @@ int sqlite3FixSrcList(
|
||||
DbFixer *pFix, /* Context of the fixation */
|
||||
SrcList *pList /* The Source list to check and modify */
|
||||
){
|
||||
int i;
|
||||
struct SrcList_item *pItem;
|
||||
sqlite3 *db = pFix->pParse->db;
|
||||
int iDb = sqlite3FindDbName(db, pFix->zDb);
|
||||
|
||||
if( NEVER(pList==0) ) return 0;
|
||||
|
||||
for(i=0, pItem=pList->a; i<pList->nSrc; i++, pItem++){
|
||||
if( pFix->bTemp==0 ){
|
||||
if( pItem->zDatabase && iDb!=sqlite3FindDbName(db, pItem->zDatabase) ){
|
||||
sqlite3ErrorMsg(pFix->pParse,
|
||||
"%s %T cannot reference objects in database %s",
|
||||
pFix->zType, pFix->pName, pItem->zDatabase);
|
||||
return 1;
|
||||
}
|
||||
sqlite3DbFree(db, pItem->zDatabase);
|
||||
pItem->zDatabase = 0;
|
||||
pItem->pSchema = pFix->pSchema;
|
||||
pItem->fg.fromDDL = 1;
|
||||
}
|
||||
#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER)
|
||||
if( sqlite3FixSelect(pFix, pItem->pSelect) ) return 1;
|
||||
if( sqlite3FixExpr(pFix, pItem->pOn) ) return 1;
|
||||
#endif
|
||||
if( pItem->fg.isTabFunc && sqlite3FixExprList(pFix, pItem->u1.pFuncArg) ){
|
||||
return 1;
|
||||
}
|
||||
int res = 0;
|
||||
if( pList ){
|
||||
Select s;
|
||||
memset(&s, 0, sizeof(s));
|
||||
s.pSrc = pList;
|
||||
res = sqlite3WalkSelect(&pFix->w, &s);
|
||||
}
|
||||
return 0;
|
||||
return res;
|
||||
}
|
||||
#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER)
|
||||
int sqlite3FixSelect(
|
||||
DbFixer *pFix, /* Context of the fixation */
|
||||
Select *pSelect /* The SELECT statement to be fixed to one database */
|
||||
){
|
||||
while( pSelect ){
|
||||
if( sqlite3FixExprList(pFix, pSelect->pEList) ){
|
||||
return 1;
|
||||
}
|
||||
if( sqlite3FixSrcList(pFix, pSelect->pSrc) ){
|
||||
return 1;
|
||||
}
|
||||
if( sqlite3FixExpr(pFix, pSelect->pWhere) ){
|
||||
return 1;
|
||||
}
|
||||
if( sqlite3FixExprList(pFix, pSelect->pGroupBy) ){
|
||||
return 1;
|
||||
}
|
||||
if( sqlite3FixExpr(pFix, pSelect->pHaving) ){
|
||||
return 1;
|
||||
}
|
||||
if( sqlite3FixExprList(pFix, pSelect->pOrderBy) ){
|
||||
return 1;
|
||||
}
|
||||
if( sqlite3FixExpr(pFix, pSelect->pLimit) ){
|
||||
return 1;
|
||||
}
|
||||
if( pSelect->pWith ){
|
||||
int i;
|
||||
for(i=0; i<pSelect->pWith->nCte; i++){
|
||||
if( sqlite3FixSelect(pFix, pSelect->pWith->a[i].pSelect) ){
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
pSelect = pSelect->pPrior;
|
||||
}
|
||||
return 0;
|
||||
return sqlite3WalkSelect(&pFix->w, pSelect);
|
||||
}
|
||||
int sqlite3FixExpr(
|
||||
DbFixer *pFix, /* Context of the fixation */
|
||||
Expr *pExpr /* The expression to be fixed to one database */
|
||||
){
|
||||
while( pExpr ){
|
||||
if( !pFix->bTemp ) ExprSetProperty(pExpr, EP_FromDDL);
|
||||
if( pExpr->op==TK_VARIABLE ){
|
||||
if( pFix->pParse->db->init.busy ){
|
||||
pExpr->op = TK_NULL;
|
||||
}else{
|
||||
sqlite3ErrorMsg(pFix->pParse, "%s cannot use variables", pFix->zType);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if( ExprHasProperty(pExpr, EP_TokenOnly|EP_Leaf) ) break;
|
||||
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
|
||||
if( sqlite3FixSelect(pFix, pExpr->x.pSelect) ) return 1;
|
||||
}else{
|
||||
if( sqlite3FixExprList(pFix, pExpr->x.pList) ) return 1;
|
||||
}
|
||||
if( sqlite3FixExpr(pFix, pExpr->pRight) ){
|
||||
return 1;
|
||||
}
|
||||
pExpr = pExpr->pLeft;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
int sqlite3FixExprList(
|
||||
DbFixer *pFix, /* Context of the fixation */
|
||||
ExprList *pList /* The expression to be fixed to one database */
|
||||
){
|
||||
int i;
|
||||
struct ExprList_item *pItem;
|
||||
if( pList==0 ) return 0;
|
||||
for(i=0, pItem=pList->a; i<pList->nExpr; i++, pItem++){
|
||||
if( sqlite3FixExpr(pFix, pItem->pExpr) ){
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
return sqlite3WalkExpr(&pFix->w, pExpr);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -592,25 +566,20 @@ int sqlite3FixTriggerStep(
|
||||
TriggerStep *pStep /* The trigger step be fixed to one database */
|
||||
){
|
||||
while( pStep ){
|
||||
if( sqlite3FixSelect(pFix, pStep->pSelect) ){
|
||||
return 1;
|
||||
}
|
||||
if( sqlite3FixExpr(pFix, pStep->pWhere) ){
|
||||
return 1;
|
||||
}
|
||||
if( sqlite3FixExprList(pFix, pStep->pExprList) ){
|
||||
return 1;
|
||||
}
|
||||
if( pStep->pFrom && sqlite3FixSrcList(pFix, pStep->pFrom) ){
|
||||
if( sqlite3WalkSelect(&pFix->w, pStep->pSelect)
|
||||
|| sqlite3WalkExpr(&pFix->w, pStep->pWhere)
|
||||
|| sqlite3WalkExprList(&pFix->w, pStep->pExprList)
|
||||
|| sqlite3FixSrcList(pFix, pStep->pFrom)
|
||||
){
|
||||
return 1;
|
||||
}
|
||||
#ifndef SQLITE_OMIT_UPSERT
|
||||
if( pStep->pUpsert ){
|
||||
Upsert *pUp = pStep->pUpsert;
|
||||
if( sqlite3FixExprList(pFix, pUp->pUpsertTarget)
|
||||
|| sqlite3FixExpr(pFix, pUp->pUpsertTargetWhere)
|
||||
|| sqlite3FixExprList(pFix, pUp->pUpsertSet)
|
||||
|| sqlite3FixExpr(pFix, pUp->pUpsertWhere)
|
||||
if( sqlite3WalkExprList(&pFix->w, pUp->pUpsertTarget)
|
||||
|| sqlite3WalkExpr(&pFix->w, pUp->pUpsertTargetWhere)
|
||||
|| sqlite3WalkExprList(&pFix->w, pUp->pUpsertSet)
|
||||
|| sqlite3WalkExpr(&pFix->w, pUp->pUpsertWhere)
|
||||
){
|
||||
return 1;
|
||||
}
|
||||
@@ -618,6 +587,7 @@ int sqlite3FixTriggerStep(
|
||||
#endif
|
||||
pStep = pStep->pNext;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
+1
-5
@@ -209,11 +209,7 @@ int sqlite3AuthCheck(
|
||||
** or if the parser is being invoked from within sqlite3_declare_vtab.
|
||||
*/
|
||||
assert( !IN_RENAME_OBJECT || db->xAuth==0 );
|
||||
if( db->init.busy || IN_SPECIAL_PARSE ){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
if( db->xAuth==0 ){
|
||||
if( db->xAuth==0 || db->init.busy || IN_SPECIAL_PARSE ){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
|
||||
+145
-4
@@ -1143,6 +1143,24 @@ static SQLITE_NOINLINE void btreeParseCellAdjustSizeForOverflow(
|
||||
pInfo->nSize = (u16)(&pInfo->pPayload[pInfo->nLocal] - pCell) + 4;
|
||||
}
|
||||
|
||||
/*
|
||||
** Given a record with nPayload bytes of payload stored within btree
|
||||
** page pPage, return the number of bytes of payload stored locally.
|
||||
*/
|
||||
static int btreePayloadToLocal(MemPage *pPage, i64 nPayload){
|
||||
int maxLocal; /* Maximum amount of payload held locally */
|
||||
maxLocal = pPage->maxLocal;
|
||||
if( nPayload<=maxLocal ){
|
||||
return nPayload;
|
||||
}else{
|
||||
int minLocal; /* Minimum amount of payload held locally */
|
||||
int surplus; /* Overflow payload available for local storage */
|
||||
minLocal = pPage->minLocal;
|
||||
surplus = minLocal + (nPayload - minLocal)%(pPage->pBt->usableSize-4);
|
||||
return ( surplus <= maxLocal ) ? surplus : minLocal;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** The following routines are implementations of the MemPage.xParseCell()
|
||||
** method.
|
||||
@@ -8660,7 +8678,8 @@ int sqlite3BtreeInsert(
|
||||
unsigned char *oldCell;
|
||||
unsigned char *newCell = 0;
|
||||
|
||||
assert( (flags & (BTREE_SAVEPOSITION|BTREE_APPEND))==flags );
|
||||
assert( (flags & (BTREE_SAVEPOSITION|BTREE_APPEND|BTREE_PREFORMAT))==flags );
|
||||
assert( (flags & BTREE_PREFORMAT)==0 || seekResult || pCur->pKeyInfo==0 );
|
||||
|
||||
if( pCur->eState==CURSOR_FAULT ){
|
||||
assert( pCur->skipNext!=SQLITE_OK );
|
||||
@@ -8678,7 +8697,7 @@ int sqlite3BtreeInsert(
|
||||
** keys with no associated data. If the cursor was opened expecting an
|
||||
** intkey table, the caller should be inserting integer keys with a
|
||||
** blob of associated data. */
|
||||
assert( (pX->pKey==0)==(pCur->pKeyInfo==0) );
|
||||
assert( (flags & BTREE_PREFORMAT) || (pX->pKey==0)==(pCur->pKeyInfo==0) );
|
||||
|
||||
/* Save the positions of any other cursors open on this table.
|
||||
**
|
||||
@@ -8788,7 +8807,7 @@ int sqlite3BtreeInsert(
|
||||
|| CORRUPT_DB );
|
||||
|
||||
pPage = pCur->pPage;
|
||||
assert( pPage->intKey || pX->nKey>=0 );
|
||||
assert( pPage->intKey || pX->nKey>=0 || (flags & BTREE_PREFORMAT) );
|
||||
assert( pPage->leaf || !pPage->intKey );
|
||||
if( pPage->nFree<0 ){
|
||||
if( pCur->eState>CURSOR_INVALID ){
|
||||
@@ -8805,7 +8824,21 @@ int sqlite3BtreeInsert(
|
||||
assert( pPage->isInit );
|
||||
newCell = pBt->pTmpSpace;
|
||||
assert( newCell!=0 );
|
||||
rc = fillInCell(pPage, newCell, pX, &szNew);
|
||||
if( flags & BTREE_PREFORMAT ){
|
||||
rc = SQLITE_OK;
|
||||
szNew = pBt->nPreformatSize;
|
||||
if( szNew<4 ) szNew = 4;
|
||||
if( ISAUTOVACUUM && szNew>pPage->maxLocal ){
|
||||
CellInfo info;
|
||||
pPage->xParseCell(pPage, newCell, &info);
|
||||
if( info.nPayload!=info.nLocal ){
|
||||
Pgno ovfl = get4byte(&newCell[szNew-4]);
|
||||
ptrmapPut(pBt, ovfl, PTRMAP_OVERFLOW1, pPage->pgno, &rc);
|
||||
}
|
||||
}
|
||||
}else{
|
||||
rc = fillInCell(pPage, newCell, pX, &szNew);
|
||||
}
|
||||
if( rc ) goto end_insert;
|
||||
assert( szNew==pPage->xCellSize(pPage, newCell) );
|
||||
assert( szNew <= MX_CELL_SIZE(pBt) );
|
||||
@@ -8912,6 +8945,114 @@ end_insert:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** This function is used as part of copying the current row from cursor
|
||||
** pSrc into cursor pDest. If the cursors are open on intkey tables, then
|
||||
** parameter iKey is used as the rowid value when the record is copied
|
||||
** into pDest. Otherwise, the record is copied verbatim.
|
||||
**
|
||||
** This function does not actually write the new value to cursor pDest.
|
||||
** Instead, it creates and populates any required overflow pages and
|
||||
** writes the data for the new cell into the BtShared.pTmpSpace buffer
|
||||
** for the destination database. The size of the cell, in bytes, is left
|
||||
** in BtShared.nPreformatSize. The caller completes the insertion by
|
||||
** calling sqlite3BtreeInsert() with the BTREE_PREFORMAT flag specified.
|
||||
**
|
||||
** SQLITE_OK is returned if successful, or an SQLite error code otherwise.
|
||||
*/
|
||||
int sqlite3BtreeTransferRow(BtCursor *pDest, BtCursor *pSrc, i64 iKey){
|
||||
int rc = SQLITE_OK;
|
||||
BtShared *pBt = pDest->pBt;
|
||||
u8 *aOut = pBt->pTmpSpace; /* Pointer to next output buffer */
|
||||
const u8 *aIn; /* Pointer to next input buffer */
|
||||
u32 nIn; /* Size of input buffer aIn[] */
|
||||
u32 nRem; /* Bytes of data still to copy */
|
||||
|
||||
getCellInfo(pSrc);
|
||||
aOut += putVarint32(aOut, pSrc->info.nPayload);
|
||||
if( pDest->pKeyInfo==0 ) aOut += putVarint(aOut, iKey);
|
||||
nIn = pSrc->info.nLocal;
|
||||
aIn = pSrc->info.pPayload;
|
||||
if( aIn+nIn>pSrc->pPage->aDataEnd ){
|
||||
return SQLITE_CORRUPT_BKPT;
|
||||
}
|
||||
nRem = pSrc->info.nPayload;
|
||||
if( nIn==nRem && nIn<pDest->pPage->maxLocal ){
|
||||
memcpy(aOut, aIn, nIn);
|
||||
pBt->nPreformatSize = nIn + (aOut - pBt->pTmpSpace);
|
||||
}else{
|
||||
Pager *pSrcPager = pSrc->pBt->pPager;
|
||||
u8 *pPgnoOut = 0;
|
||||
Pgno ovflIn = 0;
|
||||
DbPage *pPageIn = 0;
|
||||
MemPage *pPageOut = 0;
|
||||
u32 nOut; /* Size of output buffer aOut[] */
|
||||
|
||||
nOut = btreePayloadToLocal(pDest->pPage, pSrc->info.nPayload);
|
||||
pBt->nPreformatSize = nOut + (aOut - pBt->pTmpSpace);
|
||||
if( nOut<pSrc->info.nPayload ){
|
||||
pPgnoOut = &aOut[nOut];
|
||||
pBt->nPreformatSize += 4;
|
||||
}
|
||||
|
||||
if( nRem>nIn ){
|
||||
if( aIn+nIn+4>pSrc->pPage->aDataEnd ){
|
||||
return SQLITE_CORRUPT_BKPT;
|
||||
}
|
||||
ovflIn = get4byte(&pSrc->info.pPayload[nIn]);
|
||||
}
|
||||
|
||||
do {
|
||||
nRem -= nOut;
|
||||
do{
|
||||
assert( nOut>0 );
|
||||
if( nIn>0 ){
|
||||
int nCopy = MIN(nOut, nIn);
|
||||
memcpy(aOut, aIn, nCopy);
|
||||
nOut -= nCopy;
|
||||
nIn -= nCopy;
|
||||
aOut += nCopy;
|
||||
aIn += nCopy;
|
||||
}
|
||||
if( nOut>0 ){
|
||||
sqlite3PagerUnref(pPageIn);
|
||||
pPageIn = 0;
|
||||
rc = sqlite3PagerGet(pSrcPager, ovflIn, &pPageIn, PAGER_GET_READONLY);
|
||||
if( rc==SQLITE_OK ){
|
||||
aIn = (const u8*)sqlite3PagerGetData(pPageIn);
|
||||
ovflIn = get4byte(aIn);
|
||||
aIn += 4;
|
||||
nIn = pSrc->pBt->usableSize - 4;
|
||||
}
|
||||
}
|
||||
}while( rc==SQLITE_OK && nOut>0 );
|
||||
|
||||
if( rc==SQLITE_OK && nRem>0 ){
|
||||
Pgno pgnoNew;
|
||||
MemPage *pNew = 0;
|
||||
rc = allocateBtreePage(pBt, &pNew, &pgnoNew, 0, 0);
|
||||
put4byte(pPgnoOut, pgnoNew);
|
||||
if( ISAUTOVACUUM && pPageOut ){
|
||||
ptrmapPut(pBt, pgnoNew, PTRMAP_OVERFLOW2, pPageOut->pgno, &rc);
|
||||
}
|
||||
releasePage(pPageOut);
|
||||
pPageOut = pNew;
|
||||
if( pPageOut ){
|
||||
pPgnoOut = pPageOut->aData;
|
||||
put4byte(pPgnoOut, 0);
|
||||
aOut = &pPgnoOut[4];
|
||||
nOut = MIN(pBt->usableSize - 4, nRem);
|
||||
}
|
||||
}
|
||||
}while( nRem>0 && rc==SQLITE_OK );
|
||||
|
||||
releasePage(pPageOut);
|
||||
sqlite3PagerUnref(pPageIn);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Delete the entry that the cursor is pointing to.
|
||||
**
|
||||
|
||||
@@ -262,6 +262,7 @@ int sqlite3BtreeDelete(BtCursor*, u8 flags);
|
||||
#define BTREE_SAVEPOSITION 0x02 /* Leave cursor pointing at NEXT or PREV */
|
||||
#define BTREE_AUXDELETE 0x04 /* not the primary delete operation */
|
||||
#define BTREE_APPEND 0x08 /* Insert is likely an append */
|
||||
#define BTREE_PREFORMAT 0x80 /* Insert is likely an append */
|
||||
|
||||
/* An instance of the BtreePayload object describes the content of a single
|
||||
** entry in either an index or table btree.
|
||||
@@ -361,6 +362,8 @@ void sqlite3BtreeCursorList(Btree*);
|
||||
int sqlite3BtreeCheckpoint(Btree*, int, int *, int *);
|
||||
#endif
|
||||
|
||||
int sqlite3BtreeTransferRow(BtCursor*, BtCursor*, i64);
|
||||
|
||||
/*
|
||||
** If we are not using shared cache, then there is no need to
|
||||
** use mutexes to access the BtShared structures. So make the
|
||||
|
||||
@@ -455,6 +455,7 @@ struct BtShared {
|
||||
Btree *pWriter; /* Btree with currently open write transaction */
|
||||
#endif
|
||||
u8 *pTmpSpace; /* Temp space sufficient to hold a single cell */
|
||||
int nPreformatSize; /* Size of last cell written by TransferRow() */
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
+10
-3
@@ -143,6 +143,10 @@ void sqlite3FinishCoding(Parse *pParse){
|
||||
/* Begin by generating some termination code at the end of the
|
||||
** vdbe program
|
||||
*/
|
||||
if( pParse->pVdbe==0 && db->init.busy ){
|
||||
pParse->rc = SQLITE_DONE;
|
||||
return;
|
||||
}
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
assert( !pParse->isMultiWrite
|
||||
|| sqlite3VdbeAssertMayAbort(v, pParse->mayAbort));
|
||||
@@ -1255,6 +1259,8 @@ void sqlite3AddColumn(Parse *pParse, Token *pName, Token *pType){
|
||||
char *zType;
|
||||
Column *pCol;
|
||||
sqlite3 *db = pParse->db;
|
||||
u8 hName;
|
||||
|
||||
if( (p = pParse->pNewTable)==0 ) return;
|
||||
if( p->nCol+1>db->aLimit[SQLITE_LIMIT_COLUMN] ){
|
||||
sqlite3ErrorMsg(pParse, "too many columns on %s", p->zName);
|
||||
@@ -1266,8 +1272,9 @@ void sqlite3AddColumn(Parse *pParse, Token *pName, Token *pType){
|
||||
memcpy(z, pName->z, pName->n);
|
||||
z[pName->n] = 0;
|
||||
sqlite3Dequote(z);
|
||||
hName = sqlite3StrIHash(z);
|
||||
for(i=0; i<p->nCol; i++){
|
||||
if( sqlite3_stricmp(z, p->aCol[i].zName)==0 ){
|
||||
if( p->aCol[i].hName==hName && sqlite3StrICmp(z, p->aCol[i].zName)==0 ){
|
||||
sqlite3ErrorMsg(pParse, "duplicate column name: %s", z);
|
||||
sqlite3DbFree(db, z);
|
||||
return;
|
||||
@@ -1285,7 +1292,7 @@ void sqlite3AddColumn(Parse *pParse, Token *pName, Token *pType){
|
||||
pCol = &p->aCol[p->nCol];
|
||||
memset(pCol, 0, sizeof(p->aCol[0]));
|
||||
pCol->zName = z;
|
||||
pCol->hName = sqlite3StrIHash(z);
|
||||
pCol->hName = hName;
|
||||
sqlite3ColumnPropertiesFromName(p, pCol);
|
||||
|
||||
if( pType->n==0 ){
|
||||
@@ -2561,7 +2568,7 @@ void sqlite3EndTable(
|
||||
pCons = pEnd;
|
||||
}
|
||||
nName = (int)((const char *)pCons->z - zName);
|
||||
p->addColOffset = 13 + sqlite3Utf8CharLen(zName, nName);
|
||||
p->addColOffset = 13 + nName;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -259,6 +259,9 @@ static const char * const sqlite3azCompileOpt[] = {
|
||||
#ifdef SQLITE_ENABLE_LOCKING_STYLE
|
||||
"ENABLE_LOCKING_STYLE=" CTIMEOPT_VAL(SQLITE_ENABLE_LOCKING_STYLE),
|
||||
#endif
|
||||
#if SQLITE_ENABLE_MATH_FUNCTIONS
|
||||
"ENABLE_MATH_FUNCTIONS",
|
||||
#endif
|
||||
#if SQLITE_ENABLE_MEMORY_MANAGEMENT
|
||||
"ENABLE_MEMORY_MANAGEMENT",
|
||||
#endif
|
||||
|
||||
+12
-1
@@ -95,7 +95,18 @@ Expr *sqlite3ExprAddCollateToken(
|
||||
const Token *pCollName, /* Name of collating sequence */
|
||||
int dequote /* True to dequote pCollName */
|
||||
){
|
||||
if( pCollName->n>0 ){
|
||||
assert( pExpr!=0 || pParse->db->mallocFailed );
|
||||
if( pExpr==0 ) return 0;
|
||||
if( pExpr->op==TK_VECTOR ){
|
||||
ExprList *pList = pExpr->x.pList;
|
||||
if( ALWAYS(pList!=0) ){
|
||||
int i;
|
||||
for(i=0; i<pList->nExpr; i++){
|
||||
pList->a[i].pExpr = sqlite3ExprAddCollateToken(pParse,pList->a[i].pExpr,
|
||||
pCollName, dequote);
|
||||
}
|
||||
}
|
||||
}else if( pCollName->n>0 ){
|
||||
Expr *pNew = sqlite3ExprAlloc(pParse->db, TK_COLLATE, pCollName, dequote);
|
||||
if( pNew ){
|
||||
pNew->pLeft = pExpr;
|
||||
|
||||
+233
@@ -1904,6 +1904,202 @@ int sqlite3IsLikeFunction(sqlite3 *db, Expr *pExpr, int *pIsNocase, char *aWc){
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Mathematical Constants */
|
||||
#ifndef M_PI
|
||||
# define M_PI 3.141592653589793238462643383279502884
|
||||
#endif
|
||||
#ifndef M_LN10
|
||||
# define M_LN10 2.302585092994045684017991454684364208
|
||||
#endif
|
||||
#ifndef M_LN2
|
||||
# define M_LN2 0.693147180559945309417232121458176568
|
||||
#endif
|
||||
|
||||
|
||||
/* Extra math functions that require linking with -lm
|
||||
*/
|
||||
#ifdef SQLITE_ENABLE_MATH_FUNCTIONS
|
||||
/*
|
||||
** Implementation SQL functions:
|
||||
**
|
||||
** ceil(X)
|
||||
** ceiling(X)
|
||||
** floor(X)
|
||||
**
|
||||
** The sqlite3_user_data() pointer is a pointer to the libm implementation
|
||||
** of the underlying C function.
|
||||
*/
|
||||
static void ceilingFunc(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
assert( argc==1 );
|
||||
switch( sqlite3_value_numeric_type(argv[0]) ){
|
||||
case SQLITE_INTEGER: {
|
||||
sqlite3_result_int64(context, sqlite3_value_int64(argv[0]));
|
||||
break;
|
||||
}
|
||||
case SQLITE_FLOAT: {
|
||||
double (*x)(double) = (double(*)(double))sqlite3_user_data(context);
|
||||
sqlite3_result_double(context, x(sqlite3_value_double(argv[0])));
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** On some systems, ceil() and floor() are intrinsic function. You are
|
||||
** unable to take a pointer to these functions. Hence, we here wrap them
|
||||
** in our own actual functions.
|
||||
*/
|
||||
static double xCeil(double x){ return ceil(x); }
|
||||
static double xFloor(double x){ return floor(x); }
|
||||
|
||||
/*
|
||||
** Implementation of SQL functions:
|
||||
**
|
||||
** ln(X) - natural logarithm
|
||||
** log(X) - log X base 10
|
||||
** log10(X) - log X base 10
|
||||
** log(B,X) - log X base B
|
||||
*/
|
||||
static void logFunc(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
double x, b, ans;
|
||||
assert( argc==1 || argc==2 );
|
||||
switch( sqlite3_value_numeric_type(argv[0]) ){
|
||||
case SQLITE_INTEGER:
|
||||
case SQLITE_FLOAT:
|
||||
x = sqlite3_value_double(argv[0]);
|
||||
if( x<0.0 ) return;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
if( argc==2 ){
|
||||
switch( sqlite3_value_numeric_type(argv[0]) ){
|
||||
case SQLITE_INTEGER:
|
||||
case SQLITE_FLOAT:
|
||||
b = x;
|
||||
x = sqlite3_value_double(argv[1]);
|
||||
if( x<0.0 ) return;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
ans = log(x)/log(b);
|
||||
}else{
|
||||
ans = log(x);
|
||||
switch( SQLITE_PTR_TO_INT(sqlite3_user_data(context)) ){
|
||||
case 1:
|
||||
/* Convert from natural logarithm to log base 10 */
|
||||
ans *= 1.0/M_LN10;
|
||||
break;
|
||||
case 2:
|
||||
/* Convert from natural logarithm to log base 2 */
|
||||
ans *= 1.0/M_LN2;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
sqlite3_result_double(context, ans);
|
||||
}
|
||||
|
||||
/*
|
||||
** Functions to converts degrees to radians and radians to degrees.
|
||||
*/
|
||||
static double degToRad(double x){ return x*(M_PI/180.0); }
|
||||
static double radToDeg(double x){ return x*(180.0/M_PI); }
|
||||
|
||||
/*
|
||||
** Implementation of 1-argument SQL math functions:
|
||||
**
|
||||
** exp(X) - Compute e to the X-th power
|
||||
*/
|
||||
static void math1Func(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
int type0;
|
||||
double v0, ans;
|
||||
double (*x)(double);
|
||||
assert( argc==1 );
|
||||
type0 = sqlite3_value_numeric_type(argv[0]);
|
||||
if( type0!=SQLITE_INTEGER && type0!=SQLITE_FLOAT ) return;
|
||||
v0 = sqlite3_value_double(argv[0]);
|
||||
x = (double(*)(double))sqlite3_user_data(context);
|
||||
ans = x(v0);
|
||||
sqlite3_result_double(context, ans);
|
||||
}
|
||||
|
||||
/*
|
||||
** Implementation of 2-argument SQL math functions:
|
||||
**
|
||||
** power(X,Y) - Compute X to the Y-th power
|
||||
*/
|
||||
static void math2Func(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
int type0, type1;
|
||||
double v0, v1, ans;
|
||||
double (*x)(double,double);
|
||||
assert( argc==2 );
|
||||
type0 = sqlite3_value_numeric_type(argv[0]);
|
||||
if( type0!=SQLITE_INTEGER && type0!=SQLITE_FLOAT ) return;
|
||||
type1 = sqlite3_value_numeric_type(argv[1]);
|
||||
if( type1!=SQLITE_INTEGER && type1!=SQLITE_FLOAT ) return;
|
||||
v0 = sqlite3_value_double(argv[0]);
|
||||
v1 = sqlite3_value_double(argv[1]);
|
||||
x = (double(*)(double,double))sqlite3_user_data(context);
|
||||
ans = x(v0, v1);
|
||||
sqlite3_result_double(context, ans);
|
||||
}
|
||||
|
||||
/*
|
||||
** Implementation of 2-argument SQL math functions:
|
||||
**
|
||||
** power(X,Y) - Compute X to the Y-th power
|
||||
*/
|
||||
static void piFunc(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
assert( argc==0 );
|
||||
sqlite3_result_double(context, M_PI);
|
||||
}
|
||||
|
||||
#endif /* SQLITE_ENABLE_MATH_FUNCTIONS */
|
||||
|
||||
/*
|
||||
** Implementation of sign(X) function.
|
||||
*/
|
||||
static void signFunc(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
int type0;
|
||||
double x;
|
||||
UNUSED_PARAMETER(argc);
|
||||
assert( argc==1 );
|
||||
type0 = sqlite3_value_numeric_type(argv[0]);
|
||||
if( type0!=SQLITE_INTEGER && type0!=SQLITE_FLOAT ) return;
|
||||
x = sqlite3_value_double(argv[0]);
|
||||
sqlite3_result_int(context, x<0.0 ? -1 : x>0.0 ? +1 : 0);
|
||||
}
|
||||
|
||||
/*
|
||||
** All of the FuncDef structures in the aBuiltinFunc[] array above
|
||||
** to the global function hash table. This occurs at start-time (as
|
||||
@@ -2022,6 +2218,43 @@ void sqlite3RegisterBuiltinFunctions(void){
|
||||
#endif
|
||||
FUNCTION(coalesce, 1, 0, 0, 0 ),
|
||||
FUNCTION(coalesce, 0, 0, 0, 0 ),
|
||||
#ifdef SQLITE_ENABLE_MATH_FUNCTIONS
|
||||
MFUNCTION(ceil, 1, xCeil, ceilingFunc ),
|
||||
MFUNCTION(ceiling, 1, xCeil, ceilingFunc ),
|
||||
MFUNCTION(floor, 1, xFloor, ceilingFunc ),
|
||||
#if SQLITE_HAVE_C99_MATH_FUNCS
|
||||
MFUNCTION(trunc, 1, trunc, ceilingFunc ),
|
||||
#endif
|
||||
FUNCTION(ln, 1, 0, 0, logFunc ),
|
||||
FUNCTION(log, 1, 1, 0, logFunc ),
|
||||
FUNCTION(log10, 1, 1, 0, logFunc ),
|
||||
FUNCTION(log2, 1, 2, 0, logFunc ),
|
||||
FUNCTION(log, 2, 0, 0, logFunc ),
|
||||
MFUNCTION(exp, 1, exp, math1Func ),
|
||||
MFUNCTION(pow, 2, pow, math2Func ),
|
||||
MFUNCTION(power, 2, pow, math2Func ),
|
||||
MFUNCTION(mod, 2, fmod, math2Func ),
|
||||
MFUNCTION(acos, 1, acos, math1Func ),
|
||||
MFUNCTION(asin, 1, asin, math1Func ),
|
||||
MFUNCTION(atan, 1, atan, math1Func ),
|
||||
MFUNCTION(atan2, 2, atan2, math2Func ),
|
||||
MFUNCTION(cos, 1, cos, math1Func ),
|
||||
MFUNCTION(sin, 1, sin, math1Func ),
|
||||
MFUNCTION(tan, 1, tan, math1Func ),
|
||||
MFUNCTION(cosh, 1, cosh, math1Func ),
|
||||
MFUNCTION(sinh, 1, sinh, math1Func ),
|
||||
MFUNCTION(tanh, 1, tanh, math1Func ),
|
||||
#if SQLITE_HAVE_C99_MATH_FUNCS
|
||||
MFUNCTION(acosh, 1, acosh, math1Func ),
|
||||
MFUNCTION(asinh, 1, asinh, math1Func ),
|
||||
MFUNCTION(atanh, 1, atanh, math1Func ),
|
||||
#endif
|
||||
MFUNCTION(sqrt, 1, sqrt, math1Func ),
|
||||
MFUNCTION(radians, 1, degToRad, math1Func ),
|
||||
MFUNCTION(degrees, 1, radToDeg, math1Func ),
|
||||
FUNCTION(pi, 0, 0, 0, piFunc ),
|
||||
#endif /* SQLITE_ENABLE_MATH_FUNCTIONS */
|
||||
FUNCTION(sign, 1, 0, 0, signFunc ),
|
||||
INLINE_FUNC(coalesce, -1, INLINEFUNC_coalesce, 0 ),
|
||||
INLINE_FUNC(iif, 3, INLINEFUNC_iif, 0 ),
|
||||
};
|
||||
|
||||
+210
-60
@@ -370,7 +370,9 @@ static int autoIncBegin(
|
||||
while( pInfo && pInfo->pTab!=pTab ){ pInfo = pInfo->pNext; }
|
||||
if( pInfo==0 ){
|
||||
pInfo = sqlite3DbMallocRawNN(pParse->db, sizeof(*pInfo));
|
||||
if( pInfo==0 ) return 0;
|
||||
sqlite3ParserAddCleanup(pToplevel, sqlite3DbFree, pInfo);
|
||||
testcase( pParse->earlyCleanup );
|
||||
if( pParse->db->mallocFailed ) return 0;
|
||||
pInfo->pNext = pToplevel->pAinc;
|
||||
pToplevel->pAinc = pInfo;
|
||||
pInfo->pTab = pTab;
|
||||
@@ -975,6 +977,7 @@ void sqlite3Insert(
|
||||
}
|
||||
#ifndef SQLITE_OMIT_UPSERT
|
||||
if( pUpsert ){
|
||||
Upsert *pNx;
|
||||
if( IsVirtual(pTab) ){
|
||||
sqlite3ErrorMsg(pParse, "UPSERT not implemented for virtual table \"%s\"",
|
||||
pTab->zName);
|
||||
@@ -988,13 +991,17 @@ void sqlite3Insert(
|
||||
goto insert_cleanup;
|
||||
}
|
||||
pTabList->a[0].iCursor = iDataCur;
|
||||
pUpsert->pUpsertSrc = pTabList;
|
||||
pUpsert->regData = regData;
|
||||
pUpsert->iDataCur = iDataCur;
|
||||
pUpsert->iIdxCur = iIdxCur;
|
||||
if( pUpsert->pUpsertTarget ){
|
||||
sqlite3UpsertAnalyzeTarget(pParse, pTabList, pUpsert);
|
||||
}
|
||||
pNx = pUpsert;
|
||||
do{
|
||||
pNx->pUpsertSrc = pTabList;
|
||||
pNx->regData = regData;
|
||||
pNx->iDataCur = iDataCur;
|
||||
pNx->iIdxCur = iIdxCur;
|
||||
if( pNx->pUpsertTarget ){
|
||||
sqlite3UpsertAnalyzeTarget(pParse, pTabList, pNx);
|
||||
}
|
||||
pNx = pNx->pNextUpsert;
|
||||
}while( pNx!=0 );
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1294,7 +1301,9 @@ void sqlite3Insert(
|
||||
sqlite3VdbeJumpHere(v, addrInsTop);
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_XFER_OPT
|
||||
insert_end:
|
||||
#endif /* SQLITE_OMIT_XFER_OPT */
|
||||
/* Update the sqlite_sequence table by storing the content of the
|
||||
** maximum rowid counter values recorded while inserting into
|
||||
** autoincrement tables.
|
||||
@@ -1399,6 +1408,70 @@ int sqlite3ExprReferencesUpdatedColumn(
|
||||
return w.eCode!=0;
|
||||
}
|
||||
|
||||
/*
|
||||
** The sqlite3GenerateConstraintChecks() routine usually wants to visit
|
||||
** the indexes of a table in the order provided in the Table->pIndex list.
|
||||
** However, sometimes (rarely - when there is an upsert) it wants to visit
|
||||
** the indexes in a different order. The following data structures accomplish
|
||||
** this.
|
||||
**
|
||||
** The IndexIterator object is used to walk through all of the indexes
|
||||
** of a table in either Index.pNext order, or in some other order established
|
||||
** by an array of IndexListTerm objects.
|
||||
*/
|
||||
typedef struct IndexListTerm IndexListTerm;
|
||||
typedef struct IndexIterator IndexIterator;
|
||||
struct IndexIterator {
|
||||
int eType; /* 0 for Index.pNext list. 1 for an array of IndexListTerm */
|
||||
int i; /* Index of the current item from the list */
|
||||
union {
|
||||
struct { /* Use this object for eType==0: A Index.pNext list */
|
||||
Index *pIdx; /* The current Index */
|
||||
} lx;
|
||||
struct { /* Use this object for eType==1; Array of IndexListTerm */
|
||||
int nIdx; /* Size of the array */
|
||||
IndexListTerm *aIdx; /* Array of IndexListTerms */
|
||||
} ax;
|
||||
} u;
|
||||
};
|
||||
|
||||
/* When IndexIterator.eType==1, then each index is an array of instances
|
||||
** of the following object
|
||||
*/
|
||||
struct IndexListTerm {
|
||||
Index *p; /* The index */
|
||||
int ix; /* Which entry in the original Table.pIndex list is this index*/
|
||||
};
|
||||
|
||||
/* Return the first index on the list */
|
||||
static Index *indexIteratorFirst(IndexIterator *pIter, int *pIx){
|
||||
assert( pIter->i==0 );
|
||||
if( pIter->eType ){
|
||||
*pIx = pIter->u.ax.aIdx[0].ix;
|
||||
return pIter->u.ax.aIdx[0].p;
|
||||
}else{
|
||||
*pIx = 0;
|
||||
return pIter->u.lx.pIdx;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return the next index from the list. Return NULL when out of indexes */
|
||||
static Index *indexIteratorNext(IndexIterator *pIter, int *pIx){
|
||||
if( pIter->eType ){
|
||||
int i = ++pIter->i;
|
||||
if( i>=pIter->u.ax.nIdx ){
|
||||
*pIx = i;
|
||||
return 0;
|
||||
}
|
||||
*pIx = pIter->u.ax.aIdx[i].ix;
|
||||
return pIter->u.ax.aIdx[i].p;
|
||||
}else{
|
||||
++(*pIx);
|
||||
pIter->u.lx.pIdx = pIter->u.lx.pIdx->pNext;
|
||||
return pIter->u.lx.pIdx;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate code to do constraint checks prior to an INSERT or an UPDATE
|
||||
** on table pTab.
|
||||
@@ -1507,7 +1580,7 @@ void sqlite3GenerateConstraintChecks(
|
||||
){
|
||||
Vdbe *v; /* VDBE under constrution */
|
||||
Index *pIdx; /* Pointer to one of the indices */
|
||||
Index *pPk = 0; /* The PRIMARY KEY index */
|
||||
Index *pPk = 0; /* The PRIMARY KEY index for WITHOUT ROWID tables */
|
||||
sqlite3 *db; /* Database connection */
|
||||
int i; /* loop counter */
|
||||
int ix; /* Index loop counter */
|
||||
@@ -1515,11 +1588,11 @@ void sqlite3GenerateConstraintChecks(
|
||||
int onError; /* Conflict resolution strategy */
|
||||
int seenReplace = 0; /* True if REPLACE is used to resolve INT PK conflict */
|
||||
int nPkField; /* Number of fields in PRIMARY KEY. 1 for ROWID tables */
|
||||
Index *pUpIdx = 0; /* Index to which to apply the upsert */
|
||||
u8 isUpdate; /* True if this is an UPDATE operation */
|
||||
Upsert *pUpsertClause = 0; /* The specific ON CONFLICT clause for pIdx */
|
||||
u8 isUpdate; /* True if this is an UPDATE operation */
|
||||
u8 bAffinityDone = 0; /* True if the OP_Affinity operation has been run */
|
||||
int upsertBypass = 0; /* Address of Goto to bypass upsert subroutine */
|
||||
int upsertJump = 0; /* Address of Goto that jumps into upsert subroutine */
|
||||
int upsertIpkReturn = 0; /* Address of Goto at end of IPK uniqueness check */
|
||||
int upsertIpkDelay = 0; /* Address of Goto to bypass initial IPK check */
|
||||
int ipkTop = 0; /* Top of the IPK uniqueness check */
|
||||
int ipkBottom = 0; /* OP_Goto at the end of the IPK uniqueness check */
|
||||
/* Variables associated with retesting uniqueness constraints after
|
||||
@@ -1529,6 +1602,7 @@ void sqlite3GenerateConstraintChecks(
|
||||
int lblRecheckOk = 0; /* Each recheck jumps to this label if it passes */
|
||||
Trigger *pTrigger; /* List of DELETE triggers on the table pTab */
|
||||
int nReplaceTrig = 0; /* Number of replace triggers coded */
|
||||
IndexIterator sIdxIter; /* Index iterator */
|
||||
|
||||
isUpdate = regOldData!=0;
|
||||
db = pParse->db;
|
||||
@@ -1726,19 +1800,63 @@ void sqlite3GenerateConstraintChecks(
|
||||
** list of indexes attached to a table puts all OE_Replace indexes last
|
||||
** in the list. See sqlite3CreateIndex() for where that happens.
|
||||
*/
|
||||
|
||||
sIdxIter.eType = 0;
|
||||
sIdxIter.i = 0;
|
||||
sIdxIter.u.ax.aIdx = 0; /* Silence harmless compiler warning */
|
||||
sIdxIter.u.lx.pIdx = pTab->pIndex;
|
||||
if( pUpsert ){
|
||||
if( pUpsert->pUpsertTarget==0 ){
|
||||
/* An ON CONFLICT DO NOTHING clause, without a constraint-target.
|
||||
** Make all unique constraint resolution be OE_Ignore */
|
||||
assert( pUpsert->pUpsertSet==0 );
|
||||
overrideError = OE_Ignore;
|
||||
pUpsert = 0;
|
||||
}else if( (pUpIdx = pUpsert->pUpsertIdx)!=0 ){
|
||||
/* If the constraint-target uniqueness check must be run first.
|
||||
** Jump to that uniqueness check now */
|
||||
upsertJump = sqlite3VdbeAddOp0(v, OP_Goto);
|
||||
VdbeComment((v, "UPSERT constraint goes first"));
|
||||
/* There is just on ON CONFLICT clause and it has no constraint-target */
|
||||
assert( pUpsert->pNextUpsert==0 );
|
||||
if( pUpsert->isDoUpdate==0 ){
|
||||
/* A single ON CONFLICT DO NOTHING clause, without a constraint-target.
|
||||
** Make all unique constraint resolution be OE_Ignore */
|
||||
overrideError = OE_Ignore;
|
||||
pUpsert = 0;
|
||||
}else{
|
||||
/* A single ON CONFLICT DO UPDATE. Make all resolutions OE_Update */
|
||||
overrideError = OE_Update;
|
||||
}
|
||||
}else if( pTab->pIndex!=0 ){
|
||||
/* Otherwise, we'll need to run the IndexListTerm array version of the
|
||||
** iterator to ensure that all of the ON CONFLICT conditions are
|
||||
** checked first and in order. */
|
||||
int nIdx, jj;
|
||||
u64 nByte;
|
||||
Upsert *pTerm;
|
||||
u8 *bUsed;
|
||||
for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){
|
||||
assert( aRegIdx[nIdx]>0 );
|
||||
}
|
||||
sIdxIter.eType = 1;
|
||||
sIdxIter.u.ax.nIdx = nIdx;
|
||||
nByte = (sizeof(IndexListTerm)+1)*nIdx + nIdx;
|
||||
sIdxIter.u.ax.aIdx = sqlite3DbMallocZero(db, nByte);
|
||||
if( sIdxIter.u.ax.aIdx==0 ) return; /* OOM */
|
||||
bUsed = (u8*)&sIdxIter.u.ax.aIdx[nIdx];
|
||||
pUpsert->pToFree = sIdxIter.u.ax.aIdx;
|
||||
for(i=0, pTerm=pUpsert; pTerm; pTerm=pTerm->pNextUpsert){
|
||||
if( pTerm->pUpsertTarget==0 ) break;
|
||||
if( pTerm->pUpsertIdx==0 ) continue; /* Skip ON CONFLICT for the IPK */
|
||||
jj = 0;
|
||||
pIdx = pTab->pIndex;
|
||||
while( ALWAYS(pIdx!=0) && pIdx!=pTerm->pUpsertIdx ){
|
||||
pIdx = pIdx->pNext;
|
||||
jj++;
|
||||
}
|
||||
if( bUsed[jj] ) continue; /* Duplicate ON CONFLICT clause ignored */
|
||||
bUsed[jj] = 1;
|
||||
sIdxIter.u.ax.aIdx[i].p = pIdx;
|
||||
sIdxIter.u.ax.aIdx[i].ix = jj;
|
||||
i++;
|
||||
}
|
||||
for(jj=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, jj++){
|
||||
if( bUsed[jj] ) continue;
|
||||
sIdxIter.u.ax.aIdx[i].p = pIdx;
|
||||
sIdxIter.u.ax.aIdx[i].ix = jj;
|
||||
i++;
|
||||
}
|
||||
assert( i==nIdx );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1801,11 +1919,20 @@ void sqlite3GenerateConstraintChecks(
|
||||
}
|
||||
|
||||
/* figure out whether or not upsert applies in this case */
|
||||
if( pUpsert && pUpsert->pUpsertIdx==0 ){
|
||||
if( pUpsert->pUpsertSet==0 ){
|
||||
onError = OE_Ignore; /* DO NOTHING is the same as INSERT OR IGNORE */
|
||||
}else{
|
||||
onError = OE_Update; /* DO UPDATE */
|
||||
if( pUpsert ){
|
||||
pUpsertClause = sqlite3UpsertOfIndex(pUpsert,0);
|
||||
if( pUpsertClause!=0 ){
|
||||
if( pUpsertClause->isDoUpdate==0 ){
|
||||
onError = OE_Ignore; /* DO NOTHING is the same as INSERT OR IGNORE */
|
||||
}else{
|
||||
onError = OE_Update; /* DO UPDATE */
|
||||
}
|
||||
}
|
||||
if( pUpsertClause!=pUpsert ){
|
||||
/* The first ON CONFLICT clause has a conflict target other than
|
||||
** the IPK. We have to jump ahead to that first ON CONFLICT clause
|
||||
** and then come back here and deal with the IPK afterwards */
|
||||
upsertIpkDelay = sqlite3VdbeAddOp0(v, OP_Goto);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1815,7 +1942,7 @@ void sqlite3GenerateConstraintChecks(
|
||||
** the UNIQUE constraints have run.
|
||||
*/
|
||||
if( onError==OE_Replace /* IPK rule is REPLACE */
|
||||
&& onError!=overrideError /* Rules for other contraints are different */
|
||||
&& onError!=overrideError /* Rules for other constraints are different */
|
||||
&& pTab->pIndex /* There exist other constraints */
|
||||
){
|
||||
ipkTop = sqlite3VdbeAddOp0(v, OP_Goto)+1;
|
||||
@@ -1912,7 +2039,9 @@ void sqlite3GenerateConstraintChecks(
|
||||
}
|
||||
}
|
||||
sqlite3VdbeResolveLabel(v, addrRowidOk);
|
||||
if( ipkTop ){
|
||||
if( pUpsert && pUpsertClause!=pUpsert ){
|
||||
upsertIpkReturn = sqlite3VdbeAddOp0(v, OP_Goto);
|
||||
}else if( ipkTop ){
|
||||
ipkBottom = sqlite3VdbeAddOp0(v, OP_Goto);
|
||||
sqlite3VdbeJumpHere(v, ipkTop-1);
|
||||
}
|
||||
@@ -1925,7 +2054,10 @@ void sqlite3GenerateConstraintChecks(
|
||||
** This loop also handles the case of the PRIMARY KEY index for a
|
||||
** WITHOUT ROWID table.
|
||||
*/
|
||||
for(ix=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, ix++){
|
||||
for(pIdx = indexIteratorFirst(&sIdxIter, &ix);
|
||||
pIdx;
|
||||
pIdx = indexIteratorNext(&sIdxIter, &ix)
|
||||
){
|
||||
int regIdx; /* Range of registers hold conent for pIdx */
|
||||
int regR; /* Range of registers holding conflicting PK */
|
||||
int iThisCur; /* Cursor for this UNIQUE index */
|
||||
@@ -1933,15 +2065,14 @@ void sqlite3GenerateConstraintChecks(
|
||||
int addrConflictCk; /* First opcode in the conflict check logic */
|
||||
|
||||
if( aRegIdx[ix]==0 ) continue; /* Skip indices that do not change */
|
||||
if( pUpIdx==pIdx ){
|
||||
addrUniqueOk = upsertJump+1;
|
||||
upsertBypass = sqlite3VdbeGoto(v, 0);
|
||||
VdbeComment((v, "Skip upsert subroutine"));
|
||||
sqlite3VdbeJumpHere(v, upsertJump);
|
||||
}else{
|
||||
addrUniqueOk = sqlite3VdbeMakeLabel(pParse);
|
||||
if( pUpsert ){
|
||||
pUpsertClause = sqlite3UpsertOfIndex(pUpsert, pIdx);
|
||||
if( upsertIpkDelay && pUpsertClause==pUpsert ){
|
||||
sqlite3VdbeJumpHere(v, upsertIpkDelay);
|
||||
}
|
||||
}
|
||||
if( bAffinityDone==0 && (pUpIdx==0 || pUpIdx==pIdx) ){
|
||||
addrUniqueOk = sqlite3VdbeMakeLabel(pParse);
|
||||
if( bAffinityDone==0 ){
|
||||
sqlite3TableAffinity(v, pTab, regNewData+1);
|
||||
bAffinityDone = 1;
|
||||
}
|
||||
@@ -2012,8 +2143,8 @@ void sqlite3GenerateConstraintChecks(
|
||||
}
|
||||
|
||||
/* Figure out if the upsert clause applies to this index */
|
||||
if( pUpIdx==pIdx ){
|
||||
if( pUpsert->pUpsertSet==0 ){
|
||||
if( pUpsertClause ){
|
||||
if( pUpsertClause->isDoUpdate==0 ){
|
||||
onError = OE_Ignore; /* DO NOTHING is the same as INSERT OR IGNORE */
|
||||
}else{
|
||||
onError = OE_Update; /* DO UPDATE */
|
||||
@@ -2051,7 +2182,7 @@ void sqlite3GenerateConstraintChecks(
|
||||
regIdx, pIdx->nKeyCol); VdbeCoverage(v);
|
||||
|
||||
/* Generate code to handle collisions */
|
||||
regR = (pIdx==pPk) ? regIdx : sqlite3GetTempRange(pParse, nPkField);
|
||||
regR = pIdx==pPk ? regIdx : sqlite3GetTempRange(pParse, nPkField);
|
||||
if( isUpdate || onError==OE_Replace ){
|
||||
if( HasRowid(pTab) ){
|
||||
sqlite3VdbeAddOp2(v, OP_IdxRowid, iThisCur, regR);
|
||||
@@ -2203,13 +2334,16 @@ void sqlite3GenerateConstraintChecks(
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( pUpIdx==pIdx ){
|
||||
sqlite3VdbeGoto(v, upsertJump+1);
|
||||
sqlite3VdbeJumpHere(v, upsertBypass);
|
||||
}else{
|
||||
sqlite3VdbeResolveLabel(v, addrUniqueOk);
|
||||
}
|
||||
sqlite3VdbeResolveLabel(v, addrUniqueOk);
|
||||
if( regR!=regIdx ) sqlite3ReleaseTempRange(pParse, regR, nPkField);
|
||||
if( pUpsertClause
|
||||
&& upsertIpkReturn
|
||||
&& sqlite3UpsertNextIsIPK(pUpsertClause)
|
||||
){
|
||||
sqlite3VdbeGoto(v, upsertIpkDelay+1);
|
||||
sqlite3VdbeJumpHere(v, upsertIpkReturn);
|
||||
upsertIpkReturn = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* If the IPK constraint is a REPLACE, run it last */
|
||||
@@ -2748,6 +2882,7 @@ static int xferOptimization(
|
||||
iDest = pParse->nTab++;
|
||||
regAutoinc = autoIncBegin(pParse, iDbDest, pDest);
|
||||
regData = sqlite3GetTempReg(pParse);
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, regData);
|
||||
regRowid = sqlite3GetTempReg(pParse);
|
||||
sqlite3OpenTable(pParse, iDest, iDbDest, pDest, OP_OpenWrite);
|
||||
assert( HasRowid(pDest) || destHasUniqueIdx );
|
||||
@@ -2783,11 +2918,13 @@ static int xferOptimization(
|
||||
emptySrcTest = sqlite3VdbeAddOp2(v, OP_Rewind, iSrc, 0); VdbeCoverage(v);
|
||||
if( pDest->iPKey>=0 ){
|
||||
addr1 = sqlite3VdbeAddOp2(v, OP_Rowid, iSrc, regRowid);
|
||||
sqlite3VdbeVerifyAbortable(v, onError);
|
||||
addr2 = sqlite3VdbeAddOp3(v, OP_NotExists, iDest, 0, regRowid);
|
||||
VdbeCoverage(v);
|
||||
sqlite3RowidConstraint(pParse, onError, pDest);
|
||||
sqlite3VdbeJumpHere(v, addr2);
|
||||
if( (db->mDbFlags & DBFLAG_Vacuum)==0 ){
|
||||
sqlite3VdbeVerifyAbortable(v, onError);
|
||||
addr2 = sqlite3VdbeAddOp3(v, OP_NotExists, iDest, 0, regRowid);
|
||||
VdbeCoverage(v);
|
||||
sqlite3RowidConstraint(pParse, onError, pDest);
|
||||
sqlite3VdbeJumpHere(v, addr2);
|
||||
}
|
||||
autoIncStep(pParse, regAutoinc, regRowid);
|
||||
}else if( pDest->pIndex==0 && !(db->mDbFlags & DBFLAG_VacuumInto) ){
|
||||
addr1 = sqlite3VdbeAddOp2(v, OP_NewRowid, iDest, regRowid);
|
||||
@@ -2795,16 +2932,26 @@ static int xferOptimization(
|
||||
addr1 = sqlite3VdbeAddOp2(v, OP_Rowid, iSrc, regRowid);
|
||||
assert( (pDest->tabFlags & TF_Autoincrement)==0 );
|
||||
}
|
||||
|
||||
if( db->mDbFlags & DBFLAG_Vacuum ){
|
||||
sqlite3VdbeAddOp1(v, OP_SeekEnd, iDest);
|
||||
insFlags = OPFLAG_APPEND|OPFLAG_USESEEKRESULT;
|
||||
insFlags = OPFLAG_APPEND|OPFLAG_USESEEKRESULT|OPFLAG_PREFORMAT;
|
||||
}else{
|
||||
insFlags = OPFLAG_NCHANGE|OPFLAG_LASTROWID|OPFLAG_APPEND;
|
||||
insFlags = OPFLAG_NCHANGE|OPFLAG_LASTROWID|OPFLAG_APPEND|OPFLAG_PREFORMAT;
|
||||
}
|
||||
#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
|
||||
if( db->xPreUpdateCallback ){
|
||||
sqlite3VdbeAddOp3(v, OP_RowData, iSrc, regData, 1);
|
||||
insFlags &= ~OPFLAG_PREFORMAT;
|
||||
}else
|
||||
#endif
|
||||
{
|
||||
sqlite3VdbeAddOp3(v, OP_RowCell, iDest, iSrc, regRowid);
|
||||
}
|
||||
sqlite3VdbeAddOp3(v, OP_RowData, iSrc, regData, 1);
|
||||
sqlite3VdbeAddOp4(v, OP_Insert, iDest, regData, regRowid,
|
||||
(char*)pDest, P4_TABLE);
|
||||
(char*)pDest, P4_TABLE);
|
||||
sqlite3VdbeChangeP5(v, insFlags);
|
||||
|
||||
sqlite3VdbeAddOp2(v, OP_Next, iSrc, addr1); VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp2(v, OP_Close, iSrc, 0);
|
||||
sqlite3VdbeAddOp2(v, OP_Close, iDest, 0);
|
||||
@@ -2846,13 +2993,16 @@ static int xferOptimization(
|
||||
if( sqlite3_stricmp(sqlite3StrBINARY, zColl) ) break;
|
||||
}
|
||||
if( i==pSrcIdx->nColumn ){
|
||||
idxInsFlags = OPFLAG_USESEEKRESULT;
|
||||
idxInsFlags = OPFLAG_USESEEKRESULT|OPFLAG_PREFORMAT;
|
||||
sqlite3VdbeAddOp1(v, OP_SeekEnd, iDest);
|
||||
sqlite3VdbeAddOp2(v, OP_RowCell, iDest, iSrc);
|
||||
}
|
||||
}else if( !HasRowid(pSrc) && pDestIdx->idxType==SQLITE_IDXTYPE_PRIMARYKEY ){
|
||||
idxInsFlags |= OPFLAG_NCHANGE;
|
||||
}
|
||||
sqlite3VdbeAddOp3(v, OP_RowData, iSrc, regData, 1);
|
||||
if( idxInsFlags!=(OPFLAG_USESEEKRESULT|OPFLAG_PREFORMAT) ){
|
||||
sqlite3VdbeAddOp3(v, OP_RowData, iSrc, regData, 1);
|
||||
}
|
||||
sqlite3VdbeAddOp2(v, OP_IdxInsert, iDest, regData);
|
||||
sqlite3VdbeChangeP5(v, idxInsFlags|OPFLAG_APPEND);
|
||||
sqlite3VdbeAddOp2(v, OP_Next, iSrc, addr1+1); VdbeCoverage(v);
|
||||
|
||||
+1
-1
@@ -4080,7 +4080,7 @@ int sqlite3_test_control(int op, ...){
|
||||
*/
|
||||
case SQLITE_TESTCTRL_OPTIMIZATIONS: {
|
||||
sqlite3 *db = va_arg(ap, sqlite3*);
|
||||
db->dbOptFlags = (u16)(va_arg(ap, int) & 0xffff);
|
||||
db->dbOptFlags = va_arg(ap, u32);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -129,6 +129,8 @@ int sqlite3OsFileControl(sqlite3_file *id, int op, void *pArg){
|
||||
#ifdef SQLITE_TEST
|
||||
if( op!=SQLITE_FCNTL_COMMIT_PHASETWO
|
||||
&& op!=SQLITE_FCNTL_LOCK_TIMEOUT
|
||||
&& op!=SQLITE_FCNTL_CKPT_DONE
|
||||
&& op!=SQLITE_FCNTL_CKPT_START
|
||||
){
|
||||
/* Faults are not injected into COMMIT_PHASETWO because, assuming SQLite
|
||||
** is using a regular VFS, it is called after the corresponding
|
||||
@@ -139,7 +141,12 @@ int sqlite3OsFileControl(sqlite3_file *id, int op, void *pArg){
|
||||
** The core must call OsFileControl() though, not OsFileControlHint(),
|
||||
** as if a custom VFS (e.g. zipvfs) returns an error here, it probably
|
||||
** means the commit really has failed and an error should be returned
|
||||
** to the user. */
|
||||
** to the user.
|
||||
**
|
||||
** The CKPT_DONE and CKPT_START file-controls are write-only signals
|
||||
** to the cksumvfs. Their return code is meaningless and is ignored
|
||||
** by the SQLite core, so there is no point in simulating OOMs for them.
|
||||
*/
|
||||
DO_OS_MALLOC_TEST(id);
|
||||
}
|
||||
#endif
|
||||
|
||||
+7
-5
@@ -960,12 +960,14 @@ cmd ::= with insert_cmd(R) INTO xfullname(X) idlist_opt(F) DEFAULT VALUES.
|
||||
//%destructor upsert {sqlite3UpsertDelete(pParse->db,$$);}
|
||||
upsert(A) ::= . { A = 0; }
|
||||
upsert(A) ::= ON CONFLICT LP sortlist(T) RP where_opt(TW)
|
||||
DO UPDATE SET setlist(Z) where_opt(W).
|
||||
{ A = sqlite3UpsertNew(pParse->db,T,TW,Z,W);}
|
||||
upsert(A) ::= ON CONFLICT LP sortlist(T) RP where_opt(TW) DO NOTHING.
|
||||
{ A = sqlite3UpsertNew(pParse->db,T,TW,0,0); }
|
||||
DO UPDATE SET setlist(Z) where_opt(W) upsert(N).
|
||||
{ A = sqlite3UpsertNew(pParse->db,T,TW,Z,W,N);}
|
||||
upsert(A) ::= ON CONFLICT LP sortlist(T) RP where_opt(TW) DO NOTHING upsert(N).
|
||||
{ A = sqlite3UpsertNew(pParse->db,T,TW,0,0,N); }
|
||||
upsert(A) ::= ON CONFLICT DO NOTHING.
|
||||
{ A = sqlite3UpsertNew(pParse->db,0,0,0,0); }
|
||||
{ A = sqlite3UpsertNew(pParse->db,0,0,0,0,0); }
|
||||
upsert(A) ::= ON CONFLICT DO UPDATE SET setlist(Z) where_opt(W).
|
||||
{ A = sqlite3UpsertNew(pParse->db,0,0,Z,W,0);}
|
||||
|
||||
%type insert_cmd {int}
|
||||
insert_cmd(A) ::= INSERT orconf(R). {A = R;}
|
||||
|
||||
+74
-18
@@ -102,11 +102,18 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){
|
||||
if( argv==0 ) return 0; /* Might happen if EMPTY_RESULT_CALLBACKS are on */
|
||||
if( argv[3]==0 ){
|
||||
corruptSchema(pData, argv[1], 0);
|
||||
}else if( sqlite3_strnicmp(argv[4],"create ",7)==0 ){
|
||||
}else if( argv[4]
|
||||
&& 'c'==sqlite3UpperToLower[(unsigned char)argv[4][0]]
|
||||
&& 'r'==sqlite3UpperToLower[(unsigned char)argv[4][1]] ){
|
||||
/* Call the parser to process a CREATE TABLE, INDEX or VIEW.
|
||||
** But because db->init.busy is set to 1, no VDBE code is generated
|
||||
** or executed. All the parser does is build the internal data
|
||||
** structures that describe the table, index, or view.
|
||||
**
|
||||
** No other valid SQL statement, other than the variable CREATE statements,
|
||||
** can begin with the letters "C" and "R". Thus, it is not possible run
|
||||
** any other kind of statement while parsing the schema, even a corrupt
|
||||
** schema.
|
||||
*/
|
||||
int rc;
|
||||
u8 saved_iDb = db->init.iDb;
|
||||
@@ -563,8 +570,16 @@ void sqlite3ParserReset(Parse *pParse){
|
||||
agginfoFree(db, pThis);
|
||||
pThis = pNext;
|
||||
}
|
||||
while( pParse->pCleanup ){
|
||||
ParseCleanup *pCleanup = pParse->pCleanup;
|
||||
pParse->pCleanup = pCleanup->pNext;
|
||||
pCleanup->xCleanup(db, pCleanup->pPtr);
|
||||
sqlite3DbFree(db, pCleanup);
|
||||
}
|
||||
sqlite3DbFree(db, pParse->aLabel);
|
||||
sqlite3ExprListDelete(db, pParse->pConstExpr);
|
||||
if( pParse->pConstExpr ){
|
||||
sqlite3ExprListDelete(db, pParse->pConstExpr);
|
||||
}
|
||||
if( db ){
|
||||
assert( db->lookaside.bDisable >= pParse->disableLookaside );
|
||||
db->lookaside.bDisable -= pParse->disableLookaside;
|
||||
@@ -573,6 +588,45 @@ void sqlite3ParserReset(Parse *pParse){
|
||||
pParse->disableLookaside = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Add a new cleanup operation to a Parser. The cleanup should happen when
|
||||
** the parser object is destroyed. But, beware: the cleanup might happen
|
||||
** immediately.
|
||||
**
|
||||
** Use this mechanism for uncommon cleanups. There is a higher setup
|
||||
** cost for this mechansim (an extra malloc), so it should not be used
|
||||
** for common cleanups that happen on most calls. But for less
|
||||
** common cleanups, we save a single NULL-pointer comparison in
|
||||
** sqlite3ParserReset(), which reduces the total CPU cycle count.
|
||||
**
|
||||
** If a memory allocation error occurs, then the cleanup happens immediately.
|
||||
** When eithr SQLITE_DEBUG or SQLITE_COVERAGE_TEST are defined, the
|
||||
** pParse->earlyCleanup flag is set in that case. Calling code show verify
|
||||
** that test cases exist for which this happens, to guard against possible
|
||||
** use-after-free errors following an OOM. The preferred way to do this is
|
||||
** to immediately follow the call to this routine with:
|
||||
**
|
||||
** testcase( pParse->earlyCleanup );
|
||||
*/
|
||||
void sqlite3ParserAddCleanup(
|
||||
Parse *pParse, /* Destroy when this Parser finishes */
|
||||
void (*xCleanup)(sqlite3*,void*), /* The cleanup routine */
|
||||
void *pPtr /* Pointer to object to be cleaned up */
|
||||
){
|
||||
ParseCleanup *pCleanup = sqlite3DbMallocRaw(pParse->db, sizeof(*pCleanup));
|
||||
if( pCleanup ){
|
||||
pCleanup->pNext = pParse->pCleanup;
|
||||
pParse->pCleanup = pCleanup;
|
||||
pCleanup->pPtr = pPtr;
|
||||
pCleanup->xCleanup = xCleanup;
|
||||
}else{
|
||||
xCleanup(pParse->db, pPtr);
|
||||
#if defined(SQLITE_DEBUG) || defined(SQLITE_COVERAGE_TEST)
|
||||
pParse->earlyCleanup = 1;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Compile the UTF-8 encoded SQL statement zSql into a statement handle.
|
||||
*/
|
||||
@@ -671,12 +725,6 @@ static int sqlite3Prepare(
|
||||
}
|
||||
assert( 0==sParse.nQueryLoop );
|
||||
|
||||
if( sParse.rc==SQLITE_DONE ){
|
||||
sParse.rc = SQLITE_OK;
|
||||
}
|
||||
if( sParse.checkSchema ){
|
||||
schemaIsValid(&sParse);
|
||||
}
|
||||
if( pzTail ){
|
||||
*pzTail = sParse.zTail;
|
||||
}
|
||||
@@ -687,20 +735,28 @@ static int sqlite3Prepare(
|
||||
if( db->mallocFailed ){
|
||||
sParse.rc = SQLITE_NOMEM_BKPT;
|
||||
}
|
||||
rc = sParse.rc;
|
||||
if( rc!=SQLITE_OK ){
|
||||
if( sParse.pVdbe ) sqlite3VdbeFinalize(sParse.pVdbe);
|
||||
assert(!(*ppStmt));
|
||||
if( sParse.rc!=SQLITE_OK && sParse.rc!=SQLITE_DONE ){
|
||||
if( sParse.checkSchema ){
|
||||
schemaIsValid(&sParse);
|
||||
}
|
||||
if( sParse.pVdbe ){
|
||||
sqlite3VdbeFinalize(sParse.pVdbe);
|
||||
}
|
||||
assert( 0==(*ppStmt) );
|
||||
rc = sParse.rc;
|
||||
if( zErrMsg ){
|
||||
sqlite3ErrorWithMsg(db, rc, "%s", zErrMsg);
|
||||
sqlite3DbFree(db, zErrMsg);
|
||||
}else{
|
||||
sqlite3Error(db, rc);
|
||||
}
|
||||
}else{
|
||||
assert( zErrMsg==0 );
|
||||
*ppStmt = (sqlite3_stmt*)sParse.pVdbe;
|
||||
rc = SQLITE_OK;
|
||||
sqlite3ErrorClear(db);
|
||||
}
|
||||
|
||||
if( zErrMsg ){
|
||||
sqlite3ErrorWithMsg(db, rc, "%s", zErrMsg);
|
||||
sqlite3DbFree(db, zErrMsg);
|
||||
}else{
|
||||
sqlite3Error(db, rc);
|
||||
}
|
||||
|
||||
/* Delete any TriggerPrg structures allocated while parsing this statement. */
|
||||
while( sParse.pTriggerPrg ){
|
||||
|
||||
+156
-63
@@ -347,7 +347,7 @@ static void addWhereTerm(
|
||||
ExprSetProperty(pEq, EP_FromJoin);
|
||||
assert( !ExprHasProperty(pEq, EP_TokenOnly|EP_Reduced) );
|
||||
ExprSetVVAProperty(pEq, EP_NoReduce);
|
||||
pEq->iRightJoinTable = (i16)pE2->iTable;
|
||||
pEq->iRightJoinTable = pE2->iTable;
|
||||
}
|
||||
*ppWhere = sqlite3ExprAnd(pParse, *ppWhere, pEq);
|
||||
}
|
||||
@@ -383,7 +383,7 @@ void sqlite3SetJoinExpr(Expr *p, int iTable){
|
||||
ExprSetProperty(p, EP_FromJoin);
|
||||
assert( !ExprHasProperty(p, EP_TokenOnly|EP_Reduced) );
|
||||
ExprSetVVAProperty(p, EP_NoReduce);
|
||||
p->iRightJoinTable = (i16)iTable;
|
||||
p->iRightJoinTable = iTable;
|
||||
if( p->op==TK_FUNCTION && p->x.pList ){
|
||||
int i;
|
||||
for(i=0; i<p->x.pList->nExpr; i++){
|
||||
@@ -3649,6 +3649,88 @@ static void recomputeColumnsUsed(
|
||||
}
|
||||
#endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */
|
||||
|
||||
#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
|
||||
/*
|
||||
** Assign new cursor numbers to each of the items in pSrc. For each
|
||||
** new cursor number assigned, set an entry in the aCsrMap[] array
|
||||
** to map the old cursor number to the new:
|
||||
**
|
||||
** aCsrMap[iOld] = iNew;
|
||||
**
|
||||
** The array is guaranteed by the caller to be large enough for all
|
||||
** existing cursor numbers in pSrc.
|
||||
**
|
||||
** If pSrc contains any sub-selects, call this routine recursively
|
||||
** on the FROM clause of each such sub-select, with iExcept set to -1.
|
||||
*/
|
||||
static void srclistRenumberCursors(
|
||||
Parse *pParse, /* Parse context */
|
||||
int *aCsrMap, /* Array to store cursor mappings in */
|
||||
SrcList *pSrc, /* FROM clause to renumber */
|
||||
int iExcept /* FROM clause item to skip */
|
||||
){
|
||||
int i;
|
||||
struct SrcList_item *pItem;
|
||||
for(i=0, pItem=pSrc->a; i<pSrc->nSrc; i++, pItem++){
|
||||
if( i!=iExcept ){
|
||||
Select *p;
|
||||
pItem->iCursor = aCsrMap[pItem->iCursor] = pParse->nTab++;
|
||||
for(p=pItem->pSelect; p; p=p->pPrior){
|
||||
srclistRenumberCursors(pParse, aCsrMap, p->pSrc, -1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Expression walker callback used by renumberCursors() to update
|
||||
** Expr objects to match newly assigned cursor numbers.
|
||||
*/
|
||||
static int renumberCursorsCb(Walker *pWalker, Expr *pExpr){
|
||||
int *aCsrMap = pWalker->u.aiCol;
|
||||
if( pExpr->op==TK_COLUMN && aCsrMap[pExpr->iTable] ){
|
||||
pExpr->iTable = aCsrMap[pExpr->iTable];
|
||||
}
|
||||
if( ExprHasProperty(pExpr, EP_FromJoin) && aCsrMap[pExpr->iRightJoinTable] ){
|
||||
pExpr->iRightJoinTable = aCsrMap[pExpr->iRightJoinTable];
|
||||
}
|
||||
return WRC_Continue;
|
||||
}
|
||||
|
||||
/*
|
||||
** Assign a new cursor number to each cursor in the FROM clause (Select.pSrc)
|
||||
** of the SELECT statement passed as the second argument, and to each
|
||||
** cursor in the FROM clause of any FROM clause sub-selects, recursively.
|
||||
** Except, do not assign a new cursor number to the iExcept'th element in
|
||||
** the FROM clause of (*p). Update all expressions and other references
|
||||
** to refer to the new cursor numbers.
|
||||
**
|
||||
** Argument aCsrMap is an array that may be used for temporary working
|
||||
** space. Two guarantees are made by the caller:
|
||||
**
|
||||
** * the array is larger than the largest cursor number used within the
|
||||
** select statement passed as an argument, and
|
||||
**
|
||||
** * the array entries for all cursor numbers that do *not* appear in
|
||||
** FROM clauses of the select statement as described above are
|
||||
** initialized to zero.
|
||||
*/
|
||||
static void renumberCursors(
|
||||
Parse *pParse, /* Parse context */
|
||||
Select *p, /* Select to renumber cursors within */
|
||||
int iExcept, /* FROM clause item to skip */
|
||||
int *aCsrMap /* Working space */
|
||||
){
|
||||
Walker w;
|
||||
srclistRenumberCursors(pParse, aCsrMap, p->pSrc, iExcept);
|
||||
memset(&w, 0, sizeof(w));
|
||||
w.u.aiCol = aCsrMap;
|
||||
w.xExprCallback = renumberCursorsCb;
|
||||
w.xSelectCallback = sqlite3SelectWalkNoop;
|
||||
sqlite3WalkSelect(&w, p);
|
||||
}
|
||||
#endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */
|
||||
|
||||
#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
|
||||
/*
|
||||
** This routine attempts to flatten subqueries as a performance optimization.
|
||||
@@ -3743,9 +3825,9 @@ static void recomputeColumnsUsed(
|
||||
** (17c) every term within the subquery compound must have a FROM clause
|
||||
** (17d) the outer query may not be
|
||||
** (17d1) aggregate, or
|
||||
** (17d2) DISTINCT, or
|
||||
** (17d3) a join.
|
||||
** (17e) the subquery may not contain window functions
|
||||
** (17d2) DISTINCT
|
||||
** (17e) the subquery may not contain window functions, and
|
||||
** (17f) the subquery must not be the RHS of a LEFT JOIN.
|
||||
**
|
||||
** The parent and sub-query may contain WHERE clauses. Subject to
|
||||
** rules (11), (13) and (14), they may also contain ORDER BY,
|
||||
@@ -3761,8 +3843,8 @@ static void recomputeColumnsUsed(
|
||||
** syntax error and return a detailed message.
|
||||
**
|
||||
** (18) If the sub-query is a compound select, then all terms of the
|
||||
** ORDER BY clause of the parent must be simple references to
|
||||
** columns of the sub-query.
|
||||
** ORDER BY clause of the parent must be copies of a term returned
|
||||
** by the parent query.
|
||||
**
|
||||
** (19) If the subquery uses LIMIT then the outer query may not
|
||||
** have a WHERE clause.
|
||||
@@ -3778,9 +3860,8 @@ static void recomputeColumnsUsed(
|
||||
**
|
||||
** (22) The subquery may not be a recursive CTE.
|
||||
**
|
||||
** (**) Subsumed into restriction (17d3). Was: If the outer query is
|
||||
** a recursive CTE, then the sub-query may not be a compound query.
|
||||
** This restriction is because transforming the
|
||||
** (23) If the outer query is a recursive CTE, then the sub-query may not be
|
||||
** a compound query. This restriction is because transforming the
|
||||
** parent to a compound query confuses the code that handles
|
||||
** recursive queries in multiSelect().
|
||||
**
|
||||
@@ -3825,6 +3906,7 @@ static int flattenSubquery(
|
||||
struct SrcList_item *pSubitem; /* The subquery */
|
||||
sqlite3 *db = pParse->db;
|
||||
Walker w; /* Walker to persist agginfo data */
|
||||
int *aCsrMap = 0;
|
||||
|
||||
/* Check to see if flattening is permitted. Return 0 if not.
|
||||
*/
|
||||
@@ -3920,13 +4002,14 @@ static int flattenSubquery(
|
||||
if( pSub->pOrderBy ){
|
||||
return 0; /* Restriction (20) */
|
||||
}
|
||||
if( isAgg || (p->selFlags & SF_Distinct)!=0 || pSrc->nSrc!=1 ){
|
||||
return 0; /* (17d1), (17d2), or (17d3) */
|
||||
if( isAgg || (p->selFlags & SF_Distinct)!=0 || isLeftJoin>0 ){
|
||||
return 0; /* (17d1), (17d2), or (17f) */
|
||||
}
|
||||
for(pSub1=pSub; pSub1; pSub1=pSub1->pPrior){
|
||||
testcase( (pSub1->selFlags & (SF_Distinct|SF_Aggregate))==SF_Distinct );
|
||||
testcase( (pSub1->selFlags & (SF_Distinct|SF_Aggregate))==SF_Aggregate );
|
||||
assert( pSub->pSrc!=0 );
|
||||
assert( (pSub->selFlags & SF_Recursive)==0 );
|
||||
assert( pSub->pEList->nExpr==pSub1->pEList->nExpr );
|
||||
if( (pSub1->selFlags & (SF_Distinct|SF_Aggregate))!=0 /* (17b) */
|
||||
|| (pSub1->pPrior && pSub1->op!=TK_ALL) /* (17a) */
|
||||
@@ -3947,15 +4030,14 @@ static int flattenSubquery(
|
||||
if( p->pOrderBy->a[ii].u.x.iOrderByCol==0 ) return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Ex-restriction (23):
|
||||
** The only way that the recursive part of a CTE can contain a compound
|
||||
** subquery is for the subquery to be one term of a join. But if the
|
||||
** subquery is a join, then the flattening has already been stopped by
|
||||
** restriction (17d3)
|
||||
*/
|
||||
assert( (p->selFlags & SF_Recursive)==0 || pSub->pPrior==0 );
|
||||
/* Restriction (23) */
|
||||
if( (p->selFlags & SF_Recursive) ) return 0;
|
||||
|
||||
if( pSrc->nSrc>1 ){
|
||||
aCsrMap = sqlite3DbMallocZero(db, pParse->nTab*sizeof(int));
|
||||
}
|
||||
}
|
||||
|
||||
/***** If we reach this point, flattening is permitted. *****/
|
||||
SELECTTRACE(1,pParse,p,("flatten %u.%p from term %d\n",
|
||||
@@ -3967,6 +4049,17 @@ static int flattenSubquery(
|
||||
testcase( i==SQLITE_DENY );
|
||||
pParse->zAuthContext = zSavedAuthContext;
|
||||
|
||||
/* Delete the transient structures associated with thesubquery */
|
||||
pSub1 = pSubitem->pSelect;
|
||||
sqlite3DbFree(db, pSubitem->zDatabase);
|
||||
sqlite3DbFree(db, pSubitem->zName);
|
||||
sqlite3DbFree(db, pSubitem->zAlias);
|
||||
pSubitem->zDatabase = 0;
|
||||
pSubitem->zName = 0;
|
||||
pSubitem->zAlias = 0;
|
||||
pSubitem->pSelect = 0;
|
||||
assert( pSubitem->pOn==0 );
|
||||
|
||||
/* If the sub-query is a compound SELECT statement, then (by restrictions
|
||||
** 17 and 18 above) it must be a UNION ALL and the parent query must
|
||||
** be of the form:
|
||||
@@ -4005,18 +4098,22 @@ static int flattenSubquery(
|
||||
ExprList *pOrderBy = p->pOrderBy;
|
||||
Expr *pLimit = p->pLimit;
|
||||
Select *pPrior = p->pPrior;
|
||||
Table *pItemTab = pSubitem->pTab;
|
||||
pSubitem->pTab = 0;
|
||||
p->pOrderBy = 0;
|
||||
p->pSrc = 0;
|
||||
p->pPrior = 0;
|
||||
p->pLimit = 0;
|
||||
pNew = sqlite3SelectDup(db, p, 0);
|
||||
p->pLimit = pLimit;
|
||||
p->pOrderBy = pOrderBy;
|
||||
p->pSrc = pSrc;
|
||||
p->op = TK_ALL;
|
||||
pSubitem->pTab = pItemTab;
|
||||
if( pNew==0 ){
|
||||
p->pPrior = pPrior;
|
||||
}else{
|
||||
if( aCsrMap && db->mallocFailed==0 ){
|
||||
renumberCursors(pParse, pNew, iFrom, aCsrMap);
|
||||
}
|
||||
pNew->pPrior = pPrior;
|
||||
if( pPrior ) pPrior->pNext = pNew;
|
||||
pNew->pNext = p;
|
||||
@@ -4024,24 +4121,13 @@ static int flattenSubquery(
|
||||
SELECTTRACE(2,pParse,p,("compound-subquery flattener"
|
||||
" creates %u as peer\n",pNew->selId));
|
||||
}
|
||||
if( db->mallocFailed ) return 1;
|
||||
assert( pSubitem->pSelect==0 );
|
||||
}
|
||||
sqlite3DbFree(db, aCsrMap);
|
||||
if( db->mallocFailed ){
|
||||
pSubitem->pSelect = pSub1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Begin flattening the iFrom-th entry of the FROM clause
|
||||
** in the outer query.
|
||||
*/
|
||||
pSub = pSub1 = pSubitem->pSelect;
|
||||
|
||||
/* Delete the transient table structure associated with the
|
||||
** subquery
|
||||
*/
|
||||
sqlite3DbFree(db, pSubitem->zDatabase);
|
||||
sqlite3DbFree(db, pSubitem->zName);
|
||||
sqlite3DbFree(db, pSubitem->zAlias);
|
||||
pSubitem->zDatabase = 0;
|
||||
pSubitem->zName = 0;
|
||||
pSubitem->zAlias = 0;
|
||||
pSubitem->pSelect = 0;
|
||||
|
||||
/* Defer deleting the Table object associated with the
|
||||
** subquery until code generation is
|
||||
@@ -4054,8 +4140,10 @@ static int flattenSubquery(
|
||||
Table *pTabToDel = pSubitem->pTab;
|
||||
if( pTabToDel->nTabRef==1 ){
|
||||
Parse *pToplevel = sqlite3ParseToplevel(pParse);
|
||||
pTabToDel->pNextZombie = pToplevel->pZombieTab;
|
||||
pToplevel->pZombieTab = pTabToDel;
|
||||
sqlite3ParserAddCleanup(pToplevel,
|
||||
(void(*)(sqlite3*,void*))sqlite3DeleteTable,
|
||||
pTabToDel);
|
||||
testcase( pToplevel->earlyCleanup );
|
||||
}else{
|
||||
pTabToDel->nTabRef--;
|
||||
}
|
||||
@@ -4075,6 +4163,7 @@ static int flattenSubquery(
|
||||
** those references with expressions that resolve to the subquery FROM
|
||||
** elements we are now copying in.
|
||||
*/
|
||||
pSub = pSub1;
|
||||
for(pParent=p; pParent; pParent=pParent->pPrior, pSub=pSub->pPrior){
|
||||
int nSubSrc;
|
||||
u8 jointype = 0;
|
||||
@@ -4083,16 +4172,10 @@ static int flattenSubquery(
|
||||
nSubSrc = pSubSrc->nSrc; /* Number of terms in subquery FROM clause */
|
||||
pSrc = pParent->pSrc; /* FROM clause of the outer query */
|
||||
|
||||
if( pSrc ){
|
||||
assert( pParent==p ); /* First time through the loop */
|
||||
jointype = pSubitem->fg.jointype;
|
||||
}else{
|
||||
assert( pParent!=p ); /* 2nd and subsequent times through the loop */
|
||||
pSrc = sqlite3SrcListAppend(pParse, 0, 0, 0);
|
||||
if( pSrc==0 ) break;
|
||||
pParent->pSrc = pSrc;
|
||||
if( pParent==p ){
|
||||
jointype = pSubitem->fg.jointype; /* First time through the loop */
|
||||
}
|
||||
|
||||
|
||||
/* The subquery uses a single slot of the FROM clause of the outer
|
||||
** query. If the subquery has more than one element in its FROM clause,
|
||||
** then expand the outer query to make space for it to hold all elements
|
||||
@@ -4557,7 +4640,11 @@ static u8 minMaxQuery(sqlite3 *db, Expr *pFunc, ExprList **ppMinMax){
|
||||
assert( *ppMinMax==0 );
|
||||
assert( pFunc->op==TK_AGG_FUNCTION );
|
||||
assert( !IsWindowFunc(pFunc) );
|
||||
if( pEList==0 || pEList->nExpr!=1 || ExprHasProperty(pFunc, EP_WinFunc) ){
|
||||
if( pEList==0
|
||||
|| pEList->nExpr!=1
|
||||
|| ExprHasProperty(pFunc, EP_WinFunc)
|
||||
|| OptimizationDisabled(db, SQLITE_MinMaxOpt)
|
||||
){
|
||||
return eRet;
|
||||
}
|
||||
zFunc = pFunc->u.zToken;
|
||||
@@ -4775,12 +4862,16 @@ static struct Cte *searchWith(
|
||||
** statement with which it is associated.
|
||||
*/
|
||||
void sqlite3WithPush(Parse *pParse, With *pWith, u8 bFree){
|
||||
assert( bFree==0 || (pParse->pWith==0 && pParse->pWithToFree==0) );
|
||||
if( pWith ){
|
||||
assert( pParse->pWith!=pWith );
|
||||
pWith->pOuter = pParse->pWith;
|
||||
pParse->pWith = pWith;
|
||||
if( bFree ) pParse->pWithToFree = pWith;
|
||||
if( bFree ){
|
||||
sqlite3ParserAddCleanup(pParse,
|
||||
(void(*)(sqlite3*,void*))sqlite3WithDelete,
|
||||
pWith);
|
||||
testcase( pParse->earlyCleanup );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5615,7 +5706,9 @@ static void explainSimpleCount(
|
||||
static int havingToWhereExprCb(Walker *pWalker, Expr *pExpr){
|
||||
if( pExpr->op!=TK_AND ){
|
||||
Select *pS = pWalker->u.pSelect;
|
||||
if( sqlite3ExprIsConstantOrGroupBy(pWalker->pParse, pExpr, pS->pGroupBy) ){
|
||||
if( sqlite3ExprIsConstantOrGroupBy(pWalker->pParse, pExpr, pS->pGroupBy)
|
||||
&& ExprAlwaysFalse(pExpr)==0
|
||||
){
|
||||
sqlite3 *db = pWalker->pParse->db;
|
||||
Expr *pNew = sqlite3Expr(db, TK_INTEGER, "1");
|
||||
if( pNew ){
|
||||
@@ -6491,6 +6584,10 @@ int sqlite3Select(
|
||||
int ii;
|
||||
SELECTTRACE(0x400,pParse,p,("After aggregate analysis %p:\n", pAggInfo));
|
||||
sqlite3TreeViewSelect(0, p, 0);
|
||||
if( minMaxFlag ){
|
||||
sqlite3DebugPrintf("MIN/MAX Optimization (0x%02x) adds:\n", minMaxFlag);
|
||||
sqlite3TreeViewExprList(0, pMinMaxOrderBy, 0, "ORDERBY");
|
||||
}
|
||||
for(ii=0; ii<pAggInfo->nColumn; ii++){
|
||||
sqlite3DebugPrintf("agg-column[%d] iMem=%d\n",
|
||||
ii, pAggInfo->aCol[ii].iMem);
|
||||
@@ -6680,7 +6777,7 @@ int sqlite3Select(
|
||||
/* End of the loop
|
||||
*/
|
||||
if( groupBySort ){
|
||||
sqlite3VdbeAddOp2(v, OP_SorterNext, pAggInfo->sortingIdx, addrTopOfLoop);
|
||||
sqlite3VdbeAddOp2(v, OP_SorterNext, pAggInfo->sortingIdx,addrTopOfLoop);
|
||||
VdbeCoverage(v);
|
||||
}else{
|
||||
sqlite3WhereEnd(pWInfo);
|
||||
@@ -6792,7 +6889,6 @@ int sqlite3Select(
|
||||
explainSimpleCount(pParse, pTab, pBest);
|
||||
}else{
|
||||
int regAcc = 0; /* "populate accumulators" flag */
|
||||
int addrSkip;
|
||||
|
||||
/* If there are accumulator registers but no min() or max() functions
|
||||
** without FILTER clauses, allocate register regAcc. Register regAcc
|
||||
@@ -6841,9 +6937,8 @@ int sqlite3Select(
|
||||
}
|
||||
updateAccumulator(pParse, regAcc, pAggInfo);
|
||||
if( regAcc ) sqlite3VdbeAddOp2(v, OP_Integer, 1, regAcc);
|
||||
addrSkip = sqlite3WhereOrderByLimitOptLabel(pWInfo);
|
||||
if( addrSkip!=sqlite3WhereContinueLabel(pWInfo) ){
|
||||
sqlite3VdbeGoto(v, addrSkip);
|
||||
if( minMaxFlag ){
|
||||
sqlite3WhereMinMaxOptEarlyOut(v, pWInfo);
|
||||
}
|
||||
sqlite3WhereEnd(pWInfo);
|
||||
finalizeAggFunctions(pParse, pAggInfo);
|
||||
@@ -6889,15 +6984,13 @@ select_end:
|
||||
if( pAggInfo && !db->mallocFailed ){
|
||||
for(i=0; i<pAggInfo->nColumn; i++){
|
||||
Expr *pExpr = pAggInfo->aCol[i].pCExpr;
|
||||
assert( pExpr!=0 || db->mallocFailed );
|
||||
if( pExpr==0 ) continue;
|
||||
assert( pExpr!=0 );
|
||||
assert( pExpr->pAggInfo==pAggInfo );
|
||||
assert( pExpr->iAgg==i );
|
||||
}
|
||||
for(i=0; i<pAggInfo->nFunc; i++){
|
||||
Expr *pExpr = pAggInfo->aFunc[i].pFExpr;
|
||||
assert( pExpr!=0 || db->mallocFailed );
|
||||
if( pExpr==0 ) continue;
|
||||
assert( pExpr!=0 );
|
||||
assert( pExpr->pAggInfo==pAggInfo );
|
||||
assert( pExpr->iAgg==i );
|
||||
}
|
||||
|
||||
+54
-20
@@ -1085,12 +1085,12 @@ struct ShellState {
|
||||
u8 autoEQP; /* Run EXPLAIN QUERY PLAN prior to seach SQL stmt */
|
||||
u8 autoEQPtest; /* autoEQP is in test mode */
|
||||
u8 autoEQPtrace; /* autoEQP is in trace mode */
|
||||
u8 statsOn; /* True to display memory stats before each finalize */
|
||||
u8 scanstatsOn; /* True to display scan stats before each finalize */
|
||||
u8 openMode; /* SHELL_OPEN_NORMAL, _APPENDVFS, or _ZIPFILE */
|
||||
u8 doXdgOpen; /* Invoke start/open/xdg-open in output_reset() */
|
||||
u8 nEqpLevel; /* Depth of the EQP output graph */
|
||||
u8 eTraceType; /* SHELL_TRACE_* value for type of trace */
|
||||
unsigned statsOn; /* True to display memory stats before each finalize */
|
||||
unsigned mEqpLines; /* Mask of veritical lines in the EQP output graph */
|
||||
int outCount; /* Revert to stdout when reaching zero */
|
||||
int cnt; /* Number of records displayed so far */
|
||||
@@ -2027,6 +2027,7 @@ static int shell_callback(
|
||||
if( azArg==0 ) break;
|
||||
for(i=0; i<nArg; i++){
|
||||
int w = aExplainWidth[i];
|
||||
if( i==nArg-1 ) w = 0;
|
||||
if( azArg[i] && strlenChar(azArg[i])>w ){
|
||||
w = strlenChar(azArg[i]);
|
||||
}
|
||||
@@ -2591,7 +2592,7 @@ static int display_stats(
|
||||
if( pArg==0 || pArg->out==0 ) return 0;
|
||||
out = pArg->out;
|
||||
|
||||
if( pArg->pStmt && (pArg->statsOn & 2) ){
|
||||
if( pArg->pStmt && pArg->statsOn==2 ){
|
||||
int nCol, i, x;
|
||||
sqlite3_stmt *pStmt = pArg->pStmt;
|
||||
char z[100];
|
||||
@@ -2615,6 +2616,14 @@ static int display_stats(
|
||||
}
|
||||
}
|
||||
|
||||
if( pArg->statsOn==3 ){
|
||||
if( pArg->pStmt ){
|
||||
iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_VM_STEP, bReset);
|
||||
raw_printf(pArg->out, "VM-steps: %d\n", iCur);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
displayStatLine(pArg, "Memory Used:",
|
||||
"%lld (max %lld) bytes", SQLITE_STATUS_MEMORY_USED, bReset);
|
||||
displayStatLine(pArg, "Number of Outstanding Allocations:",
|
||||
@@ -2884,10 +2893,11 @@ static void explain_data_delete(ShellState *p){
|
||||
static unsigned int savedSelectTrace;
|
||||
static unsigned int savedWhereTrace;
|
||||
static void disable_debug_trace_modes(void){
|
||||
unsigned int zero = 0;
|
||||
sqlite3_test_control(SQLITE_TESTCTRL_TRACEFLAGS, 0, &savedSelectTrace);
|
||||
sqlite3_test_control(SQLITE_TESTCTRL_TRACEFLAGS, 1, 0);
|
||||
sqlite3_test_control(SQLITE_TESTCTRL_TRACEFLAGS, 1, &zero);
|
||||
sqlite3_test_control(SQLITE_TESTCTRL_TRACEFLAGS, 2, &savedWhereTrace);
|
||||
sqlite3_test_control(SQLITE_TESTCTRL_TRACEFLAGS, 3, 0);
|
||||
sqlite3_test_control(SQLITE_TESTCTRL_TRACEFLAGS, 3, &zero);
|
||||
}
|
||||
static void restore_debug_trace_modes(void){
|
||||
sqlite3_test_control(SQLITE_TESTCTRL_TRACEFLAGS, 1, &savedSelectTrace);
|
||||
@@ -4046,7 +4056,11 @@ static const char *(azHelp[]) = {
|
||||
".shell CMD ARGS... Run CMD ARGS... in a system shell",
|
||||
#endif
|
||||
".show Show the current values for various settings",
|
||||
".stats ?on|off? Show stats or turn stats on or off",
|
||||
".stats ?ARG? Show stats or turn stats on or off",
|
||||
" off Turn off automatic stat display",
|
||||
" on Turn on automatic stat display",
|
||||
" stmt Show statement stats",
|
||||
" vmstep Show the virtual machine step count only",
|
||||
#ifndef SQLITE_NOHAVE_SYSTEM
|
||||
".system CMD ARGS... Run CMD ARGS... in a system shell",
|
||||
#endif
|
||||
@@ -7862,16 +7876,17 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
int ctrlCode; /* Integer code for that option */
|
||||
const char *zUsage; /* Usage notes */
|
||||
} aCtrl[] = {
|
||||
{ "size_limit", SQLITE_FCNTL_SIZE_LIMIT, "[LIMIT]" },
|
||||
{ "chunk_size", SQLITE_FCNTL_CHUNK_SIZE, "SIZE" },
|
||||
/* { "win32_av_retry", SQLITE_FCNTL_WIN32_AV_RETRY, "COUNT DELAY" },*/
|
||||
{ "persist_wal", SQLITE_FCNTL_PERSIST_WAL, "[BOOLEAN]" },
|
||||
{ "psow", SQLITE_FCNTL_POWERSAFE_OVERWRITE, "[BOOLEAN]" },
|
||||
/* { "pragma", SQLITE_FCNTL_PRAGMA, "NAME ARG" },*/
|
||||
{ "tempfilename", SQLITE_FCNTL_TEMPFILENAME, "" },
|
||||
{ "data_version", SQLITE_FCNTL_DATA_VERSION, "" },
|
||||
{ "has_moved", SQLITE_FCNTL_HAS_MOVED, "" },
|
||||
{ "lock_timeout", SQLITE_FCNTL_LOCK_TIMEOUT, "MILLISEC" },
|
||||
{ "persist_wal", SQLITE_FCNTL_PERSIST_WAL, "[BOOLEAN]" },
|
||||
/* { "pragma", SQLITE_FCNTL_PRAGMA, "NAME ARG" },*/
|
||||
{ "psow", SQLITE_FCNTL_POWERSAFE_OVERWRITE, "[BOOLEAN]" },
|
||||
{ "reserve_bytes", SQLITE_FCNTL_RESERVE_BYTES, "[N]" },
|
||||
{ "size_limit", SQLITE_FCNTL_SIZE_LIMIT, "[LIMIT]" },
|
||||
{ "tempfilename", SQLITE_FCNTL_TEMPFILENAME, "" },
|
||||
/* { "win32_av_retry", SQLITE_FCNTL_WIN32_AV_RETRY, "COUNT DELAY" },*/
|
||||
};
|
||||
int filectrl = -1;
|
||||
int iCtrl = -1;
|
||||
@@ -7958,6 +7973,7 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
isOk = 1;
|
||||
break;
|
||||
}
|
||||
case SQLITE_FCNTL_DATA_VERSION:
|
||||
case SQLITE_FCNTL_HAS_MOVED: {
|
||||
int x;
|
||||
if( nArg!=2 ) break;
|
||||
@@ -8666,9 +8682,9 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
#endif /* SQLITE_DEBUG */
|
||||
|
||||
if( c=='o' && strncmp(azArg[0], "open", n)==0 && n>=2 ){
|
||||
char *zNewFilename; /* 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 */
|
||||
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);
|
||||
close_db(p->db);
|
||||
@@ -8680,7 +8696,7 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
p->openFlags = 0;
|
||||
p->szMax = 0;
|
||||
/* Check for command-line arguments */
|
||||
for(iName=1; iName<nArg && azArg[iName][0]=='-'; iName++){
|
||||
for(iName=1; iName<nArg; iName++){
|
||||
const char *z = azArg[iName];
|
||||
if( optionMatch(z,"new") ){
|
||||
newFlag = 1;
|
||||
@@ -8706,10 +8722,15 @@ 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 ){
|
||||
utf8_printf(stderr, "extra argument: \"%s\"\n", z);
|
||||
rc = 1;
|
||||
goto meta_command_exit;
|
||||
}else{
|
||||
zNewFilename = sqlite3_mprintf("%s", z);
|
||||
}
|
||||
}
|
||||
/* If a filename is specified, try to open it first */
|
||||
zNewFilename = nArg>iName ? sqlite3_mprintf("%s", azArg[iName]) : 0;
|
||||
if( zNewFilename || p->openMode==SHELL_OPEN_HEXDB ){
|
||||
if( newFlag ) shellDeleteFile(zNewFilename);
|
||||
p->zDbFilename = zNewFilename;
|
||||
@@ -9716,6 +9737,7 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
|
||||
if( c=='s' && strncmp(azArg[0], "show", n)==0 ){
|
||||
static const char *azBool[] = { "off", "on", "trigger", "full"};
|
||||
const char *zOut;
|
||||
int i;
|
||||
if( nArg!=1 ){
|
||||
raw_printf(stderr, "Usage: .show\n");
|
||||
@@ -9740,7 +9762,13 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
utf8_printf(p->out,"%12.12s: ", "rowseparator");
|
||||
output_c_string(p->out, p->rowSeparator);
|
||||
raw_printf(p->out, "\n");
|
||||
utf8_printf(p->out, "%12.12s: %s\n","stats", azBool[p->statsOn!=0]);
|
||||
switch( p->statsOn ){
|
||||
case 0: zOut = "off"; break;
|
||||
default: zOut = "on"; break;
|
||||
case 2: zOut = "stmt"; break;
|
||||
case 3: zOut = "vmstep"; break;
|
||||
}
|
||||
utf8_printf(p->out, "%12.12s: %s\n","stats", zOut);
|
||||
utf8_printf(p->out, "%12.12s: ", "width");
|
||||
for (i=0;i<p->nWidth;i++) {
|
||||
raw_printf(p->out, "%d ", p->colWidth[i]);
|
||||
@@ -9752,11 +9780,17 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
|
||||
if( c=='s' && strncmp(azArg[0], "stats", n)==0 ){
|
||||
if( nArg==2 ){
|
||||
p->statsOn = (u8)booleanValue(azArg[1]);
|
||||
if( strcmp(azArg[1],"stmt")==0 ){
|
||||
p->statsOn = 2;
|
||||
}else if( strcmp(azArg[1],"vmstep")==0 ){
|
||||
p->statsOn = 3;
|
||||
}else{
|
||||
p->statsOn = (u8)booleanValue(azArg[1]);
|
||||
}
|
||||
}else if( nArg==1 ){
|
||||
display_stats(p->db, p, 0);
|
||||
}else{
|
||||
raw_printf(stderr, "Usage: .stats ?on|off?\n");
|
||||
raw_printf(stderr, "Usage: .stats ?on|off|stmt|vmstep?\n");
|
||||
rc = 1;
|
||||
}
|
||||
}else
|
||||
@@ -9961,7 +9995,7 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
/* sqlite3_test_control(int, db, int) */
|
||||
case SQLITE_TESTCTRL_OPTIMIZATIONS:
|
||||
if( nArg==3 ){
|
||||
int opt = (int)strtol(azArg[2], 0, 0);
|
||||
unsigned int opt = (unsigned int)strtol(azArg[2], 0, 0);
|
||||
rc2 = sqlite3_test_control(testctrl, p->db, opt);
|
||||
isOk = 3;
|
||||
}
|
||||
|
||||
+2
-1
@@ -3499,6 +3499,7 @@ void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
|
||||
** that uses dot-files in place of posix advisory locking.
|
||||
** <tr><td> file:data.db?mode=readonly <td>
|
||||
** An error. "readonly" is not a valid option for the "mode" parameter.
|
||||
** Use "ro" instead: "file:data.db?mode=ro".
|
||||
** </table>
|
||||
**
|
||||
** ^URI hexadecimal escape sequences (%HH) are supported within the path and
|
||||
@@ -3697,7 +3698,7 @@ sqlite3_file *sqlite3_database_file_object(const char*);
|
||||
** If the Y parameter to sqlite3_free_filename(Y) is anything other
|
||||
** than a NULL pointer or a pointer previously acquired from
|
||||
** sqlite3_create_filename(), then bad things such as heap
|
||||
** corruption or segfaults may occur. The value Y should be
|
||||
** corruption or segfaults may occur. The value Y should not be
|
||||
** used again after sqlite3_free_filename(Y) has been called. This means
|
||||
** that if the [sqlite3_vfs.xOpen()] method of a VFS has been called using Y,
|
||||
** then the corresponding [sqlite3_module.xClose() method should also be
|
||||
|
||||
+108
-55
@@ -119,6 +119,18 @@
|
||||
# define MSVC_VERSION 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Some C99 functions in "math.h" are only present for MSVC when its version
|
||||
** is associated with Visual Studio 2013 or higher.
|
||||
*/
|
||||
#ifndef SQLITE_HAVE_C99_MATH_FUNCS
|
||||
# if MSVC_VERSION==0 || MSVC_VERSION>=1800
|
||||
# define SQLITE_HAVE_C99_MATH_FUNCS (1)
|
||||
# else
|
||||
# define SQLITE_HAVE_C99_MATH_FUNCS (0)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Needed for various definitions... */
|
||||
#if defined(__GNUC__) && !defined(_GNU_SOURCE)
|
||||
# define _GNU_SOURCE
|
||||
@@ -202,7 +214,8 @@
|
||||
#ifndef __has_extension
|
||||
# define __has_extension(x) 0 /* compatibility with non-clang compilers */
|
||||
#endif
|
||||
#if GCC_VERSION>=4007000 || __has_extension(c_atomic)
|
||||
#if GCC_VERSION>=4007000 || \
|
||||
(__has_extension(c_atomic) && __has_extension(c_atomic_store_n))
|
||||
# define AtomicLoad(PTR) __atomic_load_n((PTR),__ATOMIC_RELAXED)
|
||||
# define AtomicStore(PTR,VAL) __atomic_store_n((PTR),(VAL),__ATOMIC_RELAXED)
|
||||
#else
|
||||
@@ -1002,9 +1015,7 @@ extern u32 sqlite3SelectTrace;
|
||||
/*
|
||||
** Macros for "wheretrace"
|
||||
*/
|
||||
#if !defined(SQLITE_AMAGAMATION)
|
||||
extern u32 sqlite3WhereTrace;
|
||||
#endif
|
||||
#if defined(SQLITE_DEBUG) \
|
||||
&& (defined(SQLITE_TEST) || defined(SQLITE_ENABLE_WHERETRACE))
|
||||
# define WHERETRACE(K,X) if(sqlite3WhereTrace&(K)) sqlite3DebugPrintf X
|
||||
@@ -1126,6 +1137,7 @@ typedef struct Bitvec Bitvec;
|
||||
typedef struct CollSeq CollSeq;
|
||||
typedef struct Column Column;
|
||||
typedef struct Db Db;
|
||||
typedef struct DbFixer DbFixer;
|
||||
typedef struct Schema Schema;
|
||||
typedef struct Expr Expr;
|
||||
typedef struct ExprList ExprList;
|
||||
@@ -1143,6 +1155,7 @@ typedef struct LookasideSlot LookasideSlot;
|
||||
typedef struct Module Module;
|
||||
typedef struct NameContext NameContext;
|
||||
typedef struct Parse Parse;
|
||||
typedef struct ParseCleanup ParseCleanup;
|
||||
typedef struct PreUpdate PreUpdate;
|
||||
typedef struct PrintfArguments PrintfArguments;
|
||||
typedef struct RenameToken RenameToken;
|
||||
@@ -1484,7 +1497,7 @@ struct sqlite3 {
|
||||
int errCode; /* Most recent error code (SQLITE_*) */
|
||||
int errMask; /* & result codes with this before returning */
|
||||
int iSysErrno; /* Errno value from last system error */
|
||||
u16 dbOptFlags; /* Flags to enable/disable optimizations */
|
||||
u32 dbOptFlags; /* Flags to enable/disable optimizations */
|
||||
u8 enc; /* Text encoding */
|
||||
u8 autoCommit; /* The auto-commit flag. */
|
||||
u8 temp_store; /* 1: file 2: memory 0: default */
|
||||
@@ -1691,24 +1704,26 @@ struct sqlite3 {
|
||||
** sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS,...) interface to
|
||||
** selectively disable various optimizations.
|
||||
*/
|
||||
#define SQLITE_QueryFlattener 0x0001 /* Query flattening */
|
||||
#define SQLITE_WindowFunc 0x0002 /* Use xInverse for window functions */
|
||||
#define SQLITE_GroupByOrder 0x0004 /* GROUPBY cover of ORDERBY */
|
||||
#define SQLITE_FactorOutConst 0x0008 /* Constant factoring */
|
||||
#define SQLITE_DistinctOpt 0x0010 /* DISTINCT using indexes */
|
||||
#define SQLITE_CoverIdxScan 0x0020 /* Covering index scans */
|
||||
#define SQLITE_OrderByIdxJoin 0x0040 /* ORDER BY of joins via index */
|
||||
#define SQLITE_Transitive 0x0080 /* Transitive constraints */
|
||||
#define SQLITE_OmitNoopJoin 0x0100 /* Omit unused tables in joins */
|
||||
#define SQLITE_CountOfView 0x0200 /* The count-of-view optimization */
|
||||
#define SQLITE_CursorHints 0x0400 /* Add OP_CursorHint opcodes */
|
||||
#define SQLITE_Stat4 0x0800 /* Use STAT4 data */
|
||||
/* TH3 expects the Stat4 ^^^^^^ value to be 0x0800. Don't change it */
|
||||
#define SQLITE_PushDown 0x1000 /* The push-down optimization */
|
||||
#define SQLITE_SimplifyJoin 0x2000 /* Convert LEFT JOIN to JOIN */
|
||||
#define SQLITE_SkipScan 0x4000 /* Skip-scans */
|
||||
#define SQLITE_PropagateConst 0x8000 /* The constant propagation opt */
|
||||
#define SQLITE_AllOpts 0xffff /* All optimizations */
|
||||
#define SQLITE_QueryFlattener 0x00000001 /* Query flattening */
|
||||
#define SQLITE_WindowFunc 0x00000002 /* Use xInverse for window functions */
|
||||
#define SQLITE_GroupByOrder 0x00000004 /* GROUPBY cover of ORDERBY */
|
||||
#define SQLITE_FactorOutConst 0x00000008 /* Constant factoring */
|
||||
#define SQLITE_DistinctOpt 0x00000010 /* DISTINCT using indexes */
|
||||
#define SQLITE_CoverIdxScan 0x00000020 /* Covering index scans */
|
||||
#define SQLITE_OrderByIdxJoin 0x00000040 /* ORDER BY of joins via index */
|
||||
#define SQLITE_Transitive 0x00000080 /* Transitive constraints */
|
||||
#define SQLITE_OmitNoopJoin 0x00000100 /* Omit unused tables in joins */
|
||||
#define SQLITE_CountOfView 0x00000200 /* The count-of-view optimization */
|
||||
#define SQLITE_CursorHints 0x00000400 /* Add OP_CursorHint opcodes */
|
||||
#define SQLITE_Stat4 0x00000800 /* Use STAT4 data */
|
||||
/* TH3 expects this value ^^^^^^^^^^ to be 0x0000800. Don't change it */
|
||||
#define SQLITE_PushDown 0x00001000 /* The push-down optimization */
|
||||
#define SQLITE_SimplifyJoin 0x00002000 /* Convert LEFT JOIN to JOIN */
|
||||
#define SQLITE_SkipScan 0x00004000 /* Skip-scans */
|
||||
#define SQLITE_PropagateConst 0x00008000 /* The constant propagation opt */
|
||||
#define SQLITE_MinMaxOpt 0x00010000 /* The min/max optimization */
|
||||
#define SQLITE_ExistsToIN 0x00020000 /* The EXISTS-to-IN optimization */
|
||||
#define SQLITE_AllOpts 0xffffffff /* All optimizations */
|
||||
|
||||
/*
|
||||
** Macros for testing whether or not optimizations are enabled or disabled.
|
||||
@@ -1864,6 +1879,9 @@ struct FuncDestructor {
|
||||
** a single query. The iArg is ignored. The user-data is always set
|
||||
** to a NULL pointer. The bNC parameter is not used.
|
||||
**
|
||||
** MFUNCTION(zName, nArg, xPtr, xFunc)
|
||||
** For math-library functions. xPtr is an arbitrary pointer.
|
||||
**
|
||||
** PURE_DATE(zName, nArg, iArg, bNC, xFunc)
|
||||
** Used for "pure" date/time functions, this macro is like DFUNCTION
|
||||
** except that it does set the SQLITE_FUNC_CONSTANT flags. iArg is
|
||||
@@ -1899,6 +1917,9 @@ struct FuncDestructor {
|
||||
#define SFUNCTION(zName, nArg, iArg, bNC, xFunc) \
|
||||
{nArg, SQLITE_UTF8|SQLITE_DIRECTONLY|SQLITE_FUNC_UNSAFE, \
|
||||
SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, 0, #zName, {0} }
|
||||
#define MFUNCTION(zName, nArg, xPtr, xFunc) \
|
||||
{nArg, SQLITE_FUNC_CONSTANT|SQLITE_UTF8, \
|
||||
xPtr, 0, xFunc, 0, 0, 0, #zName, {0} }
|
||||
#define INLINE_FUNC(zName, nArg, iArg, mFlags) \
|
||||
{nArg, SQLITE_UTF8|SQLITE_FUNC_INLINE|SQLITE_FUNC_CONSTANT|(mFlags), \
|
||||
SQLITE_INT_TO_PTR(iArg), 0, noopFunc, 0, 0, 0, #zName, {0} }
|
||||
@@ -2169,7 +2190,6 @@ struct Table {
|
||||
#endif
|
||||
Trigger *pTrigger; /* List of triggers stored in pSchema */
|
||||
Schema *pSchema; /* Schema that contains this table */
|
||||
Table *pNextZombie; /* Next on the Parse.pZombieTab list */
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -2298,16 +2318,22 @@ struct FKey {
|
||||
** is returned. REPLACE means that preexisting database rows that caused
|
||||
** a UNIQUE constraint violation are removed so that the new insert or
|
||||
** update can proceed. Processing continues and no error is reported.
|
||||
** UPDATE applies to insert operations only and means that the insert
|
||||
** is omitted and the DO UPDATE clause of an upsert is run instead.
|
||||
**
|
||||
** RESTRICT, SETNULL, and CASCADE actions apply only to foreign keys.
|
||||
** RESTRICT, SETNULL, SETDFLT, and CASCADE actions apply only to foreign keys.
|
||||
** RESTRICT is the same as ABORT for IMMEDIATE foreign keys and the
|
||||
** same as ROLLBACK for DEFERRED keys. SETNULL means that the foreign
|
||||
** key is set to NULL. CASCADE means that a DELETE or UPDATE of the
|
||||
** key is set to NULL. SETDFLT means that the foreign key is set
|
||||
** to its default value. CASCADE means that a DELETE or UPDATE of the
|
||||
** referenced table row is propagated into the row that holds the
|
||||
** foreign key.
|
||||
**
|
||||
** The OE_Default value is a place holder that means to use whatever
|
||||
** conflict resolution algorthm is required from context.
|
||||
**
|
||||
** The following symbolic values are used to record which type
|
||||
** of action to take.
|
||||
** of conflict resolution action to take.
|
||||
*/
|
||||
#define OE_None 0 /* There is no constraint to check */
|
||||
#define OE_Rollback 1 /* Fail the operation and rollback the transaction */
|
||||
@@ -2693,7 +2719,7 @@ struct Expr {
|
||||
** TK_VARIABLE: variable number (always >= 1).
|
||||
** TK_SELECT_COLUMN: column of the result vector */
|
||||
i16 iAgg; /* Which entry in pAggInfo->aCol[] or ->aFunc[] */
|
||||
i16 iRightJoinTable; /* If EP_FromJoin, the right table of the join */
|
||||
int iRightJoinTable; /* If EP_FromJoin, the right table of the join */
|
||||
AggInfo *pAggInfo; /* Used by TK_AGG_COLUMN and TK_AGG_FUNCTION */
|
||||
union {
|
||||
Table *pTab; /* TK_COLUMN: Table containing column. Can be NULL
|
||||
@@ -3061,15 +3087,21 @@ struct NameContext {
|
||||
** WHERE clause is omitted.
|
||||
*/
|
||||
struct Upsert {
|
||||
ExprList *pUpsertTarget; /* Optional description of conflicting index */
|
||||
ExprList *pUpsertTarget; /* Optional description of conflict target */
|
||||
Expr *pUpsertTargetWhere; /* WHERE clause for partial index targets */
|
||||
ExprList *pUpsertSet; /* The SET clause from an ON CONFLICT UPDATE */
|
||||
Expr *pUpsertWhere; /* WHERE clause for the ON CONFLICT UPDATE */
|
||||
/* The fields above comprise the parse tree for the upsert clause.
|
||||
** The fields below are used to transfer information from the INSERT
|
||||
** processing down into the UPDATE processing while generating code.
|
||||
** Upsert owns the memory allocated above, but not the memory below. */
|
||||
Index *pUpsertIdx; /* Constraint that pUpsertTarget identifies */
|
||||
Upsert *pNextUpsert; /* Next ON CONFLICT clause in the list */
|
||||
u8 isDoUpdate; /* True for DO UPDATE. False for DO NOTHING */
|
||||
/* Above this point is the parse tree for the ON CONFLICT clauses.
|
||||
** The next group of fields stores intermediate data. */
|
||||
void *pToFree; /* Free memory when deleting the Upsert object */
|
||||
/* All fields above are owned by the Upsert object and must be freed
|
||||
** when the Upsert is destroyed. The fields below are used to transfer
|
||||
** information from the INSERT processing down into the UPDATE processing
|
||||
** while generating code. The fields below are owned by the INSERT
|
||||
** statement and will be freed by INSERT processing. */
|
||||
Index *pUpsertIdx; /* UNIQUE constraint specified by pUpsertTarget */
|
||||
SrcList *pUpsertSrc; /* Table to be updated */
|
||||
int regData; /* First register holding array of VALUES */
|
||||
int iDataCur; /* Index of the data cursor */
|
||||
@@ -3319,6 +3351,17 @@ struct TriggerPrg {
|
||||
# define DbMaskNonZero(M) (M)!=0
|
||||
#endif
|
||||
|
||||
/*
|
||||
** An instance of the ParseCleanup object specifies an operation that
|
||||
** should be performed after parsing to deallocation resources obtained
|
||||
** during the parse and which are no longer needed.
|
||||
*/
|
||||
struct ParseCleanup {
|
||||
ParseCleanup *pNext; /* Next cleanup task */
|
||||
void *pPtr; /* Pointer to object to deallocate */
|
||||
void (*xCleanup)(sqlite3*,void*); /* Deallocation routine */
|
||||
};
|
||||
|
||||
/*
|
||||
** An SQL parser context. A copy of this structure is passed through
|
||||
** the parser and down into all the parser action routine in order to
|
||||
@@ -3350,6 +3393,9 @@ struct Parse {
|
||||
u8 okConstFactor; /* OK to factor out constants */
|
||||
u8 disableLookaside; /* Number of times lookaside has been disabled */
|
||||
u8 disableVtab; /* Disable all virtual tables for this parse */
|
||||
#if defined(SQLITE_DEBUG) || defined(SQLITE_COVERAGE_TEST)
|
||||
u8 earlyCleanup; /* OOM inside sqlite3ParserAddCleanup() */
|
||||
#endif
|
||||
int nRangeReg; /* Size of the temporary register block */
|
||||
int iRangeReg; /* First register in temporary register block */
|
||||
int nErr; /* Number of errors seen */
|
||||
@@ -3428,10 +3474,9 @@ struct Parse {
|
||||
Token sArg; /* Complete text of a module argument */
|
||||
Table **apVtabLock; /* Pointer to virtual tables needing locking */
|
||||
#endif
|
||||
Table *pZombieTab; /* List of Table objects to delete after code gen */
|
||||
TriggerPrg *pTriggerPrg; /* Linked list of coded triggers */
|
||||
With *pWith; /* Current WITH clause, or NULL */
|
||||
With *pWithToFree; /* Free this WITH object at the end of the parse */
|
||||
ParseCleanup *pCleanup; /* List of cleanup operations to run after parse */
|
||||
#ifndef SQLITE_OMIT_ALTERTABLE
|
||||
RenameToken *pRename; /* Tokens subject to renaming by ALTER TABLE */
|
||||
#endif
|
||||
@@ -3511,6 +3556,7 @@ struct AuthContext {
|
||||
#define OPFLAG_SAVEPOSITION 0x02 /* OP_Delete/Insert: save cursor pos */
|
||||
#define OPFLAG_AUXDELETE 0x04 /* OP_Delete: index in a DELETE op */
|
||||
#define OPFLAG_NOCHNG_MAGIC 0x6d /* OP_MakeRecord: serialtype 10 is ok */
|
||||
#define OPFLAG_PREFORMAT 0x80 /* OP_Insert uses preformatted cell */
|
||||
|
||||
/*
|
||||
* Each trigger present in the database schema is stored as an instance of
|
||||
@@ -3605,21 +3651,6 @@ struct TriggerStep {
|
||||
TriggerStep *pLast; /* Last element in link-list. Valid for 1st elem only */
|
||||
};
|
||||
|
||||
/*
|
||||
** The following structure contains information used by the sqliteFix...
|
||||
** routines as they walk the parse tree to make database references
|
||||
** explicit.
|
||||
*/
|
||||
typedef struct DbFixer DbFixer;
|
||||
struct DbFixer {
|
||||
Parse *pParse; /* The parsing context. Error messages written here */
|
||||
Schema *pSchema; /* Fix items to this schema */
|
||||
u8 bTemp; /* True for TEMP schema entries */
|
||||
const char *zDb; /* Make sure all objects are contained in this database */
|
||||
const char *zType; /* Type of the container - used for error messages */
|
||||
const Token *pName; /* Name of the container - used for error messages */
|
||||
};
|
||||
|
||||
/*
|
||||
** An objected used to accumulate the text of a string where we
|
||||
** do not necessarily know how big the string will be in the end.
|
||||
@@ -3770,9 +3801,25 @@ struct Walker {
|
||||
struct RenameCtx *pRename; /* RENAME COLUMN context */
|
||||
struct Table *pTab; /* Table of generated column */
|
||||
struct SrcList_item *pSrcItem; /* A single FROM clause item */
|
||||
DbFixer *pFix;
|
||||
} u;
|
||||
};
|
||||
|
||||
/*
|
||||
** The following structure contains information used by the sqliteFix...
|
||||
** routines as they walk the parse tree to make database references
|
||||
** explicit.
|
||||
*/
|
||||
struct DbFixer {
|
||||
Parse *pParse; /* The parsing context. Error messages written here */
|
||||
Walker w; /* Walker object */
|
||||
Schema *pSchema; /* Fix items to this schema */
|
||||
u8 bTemp; /* True for TEMP schema entries */
|
||||
const char *zDb; /* Make sure all objects are contained in this database */
|
||||
const char *zType; /* Type of the container - used for error messages */
|
||||
const Token *pName; /* Name of the container - used for error messages */
|
||||
};
|
||||
|
||||
/* Forward declarations */
|
||||
int sqlite3WalkExpr(Walker*, Expr*);
|
||||
int sqlite3WalkExprList(Walker*, ExprList*);
|
||||
@@ -3889,7 +3936,6 @@ int sqlite3WindowCompare(Parse*, Window*, Window*, int);
|
||||
void sqlite3WindowCodeInit(Parse*, Select*);
|
||||
void sqlite3WindowCodeStep(Parse*, Select*, WhereInfo*, int, int);
|
||||
int sqlite3WindowRewrite(Parse*, Select*);
|
||||
int sqlite3ExpandSubquery(Parse*, struct SrcList_item*);
|
||||
void sqlite3WindowUpdate(Parse*, Window*, Window*, FuncDef*);
|
||||
Window *sqlite3WindowDup(sqlite3 *db, Expr *pOwner, Window *p);
|
||||
Window *sqlite3WindowListDup(sqlite3 *db, Window *p);
|
||||
@@ -4299,6 +4345,7 @@ LogEst sqlite3WhereOutputRowCount(WhereInfo*);
|
||||
int sqlite3WhereIsDistinct(WhereInfo*);
|
||||
int sqlite3WhereIsOrdered(WhereInfo*);
|
||||
int sqlite3WhereOrderByLimitOptLabel(WhereInfo*);
|
||||
void sqlite3WhereMinMaxOptEarlyOut(Vdbe*,WhereInfo*);
|
||||
int sqlite3WhereIsSorted(WhereInfo*);
|
||||
int sqlite3WhereContinueLabel(WhereInfo*);
|
||||
int sqlite3WhereBreakLabel(WhereInfo*);
|
||||
@@ -4482,7 +4529,6 @@ void sqlite3FixInit(DbFixer*, Parse*, int, const char*, const Token*);
|
||||
int sqlite3FixSrcList(DbFixer*, SrcList*);
|
||||
int sqlite3FixSelect(DbFixer*, Select*);
|
||||
int sqlite3FixExpr(DbFixer*, Expr*);
|
||||
int sqlite3FixExprList(DbFixer*, ExprList*);
|
||||
int sqlite3FixTriggerStep(DbFixer*, TriggerStep*);
|
||||
int sqlite3RealSameAsInt(double,sqlite3_int64);
|
||||
void sqlite3Int64ToText(i64,char*);
|
||||
@@ -4545,6 +4591,7 @@ int sqlite3Atoi64(const char*, i64*, int, u8);
|
||||
int sqlite3DecOrHexToI64(const char*, i64*);
|
||||
void sqlite3ErrorWithMsg(sqlite3*, int, const char*,...);
|
||||
void sqlite3Error(sqlite3*,int);
|
||||
void sqlite3ErrorClear(sqlite3*);
|
||||
void sqlite3SystemError(sqlite3*,int);
|
||||
void *sqlite3HexToBlob(sqlite3*, const char *z, int n);
|
||||
u8 sqlite3HexToInt(int h);
|
||||
@@ -4626,6 +4673,7 @@ void sqlite3ExpirePreparedStatements(sqlite3*, int);
|
||||
void sqlite3CodeRhsOfIN(Parse*, Expr*, int);
|
||||
int sqlite3CodeSubselect(Parse*, Expr*);
|
||||
void sqlite3SelectPrep(Parse*, Select*, NameContext*);
|
||||
int sqlite3ExpandSubquery(Parse*, struct SrcList_item*);
|
||||
void sqlite3SelectWrongNumTermsError(Parse *pParse, Select *p);
|
||||
int sqlite3MatchEName(
|
||||
const struct ExprList_item*,
|
||||
@@ -4796,6 +4844,7 @@ sqlite3_int64 sqlite3StmtCurrentTime(sqlite3_context*);
|
||||
int sqlite3VdbeParameterIndex(Vdbe*, const char*, int);
|
||||
int sqlite3TransferBindings(sqlite3_stmt *, sqlite3_stmt *);
|
||||
void sqlite3ParserReset(Parse*);
|
||||
void sqlite3ParserAddCleanup(Parse*,void(*)(sqlite3*,void*),void*);
|
||||
#ifdef SQLITE_ENABLE_NORMALIZE
|
||||
char *sqlite3Normalize(Vdbe*, const char*);
|
||||
#endif
|
||||
@@ -4818,15 +4867,19 @@ const char *sqlite3JournalModename(int);
|
||||
#define sqlite3WithDelete(x,y)
|
||||
#endif
|
||||
#ifndef SQLITE_OMIT_UPSERT
|
||||
Upsert *sqlite3UpsertNew(sqlite3*,ExprList*,Expr*,ExprList*,Expr*);
|
||||
Upsert *sqlite3UpsertNew(sqlite3*,ExprList*,Expr*,ExprList*,Expr*,Upsert*);
|
||||
void sqlite3UpsertDelete(sqlite3*,Upsert*);
|
||||
Upsert *sqlite3UpsertDup(sqlite3*,Upsert*);
|
||||
int sqlite3UpsertAnalyzeTarget(Parse*,SrcList*,Upsert*);
|
||||
void sqlite3UpsertDoUpdate(Parse*,Upsert*,Table*,Index*,int);
|
||||
Upsert *sqlite3UpsertOfIndex(Upsert*,Index*);
|
||||
int sqlite3UpsertNextIsIPK(Upsert*);
|
||||
#else
|
||||
#define sqlite3UpsertNew(v,w,x,y,z) ((Upsert*)0)
|
||||
#define sqlite3UpsertNew(u,v,w,x,y,z) ((Upsert*)0)
|
||||
#define sqlite3UpsertDelete(x,y)
|
||||
#define sqlite3UpsertDup(x,y) ((Upsert*)0)
|
||||
#define sqlite3UpsertDup(x,y) ((Upsert*)0)
|
||||
#define sqlite3UpsertOfIndex(x,y) ((Upsert*)0)
|
||||
#define sqlite3UpsertNextIsIPK(x) 0
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
+1
-1
@@ -8512,7 +8512,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
||||
extern LONG volatile sqlite3_os_type;
|
||||
#endif
|
||||
#ifdef SQLITE_DEBUG
|
||||
extern int sqlite3WhereTrace;
|
||||
extern u32 sqlite3WhereTrace;
|
||||
extern int sqlite3OSTrace;
|
||||
extern int sqlite3WalTrace;
|
||||
#endif
|
||||
|
||||
@@ -154,6 +154,12 @@ static void set_options(Tcl_Interp *interp){
|
||||
Tcl_SetVar2(interp, "sqlite_options", "deserialize", "0", TCL_GLOBAL_ONLY);
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_ENABLE_MATH_FUNCTIONS
|
||||
Tcl_SetVar2(interp, "sqlite_options", "mathlib", "1", TCL_GLOBAL_ONLY);
|
||||
#else
|
||||
Tcl_SetVar2(interp, "sqlite_options", "mathlib", "0", TCL_GLOBAL_ONLY);
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_ENABLE_MEMSYS3
|
||||
Tcl_SetVar2(interp, "sqlite_options", "mem3", "1", TCL_GLOBAL_ONLY);
|
||||
#else
|
||||
|
||||
+27
-37
@@ -27,8 +27,8 @@
|
||||
** all of them need to be used within the switch.
|
||||
*/
|
||||
#define CC_X 0 /* The letter 'x', or start of BLOB literal */
|
||||
#define CC_KYWD 1 /* Alphabetics or '_'. Usable in a keyword */
|
||||
#define CC_ID 2 /* unicode characters usable in IDs */
|
||||
#define CC_KYWD0 1 /* First letter of a keyword */
|
||||
#define CC_KYWD 2 /* Alphabetics or '_'. Usable in a keyword */
|
||||
#define CC_DIGIT 3 /* Digits */
|
||||
#define CC_DOLLAR 4 /* '$' */
|
||||
#define CC_VARALPHA 5 /* '@', '#', ':'. Alphabetic SQL variables */
|
||||
@@ -53,20 +53,21 @@
|
||||
#define CC_AND 24 /* '&' */
|
||||
#define CC_TILDA 25 /* '~' */
|
||||
#define CC_DOT 26 /* '.' */
|
||||
#define CC_ILLEGAL 27 /* Illegal character */
|
||||
#define CC_NUL 28 /* 0x00 */
|
||||
#define CC_ID 27 /* unicode characters usable in IDs */
|
||||
#define CC_ILLEGAL 28 /* Illegal character */
|
||||
#define CC_NUL 29 /* 0x00 */
|
||||
|
||||
static const unsigned char aiClass[] = {
|
||||
#ifdef SQLITE_ASCII
|
||||
/* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xa xb xc xd xe xf */
|
||||
/* 0x */ 28, 27, 27, 27, 27, 27, 27, 27, 27, 7, 7, 27, 7, 7, 27, 27,
|
||||
/* 1x */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
|
||||
/* 0x */ 29, 28, 28, 28, 28, 28, 28, 28, 28, 7, 7, 28, 7, 7, 28, 28,
|
||||
/* 1x */ 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
|
||||
/* 2x */ 7, 15, 8, 5, 4, 22, 24, 8, 17, 18, 21, 20, 23, 11, 26, 16,
|
||||
/* 3x */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 19, 12, 14, 13, 6,
|
||||
/* 4x */ 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
/* 5x */ 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 9, 27, 27, 27, 1,
|
||||
/* 5x */ 1, 1, 1, 1, 1, 1, 1, 1, 0, 2, 2, 9, 28, 28, 28, 2,
|
||||
/* 6x */ 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
/* 7x */ 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 27, 10, 27, 25, 27,
|
||||
/* 7x */ 1, 1, 1, 1, 1, 1, 1, 1, 0, 2, 2, 28, 10, 28, 25, 28,
|
||||
/* 8x */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
/* 9x */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
/* Ax */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
@@ -78,22 +79,22 @@ static const unsigned char aiClass[] = {
|
||||
#endif
|
||||
#ifdef SQLITE_EBCDIC
|
||||
/* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xa xb xc xd xe xf */
|
||||
/* 0x */ 27, 27, 27, 27, 27, 7, 27, 27, 27, 27, 27, 27, 7, 7, 27, 27,
|
||||
/* 1x */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
|
||||
/* 2x */ 27, 27, 27, 27, 27, 7, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
|
||||
/* 3x */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
|
||||
/* 4x */ 7, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 26, 12, 17, 20, 10,
|
||||
/* 5x */ 24, 27, 27, 27, 27, 27, 27, 27, 27, 27, 15, 4, 21, 18, 19, 27,
|
||||
/* 6x */ 11, 16, 27, 27, 27, 27, 27, 27, 27, 27, 27, 23, 22, 1, 13, 6,
|
||||
/* 7x */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 8, 5, 5, 5, 8, 14, 8,
|
||||
/* 8x */ 27, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 27, 27, 27, 27, 27,
|
||||
/* 9x */ 27, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 27, 27, 27, 27, 27,
|
||||
/* Ax */ 27, 25, 1, 1, 1, 1, 1, 0, 1, 1, 27, 27, 27, 27, 27, 27,
|
||||
/* Bx */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 9, 27, 27, 27, 27, 27,
|
||||
/* Cx */ 27, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 27, 27, 27, 27, 27,
|
||||
/* Dx */ 27, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 27, 27, 27, 27, 27,
|
||||
/* Ex */ 27, 27, 1, 1, 1, 1, 1, 0, 1, 1, 27, 27, 27, 27, 27, 27,
|
||||
/* Fx */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 27, 27, 27, 27, 27, 27,
|
||||
/* 0x */ 29, 28, 28, 28, 28, 7, 28, 28, 28, 28, 28, 28, 7, 7, 28, 28,
|
||||
/* 1x */ 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
|
||||
/* 2x */ 28, 28, 28, 28, 28, 7, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
|
||||
/* 3x */ 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
|
||||
/* 4x */ 7, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 26, 12, 17, 20, 10,
|
||||
/* 5x */ 24, 28, 28, 28, 28, 28, 28, 28, 28, 28, 15, 4, 21, 18, 19, 28,
|
||||
/* 6x */ 11, 16, 28, 28, 28, 28, 28, 28, 28, 28, 28, 23, 22, 2, 13, 6,
|
||||
/* 7x */ 28, 28, 28, 28, 28, 28, 28, 28, 28, 8, 5, 5, 5, 8, 14, 8,
|
||||
/* 8x */ 28, 1, 1, 1, 1, 1, 1, 1, 1, 1, 28, 28, 28, 28, 28, 28,
|
||||
/* 9x */ 28, 1, 1, 1, 1, 1, 1, 1, 1, 1, 28, 28, 28, 28, 28, 28,
|
||||
/* Ax */ 28, 25, 1, 1, 1, 1, 1, 0, 2, 2, 28, 28, 28, 28, 28, 28,
|
||||
/* Bx */ 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 9, 28, 28, 28, 28, 28,
|
||||
/* Cx */ 28, 1, 1, 1, 1, 1, 1, 1, 1, 1, 28, 28, 28, 28, 28, 28,
|
||||
/* Dx */ 28, 1, 1, 1, 1, 1, 1, 1, 1, 1, 28, 28, 28, 28, 28, 28,
|
||||
/* Ex */ 28, 28, 1, 1, 1, 1, 1, 0, 2, 2, 28, 28, 28, 28, 28, 28,
|
||||
/* Fx */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 28, 28, 28, 28, 28, 28,
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -499,7 +500,7 @@ int sqlite3GetToken(const unsigned char *z, int *tokenType){
|
||||
if( n==0 ) *tokenType = TK_ILLEGAL;
|
||||
return i;
|
||||
}
|
||||
case CC_KYWD: {
|
||||
case CC_KYWD0: {
|
||||
for(i=1; aiClass[z[i]]<=CC_KYWD; i++){}
|
||||
if( IdChar(z[i]) ){
|
||||
/* This token started out using characters that can appear in keywords,
|
||||
@@ -529,6 +530,7 @@ int sqlite3GetToken(const unsigned char *z, int *tokenType){
|
||||
** SQL keywords start with the letter 'x'. Fall through */
|
||||
/* no break */ deliberate_fall_through
|
||||
}
|
||||
case CC_KYWD:
|
||||
case CC_ID: {
|
||||
i = 1;
|
||||
break;
|
||||
@@ -711,19 +713,7 @@ int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
|
||||
if( !IN_RENAME_OBJECT ){
|
||||
sqlite3DeleteTrigger(db, pParse->pNewTrigger);
|
||||
}
|
||||
|
||||
if( pParse->pWithToFree ) sqlite3WithDelete(db, pParse->pWithToFree);
|
||||
sqlite3DbFree(db, pParse->pVList);
|
||||
while( pParse->pAinc ){
|
||||
AutoincInfo *p = pParse->pAinc;
|
||||
pParse->pAinc = p->pNext;
|
||||
sqlite3DbFreeNN(db, p);
|
||||
}
|
||||
while( pParse->pZombieTab ){
|
||||
Table *p = pParse->pZombieTab;
|
||||
pParse->pZombieTab = p->pNextZombie;
|
||||
sqlite3DeleteTable(db, p);
|
||||
}
|
||||
db->pParse = pParse->pParentParse;
|
||||
pParse->pParentParse = 0;
|
||||
assert( nErr==0 || pParse->rc!=SQLITE_OK );
|
||||
|
||||
@@ -1000,7 +1000,6 @@ static TriggerPrg *codeRowTrigger(
|
||||
sqlite3VdbeDelete(v);
|
||||
}
|
||||
|
||||
assert( !pSubParse->pAinc && !pSubParse->pZombieTab );
|
||||
assert( !pSubParse->pTriggerPrg && !pSubParse->nMaxArg );
|
||||
sqlite3ParserReset(pSubParse);
|
||||
sqlite3StackFree(db, pSubParse);
|
||||
|
||||
+150
-94
@@ -18,15 +18,22 @@
|
||||
/*
|
||||
** Free a list of Upsert objects
|
||||
*/
|
||||
void sqlite3UpsertDelete(sqlite3 *db, Upsert *p){
|
||||
if( p ){
|
||||
static void SQLITE_NOINLINE upsertDelete(sqlite3 *db, Upsert *p){
|
||||
do{
|
||||
Upsert *pNext = p->pNextUpsert;
|
||||
sqlite3ExprListDelete(db, p->pUpsertTarget);
|
||||
sqlite3ExprDelete(db, p->pUpsertTargetWhere);
|
||||
sqlite3ExprListDelete(db, p->pUpsertSet);
|
||||
sqlite3ExprDelete(db, p->pUpsertWhere);
|
||||
sqlite3DbFree(db, p->pToFree);
|
||||
sqlite3DbFree(db, p);
|
||||
}
|
||||
p = pNext;
|
||||
}while( p );
|
||||
}
|
||||
void sqlite3UpsertDelete(sqlite3 *db, Upsert *p){
|
||||
if( p ) upsertDelete(db, p);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Duplicate an Upsert object.
|
||||
@@ -37,7 +44,8 @@ Upsert *sqlite3UpsertDup(sqlite3 *db, Upsert *p){
|
||||
sqlite3ExprListDup(db, p->pUpsertTarget, 0),
|
||||
sqlite3ExprDup(db, p->pUpsertTargetWhere, 0),
|
||||
sqlite3ExprListDup(db, p->pUpsertSet, 0),
|
||||
sqlite3ExprDup(db, p->pUpsertWhere, 0)
|
||||
sqlite3ExprDup(db, p->pUpsertWhere, 0),
|
||||
sqlite3UpsertDup(db, p->pNextUpsert)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -49,22 +57,25 @@ Upsert *sqlite3UpsertNew(
|
||||
ExprList *pTarget, /* Target argument to ON CONFLICT, or NULL */
|
||||
Expr *pTargetWhere, /* Optional WHERE clause on the target */
|
||||
ExprList *pSet, /* UPDATE columns, or NULL for a DO NOTHING */
|
||||
Expr *pWhere /* WHERE clause for the ON CONFLICT UPDATE */
|
||||
Expr *pWhere, /* WHERE clause for the ON CONFLICT UPDATE */
|
||||
Upsert *pNext /* Next ON CONFLICT clause in the list */
|
||||
){
|
||||
Upsert *pNew;
|
||||
pNew = sqlite3DbMallocRaw(db, sizeof(Upsert));
|
||||
pNew = sqlite3DbMallocZero(db, sizeof(Upsert));
|
||||
if( pNew==0 ){
|
||||
sqlite3ExprListDelete(db, pTarget);
|
||||
sqlite3ExprDelete(db, pTargetWhere);
|
||||
sqlite3ExprListDelete(db, pSet);
|
||||
sqlite3ExprDelete(db, pWhere);
|
||||
sqlite3UpsertDelete(db, pNext);
|
||||
return 0;
|
||||
}else{
|
||||
pNew->pUpsertTarget = pTarget;
|
||||
pNew->pUpsertTargetWhere = pTargetWhere;
|
||||
pNew->pUpsertSet = pSet;
|
||||
pNew->pUpsertWhere = pWhere;
|
||||
pNew->pUpsertIdx = 0;
|
||||
pNew->isDoUpdate = pSet!=0;
|
||||
pNew->pNextUpsert = pNext;
|
||||
}
|
||||
return pNew;
|
||||
}
|
||||
@@ -89,6 +100,7 @@ int sqlite3UpsertAnalyzeTarget(
|
||||
Expr *pTerm; /* One term of the conflict-target clause */
|
||||
NameContext sNC; /* Context for resolving symbolic names */
|
||||
Expr sCol[2]; /* Index column converted into an Expr */
|
||||
int nClause = 0; /* Counter of ON CONFLICT clauses */
|
||||
|
||||
assert( pTabList->nSrc==1 );
|
||||
assert( pTabList->a[0].pTab!=0 );
|
||||
@@ -102,87 +114,131 @@ int sqlite3UpsertAnalyzeTarget(
|
||||
memset(&sNC, 0, sizeof(sNC));
|
||||
sNC.pParse = pParse;
|
||||
sNC.pSrcList = pTabList;
|
||||
rc = sqlite3ResolveExprListNames(&sNC, pUpsert->pUpsertTarget);
|
||||
if( rc ) return rc;
|
||||
rc = sqlite3ResolveExprNames(&sNC, pUpsert->pUpsertTargetWhere);
|
||||
if( rc ) return rc;
|
||||
|
||||
/* Check to see if the conflict target matches the rowid. */
|
||||
pTab = pTabList->a[0].pTab;
|
||||
pTarget = pUpsert->pUpsertTarget;
|
||||
iCursor = pTabList->a[0].iCursor;
|
||||
if( HasRowid(pTab)
|
||||
&& pTarget->nExpr==1
|
||||
&& (pTerm = pTarget->a[0].pExpr)->op==TK_COLUMN
|
||||
&& pTerm->iColumn==XN_ROWID
|
||||
){
|
||||
/* The conflict-target is the rowid of the primary table */
|
||||
assert( pUpsert->pUpsertIdx==0 );
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/* Initialize sCol[0..1] to be an expression parse tree for a
|
||||
** single column of an index. The sCol[0] node will be the TK_COLLATE
|
||||
** operator and sCol[1] will be the TK_COLUMN operator. Code below
|
||||
** will populate the specific collation and column number values
|
||||
** prior to comparing against the conflict-target expression.
|
||||
*/
|
||||
memset(sCol, 0, sizeof(sCol));
|
||||
sCol[0].op = TK_COLLATE;
|
||||
sCol[0].pLeft = &sCol[1];
|
||||
sCol[1].op = TK_COLUMN;
|
||||
sCol[1].iTable = pTabList->a[0].iCursor;
|
||||
|
||||
/* Check for matches against other indexes */
|
||||
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
||||
int ii, jj, nn;
|
||||
if( !IsUniqueIndex(pIdx) ) continue;
|
||||
if( pTarget->nExpr!=pIdx->nKeyCol ) continue;
|
||||
if( pIdx->pPartIdxWhere ){
|
||||
if( pUpsert->pUpsertTargetWhere==0 ) continue;
|
||||
if( sqlite3ExprCompare(pParse, pUpsert->pUpsertTargetWhere,
|
||||
pIdx->pPartIdxWhere, iCursor)!=0 ){
|
||||
continue;
|
||||
}
|
||||
}
|
||||
nn = pIdx->nKeyCol;
|
||||
for(ii=0; ii<nn; ii++){
|
||||
Expr *pExpr;
|
||||
sCol[0].u.zToken = (char*)pIdx->azColl[ii];
|
||||
if( pIdx->aiColumn[ii]==XN_EXPR ){
|
||||
assert( pIdx->aColExpr!=0 );
|
||||
assert( pIdx->aColExpr->nExpr>ii );
|
||||
pExpr = pIdx->aColExpr->a[ii].pExpr;
|
||||
if( pExpr->op!=TK_COLLATE ){
|
||||
sCol[0].pLeft = pExpr;
|
||||
pExpr = &sCol[0];
|
||||
}
|
||||
}else{
|
||||
sCol[0].pLeft = &sCol[1];
|
||||
sCol[1].iColumn = pIdx->aiColumn[ii];
|
||||
pExpr = &sCol[0];
|
||||
}
|
||||
for(jj=0; jj<nn; jj++){
|
||||
if( sqlite3ExprCompare(pParse, pTarget->a[jj].pExpr, pExpr,iCursor)<2 ){
|
||||
break; /* Column ii of the index matches column jj of target */
|
||||
}
|
||||
}
|
||||
if( jj>=nn ){
|
||||
/* The target contains no match for column jj of the index */
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( ii<nn ){
|
||||
/* Column ii of the index did not match any term of the conflict target.
|
||||
** Continue the search with the next index. */
|
||||
for(; pUpsert && pUpsert->pUpsertTarget;
|
||||
pUpsert=pUpsert->pNextUpsert, nClause++){
|
||||
rc = sqlite3ResolveExprListNames(&sNC, pUpsert->pUpsertTarget);
|
||||
if( rc ) return rc;
|
||||
rc = sqlite3ResolveExprNames(&sNC, pUpsert->pUpsertTargetWhere);
|
||||
if( rc ) return rc;
|
||||
|
||||
/* Check to see if the conflict target matches the rowid. */
|
||||
pTab = pTabList->a[0].pTab;
|
||||
pTarget = pUpsert->pUpsertTarget;
|
||||
iCursor = pTabList->a[0].iCursor;
|
||||
if( HasRowid(pTab)
|
||||
&& pTarget->nExpr==1
|
||||
&& (pTerm = pTarget->a[0].pExpr)->op==TK_COLUMN
|
||||
&& pTerm->iColumn==XN_ROWID
|
||||
){
|
||||
/* The conflict-target is the rowid of the primary table */
|
||||
assert( pUpsert->pUpsertIdx==0 );
|
||||
continue;
|
||||
}
|
||||
pUpsert->pUpsertIdx = pIdx;
|
||||
return SQLITE_OK;
|
||||
|
||||
/* Initialize sCol[0..1] to be an expression parse tree for a
|
||||
** single column of an index. The sCol[0] node will be the TK_COLLATE
|
||||
** operator and sCol[1] will be the TK_COLUMN operator. Code below
|
||||
** will populate the specific collation and column number values
|
||||
** prior to comparing against the conflict-target expression.
|
||||
*/
|
||||
memset(sCol, 0, sizeof(sCol));
|
||||
sCol[0].op = TK_COLLATE;
|
||||
sCol[0].pLeft = &sCol[1];
|
||||
sCol[1].op = TK_COLUMN;
|
||||
sCol[1].iTable = pTabList->a[0].iCursor;
|
||||
|
||||
/* Check for matches against other indexes */
|
||||
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
||||
int ii, jj, nn;
|
||||
if( !IsUniqueIndex(pIdx) ) continue;
|
||||
if( pTarget->nExpr!=pIdx->nKeyCol ) continue;
|
||||
if( pIdx->pPartIdxWhere ){
|
||||
if( pUpsert->pUpsertTargetWhere==0 ) continue;
|
||||
if( sqlite3ExprCompare(pParse, pUpsert->pUpsertTargetWhere,
|
||||
pIdx->pPartIdxWhere, iCursor)!=0 ){
|
||||
continue;
|
||||
}
|
||||
}
|
||||
nn = pIdx->nKeyCol;
|
||||
for(ii=0; ii<nn; ii++){
|
||||
Expr *pExpr;
|
||||
sCol[0].u.zToken = (char*)pIdx->azColl[ii];
|
||||
if( pIdx->aiColumn[ii]==XN_EXPR ){
|
||||
assert( pIdx->aColExpr!=0 );
|
||||
assert( pIdx->aColExpr->nExpr>ii );
|
||||
pExpr = pIdx->aColExpr->a[ii].pExpr;
|
||||
if( pExpr->op!=TK_COLLATE ){
|
||||
sCol[0].pLeft = pExpr;
|
||||
pExpr = &sCol[0];
|
||||
}
|
||||
}else{
|
||||
sCol[0].pLeft = &sCol[1];
|
||||
sCol[1].iColumn = pIdx->aiColumn[ii];
|
||||
pExpr = &sCol[0];
|
||||
}
|
||||
for(jj=0; jj<nn; jj++){
|
||||
if( sqlite3ExprCompare(pParse,pTarget->a[jj].pExpr,pExpr,iCursor)<2 ){
|
||||
break; /* Column ii of the index matches column jj of target */
|
||||
}
|
||||
}
|
||||
if( jj>=nn ){
|
||||
/* The target contains no match for column jj of the index */
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( ii<nn ){
|
||||
/* Column ii of the index did not match any term of the conflict target.
|
||||
** Continue the search with the next index. */
|
||||
continue;
|
||||
}
|
||||
pUpsert->pUpsertIdx = pIdx;
|
||||
break;
|
||||
}
|
||||
if( pUpsert->pUpsertIdx==0 ){
|
||||
char zWhich[16];
|
||||
if( nClause==0 && pUpsert->pNextUpsert==0 ){
|
||||
zWhich[0] = 0;
|
||||
}else{
|
||||
sqlite3_snprintf(sizeof(zWhich),zWhich,"%r ", nClause+1);
|
||||
}
|
||||
sqlite3ErrorMsg(pParse, "%sON CONFLICT clause does not match any "
|
||||
"PRIMARY KEY or UNIQUE constraint", zWhich);
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
}
|
||||
sqlite3ErrorMsg(pParse, "ON CONFLICT clause does not match any "
|
||||
"PRIMARY KEY or UNIQUE constraint");
|
||||
return SQLITE_ERROR;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return true if pUpsert is the last ON CONFLICT clause with a
|
||||
** conflict target, or if pUpsert is followed by another ON CONFLICT
|
||||
** clause that targets the INTEGER PRIMARY KEY.
|
||||
*/
|
||||
int sqlite3UpsertNextIsIPK(Upsert *pUpsert){
|
||||
Upsert *pNext;
|
||||
if( NEVER(pUpsert==0) ) return 0;
|
||||
pNext = pUpsert->pNextUpsert;
|
||||
if( pNext==0 ) return 1;
|
||||
if( pNext->pUpsertTarget==0 ) return 1;
|
||||
if( pNext->pUpsertIdx==0 ) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Given the list of ON CONFLICT clauses described by pUpsert, and
|
||||
** a particular index pIdx, return a pointer to the particular ON CONFLICT
|
||||
** clause that applies to the index. Or, if the index is not subject to
|
||||
** any ON CONFLICT clause, return NULL.
|
||||
*/
|
||||
Upsert *sqlite3UpsertOfIndex(Upsert *pUpsert, Index *pIdx){
|
||||
while(
|
||||
pUpsert
|
||||
&& pUpsert->pUpsertTarget!=0
|
||||
&& pUpsert->pUpsertIdx!=pIdx
|
||||
){
|
||||
pUpsert = pUpsert->pNextUpsert;
|
||||
}
|
||||
return pUpsert;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -206,11 +262,13 @@ void sqlite3UpsertDoUpdate(
|
||||
SrcList *pSrc; /* FROM clause for the UPDATE */
|
||||
int iDataCur;
|
||||
int i;
|
||||
Upsert *pTop = pUpsert;
|
||||
|
||||
assert( v!=0 );
|
||||
assert( pUpsert!=0 );
|
||||
VdbeNoopComment((v, "Begin DO UPDATE of UPSERT"));
|
||||
iDataCur = pUpsert->iDataCur;
|
||||
pUpsert = sqlite3UpsertOfIndex(pTop, pIdx);
|
||||
VdbeNoopComment((v, "Begin DO UPDATE of UPSERT"));
|
||||
if( pIdx && iCur!=iDataCur ){
|
||||
if( HasRowid(pTab) ){
|
||||
int regRowid = sqlite3GetTempReg(pParse);
|
||||
@@ -240,19 +298,17 @@ void sqlite3UpsertDoUpdate(
|
||||
sqlite3VdbeJumpHere(v, i);
|
||||
}
|
||||
}
|
||||
/* pUpsert does not own pUpsertSrc - the outer INSERT statement does. So
|
||||
** we have to make a copy before passing it down into sqlite3Update() */
|
||||
pSrc = sqlite3SrcListDup(db, pUpsert->pUpsertSrc, 0);
|
||||
/* pUpsert does not own pTop->pUpsertSrc - the outer INSERT statement does.
|
||||
** So we have to make a copy before passing it down into sqlite3Update() */
|
||||
pSrc = sqlite3SrcListDup(db, pTop->pUpsertSrc, 0);
|
||||
/* excluded.* columns of type REAL need to be converted to a hard real */
|
||||
for(i=0; i<pTab->nCol; i++){
|
||||
if( pTab->aCol[i].affinity==SQLITE_AFF_REAL ){
|
||||
sqlite3VdbeAddOp1(v, OP_RealAffinity, pUpsert->regData+i);
|
||||
sqlite3VdbeAddOp1(v, OP_RealAffinity, pTop->regData+i);
|
||||
}
|
||||
}
|
||||
sqlite3Update(pParse, pSrc, pUpsert->pUpsertSet,
|
||||
pUpsert->pUpsertWhere, OE_Abort, 0, 0, pUpsert);
|
||||
pUpsert->pUpsertSet = 0; /* Will have been deleted by sqlite3Update() */
|
||||
pUpsert->pUpsertWhere = 0; /* Will have been deleted by sqlite3Update() */
|
||||
sqlite3Update(pParse, pSrc, sqlite3ExprListDup(db,pUpsert->pUpsertSet,0),
|
||||
sqlite3ExprDup(db,pUpsert->pUpsertWhere,0), OE_Abort, 0, 0, pUpsert);
|
||||
VdbeNoopComment((v, "End DO UPDATE of UPSERT"));
|
||||
}
|
||||
|
||||
|
||||
+10
@@ -114,6 +114,16 @@ void sqlite3Error(sqlite3 *db, int err_code){
|
||||
if( err_code || db->pErr ) sqlite3ErrorFinish(db, err_code);
|
||||
}
|
||||
|
||||
/*
|
||||
** The equivalent of sqlite3Error(db, SQLITE_OK). Clear the error state
|
||||
** and error message.
|
||||
*/
|
||||
void sqlite3ErrorClear(sqlite3 *db){
|
||||
assert( db!=0 );
|
||||
db->errCode = SQLITE_OK;
|
||||
if( db->pErr ) sqlite3ValueSetNull(db->pErr);
|
||||
}
|
||||
|
||||
/*
|
||||
** Load the sqlite3.iSysErrno field if that is an appropriate thing
|
||||
** to do based on the SQLite error code in rc.
|
||||
|
||||
+33
-3
@@ -4909,8 +4909,10 @@ case OP_NewRowid: { /* out2 */
|
||||
VdbeCursor *pC; /* Cursor of table to get the new rowid */
|
||||
int res; /* Result of an sqlite3BtreeLast() */
|
||||
int cnt; /* Counter to limit the number of searches */
|
||||
#ifndef SQLITE_OMIT_AUTOINCREMENT
|
||||
Mem *pMem; /* Register holding largest rowid for AUTOINCREMENT */
|
||||
VdbeFrame *pFrame; /* Root frame of VDBE */
|
||||
#endif
|
||||
|
||||
v = 0;
|
||||
res = 0;
|
||||
@@ -5126,7 +5128,8 @@ case OP_Insert: {
|
||||
}
|
||||
x.pKey = 0;
|
||||
rc = sqlite3BtreeInsert(pC->uc.pCursor, &x,
|
||||
(pOp->p5 & (OPFLAG_APPEND|OPFLAG_SAVEPOSITION)), seekResult
|
||||
(pOp->p5 & (OPFLAG_APPEND|OPFLAG_SAVEPOSITION|OPFLAG_PREFORMAT)),
|
||||
seekResult
|
||||
);
|
||||
pC->deferredMoveto = 0;
|
||||
pC->cacheStatus = CACHE_STALE;
|
||||
@@ -5143,6 +5146,33 @@ case OP_Insert: {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: RowCell P1 P2 P3 * *
|
||||
**
|
||||
** P1 and P2 are both open cursors. Both must be opened on the same type
|
||||
** of table - intkey or index. This opcode is used as part of copying
|
||||
** the current row from P2 into P1. If the cursors are opened on intkey
|
||||
** tables, register P3 contains the rowid to use with the new record in
|
||||
** P1. If they are opened on index tables, P3 is not used.
|
||||
**
|
||||
** This opcode must be followed by either an Insert or InsertIdx opcode
|
||||
** with the OPFLAG_PREFORMAT flag set to complete the insert operation.
|
||||
*/
|
||||
case OP_RowCell: {
|
||||
VdbeCursor *pDest; /* Cursor to write to */
|
||||
VdbeCursor *pSrc; /* Cursor to read from */
|
||||
i64 iKey; /* Rowid value to insert with */
|
||||
assert( pOp[1].opcode==OP_Insert || pOp[1].opcode==OP_IdxInsert );
|
||||
assert( pOp[1].opcode==OP_Insert || pOp->p3==0 );
|
||||
assert( pOp[1].opcode==OP_IdxInsert || pOp->p3>0 );
|
||||
assert( pOp[1].p5 & OPFLAG_PREFORMAT );
|
||||
pDest = p->apCsr[pOp->p1];
|
||||
pSrc = p->apCsr[pOp->p2];
|
||||
iKey = pOp->p3 ? aMem[pOp->p3].u.i : 0;
|
||||
rc = sqlite3BtreeTransferRow(pDest->uc.pCursor, pSrc->uc.pCursor, iKey);
|
||||
if( rc!=SQLITE_OK ) goto abort_due_to_error;
|
||||
break;
|
||||
};
|
||||
|
||||
/* Opcode: Delete P1 P2 P3 P4 P5
|
||||
**
|
||||
** Delete the record at which the P1 cursor is currently pointing.
|
||||
@@ -5798,7 +5828,7 @@ case OP_IdxInsert: { /* in2 */
|
||||
assert( pC!=0 );
|
||||
assert( !isSorter(pC) );
|
||||
pIn2 = &aMem[pOp->p2];
|
||||
assert( pIn2->flags & MEM_Blob );
|
||||
assert( (pIn2->flags & MEM_Blob) || (pOp->p5 & OPFLAG_PREFORMAT) );
|
||||
if( pOp->p5 & OPFLAG_NCHANGE ) p->nChange++;
|
||||
assert( pC->eCurType==CURTYPE_BTREE );
|
||||
assert( pC->isTable==0 );
|
||||
@@ -5809,7 +5839,7 @@ case OP_IdxInsert: { /* in2 */
|
||||
x.aMem = aMem + pOp->p3;
|
||||
x.nMem = (u16)pOp->p4.i;
|
||||
rc = sqlite3BtreeInsert(pC->uc.pCursor, &x,
|
||||
(pOp->p5 & (OPFLAG_APPEND|OPFLAG_SAVEPOSITION)),
|
||||
(pOp->p5 & (OPFLAG_APPEND|OPFLAG_SAVEPOSITION|OPFLAG_PREFORMAT)),
|
||||
((pOp->p5 & OPFLAG_USESEEKRESULT) ? pC->seekResult : 0)
|
||||
);
|
||||
assert( pC->deferredMoveto==0 );
|
||||
|
||||
+2
-2
@@ -2358,6 +2358,8 @@ void sqlite3VdbeMakeReady(
|
||||
assert( pParse!=0 );
|
||||
assert( p->magic==VDBE_MAGIC_INIT );
|
||||
assert( pParse==p->pParse );
|
||||
p->pVList = pParse->pVList;
|
||||
pParse->pVList = 0;
|
||||
db = p->db;
|
||||
assert( db->mallocFailed==0 );
|
||||
nVar = pParse->nVar;
|
||||
@@ -2442,8 +2444,6 @@ void sqlite3VdbeMakeReady(
|
||||
}
|
||||
}
|
||||
|
||||
p->pVList = pParse->pVList;
|
||||
pParse->pVList = 0;
|
||||
if( db->mallocFailed ){
|
||||
p->nVar = 0;
|
||||
p->nCursor = 0;
|
||||
|
||||
+1
-1
@@ -125,7 +125,7 @@ char *sqlite3VdbeExpandSql(
|
||||
assert( idx>0 );
|
||||
}
|
||||
zRawSql += nToken;
|
||||
nextIndex = idx + 1;
|
||||
nextIndex = MAX(idx + 1, nextIndex);
|
||||
assert( idx>0 && idx<=p->nVar );
|
||||
pVar = &p->aVar[idx-1];
|
||||
if( pVar->flags & MEM_Null ){
|
||||
|
||||
+4
-3
@@ -22,7 +22,7 @@
|
||||
** Walk all expressions linked into the list of Window objects passed
|
||||
** as the second argument.
|
||||
*/
|
||||
static int walkWindowList(Walker *pWalker, Window *pList){
|
||||
static int walkWindowList(Walker *pWalker, Window *pList, int bOneOnly){
|
||||
Window *pWin;
|
||||
for(pWin=pList; pWin; pWin=pWin->pNextWin){
|
||||
int rc;
|
||||
@@ -41,6 +41,7 @@ static int walkWindowList(Walker *pWalker, Window *pList){
|
||||
if( NEVER(rc) ) return WRC_Abort;
|
||||
rc = sqlite3WalkExpr(pWalker, pWin->pEnd);
|
||||
if( NEVER(rc) ) return WRC_Abort;
|
||||
if( bOneOnly ) break;
|
||||
}
|
||||
return WRC_Continue;
|
||||
}
|
||||
@@ -88,7 +89,7 @@ static SQLITE_NOINLINE int walkExpr(Walker *pWalker, Expr *pExpr){
|
||||
}
|
||||
#ifndef SQLITE_OMIT_WINDOWFUNC
|
||||
if( ExprHasProperty(pExpr, EP_WinFunc) ){
|
||||
if( walkWindowList(pWalker, pExpr->y.pWin) ) return WRC_Abort;
|
||||
if( walkWindowList(pWalker, pExpr->y.pWin, 1) ) return WRC_Abort;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -135,7 +136,7 @@ int sqlite3WalkSelectExpr(Walker *pWalker, Select *p){
|
||||
if( pParse && IN_RENAME_OBJECT ){
|
||||
/* The following may return WRC_Abort if there are unresolvable
|
||||
** symbols (e.g. a table that does not exist) in a window definition. */
|
||||
int rc = walkWindowList(pWalker, p->pWinDefn);
|
||||
int rc = walkWindowList(pWalker, p->pWinDefn, 0);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
+27
-1
@@ -99,6 +99,32 @@ int sqlite3WhereOrderByLimitOptLabel(WhereInfo *pWInfo){
|
||||
return pInner->addrNxt;
|
||||
}
|
||||
|
||||
/*
|
||||
** While generating code for the min/max optimization, after handling
|
||||
** the aggregate-step call to min() or max(), check to see if any
|
||||
** additional looping is required. If the output order is such that
|
||||
** we are certain that the correct answer has already been found, then
|
||||
** code an OP_Goto to by pass subsequent processing.
|
||||
**
|
||||
** Any extra OP_Goto that is coded here is an optimization. The
|
||||
** correct answer should be obtained regardless. This OP_Goto just
|
||||
** makes the answer appear faster.
|
||||
*/
|
||||
void sqlite3WhereMinMaxOptEarlyOut(Vdbe *v, WhereInfo *pWInfo){
|
||||
WhereLevel *pInner;
|
||||
int i;
|
||||
if( !pWInfo->bOrderedInnerLoop ) return;
|
||||
if( pWInfo->nOBSat==0 ) return;
|
||||
for(i=pWInfo->nLevel-1; i>=0; i--){
|
||||
pInner = &pWInfo->a[i];
|
||||
if( (pInner->pWLoop->wsFlags & WHERE_COLUMN_IN)!=0 ){
|
||||
sqlite3VdbeGoto(v, pInner->addrNxt);
|
||||
return;
|
||||
}
|
||||
}
|
||||
sqlite3VdbeGoto(v, pWInfo->iBreak);
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the VDBE address or label to jump to in order to continue
|
||||
** immediately with the next row of a WHERE clause.
|
||||
@@ -2605,7 +2631,7 @@ static int whereLoopAddBtreeIndex(
|
||||
pBtm = pTerm;
|
||||
pTop = 0;
|
||||
if( pTerm->wtFlags & TERM_LIKEOPT ){
|
||||
/* Range contraints that come from the LIKE optimization are
|
||||
/* Range constraints that come from the LIKE optimization are
|
||||
** always used in pairs. */
|
||||
pTop = &pTerm[1];
|
||||
assert( (pTop-(pTerm->pWC->a))<pTerm->pWC->nTerm );
|
||||
|
||||
+275
@@ -1007,6 +1007,271 @@ static int exprMightBeIndexed(
|
||||
return exprMightBeIndexed2(pFrom,mPrereq,aiCurCol,pExpr);
|
||||
}
|
||||
|
||||
/*
|
||||
** Expression callback for exprUsesSrclist().
|
||||
*/
|
||||
static int exprUsesSrclistCb(Walker *p, Expr *pExpr){
|
||||
if( pExpr->op==TK_COLUMN ){
|
||||
SrcList *pSrc = p->u.pSrcList;
|
||||
int iCsr = pExpr->iTable;
|
||||
int ii;
|
||||
for(ii=0; ii<pSrc->nSrc; ii++){
|
||||
if( pSrc->a[ii].iCursor==iCsr ){
|
||||
return p->eCode ? WRC_Abort : WRC_Continue;
|
||||
}
|
||||
}
|
||||
return p->eCode ? WRC_Continue : WRC_Abort;
|
||||
}
|
||||
return WRC_Continue;
|
||||
}
|
||||
|
||||
/*
|
||||
** Select callback for exprUsesSrclist().
|
||||
*/
|
||||
static int exprUsesSrclistSelectCb(Walker *p, Select *pSelect){
|
||||
return WRC_Abort;
|
||||
}
|
||||
|
||||
/*
|
||||
** This function always returns true if expression pExpr contains
|
||||
** a sub-select.
|
||||
**
|
||||
** If there is no sub-select in pExpr, then return true if pExpr
|
||||
** contains a TK_COLUMN node for a table that is (bUses==1)
|
||||
** or is not (bUses==0) in pSrc.
|
||||
**
|
||||
** Said another way:
|
||||
**
|
||||
** bUses Return Meaning
|
||||
** -------- ------ ------------------------------------------------
|
||||
**
|
||||
** bUses==1 true pExpr contains either a sub-select or a
|
||||
** TK_COLUMN referencing pSrc.
|
||||
**
|
||||
** bUses==1 false pExpr contains no sub-selects and all TK_COLUMN
|
||||
** nodes reference tables not found in pSrc
|
||||
**
|
||||
** bUses==0 true pExpr contains either a sub-select or a TK_COLUMN
|
||||
** that references a table not in pSrc.
|
||||
**
|
||||
** bUses==0 false pExpr contains no sub-selects and all TK_COLUMN
|
||||
** nodes reference pSrc
|
||||
*/
|
||||
static int exprUsesSrclist(SrcList *pSrc, Expr *pExpr, int bUses){
|
||||
Walker sWalker;
|
||||
memset(&sWalker, 0, sizeof(Walker));
|
||||
sWalker.eCode = bUses;
|
||||
sWalker.u.pSrcList = pSrc;
|
||||
sWalker.xExprCallback = exprUsesSrclistCb;
|
||||
sWalker.xSelectCallback = exprUsesSrclistSelectCb;
|
||||
return (sqlite3WalkExpr(&sWalker, pExpr)==WRC_Abort);
|
||||
}
|
||||
|
||||
/*
|
||||
** Context object used by exprExistsToInIter() as it iterates through an
|
||||
** expression tree.
|
||||
*/
|
||||
struct ExistsToInCtx {
|
||||
SrcList *pSrc; /* The tables in an EXISTS(SELECT ... FROM <here> ...) */
|
||||
Expr *pInLhs; /* OUT: Use this as the LHS of the IN operator */
|
||||
Expr *pEq; /* OUT: The == term that include pInLhs */
|
||||
Expr **ppAnd; /* OUT: The AND operator that includes pEq as a child */
|
||||
Expr **ppParent; /* The AND operator currently being examined */
|
||||
};
|
||||
|
||||
/*
|
||||
** Iterate through all AND connected nodes in the expression tree
|
||||
** headed by (*ppExpr), populating the structure passed as the first
|
||||
** argument with the values required by exprAnalyzeExistsFindEq().
|
||||
**
|
||||
** This function returns non-zero if the expression tree does not meet
|
||||
** the two conditions described by the header comment for
|
||||
** exprAnalyzeExistsFindEq(), or zero if it does.
|
||||
*/
|
||||
static int exprExistsToInIter(struct ExistsToInCtx *p, Expr **ppExpr){
|
||||
Expr *pExpr = *ppExpr;
|
||||
switch( pExpr->op ){
|
||||
case TK_AND:
|
||||
p->ppParent = ppExpr;
|
||||
if( exprExistsToInIter(p, &pExpr->pLeft) ) return 1;
|
||||
p->ppParent = ppExpr;
|
||||
if( exprExistsToInIter(p, &pExpr->pRight) ) return 1;
|
||||
break;
|
||||
case TK_EQ: {
|
||||
int bLeft = exprUsesSrclist(p->pSrc, pExpr->pLeft, 0);
|
||||
int bRight = exprUsesSrclist(p->pSrc, pExpr->pRight, 0);
|
||||
if( bLeft || bRight ){
|
||||
if( (bLeft && bRight) || p->pInLhs ) return 1;
|
||||
p->pInLhs = bLeft ? pExpr->pLeft : pExpr->pRight;
|
||||
if( exprUsesSrclist(p->pSrc, p->pInLhs, 1) ) return 1;
|
||||
p->pEq = pExpr;
|
||||
p->ppAnd = p->ppParent;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
if( exprUsesSrclist(p->pSrc, pExpr, 0) ){
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** This function is used by exprAnalyzeExists() when creating virtual IN(...)
|
||||
** terms equivalent to user-supplied EXIST(...) clauses. It splits the WHERE
|
||||
** clause of the Select object passed as the first argument into one or more
|
||||
** expressions joined by AND operators, and then tests if the following are
|
||||
** true:
|
||||
**
|
||||
** 1. Exactly one of the AND separated terms refers to the outer
|
||||
** query, and it is an == (TK_EQ) expression.
|
||||
**
|
||||
** 2. Only one side of the == expression refers to the outer query, and
|
||||
** it does not refer to any columns from the inner query.
|
||||
**
|
||||
** If both these conditions are true, then a pointer to the side of the ==
|
||||
** expression that refers to the outer query is returned. The caller will
|
||||
** use this expression as the LHS of the IN(...) virtual term. Or, if one
|
||||
** or both of the above conditions are not true, NULL is returned.
|
||||
**
|
||||
** If non-NULL is returned and ppEq is non-NULL, *ppEq is set to point
|
||||
** to the == expression node before returning. If pppAnd is non-NULL and
|
||||
** the == node is not the root of the WHERE clause, then *pppAnd is set
|
||||
** to point to the pointer to the AND node that is the parent of the ==
|
||||
** node within the WHERE expression tree.
|
||||
*/
|
||||
static Expr *exprAnalyzeExistsFindEq(
|
||||
Select *pSel, /* The SELECT of the EXISTS */
|
||||
Expr **ppEq, /* OUT: == node from WHERE clause */
|
||||
Expr ***pppAnd /* OUT: Pointer to parent of ==, if any */
|
||||
){
|
||||
struct ExistsToInCtx ctx;
|
||||
memset(&ctx, 0, sizeof(ctx));
|
||||
ctx.pSrc = pSel->pSrc;
|
||||
if( exprExistsToInIter(&ctx, &pSel->pWhere) ){
|
||||
return 0;
|
||||
}
|
||||
if( ppEq ) *ppEq = ctx.pEq;
|
||||
if( pppAnd ) *pppAnd = ctx.ppAnd;
|
||||
return ctx.pInLhs;
|
||||
}
|
||||
|
||||
/*
|
||||
** Term idxTerm of the WHERE clause passed as the second argument is an
|
||||
** EXISTS expression with a correlated SELECT statement on the RHS.
|
||||
** This function analyzes the SELECT statement, and if possible adds an
|
||||
** equivalent "? IN(SELECT...)" virtual term to the WHERE clause.
|
||||
**
|
||||
** For an EXISTS term such as the following:
|
||||
**
|
||||
** EXISTS (SELECT ... FROM <srclist> WHERE <e1> = <e2> AND <e3>)
|
||||
**
|
||||
** The virtual IN() term added is:
|
||||
**
|
||||
** <e1> IN (SELECT <e2> FROM <srclist> WHERE <e3>)
|
||||
**
|
||||
** The virtual term is only added if the following conditions are met:
|
||||
**
|
||||
** 1. The sub-select must not be an aggregate or use window functions,
|
||||
**
|
||||
** 2. The sub-select must not be a compound SELECT,
|
||||
**
|
||||
** 3. Expression <e1> must refer to at least one column from the outer
|
||||
** query, and must not refer to any column from the inner query
|
||||
** (i.e. from <srclist>).
|
||||
**
|
||||
** 4. <e2> and <e3> must not refer to any values from the outer query.
|
||||
** In other words, once <e1> has been removed, the inner query
|
||||
** must not be correlated.
|
||||
**
|
||||
*/
|
||||
static void exprAnalyzeExists(
|
||||
SrcList *pSrc, /* the FROM clause */
|
||||
WhereClause *pWC, /* the WHERE clause */
|
||||
int idxTerm /* Index of the term to be analyzed */
|
||||
){
|
||||
Parse *pParse = pWC->pWInfo->pParse;
|
||||
WhereTerm *pTerm = &pWC->a[idxTerm];
|
||||
Expr *pExpr = pTerm->pExpr;
|
||||
Select *pSel = pExpr->x.pSelect;
|
||||
Expr *pDup = 0;
|
||||
Expr *pEq = 0;
|
||||
Expr *pRet = 0;
|
||||
Expr *pInLhs = 0;
|
||||
Expr **ppAnd = 0;
|
||||
int idxNew;
|
||||
sqlite3 *db = pParse->db;
|
||||
|
||||
assert( pExpr->op==TK_EXISTS );
|
||||
assert( (pExpr->flags & EP_VarSelect) && (pExpr->flags & EP_xIsSelect) );
|
||||
|
||||
if( (pSel->selFlags & SF_Aggregate) || pSel->pWin ) return;
|
||||
if( pSel->pPrior ) return;
|
||||
if( pSel->pWhere==0 ) return;
|
||||
if( 0==exprAnalyzeExistsFindEq(pSel, 0, 0) ) return;
|
||||
|
||||
pDup = sqlite3ExprDup(db, pExpr, 0);
|
||||
if( db->mallocFailed ){
|
||||
sqlite3ExprDelete(db, pDup);
|
||||
return;
|
||||
}
|
||||
pSel = pDup->x.pSelect;
|
||||
sqlite3ExprListDelete(db, pSel->pEList);
|
||||
pSel->pEList = 0;
|
||||
|
||||
pInLhs = exprAnalyzeExistsFindEq(pSel, &pEq, &ppAnd);
|
||||
assert( pInLhs && pEq );
|
||||
assert( pEq==pSel->pWhere || ppAnd );
|
||||
if( pInLhs==pEq->pLeft ){
|
||||
pRet = pEq->pRight;
|
||||
}else{
|
||||
CollSeq *p = sqlite3ExprCompareCollSeq(pParse, pEq);
|
||||
pInLhs = sqlite3ExprAddCollateString(pParse, pInLhs, p?p->zName:"BINARY");
|
||||
pRet = pEq->pLeft;
|
||||
}
|
||||
|
||||
assert( pDup->pLeft==0 );
|
||||
pDup->op = TK_IN;
|
||||
pDup->pLeft = pInLhs;
|
||||
pDup->flags &= ~EP_VarSelect;
|
||||
if( pRet->op==TK_VECTOR ){
|
||||
pSel->pEList = pRet->x.pList;
|
||||
pRet->x.pList = 0;
|
||||
sqlite3ExprDelete(db, pRet);
|
||||
}else{
|
||||
pSel->pEList = sqlite3ExprListAppend(pParse, 0, pRet);
|
||||
}
|
||||
pEq->pLeft = 0;
|
||||
pEq->pRight = 0;
|
||||
if( ppAnd ){
|
||||
Expr *pAnd = *ppAnd;
|
||||
Expr *pOther = (pAnd->pLeft==pEq) ? pAnd->pRight : pAnd->pLeft;
|
||||
pAnd->pLeft = pAnd->pRight = 0;
|
||||
sqlite3ExprDelete(db, pAnd);
|
||||
*ppAnd = pOther;
|
||||
}else{
|
||||
assert( pSel->pWhere==pEq );
|
||||
pSel->pWhere = 0;
|
||||
}
|
||||
sqlite3ExprDelete(db, pEq);
|
||||
|
||||
#ifdef WHERETRACE_ENABLED /* 0x20 */
|
||||
if( sqlite3WhereTrace & 0x20 ){
|
||||
sqlite3DebugPrintf("Convert EXISTS:\n");
|
||||
sqlite3TreeViewExpr(0, pExpr, 0);
|
||||
sqlite3DebugPrintf("into IN:\n");
|
||||
sqlite3TreeViewExpr(0, pDup, 0);
|
||||
}
|
||||
#endif
|
||||
idxNew = whereClauseInsert(pWC, pDup, TERM_VIRTUAL|TERM_DYNAMIC);
|
||||
exprAnalyze(pSrc, pWC, idxNew);
|
||||
markTermAsChild(pWC, idxNew, idxTerm);
|
||||
pWC->a[idxTerm].wtFlags |= TERM_COPIED;
|
||||
}
|
||||
|
||||
/*
|
||||
** The input to this routine is an WhereTerm structure with only the
|
||||
** "pExpr" field filled in. The job of this routine is to analyze the
|
||||
@@ -1192,6 +1457,16 @@ static void exprAnalyze(
|
||||
}
|
||||
#endif /* SQLITE_OMIT_OR_OPTIMIZATION */
|
||||
|
||||
else if( pExpr->op==TK_EXISTS ){
|
||||
/* Perhaps treat an EXISTS operator as an IN operator */
|
||||
if( (pExpr->flags & EP_VarSelect)!=0
|
||||
&& OptimizationEnabled(db, SQLITE_ExistsToIN)
|
||||
){
|
||||
exprAnalyzeExists(pSrc, pWC, idxTerm);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifndef SQLITE_OMIT_LIKE_OPTIMIZATION
|
||||
/* Add constraints to reduce the search space on a LIKE or GLOB
|
||||
** operator.
|
||||
|
||||
+1
-1
@@ -253,7 +253,7 @@ do_execsql_test 11.1 {
|
||||
|
||||
do_catchsql_test 11.2 {
|
||||
ALTER TABLE t1 RENAME TO t1x;
|
||||
} {1 {error in trigger b: no such table: abc}}
|
||||
} {1 {error in trigger b: no such table: main.abc}}
|
||||
|
||||
do_execsql_test 11.3 {
|
||||
DROP TRIGGER b;
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
# 2020-12-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.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix corruptN
|
||||
|
||||
# These tests deal with corrupt database files
|
||||
#
|
||||
database_may_be_corrupt
|
||||
|
||||
reset_db
|
||||
do_test 1.0 {
|
||||
sqlite3 db {}
|
||||
db deserialize [decode_hexdb {
|
||||
.open --hexdb
|
||||
| size 4096 pagesize 512 filename sql024239.txt.db
|
||||
| page 1 offset 0
|
||||
| 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3.
|
||||
| 16: 02 00 01 01 00 40 20 20 00 00 00 0c 00 00 00 07 .....@ ........
|
||||
| 32: 00 00 00 00 00 00 00 00 00 00 00 08 00 00 00 04 ................
|
||||
| 48: 00 00 00 00 89 00 00 04 00 10 00 01 0a 00 00 01 ................
|
||||
| 80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0c ................
|
||||
| 96: 00 2e 2c 50 0d 00 00 00 06 01 06 00 01 da 01 b0 ..,P............
|
||||
| 112: 01 56 01 86 01 2a 01 06 00 00 00 00 00 00 00 00 .V...*..........
|
||||
| 256: 00 00 00 00 00 00 22 07 06 17 11 11 01 31 74 61 .............1ta
|
||||
| 272: 62 6c 65 74 34 74 34 07 43 52 45 41 54 45 20 54 blet4t4.CREATE T
|
||||
| 288: 41 42 4c 45 20 74 34 28 78 29 2a 06 06 17 13 11 ABLE t4(x)*.....
|
||||
| 304: 01 3f 69 6e 64 65 78 74 33 78 74 33 05 43 52 45 .?indext3xt3.CRE
|
||||
| 320: 41 54 45 20 49 4e 44 45 58 20 74 33 78 20 4f 4e ATE INDEX t3x ON
|
||||
| 336: 20 74 33 28 78 29 2e 04 06 17 15 11 01 45 69 6e t3(x).......Ein
|
||||
| 352: 64 65 78 74 32 63 64 74 32 05 43 52 45 41 54 45 dext2cdt2.CREATE
|
||||
| 368: 20 49 4e 44 45 58 20 74 32 63 64 20 4f 4e 20 74 INDEX t2cd ON t
|
||||
| 384: 32 28 63 2c 64 29 28 05 06 17 11 11 01 3d 74 61 2(c,d)(......=ta
|
||||
| 400: 62 6c 65 74 33 74 33 07 43 52 45 41 54 45 20 54 blet3t3.CREATE T
|
||||
| 416: 41 42 4c 45 20 74 33 28 63 2c 78 2c 65 2c 66 29 ABLE t3(c,x,e,f)
|
||||
| 432: 28 02 06 17 11 11 01 3d 74 61 62 6c 65 74 32 74 (......=tablet2t
|
||||
| 448: 32 03 43 52 45 41 54 45 20 54 41 42 4c 45 20 74 2.CREATE TABLE t
|
||||
| 464: 32 28 63 2c 64 2c 65 2c 66 29 24 01 06 17 11 11 2(c,d,e,f)$.....
|
||||
| 480: 01 35 74 61 62 6c 65 74 31 74 31 02 43 52 45 41 .5tablet1t1.CREA
|
||||
| 496: 54 45 20 54 41 42 4c 45 20 74 31 28 61 2c 62 29 TE TABLE t1(a,b)
|
||||
| page 2 offset 512
|
||||
| 0: 0d 00 00 00 04 01 41 00 01 fa 01 f3 01 de 01 cf ......A.........
|
||||
| 160: 00 00 20 00 00 00 00 00 00 00 00 00 00 00 00 00 .. .............
|
||||
| 448: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0d ................
|
||||
| 464: 04 03 17 17 73 65 76 65 6e 65 69 67 68 74 13 03 ....seveneight..
|
||||
| 480: 03 07 07 40 14 00 00 00 00 00 00 40 18 00 00 00 ...@.......@....
|
||||
| 496: 00 00 00 05 02 03 01 01 03 04 04 01 03 09 01 02 ................
|
||||
| page 3 offset 1024
|
||||
| 0: 0d 00 00 00 08 01 54 00 01 f7 01 ec 01 c5 01 aa ......T.........
|
||||
| 16: 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
| 112: 00 00 dd 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
| 336: 00 00 00 00 19 08 05 17 17 17 17 65 69 67 68 74 ...........eight
|
||||
| 352: 65 69 67 68 74 73 65 76 65 6e 73 65 76 65 6e 25 eightsevenseven%
|
||||
| 368: 07 05 07 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
| 432: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 08 ................
|
||||
| 480: 00 00 0f 04 17 17 01 65 69 67 68 74 65 69 67 68 .......eighteigh
|
||||
| 496: 74 08 15 04 07 07 01 40 18 00 00 00 00 00 00 40 t......@.......@
|
||||
| page 4 offset 1536
|
||||
| 0: 18 00 00 00 00 00 00 07 07 04 01 01 01 04 04 06 ................
|
||||
| 16: 07 04 01 01 01 02 02 05 0f 04 17 17 01 73 6d 76 .............smv
|
||||
| 32: 65 6e 65 69 67 68 74 04 15 04 07 07 01 40 14 00 eneight......@..
|
||||
| page 5 offset 2048
|
||||
| 0: 0a 00 00 00 08 01 96 00 01 fa 01 c4 01 f2 01 bc ................
|
||||
| 16: 01 dc 01 e1 01 96 01 cc 00 00 00 00 00 00 00 00 ................
|
||||
| 160: 00 00 00 00 00 00 32 00 00 00 00 00 00 00 00 00 ......2.........
|
||||
| 368: 00 00 00 08 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
| 400: 00 00 00 00 00 00 0f 04 17 17 01 85 69 67 68 74 ............ight
|
||||
| 416: 65 69 67 68 74 08 15 04 07 07 01 40 18 00 00 00 eight......@....
|
||||
| 432: 00 00 00 40 18 00 00 00 00 00 00 07 07 04 01 01 ...@............
|
||||
| 448: 01 04 04 06 07 04 01 01 01 02 02 05 0f 04 17 17 ................
|
||||
| 464: 01 73 6d 76 65 6e 65 69 67 68 74 04 15 04 07 07 .smveneight.....
|
||||
| 480: 01 40 14 00 00 00 00 00 00 40 18 00 00 00 00 00 .@.......@......
|
||||
| 496: 00 03 07 04 01 01 01 03 04 02 05 04 03 01 09 02 ................
|
||||
| page 6 offset 2560
|
||||
| 0: 0a 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
| 16: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 10 00 ................
|
||||
| 304: 00 00 00 26 00 00 00 00 00 00 00 00 00 00 00 00 ...&............
|
||||
| page 7 offset 3072
|
||||
| 0: 0d 00 00 00 08 01 c2 00 01 fb 01 f6 01 f1 01 ec ................
|
||||
| 16: 01 e0 01 d4 01 cb 01 c2 00 00 00 00 00 00 00 00 ................
|
||||
| 128: 00 00 00 00 00 00 00 00 00 00 00 00 00 20 00 04 ............. ..
|
||||
| 384: 00 00 00 00 00 00 00 00 00 07 08 02 17 65 69 fc .............ei.
|
||||
| 400: 68 74 07 07 02 17 65 69 67 68 74 0a fb fd f8 bf ht....eight.....
|
||||
| 416: e7 ff ff ff 00 00 00 0a 05 02 07 40 18 00 00 00 ...........@....
|
||||
| 432: 00 00 00 03 04 02 01 04 03 03 02 01 04 03 02 01 ................
|
||||
| 448: ff ff ff ff ff ff 00 00 00 00 00 00 00 00 00 00 ................
|
||||
| end sql024239.txt.db
|
||||
}]} {}
|
||||
|
||||
do_catchsql_test 1.1 {
|
||||
VACUUM;
|
||||
} {1 {database disk image is malformed}}
|
||||
|
||||
|
||||
finish_test
|
||||
+46
-29
@@ -21,7 +21,7 @@ source $testdir/tester.tcl
|
||||
# Only run these tests if memory debugging is turned on.
|
||||
#
|
||||
ifcapable !crashtest||!memorymanage {
|
||||
puts "Skipping crash5 tests: not compiled with -DSQLITE_MEMDEBUG..."
|
||||
puts "Skipping crash5 tests: not compiled with -DSQLITE_ENABLE_MEMORY_MANAGEMENT..."
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
@@ -29,7 +29,7 @@ ifcapable !crashtest||!memorymanage {
|
||||
db close
|
||||
|
||||
for {set ii 0} {$ii < 10} {incr ii} {
|
||||
for {set jj 50} {$jj < 100} {incr jj} {
|
||||
for {set jj 1} {$jj < 100} {incr jj} {
|
||||
|
||||
# Set up the database so that it is an auto-vacuum database
|
||||
# containing a single table (root page 3) with a single row.
|
||||
@@ -47,6 +47,20 @@ for {set ii 0} {$ii < 10} {incr ii} {
|
||||
do_test crash5-$ii.$jj.1 {
|
||||
crashsql -delay 1 -file test.db-journal -seed $ii -tclbody [join [list \
|
||||
[list set iFail $jj] {
|
||||
proc get_pwd {} {
|
||||
if {$::tcl_platform(platform) eq "windows"} {
|
||||
if {[info exists ::env(ComSpec)]} {
|
||||
set comSpec $::env(ComSpec)
|
||||
} else {
|
||||
# NOTE: Hard-code the typical default value.
|
||||
set comSpec {C:\Windows\system32\cmd.exe}
|
||||
}
|
||||
return [string map [list \\ /] \
|
||||
[string trim [exec -- $comSpec /c echo %CD%]]]
|
||||
} else {
|
||||
return [pwd]
|
||||
}
|
||||
}
|
||||
sqlite3_crashparams 0 [file join [get_pwd] test.db-journal]
|
||||
|
||||
# Begin a transaction and evaluate a "CREATE INDEX" statement
|
||||
@@ -61,36 +75,39 @@ for {set ii 0} {$ii < 10} {incr ii} {
|
||||
#
|
||||
db eval BEGIN
|
||||
sqlite3_memdebug_fail $iFail -repeat 0
|
||||
catch {db eval { CREATE UNIQUE INDEX i1 ON t1(a); }} msg
|
||||
# puts "$n $msg ac=[sqlite3_get_autocommit db]"
|
||||
set rc [catch {db eval { CREATE UNIQUE INDEX i1 ON t1(a); }} msg]
|
||||
# puts "$msg ac=[sqlite3_get_autocommit db] iFail=$iFail"
|
||||
# puts "fail=[sqlite3_memdebug_fail -1]"
|
||||
|
||||
# If the transaction is still active (it may not be if the malloc()
|
||||
# failure occurred in the OS layer), write to the database. Make sure
|
||||
# page 4 is among those written.
|
||||
#
|
||||
if {![sqlite3_get_autocommit db]} {
|
||||
db eval {
|
||||
DELETE FROM t1; -- This will put page 4 on the free list.
|
||||
INSERT INTO t1 VALUES('111111111', '2222222222', '33333333');
|
||||
INSERT INTO t1 SELECT * FROM t1; -- 2
|
||||
INSERT INTO t1 SELECT * FROM t1; -- 4
|
||||
INSERT INTO t1 SELECT * FROM t1; -- 8
|
||||
INSERT INTO t1 SELECT * FROM t1; -- 16
|
||||
INSERT INTO t1 SELECT * FROM t1; -- 32
|
||||
INSERT INTO t1 SELECT * FROM t1 WHERE rowid%2; -- 48
|
||||
if {$rc} {
|
||||
# If the transaction is still active (it may not be if the malloc()
|
||||
# failure occurred in the OS layer), write to the database. Make sure
|
||||
# page 4 is among those written.
|
||||
#
|
||||
if {![sqlite3_get_autocommit db]} {
|
||||
db eval {
|
||||
DELETE FROM t1; -- This will put page 4 on the free list.
|
||||
INSERT INTO t1 VALUES('111111111', '2222222222', '33333333');
|
||||
INSERT INTO t1 SELECT * FROM t1; -- 2
|
||||
INSERT INTO t1 SELECT * FROM t1; -- 4
|
||||
INSERT INTO t1 SELECT * FROM t1; -- 8
|
||||
INSERT INTO t1 SELECT * FROM t1; -- 16
|
||||
INSERT INTO t1 SELECT * FROM t1; -- 32
|
||||
INSERT INTO t1 SELECT * FROM t1 WHERE rowid%2; -- 48
|
||||
}
|
||||
}
|
||||
|
||||
# If the right malloc() failed during the 'CREATE INDEX' above and
|
||||
# the transaction was not rolled back, then the sqlite cache now
|
||||
# has a dirty page 4 that it incorrectly believes is already safely
|
||||
# in the synced part of the journal file. When
|
||||
# sqlite3_release_memory() is called sqlite tries to free memory
|
||||
# by writing page 4 out to the db file. If it crashes later on,
|
||||
# before syncing the journal... Corruption!
|
||||
#
|
||||
sqlite3_crashparams 1 [file join [get_pwd] test.db-journal]
|
||||
sqlite3_release_memory 8092
|
||||
}
|
||||
|
||||
# If the right malloc() failed during the 'CREATE INDEX' above and
|
||||
# the transaction was not rolled back, then the sqlite cache now
|
||||
# has a dirty page 4 that it incorrectly believes is already safely
|
||||
# in the synced part of the journal file. When
|
||||
# sqlite3_release_memory() is called sqlite tries to free memory
|
||||
# by writing page 4 out to the db file. If it crashes later on,
|
||||
# before syncing the journal... Corruption!
|
||||
#
|
||||
sqlite3_crashparams 1 [file join [get_pwd] test.db-journal]
|
||||
sqlite3_release_memory 8092
|
||||
}]] {}
|
||||
expr 1
|
||||
} {1}
|
||||
|
||||
+12
-4
@@ -287,10 +287,6 @@ int LLVMFuzzerInitialize(int *pArgc, char ***pArgv){
|
||||
sqlite3MemTraceActivate(stdout);
|
||||
continue;
|
||||
}
|
||||
if( strcmp(z,"mem")==0 ){
|
||||
bVdbeDebug = 1;
|
||||
continue;
|
||||
}
|
||||
if( strcmp(z,"max-db-size")==0 ){
|
||||
if( i+1==argc ){
|
||||
fprintf(stderr, "missing argument to %s\n", argv[i]);
|
||||
@@ -299,6 +295,18 @@ int LLVMFuzzerInitialize(int *pArgc, char ***pArgv){
|
||||
szMax = strtol(argv[++i], 0, 0);
|
||||
continue;
|
||||
}
|
||||
if( strcmp(z, "lookaside")==0 ){
|
||||
int sz, nSlot;
|
||||
if( i+2>=argc ){
|
||||
fprintf(stderr,
|
||||
"--lookaside requires two arguments: slot-size num-slots\n");
|
||||
exit(1);
|
||||
}
|
||||
sz = atoi(argv[++i]);
|
||||
nSlot = atoi(argv[++i]);
|
||||
sqlite3_config(SQLITE_CONFIG_LOOKASIDE, sz, nSlot);
|
||||
continue;
|
||||
}
|
||||
#ifndef _WIN32
|
||||
if( strcmp(z,"max-stack")==0
|
||||
|| strcmp(z,"max-data")==0
|
||||
|
||||
@@ -0,0 +1,188 @@
|
||||
# 2021 January 15
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
# This file implements regression tests for SQLite library. The
|
||||
# focus of this file is testing cases where EXISTS expressions are
|
||||
# transformed to IN() expressions by where.c
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix exists2
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
|
||||
INSERT INTO t1 VALUES(1, 'one');
|
||||
INSERT INTO t1 VALUES(2, 'two');
|
||||
INSERT INTO t1 VALUES(3, 'three');
|
||||
INSERT INTO t1 VALUES(4, 'four');
|
||||
INSERT INTO t1 VALUES(5, 'five');
|
||||
INSERT INTO t1 VALUES(6, 'six');
|
||||
INSERT INTO t1 VALUES(7, 'seven');
|
||||
|
||||
CREATE TABLE t2(c INTEGER, d INTEGER);
|
||||
INSERT INTO t2 VALUES(1, 1);
|
||||
INSERT INTO t2 VALUES(3, 2);
|
||||
INSERT INTO t2 VALUES(5, 3);
|
||||
INSERT INTO t2 VALUES(7, 4);
|
||||
}
|
||||
|
||||
proc do_execsql_eqp_test {tn sql eqp res} {
|
||||
uplevel [list do_eqp_test $tn.1 $sql [string trim $eqp]]
|
||||
uplevel [list do_execsql_test $tn.2 $sql $res]
|
||||
}
|
||||
|
||||
do_execsql_eqp_test 1.1 {
|
||||
SELECT t1.* FROM t1 WHERE EXISTS(SELECT * FROM t2 WHERE t1.a=t2.c);
|
||||
} {
|
||||
USING INTEGER PRIMARY KEY
|
||||
} {
|
||||
1 one 3 three 5 five 7 seven
|
||||
}
|
||||
|
||||
do_execsql_eqp_test 1.2 {
|
||||
SELECT t1.* FROM t1 WHERE EXISTS(SELECT * FROM t2 WHERE t2.c=t1.a);
|
||||
} {
|
||||
SEARCH TABLE t1 USING INTEGER PRIMARY KEY
|
||||
} {
|
||||
1 one 3 three 5 five 7 seven
|
||||
}
|
||||
|
||||
do_execsql_eqp_test 1.3 {
|
||||
SELECT t1.* FROM t1 WHERE EXISTS(SELECT * FROM t2 WHERE t2.c+1=t1.a);
|
||||
} {
|
||||
SEARCH TABLE t1 USING INTEGER PRIMARY KEY
|
||||
} {
|
||||
2 two 4 four 6 six
|
||||
}
|
||||
|
||||
do_execsql_eqp_test 1.4 {
|
||||
SELECT t1.* FROM t1 WHERE EXISTS(SELECT * FROM t2 WHERE t2.c+1=t1.a+1);
|
||||
} {
|
||||
SCAN TABLE t1
|
||||
} {
|
||||
1 one 3 three 5 five 7 seven
|
||||
}
|
||||
|
||||
do_execsql_eqp_test 1.5 {
|
||||
SELECT t1.* FROM t1 WHERE EXISTS(
|
||||
SELECT * FROM t2 WHERE t1.a=t2.c AND d IN (1, 2, 3)
|
||||
);
|
||||
} {
|
||||
SEARCH TABLE t1 USING INTEGER PRIMARY KEY
|
||||
} {
|
||||
1 one 3 three 5 five
|
||||
}
|
||||
|
||||
do_execsql_eqp_test 1.6 {
|
||||
SELECT t1.* FROM t1 WHERE EXISTS(
|
||||
SELECT * FROM t2 WHERE d IN (1, 2, 3)AND t1.a=t2.c
|
||||
);
|
||||
} {
|
||||
SEARCH TABLE t1 USING INTEGER PRIMARY KEY
|
||||
} {
|
||||
1 one 3 three 5 five
|
||||
}
|
||||
|
||||
do_execsql_eqp_test 1.7 {
|
||||
SELECT t1.* FROM t1 WHERE EXISTS(
|
||||
SELECT * FROM t2 WHERE d IN (1, 2, 3)AND t1.a=t2.c
|
||||
);
|
||||
} {
|
||||
SEARCH TABLE t1 USING INTEGER PRIMARY KEY
|
||||
} {
|
||||
1 one 3 three 5 five
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 2.0 {
|
||||
CREATE TABLE t3(a TEXT PRIMARY KEY, b TEXT, x INT) WITHOUT ROWID;
|
||||
CREATE TABLE t4(c TEXT COLLATE nocase, y INT);
|
||||
|
||||
INSERT INTO t3 VALUES('one', 'i', 1);
|
||||
INSERT INTO t3 VALUES('two', 'ii', 2);
|
||||
INSERT INTO t3 VALUES('three', 'iii', 3);
|
||||
INSERT INTO t3 VALUES('four', 'iv', 4);
|
||||
INSERT INTO t3 VALUES('five', 'v', 5);
|
||||
|
||||
INSERT INTO t4 VALUES('FIVE',5), ('four',4), ('TWO',2), ('one',1);
|
||||
}
|
||||
|
||||
do_execsql_test 2.1 { SELECT a FROM t3, t4 WHERE a=c } {four one}
|
||||
do_execsql_test 2.2 { SELECT a FROM t3, t4 WHERE c=a } {five four one two}
|
||||
|
||||
do_execsql_eqp_test 2.3 {
|
||||
SELECT a FROM t3 WHERE EXISTS (SELECT 1 FROM t4 WHERE a=c)
|
||||
} {
|
||||
SEARCH TABLE t3 USING PRIMARY KEY
|
||||
} {
|
||||
four one
|
||||
}
|
||||
|
||||
do_execsql_eqp_test 2.4 {
|
||||
SELECT a FROM t3 WHERE EXISTS (SELECT 1 FROM t4 WHERE c=a)
|
||||
} {
|
||||
SCAN TABLE t3
|
||||
} {
|
||||
five four one two
|
||||
}
|
||||
|
||||
do_execsql_test 2.5 {
|
||||
CREATE INDEX t3anc ON t3(a COLLATE nocase, x);
|
||||
}
|
||||
|
||||
do_execsql_eqp_test 2.6 {
|
||||
SELECT a FROM t3 WHERE EXISTS (SELECT 1 FROM t4 WHERE c=a)
|
||||
} {
|
||||
SEARCH TABLE t3 USING COVERING INDEX t3anc
|
||||
} {
|
||||
five four one two
|
||||
}
|
||||
do_execsql_test 2.6a {
|
||||
SELECT a FROM t3 WHERE EXISTS (SELECT 1 FROM t4 WHERE (c,y)=(a,x))
|
||||
} {five four one two}
|
||||
|
||||
do_execsql_eqp_test 2.7 {
|
||||
SELECT a FROM t3 WHERE EXISTS (SELECT 1 FROM t4 WHERE a=c)
|
||||
} {
|
||||
SEARCH TABLE t3 USING PRIMARY KEY
|
||||
} {
|
||||
four one
|
||||
}
|
||||
do_execsql_test 2.7a {
|
||||
SELECT a FROM t3 WHERE EXISTS (SELECT 1 FROM t4 WHERE (a,x)=(c,y))
|
||||
} {
|
||||
four one
|
||||
}
|
||||
|
||||
# EXISTS clauses using vector expressions in the WHERE clause.
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 3.0 {
|
||||
CREATE TABLE t1(a,b);
|
||||
INSERT INTO t1(a,b) VALUES(1,111),(2,222),(8,888);
|
||||
CREATE TABLE t2(x INTEGER PRIMARY KEY, y);
|
||||
INSERT INTO t2(x,y) VALUES(2,222),(3,333),(7,333);
|
||||
SELECT y FROM t2 WHERE EXISTS(SELECT 1 FROM t1 WHERE (x,y)=(a,b));
|
||||
} {222}
|
||||
do_execsql_test 3.1 {
|
||||
SELECT y FROM t2 WHERE EXISTS(SELECT 1 FROM t1 WHERE (a,b)=(x,y));
|
||||
} {222}
|
||||
do_execsql_test 3.2 {
|
||||
SELECT y FROM t2 WHERE EXISTS(SELECT 1 FROM t1 WHERE (x,b)=(a,y));
|
||||
} {222}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
finish_test
|
||||
@@ -0,0 +1,52 @@
|
||||
# 2021 January 15
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
# This file implements regression tests for SQLite library. The
|
||||
# focus of this file is testing cases where EXISTS expressions are
|
||||
# transformed to IN() expressions by where.c
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix existsfault
|
||||
|
||||
do_execsql_test 1 {
|
||||
CREATE TABLE t1(a PRIMARY KEY, b);
|
||||
INSERT INTO t1 VALUES(1, 'one');
|
||||
INSERT INTO t1 VALUES(2, 'two');
|
||||
INSERT INTO t1 VALUES(3, 'three');
|
||||
INSERT INTO t1 VALUES(4, 'four');
|
||||
INSERT INTO t1 VALUES(5, 'five');
|
||||
INSERT INTO t1 VALUES(6, 'six');
|
||||
INSERT INTO t1 VALUES(7, 'seven');
|
||||
|
||||
CREATE TABLE t2(c INTEGER, d INTEGER);
|
||||
INSERT INTO t2 VALUES(1, 1);
|
||||
INSERT INTO t2 VALUES(3, 2);
|
||||
INSERT INTO t2 VALUES(5, 3);
|
||||
INSERT INTO t2 VALUES(7, 4);
|
||||
}
|
||||
faultsim_save_and_close
|
||||
|
||||
do_faultsim_test 1 -prep {
|
||||
faultsim_restore_and_reopen
|
||||
} -body {
|
||||
execsql {
|
||||
SELECT t1.* FROM t1 WHERE EXISTS(
|
||||
SELECT * FROM t2 WHERE t2.c=t1.a AND d IN (1, 2, 3)
|
||||
)
|
||||
}
|
||||
} -test {
|
||||
faultsim_test_result {0 {1 one 3 three 5 five}}
|
||||
}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -567,4 +567,22 @@ do_execsql_test 11.1 {
|
||||
berlin@street sydney.road
|
||||
}
|
||||
|
||||
# Test for embedded nul characters in fts4 unicode index.
|
||||
#
|
||||
do_execsql_test 12.0 {
|
||||
CREATE VIRTUAL TABLE t12 USING fts4(tokenize=unicode61);
|
||||
INSERT INTO t12 VALUES('abc' || char(0) || 'def');
|
||||
SELECT hex(CAST(content AS blob)) FROM t12;
|
||||
} {61626300646566}
|
||||
do_execsql_test 12.1 {
|
||||
INSERT INTO t12(t12) VALUES('integrity-check');
|
||||
} {}
|
||||
do_execsql_test 12.2 {
|
||||
CREATE VIRTUAL TABLE t12aux USING fts4aux(t12);
|
||||
SELECT * FROM t12aux;
|
||||
} {abc * 1 1 abc 0 1 1}
|
||||
do_execsql_test 12.3 {
|
||||
SELECT hex(CAST(content AS blob)) FROM t12 WHERE t12 MATCH 'abc'
|
||||
} {61626300646566}
|
||||
|
||||
finish_test
|
||||
|
||||
+245
@@ -0,0 +1,245 @@
|
||||
# 2020-12-07
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#*************************************************************************
|
||||
#
|
||||
# Test cases for SQL functions based off the standard math library
|
||||
#
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
ifcapable !mathlib {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
do_execsql_test func7-100 {
|
||||
SELECT ceil(99.9), ceiling(-99.01), floor(17), floor(-17.99);
|
||||
} {100.0 -99.0 17 -18.0}
|
||||
do_execsql_test func7-110 {
|
||||
SELECT quote(ceil(NULL)), ceil('-99.99');
|
||||
} {NULL -99.0}
|
||||
do_execsql_test func7-200 {
|
||||
SELECT round(ln(5),2), log(100.0), log(100), log(2,'256');
|
||||
} {1.61 2.0 2.0 8.0}
|
||||
do_execsql_test func7-210 {
|
||||
SELECT ln(-5), log(-5,100.0);
|
||||
} {{} {}}
|
||||
|
||||
# Test cases derived from PostgreSQL documentation
|
||||
#
|
||||
do_execsql_test func7-pg-100 {
|
||||
SELECT abs(-17.4)
|
||||
} {17.4}
|
||||
do_execsql_test func7-pg-110 {
|
||||
SELECT ceil(42.2)
|
||||
} {43.0}
|
||||
do_execsql_test func7-pg-120 {
|
||||
SELECT ceil(-42.2)
|
||||
} {-42.0}
|
||||
do_execsql_test func7-pg-130 {
|
||||
SELECT round(exp(1.0),7)
|
||||
} {2.7182818}
|
||||
do_execsql_test func7-pg-140 {
|
||||
SELECT floor(42.8)
|
||||
} {42.0}
|
||||
do_execsql_test func7-pg-150 {
|
||||
SELECT floor(-42.8)
|
||||
} {-43.0}
|
||||
do_execsql_test func7-pg-160 {
|
||||
SELECT round(ln(2.0),7)
|
||||
} {0.6931472}
|
||||
do_execsql_test func7-pg-170 {
|
||||
SELECT log(100.0)
|
||||
} {2.0}
|
||||
do_execsql_test func7-pg-180 {
|
||||
SELECT log10(1000.0)
|
||||
} {3.0}
|
||||
do_execsql_test func7-pg-190 {
|
||||
SELECT log(2.0, 64.0)
|
||||
} {6.0}
|
||||
do_execsql_test func7-pg-200 {
|
||||
SELECT mod(9,4);
|
||||
} {1.0}
|
||||
do_execsql_test func7-pg-210 {
|
||||
SELECT round(pi(),7);
|
||||
} {3.1415927}
|
||||
do_execsql_test func7-pg-220 {
|
||||
SELECT power(9,3);
|
||||
} {729.0}
|
||||
do_execsql_test func7-pg-230 {
|
||||
SELECT round(radians(45.0),7);
|
||||
} {0.7853982}
|
||||
do_execsql_test func7-pg-240 {
|
||||
SELECT round(42.4);
|
||||
} {42.0}
|
||||
do_execsql_test func7-pg-250 {
|
||||
SELECT round(42.4382,2);
|
||||
} {42.44}
|
||||
do_execsql_test func7-pg-260 {
|
||||
SELECT sign(-8.4);
|
||||
} {-1}
|
||||
do_execsql_test func7-pg-270 {
|
||||
SELECT round( sqrt(2), 7);
|
||||
} {1.4142136}
|
||||
do_execsql_test func7-pg-280 {
|
||||
SELECT trunc(42.8), trunc(-42.8);
|
||||
} {42.0 -42.0}
|
||||
do_execsql_test func7-pg-300 {
|
||||
SELECT acos(1);
|
||||
} {0.0}
|
||||
do_execsql_test func7-pg-301 {
|
||||
SELECT degrees(acos(0.5));
|
||||
} {60.0}
|
||||
do_execsql_test func7-pg-310 {
|
||||
SELECT round( asin(1), 7);
|
||||
} {1.5707963}
|
||||
do_execsql_test func7-pg-311 {
|
||||
SELECT degrees( asin(0.5) );
|
||||
} {30.0}
|
||||
do_execsql_test func7-pg-320 {
|
||||
SELECT round( atan(1), 7);
|
||||
} {0.7853982}
|
||||
do_execsql_test func7-pg-321 {
|
||||
SELECT degrees( atan(1) );
|
||||
} {45.0}
|
||||
do_execsql_test func7-pg-330 {
|
||||
SELECT round( atan2(1,0), 7);
|
||||
} {1.5707963}
|
||||
do_execsql_test func7-pg-331 {
|
||||
SELECT degrees( atan2(1,0) );
|
||||
} {90.0}
|
||||
do_execsql_test func7-pg-400 {
|
||||
SELECT cos(0);
|
||||
} {1.0}
|
||||
do_execsql_test func7-pg-401 {
|
||||
SELECT cos( radians(60.0) );
|
||||
} {0.5}
|
||||
do_execsql_test func7-pg-400 {
|
||||
SELECT cos(0);
|
||||
} {1.0}
|
||||
do_execsql_test func7-pg-410 {
|
||||
SELECT round( sin(1), 7);
|
||||
} {0.841471}
|
||||
do_execsql_test func7-pg-411 {
|
||||
SELECT sin( radians(30) );
|
||||
} {0.5}
|
||||
do_execsql_test func7-pg-420 {
|
||||
SELECT round( tan(1), 7);
|
||||
} {1.5574077}
|
||||
do_execsql_test func7-pg-421 {
|
||||
SELECT tan( radians(45) );
|
||||
} {1.0}
|
||||
do_execsql_test func7-pg-500 {
|
||||
SELECT round( sinh(1), 7);
|
||||
} {1.1752012}
|
||||
do_execsql_test func7-pg-510 {
|
||||
SELECT round( cosh(0), 7);
|
||||
} {1.0}
|
||||
do_execsql_test func7-pg-520 {
|
||||
SELECT round( tanh(1), 7);
|
||||
} {0.7615942}
|
||||
do_execsql_test func7-pg-530 {
|
||||
SELECT round( asinh(1), 7);
|
||||
} {0.8813736}
|
||||
do_execsql_test func7-pg-540 {
|
||||
SELECT round( acosh(1), 7);
|
||||
} {0.0}
|
||||
do_execsql_test func7-pg-550 {
|
||||
SELECT round( atanh(0.5), 7);
|
||||
} {0.5493061}
|
||||
|
||||
# Test cases derived from MySQL documentation
|
||||
#
|
||||
do_execsql_test func7-mysql-100 {
|
||||
SELECT acos(1);
|
||||
} {0.0}
|
||||
do_execsql_test func7-mysql-110 {
|
||||
SELECT acos(1.0001);
|
||||
} {{}}
|
||||
do_execsql_test func7-mysql-120 {
|
||||
SELECT round( acos(0.0), 7);
|
||||
} {1.5707963}
|
||||
do_execsql_test func7-mysql-130 {
|
||||
SELECT round( asin(0.2), 7);
|
||||
} {0.2013579}
|
||||
do_execsql_test func7-mysql-140 {
|
||||
SELECT asin('foo');
|
||||
} {{}} ;# Note: MySQL returns 0 here, not NULL.
|
||||
# SQLite deliberately returns NULL.
|
||||
# SQLServer and Oracle throw an error.
|
||||
do_execsql_test func7-mysql-150 {
|
||||
SELECT round( atan(2), 7), round( atan(-2), 7);
|
||||
} {1.1071487 -1.1071487}
|
||||
do_execsql_test func7-mysql-160 {
|
||||
SELECT round( atan2(-2,2), 7), round( atan2(pi(),0), 7);
|
||||
} {-0.7853982 1.5707963}
|
||||
do_execsql_test func7-mysql-170 {
|
||||
SELECT ceiling(1.23), ceiling(-1.23);
|
||||
} {2.0 -1.0}
|
||||
do_execsql_test func7-mysql-180 {
|
||||
SELECT cos(pi());
|
||||
} {-1.0}
|
||||
do_execsql_test func7-mysql-190 {
|
||||
SELECT degrees(pi()), degrees(pi()/2);
|
||||
} {180.0 90.0}
|
||||
do_execsql_test func7-mysql-190 {
|
||||
SELECT round( exp(2), 7), round( exp(-2), 7), exp(0);
|
||||
} {7.3890561 0.1353353 1.0}
|
||||
do_execsql_test func7-mysql-200 {
|
||||
SELECT floor(1.23), floor(-1.23);
|
||||
} {1.0 -2.0}
|
||||
do_execsql_test func7-mysql-210 {
|
||||
SELECT round(ln(2),7), quote(ln(-2));
|
||||
} {0.6931472 NULL}
|
||||
#do_execsql_test func7-mysql-220 {
|
||||
# SELECT round(log(2),7), log(-2);
|
||||
#} {0.6931472 NULL}
|
||||
# log() means natural logarithm in MySQL
|
||||
do_execsql_test func7-mysql-230 {
|
||||
SELECT log(2,65536), log(10,100), quote(log(1,100));
|
||||
} {16.0 2.0 Inf}
|
||||
do_execsql_test func7-mysql-240 {
|
||||
SELECT log2(65536), quote(log2(-100));
|
||||
} {16.0 NULL}
|
||||
do_execsql_test func7-mysql-250 {
|
||||
SELECT round(log10(2),7), log10(100), quote(log10(-100));
|
||||
} {0.30103 2.0 NULL}
|
||||
do_execsql_test func7-mysql-260 {
|
||||
SELECT mod(234,10), 253%7, mod(29,9), 29%9;
|
||||
} {4.0 1 2.0 2}
|
||||
do_execsql_test func7-mysql-270 {
|
||||
SELECT mod(34.5,3);
|
||||
} {1.5}
|
||||
do_execsql_test func7-mysql-280 {
|
||||
SELECT pow(2,2), pow(2,-2);
|
||||
} {4.0 0.25}
|
||||
do_execsql_test func7-mysql-281 {
|
||||
SELECT power(2,2), power(2,-2);
|
||||
} {4.0 0.25}
|
||||
do_execsql_test func7-mysql-290 {
|
||||
SELECT round(radians(90),7);
|
||||
} {1.5707963}
|
||||
do_execsql_test func7-mysql-300 {
|
||||
SELECT sign(-32), sign(0), sign(234);
|
||||
} {-1 0 1}
|
||||
do_execsql_test func7-mysql-310 {
|
||||
SELECT sin(pi()) BETWEEN -1.0e-15 AND 1.0e-15;
|
||||
} {1}
|
||||
do_execsql_test func7-mysql-320 {
|
||||
SELECT sqrt(4), round(sqrt(20),7), quote(sqrt(-16));
|
||||
} {2.0 4.472136 NULL}
|
||||
do_execsql_test func7-mysql-330 {
|
||||
SELECT tan(pi()) BETWEEN -1.0e-15 AND 1.0e-15;
|
||||
} {1}
|
||||
do_execsql_test func7-mysql-331 {
|
||||
SELECT round(tan(pi()+1),7);
|
||||
} {1.5574077}
|
||||
|
||||
|
||||
finish_test
|
||||
+27
-7
@@ -455,7 +455,12 @@ static void blobListFree(Blob *p){
|
||||
}
|
||||
}
|
||||
|
||||
/* Return the current wall-clock time */
|
||||
/* Return the current wall-clock time
|
||||
**
|
||||
** The number of milliseconds since the julian epoch.
|
||||
** 1907-01-01 00:00:00 -> 210866716800000
|
||||
** 2021-01-01 00:00:00 -> 212476176000000
|
||||
*/
|
||||
static sqlite3_int64 timeOfDay(void){
|
||||
static sqlite3_vfs *clockVfs = 0;
|
||||
sqlite3_int64 t;
|
||||
@@ -713,6 +718,7 @@ static int progress_handler(void *pClientData) {
|
||||
sqlite3_int64 iNow = timeOfDay();
|
||||
int rc = iNow>=p->iCutoffTime;
|
||||
sqlite3_int64 iDiff = iNow - p->iLastCb;
|
||||
/* printf("time-remaining: %lld\n", p->iCutoffTime - iNow); */
|
||||
if( iDiff > p->mxInterval ) p->mxInterval = iDiff;
|
||||
p->nCb++;
|
||||
if( rc==0 && p->mxCb>0 && p->mxCb<=p->nCb ) rc = 1;
|
||||
@@ -835,7 +841,7 @@ static int runDbSql(sqlite3 *db, const char *zSql){
|
||||
}
|
||||
|
||||
/* Invoke this routine to run a single test case */
|
||||
int runCombinedDbSqlInput(const uint8_t *aData, size_t nByte){
|
||||
int runCombinedDbSqlInput(const uint8_t *aData, size_t nByte, int iTimeout){
|
||||
int rc; /* SQLite API return value */
|
||||
int iSql; /* Index in aData[] of start of SQL */
|
||||
unsigned char *aDb = 0; /* Decoded database content */
|
||||
@@ -882,7 +888,7 @@ int runCombinedDbSqlInput(const uint8_t *aData, size_t nByte){
|
||||
** elapsed since the start of the test.
|
||||
*/
|
||||
cx.iLastCb = timeOfDay();
|
||||
cx.iCutoffTime = cx.iLastCb + giTimeout; /* Now + giTimeout seconds */
|
||||
cx.iCutoffTime = cx.iLastCb + (iTimeout<giTimeout ? iTimeout : giTimeout);
|
||||
cx.mxCb = mxProgressCb;
|
||||
#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
|
||||
sqlite3_progress_handler(cx.db, 10, progress_handler, (void*)&cx);
|
||||
@@ -1433,7 +1439,7 @@ static void showHelp(void){
|
||||
" --skip N Skip the first N test cases\n"
|
||||
" --spinner Use a spinner to show progress\n"
|
||||
" --sqlid N Use only SQL where sqlid=N\n"
|
||||
" --timeout N Abort if any single test needs more than N seconds\n"
|
||||
" --timeout N Maximum time for any one test in N millseconds\n"
|
||||
" -v|--verbose Increased output. Repeat for more output.\n"
|
||||
" --vdbe-debug Activate VDBE debugging.\n"
|
||||
);
|
||||
@@ -1471,7 +1477,7 @@ int main(int argc, char **argv){
|
||||
const char *zFailCode = 0; /* Value of the TEST_FAILURE env variable */
|
||||
int cellSzCkFlag = 0; /* --cell-size-check */
|
||||
int sqlFuzz = 0; /* True for SQL fuzz. False for DB fuzz */
|
||||
int iTimeout = 120; /* Default 120-second timeout */
|
||||
int iTimeout = 120000; /* Default 120-second timeout */
|
||||
int nMem = 0; /* Memory limit override */
|
||||
int nMemThisDb = 0; /* Memory limit set by the CONFIG table */
|
||||
char *zExpDb = 0; /* Write Databases to files in this directory */
|
||||
@@ -1482,7 +1488,9 @@ int main(int argc, char **argv){
|
||||
int nativeMalloc = 0; /* Turn off MEMSYS3/5 and lookaside if true */
|
||||
sqlite3_vfs *pDfltVfs; /* The default VFS */
|
||||
int openFlags4Data; /* Flags for sqlite3_open_v2() */
|
||||
int bTimer = 0; /* Show elapse time for each test */
|
||||
int nV; /* How much to increase verbosity with -vvvv */
|
||||
sqlite3_int64 tmStart; /* Start of each test */
|
||||
|
||||
registerOomSimulator();
|
||||
sqlite3_initialize();
|
||||
@@ -1597,6 +1605,9 @@ int main(int argc, char **argv){
|
||||
if( strcmp(z,"spinner")==0 ){
|
||||
bSpinner = 1;
|
||||
}else
|
||||
if( strcmp(z,"timer")==0 ){
|
||||
bTimer = 1;
|
||||
}else
|
||||
if( strcmp(z,"sqlid")==0 ){
|
||||
if( i>=argc-1 ) fatalError("missing arguments on %s", argv[i]);
|
||||
onlySqlid = integerValue(argv[++i]);
|
||||
@@ -1894,6 +1905,7 @@ int main(int argc, char **argv){
|
||||
*/
|
||||
if( !verboseFlag && !quietFlag && !bSpinner ) printf("%s:", zDbName);
|
||||
for(pSql=g.pFirstSql; pSql; pSql=pSql->pNext){
|
||||
tmStart = timeOfDay();
|
||||
if( isDbSql(pSql->a, pSql->sz) ){
|
||||
sqlite3_snprintf(sizeof(g.zTestName), g.zTestName, "sqlid=%d",pSql->id);
|
||||
if( bSpinner ){
|
||||
@@ -1917,9 +1929,13 @@ int main(int argc, char **argv){
|
||||
if( nSkip>0 ){
|
||||
nSkip--;
|
||||
}else{
|
||||
runCombinedDbSqlInput(pSql->a, pSql->sz);
|
||||
runCombinedDbSqlInput(pSql->a, pSql->sz, iTimeout);
|
||||
}
|
||||
nTest++;
|
||||
if( bTimer ){
|
||||
sqlite3_int64 tmEnd = timeOfDay();
|
||||
printf("%lld %s\n", tmEnd - tmStart, g.zTestName);
|
||||
}
|
||||
g.zTestName[0] = 0;
|
||||
disableOom();
|
||||
continue;
|
||||
@@ -1972,7 +1988,7 @@ int main(int argc, char **argv){
|
||||
sqlite3_limit(db, SQLITE_LIMIT_LENGTH, 100000000);
|
||||
sqlite3_limit(db, SQLITE_LIMIT_LIKE_PATTERN_LENGTH, 50);
|
||||
if( cellSzCkFlag ) runSql(db, "PRAGMA cell_size_check=ON", runFlags);
|
||||
setAlarm(iTimeout);
|
||||
setAlarm((iTimeout+999)/1000);
|
||||
#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
|
||||
if( sqlFuzz || vdbeLimitFlag ){
|
||||
sqlite3_progress_handler(db, 100000, progressHandler,
|
||||
@@ -1998,6 +2014,10 @@ int main(int argc, char **argv){
|
||||
}
|
||||
reformatVfs();
|
||||
nTest++;
|
||||
if( bTimer ){
|
||||
sqlite3_int64 tmEnd = timeOfDay();
|
||||
printf("%lld %s\n", tmEnd - tmStart, g.zTestName);
|
||||
}
|
||||
g.zTestName[0] = 0;
|
||||
|
||||
/* Simulate an error if the TEST_FAILURE environment variable is "5".
|
||||
|
||||
Binary file not shown.
+35
-2
@@ -65,8 +65,8 @@ foreach {tn sql1 sql2} {
|
||||
3 "SELECT a, sum(b) FROM t1 GROUP BY a COLLATE binary HAVING a=2"
|
||||
"SELECT a, sum(b) FROM t1 WHERE a=2 GROUP BY a COLLATE binary"
|
||||
|
||||
5 "SELECT a, sum(b) FROM t1 GROUP BY a COLLATE binary HAVING 0"
|
||||
"SELECT a, sum(b) FROM t1 WHERE 0 GROUP BY a COLLATE binary"
|
||||
5 "SELECT a, sum(b) FROM t1 GROUP BY a COLLATE binary HAVING 1"
|
||||
"SELECT a, sum(b) FROM t1 WHERE 1 GROUP BY a COLLATE binary"
|
||||
|
||||
6 "SELECT count(*) FROM t1,t2 WHERE a=c GROUP BY b, d HAVING b=d"
|
||||
"SELECT count(*) FROM t1,t2 WHERE a=c AND b=d GROUP BY b, d"
|
||||
@@ -154,5 +154,38 @@ do_execsql_test 4.3 {
|
||||
SELECT a, sum(b) FROM t3 WHERE nondeter(a) GROUP BY a
|
||||
} {1 4 2 2}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_execsql_test 5.0 {
|
||||
CREATE TABLE t1(a, b);
|
||||
CREATE TABLE t2(x, y);
|
||||
INSERT INTO t1 VALUES('a', 'b');
|
||||
}
|
||||
|
||||
# The WHERE clause (a=2), uses an aggregate column from the outer query.
|
||||
# If the HAVING term (0) is moved into the WHERE clause in this case,
|
||||
# SQLite would at one point optimize (a=2 AND 0) to simply (0). Which
|
||||
# is logically correct, but happened to cause problems in aggregate
|
||||
# processing for the outer query. This test case verifies that those
|
||||
# problems are no longer present.
|
||||
do_execsql_test 5.1 {
|
||||
SELECT min(b), (
|
||||
SELECT x FROM t2 WHERE a=2 GROUP BY y HAVING 0
|
||||
) FROM t1;
|
||||
} {b {}}
|
||||
|
||||
# From chromium
|
||||
# https://bugs.chromium.org/p/chromium/issues/detail?id=1161869
|
||||
#
|
||||
do_execsql_test 5.2 {
|
||||
SELECT EXISTS (
|
||||
SELECT * FROM (
|
||||
SELECT * FROM (
|
||||
SELECT 1
|
||||
) WHERE Col0 = 1 GROUP BY 1
|
||||
) WHERE 0
|
||||
)
|
||||
FROM (SELECT 1 Col0) GROUP BY 1
|
||||
} {0}
|
||||
|
||||
finish_test
|
||||
|
||||
+3
-3
@@ -261,10 +261,10 @@ do_execsql_test 5.2 {
|
||||
}
|
||||
|
||||
do_execsql_test 5.3 {
|
||||
SELECT * FROM x1, (SELECT b FROM vvv UNION ALL SELECT c from x3);
|
||||
SELECT * FROM x1, (SELECT b FROM vvv UNION ALL SELECT c from x3) ORDER BY 1,2;
|
||||
} {
|
||||
a 21 a 22 a 23 a 24 a 25 a 302 a 303 a 301
|
||||
b 21 b 22 b 23 b 24 b 25 b 302 b 303 b 301
|
||||
a 21 a 22 a 23 a 24 a 25 a 301 a 302 a 303
|
||||
b 21 b 22 b 23 b 24 b 25 b 301 b 302 b 303
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
+2
-2
@@ -642,7 +642,7 @@ do_test shell1-3.23.2 {
|
||||
# .stats ON|OFF Turn stats on or off
|
||||
#do_test shell1-3.23b.1 {
|
||||
# catchcmd "test.db" ".stats"
|
||||
#} {1 {Usage: .stats on|off}}
|
||||
#} {1 {Usage: .stats on|off|stmt|vmstep}}
|
||||
do_test shell1-3.23b.2 {
|
||||
catchcmd "test.db" ".stats ON"
|
||||
} {0 {}}
|
||||
@@ -652,7 +652,7 @@ do_test shell1-3.23b.3 {
|
||||
do_test shell1-3.23b.4 {
|
||||
# too many arguments
|
||||
catchcmd "test.db" ".stats OFF BAD"
|
||||
} {1 {Usage: .stats ?on|off?}}
|
||||
} {1 {Usage: .stats ?on|off|stmt|vmstep?}}
|
||||
|
||||
# Ticket 7be932dfa60a8a6b3b26bcf7623ec46e0a403ddb 2018-06-07
|
||||
# Adverse interaction between .stats and .eqp
|
||||
|
||||
+1
-1
@@ -66,7 +66,7 @@ do_test shell4-1.3.3 {
|
||||
do_test shell4-1.3.4 {
|
||||
# too many arguments
|
||||
catchcmd "test.db" ".stats OFF BAD"
|
||||
} {1 {Usage: .stats ?on|off?}}
|
||||
} {1 {Usage: .stats ?on|off|stmt|vmstep?}}
|
||||
|
||||
# NB. whitespace is important
|
||||
do_test shell4-1.4.1 {
|
||||
|
||||
+66
-66
@@ -707,9 +707,9 @@ void testset_main(void){
|
||||
maxb = roundup_allones(sz);
|
||||
speedtest1_begin_test(100, "%d INSERTs into table with no index", n);
|
||||
speedtest1_exec("BEGIN");
|
||||
speedtest1_exec("CREATE%s TABLE t1(a INTEGER %s, b INTEGER %s, c TEXT %s);",
|
||||
speedtest1_exec("CREATE%s TABLE z1(a INTEGER %s, b INTEGER %s, c TEXT %s);",
|
||||
isTemp(9), g.zNN, g.zNN, g.zNN);
|
||||
speedtest1_prepare("INSERT INTO t1 VALUES(?1,?2,?3); -- %d times", n);
|
||||
speedtest1_prepare("INSERT INTO z1 VALUES(?1,?2,?3); -- %d times", n);
|
||||
for(i=1; i<=n; i++){
|
||||
x1 = swizzle(i,maxb);
|
||||
speedtest1_numbername(x1, zNum, sizeof(zNum));
|
||||
@@ -726,9 +726,9 @@ void testset_main(void){
|
||||
speedtest1_begin_test(110, "%d ordered INSERTS with one index/PK", n);
|
||||
speedtest1_exec("BEGIN");
|
||||
speedtest1_exec(
|
||||
"CREATE%s TABLE t2(a INTEGER %s %s, b INTEGER %s, c TEXT %s) %s",
|
||||
"CREATE%s TABLE z2(a INTEGER %s %s, b INTEGER %s, c TEXT %s) %s",
|
||||
isTemp(5), g.zNN, g.zPK, g.zNN, g.zNN, g.zWR);
|
||||
speedtest1_prepare("INSERT INTO t2 VALUES(?1,?2,?3); -- %d times", n);
|
||||
speedtest1_prepare("INSERT INTO z2 VALUES(?1,?2,?3); -- %d times", n);
|
||||
for(i=1; i<=n; i++){
|
||||
x1 = swizzle(i,maxb);
|
||||
speedtest1_numbername(x1, zNum, sizeof(zNum));
|
||||
@@ -768,7 +768,7 @@ void testset_main(void){
|
||||
speedtest1_begin_test(130, "%d SELECTS, numeric BETWEEN, unindexed", n);
|
||||
speedtest1_exec("BEGIN");
|
||||
speedtest1_prepare(
|
||||
"SELECT count(*), avg(b), sum(length(c)), group_concat(c) FROM t1\n"
|
||||
"SELECT count(*), avg(b), sum(length(c)), group_concat(c) FROM z1\n"
|
||||
" WHERE b BETWEEN ?1 AND ?2; -- %d times", n
|
||||
);
|
||||
for(i=1; i<=n; i++){
|
||||
@@ -788,7 +788,7 @@ void testset_main(void){
|
||||
speedtest1_begin_test(140, "%d SELECTS, LIKE, unindexed", n);
|
||||
speedtest1_exec("BEGIN");
|
||||
speedtest1_prepare(
|
||||
"SELECT count(*), avg(b), sum(length(c)), group_concat(c) FROM t1\n"
|
||||
"SELECT count(*), avg(b), sum(length(c)), group_concat(c) FROM z1\n"
|
||||
" WHERE c LIKE ?1; -- %d times", n
|
||||
);
|
||||
for(i=1; i<=n; i++){
|
||||
@@ -810,7 +810,7 @@ void testset_main(void){
|
||||
speedtest1_begin_test(142, "%d SELECTS w/ORDER BY, unindexed", n);
|
||||
speedtest1_exec("BEGIN");
|
||||
speedtest1_prepare(
|
||||
"SELECT a, b, c FROM t1 WHERE c LIKE ?1\n"
|
||||
"SELECT a, b, c FROM z1 WHERE c LIKE ?1\n"
|
||||
" ORDER BY a; -- %d times", n
|
||||
);
|
||||
for(i=1; i<=n; i++){
|
||||
@@ -831,7 +831,7 @@ void testset_main(void){
|
||||
speedtest1_begin_test(145, "%d SELECTS w/ORDER BY and LIMIT, unindexed", n);
|
||||
speedtest1_exec("BEGIN");
|
||||
speedtest1_prepare(
|
||||
"SELECT a, b, c FROM t1 WHERE c LIKE ?1\n"
|
||||
"SELECT a, b, c FROM z1 WHERE c LIKE ?1\n"
|
||||
" ORDER BY a LIMIT 10; -- %d times", n
|
||||
);
|
||||
for(i=1; i<=n; i++){
|
||||
@@ -851,10 +851,10 @@ void testset_main(void){
|
||||
|
||||
speedtest1_begin_test(150, "CREATE INDEX five times");
|
||||
speedtest1_exec("BEGIN;");
|
||||
speedtest1_exec("CREATE UNIQUE INDEX t1b ON t1(b);");
|
||||
speedtest1_exec("CREATE INDEX t1c ON t1(c);");
|
||||
speedtest1_exec("CREATE UNIQUE INDEX t2b ON t2(b);");
|
||||
speedtest1_exec("CREATE INDEX t2c ON t2(c DESC);");
|
||||
speedtest1_exec("CREATE UNIQUE INDEX t1b ON z1(b);");
|
||||
speedtest1_exec("CREATE INDEX t1c ON z1(c);");
|
||||
speedtest1_exec("CREATE UNIQUE INDEX t2b ON z2(b);");
|
||||
speedtest1_exec("CREATE INDEX t2c ON z2(c DESC);");
|
||||
speedtest1_exec("CREATE INDEX t3bc ON t3(b,c);");
|
||||
speedtest1_exec("COMMIT;");
|
||||
speedtest1_end_test();
|
||||
@@ -864,7 +864,7 @@ void testset_main(void){
|
||||
speedtest1_begin_test(160, "%d SELECTS, numeric BETWEEN, indexed", n);
|
||||
speedtest1_exec("BEGIN");
|
||||
speedtest1_prepare(
|
||||
"SELECT count(*), avg(b), sum(length(c)), group_concat(a) FROM t1\n"
|
||||
"SELECT count(*), avg(b), sum(length(c)), group_concat(a) FROM z1\n"
|
||||
" WHERE b BETWEEN ?1 AND ?2; -- %d times", n
|
||||
);
|
||||
for(i=1; i<=n; i++){
|
||||
@@ -884,7 +884,7 @@ void testset_main(void){
|
||||
speedtest1_begin_test(161, "%d SELECTS, numeric BETWEEN, PK", n);
|
||||
speedtest1_exec("BEGIN");
|
||||
speedtest1_prepare(
|
||||
"SELECT count(*), avg(b), sum(length(c)), group_concat(a) FROM t2\n"
|
||||
"SELECT count(*), avg(b), sum(length(c)), group_concat(a) FROM z2\n"
|
||||
" WHERE a BETWEEN ?1 AND ?2; -- %d times", n
|
||||
);
|
||||
for(i=1; i<=n; i++){
|
||||
@@ -904,7 +904,7 @@ void testset_main(void){
|
||||
speedtest1_begin_test(170, "%d SELECTS, text BETWEEN, indexed", n);
|
||||
speedtest1_exec("BEGIN");
|
||||
speedtest1_prepare(
|
||||
"SELECT count(*), avg(b), sum(length(c)), group_concat(a) FROM t1\n"
|
||||
"SELECT count(*), avg(b), sum(length(c)), group_concat(a) FROM z1\n"
|
||||
" WHERE c BETWEEN ?1 AND (?1||'~'); -- %d times", n
|
||||
);
|
||||
for(i=1; i<=n; i++){
|
||||
@@ -930,14 +930,14 @@ void testset_main(void){
|
||||
isTemp(1), g.zNN, g.zPK, g.zNN, g.zNN, g.zWR);
|
||||
speedtest1_exec("CREATE INDEX t4b ON t4(b)");
|
||||
speedtest1_exec("CREATE INDEX t4c ON t4(c)");
|
||||
speedtest1_exec("INSERT INTO t4 SELECT * FROM t1");
|
||||
speedtest1_exec("INSERT INTO t4 SELECT * FROM z1");
|
||||
speedtest1_exec("COMMIT");
|
||||
speedtest1_end_test();
|
||||
|
||||
n = sz;
|
||||
speedtest1_begin_test(190, "DELETE and REFILL one table", n);
|
||||
speedtest1_exec("DELETE FROM t2;");
|
||||
speedtest1_exec("INSERT INTO t2 SELECT * FROM t1;");
|
||||
speedtest1_exec("DELETE FROM z2;");
|
||||
speedtest1_exec("INSERT INTO z2 SELECT * FROM z1;");
|
||||
speedtest1_end_test();
|
||||
|
||||
|
||||
@@ -947,8 +947,8 @@ void testset_main(void){
|
||||
|
||||
|
||||
speedtest1_begin_test(210, "ALTER TABLE ADD COLUMN, and query");
|
||||
speedtest1_exec("ALTER TABLE t2 ADD COLUMN d DEFAULT 123");
|
||||
speedtest1_exec("SELECT sum(d) FROM t2");
|
||||
speedtest1_exec("ALTER TABLE z2 ADD COLUMN d DEFAULT 123");
|
||||
speedtest1_exec("SELECT sum(d) FROM z2");
|
||||
speedtest1_end_test();
|
||||
|
||||
|
||||
@@ -956,7 +956,7 @@ void testset_main(void){
|
||||
speedtest1_begin_test(230, "%d UPDATES, numeric BETWEEN, indexed", n);
|
||||
speedtest1_exec("BEGIN");
|
||||
speedtest1_prepare(
|
||||
"UPDATE t2 SET d=b*2 WHERE b BETWEEN ?1 AND ?2; -- %d times", n
|
||||
"UPDATE z2 SET d=b*2 WHERE b BETWEEN ?1 AND ?2; -- %d times", n
|
||||
);
|
||||
for(i=1; i<=n; i++){
|
||||
x1 = speedtest1_random()%maxb;
|
||||
@@ -973,7 +973,7 @@ void testset_main(void){
|
||||
speedtest1_begin_test(240, "%d UPDATES of individual rows", n);
|
||||
speedtest1_exec("BEGIN");
|
||||
speedtest1_prepare(
|
||||
"UPDATE t2 SET d=b*3 WHERE a=?1; -- %d times", n
|
||||
"UPDATE z2 SET d=b*3 WHERE a=?1; -- %d times", n
|
||||
);
|
||||
for(i=1; i<=n; i++){
|
||||
x1 = speedtest1_random()%sz + 1;
|
||||
@@ -984,12 +984,12 @@ void testset_main(void){
|
||||
speedtest1_end_test();
|
||||
|
||||
speedtest1_begin_test(250, "One big UPDATE of the whole %d-row table", sz);
|
||||
speedtest1_exec("UPDATE t2 SET d=b*4");
|
||||
speedtest1_exec("UPDATE z2 SET d=b*4");
|
||||
speedtest1_end_test();
|
||||
|
||||
|
||||
speedtest1_begin_test(260, "Query added column after filling");
|
||||
speedtest1_exec("SELECT sum(d) FROM t2");
|
||||
speedtest1_exec("SELECT sum(d) FROM z2");
|
||||
speedtest1_end_test();
|
||||
|
||||
|
||||
@@ -998,7 +998,7 @@ void testset_main(void){
|
||||
speedtest1_begin_test(270, "%d DELETEs, numeric BETWEEN, indexed", n);
|
||||
speedtest1_exec("BEGIN");
|
||||
speedtest1_prepare(
|
||||
"DELETE FROM t2 WHERE b BETWEEN ?1 AND ?2; -- %d times", n
|
||||
"DELETE FROM z2 WHERE b BETWEEN ?1 AND ?2; -- %d times", n
|
||||
);
|
||||
for(i=1; i<=n; i++){
|
||||
x1 = speedtest1_random()%maxb + 1;
|
||||
@@ -1027,16 +1027,16 @@ void testset_main(void){
|
||||
|
||||
|
||||
speedtest1_begin_test(290, "Refill two %d-row tables using REPLACE", sz);
|
||||
speedtest1_exec("REPLACE INTO t2(a,b,c) SELECT a,b,c FROM t1");
|
||||
speedtest1_exec("REPLACE INTO t3(a,b,c) SELECT a,b,c FROM t1");
|
||||
speedtest1_exec("REPLACE INTO z2(a,b,c) SELECT a,b,c FROM z1");
|
||||
speedtest1_exec("REPLACE INTO t3(a,b,c) SELECT a,b,c FROM z1");
|
||||
speedtest1_end_test();
|
||||
|
||||
speedtest1_begin_test(300, "Refill a %d-row table using (b&1)==(a&1)", sz);
|
||||
speedtest1_exec("DELETE FROM t2;");
|
||||
speedtest1_exec("INSERT INTO t2(a,b,c)\n"
|
||||
" SELECT a,b,c FROM t1 WHERE (b&1)==(a&1);");
|
||||
speedtest1_exec("INSERT INTO t2(a,b,c)\n"
|
||||
" SELECT a,b,c FROM t1 WHERE (b&1)<>(a&1);");
|
||||
speedtest1_exec("DELETE FROM z2;");
|
||||
speedtest1_exec("INSERT INTO z2(a,b,c)\n"
|
||||
" SELECT a,b,c FROM z1 WHERE (b&1)==(a&1);");
|
||||
speedtest1_exec("INSERT INTO z2(a,b,c)\n"
|
||||
" SELECT a,b,c FROM z1 WHERE (b&1)<>(a&1);");
|
||||
speedtest1_end_test();
|
||||
|
||||
|
||||
@@ -1044,11 +1044,11 @@ void testset_main(void){
|
||||
speedtest1_begin_test(310, "%d four-ways joins", n);
|
||||
speedtest1_exec("BEGIN");
|
||||
speedtest1_prepare(
|
||||
"SELECT t1.c FROM t1, t2, t3, t4\n"
|
||||
"SELECT z1.c FROM z1, z2, t3, t4\n"
|
||||
" WHERE t4.a BETWEEN ?1 AND ?2\n"
|
||||
" AND t3.a=t4.b\n"
|
||||
" AND t2.a=t3.b\n"
|
||||
" AND t1.c=t2.c"
|
||||
" AND z2.a=t3.b\n"
|
||||
" AND z1.c=z2.c"
|
||||
);
|
||||
for(i=1; i<=n; i++){
|
||||
x1 = speedtest1_random()%sz + 1;
|
||||
@@ -1063,8 +1063,8 @@ void testset_main(void){
|
||||
speedtest1_begin_test(320, "subquery in result set", n);
|
||||
speedtest1_prepare(
|
||||
"SELECT sum(a), max(c),\n"
|
||||
" avg((SELECT a FROM t2 WHERE 5+t2.b=t1.b) AND rowid<?1), max(c)\n"
|
||||
" FROM t1 WHERE rowid<?1;"
|
||||
" avg((SELECT a FROM z2 WHERE 5+z2.b=z1.b) AND rowid<?1), max(c)\n"
|
||||
" FROM z1 WHERE rowid<?1;"
|
||||
);
|
||||
sqlite3_bind_int(g.pStmt, 1, est_square_root(g.szTest)*50);
|
||||
speedtest1_run();
|
||||
@@ -1282,10 +1282,10 @@ void testset_cte(void){
|
||||
speedtest1_begin_test(400, "EXCEPT operator on %d-element tables", nElem);
|
||||
speedtest1_prepare(
|
||||
"WITH RECURSIVE \n"
|
||||
" t1(x) AS (VALUES(2) UNION ALL SELECT x+2 FROM t1 WHERE x<%d),\n"
|
||||
" t2(y) AS (VALUES(3) UNION ALL SELECT y+3 FROM t2 WHERE y<%d)\n"
|
||||
" z1(x) AS (VALUES(2) UNION ALL SELECT x+2 FROM z1 WHERE x<%d),\n"
|
||||
" z2(y) AS (VALUES(3) UNION ALL SELECT y+3 FROM z2 WHERE y<%d)\n"
|
||||
"SELECT count(x), avg(x) FROM (\n"
|
||||
" SELECT x FROM t1 EXCEPT SELECT y FROM t2 ORDER BY 1\n"
|
||||
" SELECT x FROM z1 EXCEPT SELECT y FROM z2 ORDER BY 1\n"
|
||||
");",
|
||||
nElem, nElem
|
||||
);
|
||||
@@ -1318,9 +1318,9 @@ void testset_fp(void){
|
||||
n = g.szTest*5000;
|
||||
speedtest1_begin_test(100, "Fill a table with %d FP values", n*2);
|
||||
speedtest1_exec("BEGIN");
|
||||
speedtest1_exec("CREATE%s TABLE t1(a REAL %s, b REAL %s);",
|
||||
speedtest1_exec("CREATE%s TABLE z1(a REAL %s, b REAL %s);",
|
||||
isTemp(1), g.zNN, g.zNN);
|
||||
speedtest1_prepare("INSERT INTO t1 VALUES(?1,?2); -- %d times", n);
|
||||
speedtest1_prepare("INSERT INTO z1 VALUES(?1,?2); -- %d times", n);
|
||||
for(i=1; i<=n; i++){
|
||||
speedtest1_random_ascii_fp(zFP1);
|
||||
speedtest1_random_ascii_fp(zFP2);
|
||||
@@ -1333,7 +1333,7 @@ void testset_fp(void){
|
||||
|
||||
n = g.szTest/25 + 2;
|
||||
speedtest1_begin_test(110, "%d range queries", n);
|
||||
speedtest1_prepare("SELECT sum(b) FROM t1 WHERE a BETWEEN ?1 AND ?2");
|
||||
speedtest1_prepare("SELECT sum(b) FROM z1 WHERE a BETWEEN ?1 AND ?2");
|
||||
for(i=1; i<=n; i++){
|
||||
speedtest1_random_ascii_fp(zFP1);
|
||||
speedtest1_random_ascii_fp(zFP2);
|
||||
@@ -1345,15 +1345,15 @@ void testset_fp(void){
|
||||
|
||||
speedtest1_begin_test(120, "CREATE INDEX three times");
|
||||
speedtest1_exec("BEGIN;");
|
||||
speedtest1_exec("CREATE INDEX t1a ON t1(a);");
|
||||
speedtest1_exec("CREATE INDEX t1b ON t1(b);");
|
||||
speedtest1_exec("CREATE INDEX t1ab ON t1(a,b);");
|
||||
speedtest1_exec("CREATE INDEX t1a ON z1(a);");
|
||||
speedtest1_exec("CREATE INDEX t1b ON z1(b);");
|
||||
speedtest1_exec("CREATE INDEX t1ab ON z1(a,b);");
|
||||
speedtest1_exec("COMMIT;");
|
||||
speedtest1_end_test();
|
||||
|
||||
n = g.szTest/3 + 2;
|
||||
speedtest1_begin_test(130, "%d indexed range queries", n);
|
||||
speedtest1_prepare("SELECT sum(b) FROM t1 WHERE a BETWEEN ?1 AND ?2");
|
||||
speedtest1_prepare("SELECT sum(b) FROM z1 WHERE a BETWEEN ?1 AND ?2");
|
||||
for(i=1; i<=n; i++){
|
||||
speedtest1_random_ascii_fp(zFP1);
|
||||
speedtest1_random_ascii_fp(zFP2);
|
||||
@@ -1365,14 +1365,14 @@ void testset_fp(void){
|
||||
|
||||
n = g.szTest*5000;
|
||||
speedtest1_begin_test(140, "%d calls to round()", n);
|
||||
speedtest1_exec("SELECT sum(round(a,2)+round(b,4)) FROM t1;");
|
||||
speedtest1_exec("SELECT sum(round(a,2)+round(b,4)) FROM z1;");
|
||||
speedtest1_end_test();
|
||||
|
||||
|
||||
speedtest1_begin_test(150, "%d printf() calls", n*4);
|
||||
speedtest1_exec(
|
||||
"WITH c(fmt) AS (VALUES('%%g'),('%%e'),('%%!g'),('%%.20f'))"
|
||||
"SELECT sum(printf(fmt,a)) FROM t1, c"
|
||||
"SELECT sum(printf(fmt,a)) FROM z1, c"
|
||||
);
|
||||
speedtest1_end_test();
|
||||
}
|
||||
@@ -1458,8 +1458,8 @@ void testset_rtree(int p1, int p2){
|
||||
speedtest1_end_test();
|
||||
|
||||
speedtest1_begin_test(101, "Copy from rtree to a regular table");
|
||||
speedtest1_exec("CREATE TABLE t1(id INTEGER PRIMARY KEY,x0,x1,y0,y1,z0,z1)");
|
||||
speedtest1_exec("INSERT INTO t1 SELECT * FROM rt1");
|
||||
speedtest1_exec("CREATE TABLE z1(id INTEGER PRIMARY KEY,x0,x1,y0,y1,z0,z1)");
|
||||
speedtest1_exec("INSERT INTO z1 SELECT * FROM rt1");
|
||||
speedtest1_end_test();
|
||||
|
||||
n = g.szTest*200;
|
||||
@@ -1477,7 +1477,7 @@ void testset_rtree(int p1, int p2){
|
||||
if( g.bVerify ){
|
||||
n = g.szTest*200;
|
||||
speedtest1_begin_test(111, "Verify result from 1-D intersect slice queries");
|
||||
speedtest1_prepare("SELECT count(*) FROM t1 WHERE x0>=?1 AND x1<=?2");
|
||||
speedtest1_prepare("SELECT count(*) FROM z1 WHERE x0>=?1 AND x1<=?2");
|
||||
iStep = mxCoord/n;
|
||||
for(i=0; i<n; i++){
|
||||
sqlite3_bind_int(g.pStmt, 1, i*iStep);
|
||||
@@ -1506,7 +1506,7 @@ void testset_rtree(int p1, int p2){
|
||||
if( g.bVerify ){
|
||||
n = g.szTest*200;
|
||||
speedtest1_begin_test(121, "Verify result from 1-D overlap slice queries");
|
||||
speedtest1_prepare("SELECT count(*) FROM t1 WHERE y1>=?1 AND y0<=?2");
|
||||
speedtest1_prepare("SELECT count(*) FROM z1 WHERE y1>=?1 AND y0<=?2");
|
||||
iStep = mxCoord/n;
|
||||
for(i=0; i<n; i++){
|
||||
sqlite3_bind_int(g.pStmt, 1, i*iStep);
|
||||
@@ -1602,7 +1602,7 @@ void testset_rtree(int p1, int p2){
|
||||
speedtest1_end_test();
|
||||
|
||||
speedtest1_begin_test(170, "Restore deleted entries using INSERT OR IGNORE");
|
||||
speedtest1_exec("INSERT OR IGNORE INTO rt1 SELECT * FROM t1");
|
||||
speedtest1_exec("INSERT OR IGNORE INTO rt1 SELECT * FROM z1");
|
||||
speedtest1_end_test();
|
||||
}
|
||||
#endif /* SQLITE_ENABLE_RTREE */
|
||||
@@ -1887,11 +1887,11 @@ void testset_trigger(void){
|
||||
|
||||
speedtest1_exec(
|
||||
"BEGIN;"
|
||||
"CREATE TABLE t1(rowid INTEGER PRIMARY KEY, i INTEGER, t TEXT);"
|
||||
"CREATE TABLE t2(rowid INTEGER PRIMARY KEY, i INTEGER, t TEXT);"
|
||||
"CREATE TABLE z1(rowid INTEGER PRIMARY KEY, i INTEGER, t TEXT);"
|
||||
"CREATE TABLE z2(rowid INTEGER PRIMARY KEY, i INTEGER, t TEXT);"
|
||||
"CREATE TABLE t3(rowid INTEGER PRIMARY KEY, i INTEGER, t TEXT);"
|
||||
"CREATE VIEW v1 AS SELECT rowid, i, t FROM t1;"
|
||||
"CREATE VIEW v2 AS SELECT rowid, i, t FROM t2;"
|
||||
"CREATE VIEW v1 AS SELECT rowid, i, t FROM z1;"
|
||||
"CREATE VIEW v2 AS SELECT rowid, i, t FROM z2;"
|
||||
"CREATE VIEW v3 AS SELECT rowid, i, t FROM t3;"
|
||||
);
|
||||
for(jj=1; jj<=3; jj++){
|
||||
@@ -1905,22 +1905,22 @@ void testset_trigger(void){
|
||||
}
|
||||
}
|
||||
speedtest1_exec(
|
||||
"CREATE INDEX i1 ON t1(t);"
|
||||
"CREATE INDEX i2 ON t2(t);"
|
||||
"CREATE INDEX i1 ON z1(t);"
|
||||
"CREATE INDEX i2 ON z2(t);"
|
||||
"CREATE INDEX i3 ON t3(t);"
|
||||
"COMMIT;"
|
||||
);
|
||||
|
||||
speedtest1_begin_test(100, "speed4p-join1");
|
||||
speedtest1_prepare(
|
||||
"SELECT * FROM t1, t2, t3 WHERE t1.oid = t2.oid AND t2.oid = t3.oid"
|
||||
"SELECT * FROM z1, z2, t3 WHERE z1.oid = z2.oid AND z2.oid = t3.oid"
|
||||
);
|
||||
speedtest1_run();
|
||||
speedtest1_end_test();
|
||||
|
||||
speedtest1_begin_test(110, "speed4p-join2");
|
||||
speedtest1_prepare(
|
||||
"SELECT * FROM t1, t2, t3 WHERE t1.t = t2.t AND t2.t = t3.t"
|
||||
"SELECT * FROM z1, z2, t3 WHERE z1.t = z2.t AND z2.t = t3.t"
|
||||
);
|
||||
speedtest1_run();
|
||||
speedtest1_end_test();
|
||||
@@ -1957,8 +1957,8 @@ void testset_trigger(void){
|
||||
|
||||
speedtest1_begin_test(150, "speed4p-subselect1");
|
||||
speedtest1_prepare("SELECT "
|
||||
"(SELECT t FROM t1 WHERE rowid = ?1),"
|
||||
"(SELECT t FROM t2 WHERE rowid = ?1),"
|
||||
"(SELECT t FROM z1 WHERE rowid = ?1),"
|
||||
"(SELECT t FROM z2 WHERE rowid = ?1),"
|
||||
"(SELECT t FROM t3 WHERE rowid = ?1)"
|
||||
);
|
||||
for(jj=0; jj<NROW2; jj++){
|
||||
@@ -1969,7 +1969,7 @@ void testset_trigger(void){
|
||||
|
||||
speedtest1_begin_test(160, "speed4p-rowid-update");
|
||||
speedtest1_exec("BEGIN");
|
||||
speedtest1_prepare("UPDATE t1 SET i=i+1 WHERE rowid=?1");
|
||||
speedtest1_prepare("UPDATE z1 SET i=i+1 WHERE rowid=?1");
|
||||
for(jj=0; jj<NROW2; jj++){
|
||||
sqlite3_bind_int(g.pStmt, 1, jj);
|
||||
speedtest1_run();
|
||||
@@ -1979,7 +1979,7 @@ void testset_trigger(void){
|
||||
|
||||
speedtest1_exec("CREATE TABLE t5(t TEXT PRIMARY KEY, i INTEGER);");
|
||||
speedtest1_begin_test(170, "speed4p-insert-ignore");
|
||||
speedtest1_exec("INSERT OR IGNORE INTO t5 SELECT t, i FROM t1");
|
||||
speedtest1_exec("INSERT OR IGNORE INTO t5 SELECT t, i FROM z1");
|
||||
speedtest1_end_test();
|
||||
|
||||
speedtest1_exec(
|
||||
|
||||
+628
@@ -0,0 +1,628 @@
|
||||
/*
|
||||
** 2021-01-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.
|
||||
**
|
||||
*************************************************************************
|
||||
**
|
||||
** This file implements a program used to measure the start-up performance
|
||||
** of SQLite.
|
||||
**
|
||||
** To use:
|
||||
**
|
||||
** ./startup init
|
||||
** valgrind --tool=cachegrind ./startup run
|
||||
**
|
||||
**
|
||||
** The "./startup init" command creates the test database file named
|
||||
** "startup.db". The performance test is run by the "./startup run"
|
||||
** command. That command does nothing but open the database file and
|
||||
** parse the entire schema.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include "sqlite3.h"
|
||||
|
||||
static const char zHelp[] =
|
||||
"Usage: %s COMMAND\n"
|
||||
"Commands:\n"
|
||||
" init Initialized the startup.db database file\n"
|
||||
" run Run the startup performance test\n"
|
||||
"Options:\n"
|
||||
" --dbname NAME Set the name of the test database file\n"
|
||||
" --heap SZ MIN Memory allocator uses SZ bytes & min allocation MIN\n"
|
||||
" --stats Show statistics at the end\n"
|
||||
/* TBD
|
||||
" --journal M Set the journal_mode to M\n"
|
||||
" --lookaside N SZ Configure lookaside for N slots of SZ bytes each\n"
|
||||
" --mmap SZ MMAP the first SZ bytes of the database file\n"
|
||||
" --multithread Set multithreaded mode\n"
|
||||
" --nomemstat Disable memory statistics\n"
|
||||
" --pagesize N Set the page size to N\n"
|
||||
" --pcache N SZ Configure N pages of pagecache each of size SZ bytes\n"
|
||||
" --serialized Set serialized threading mode\n"
|
||||
" --singlethread Set single-threaded mode - disables all mutexing\n"
|
||||
" --utf16be Set text encoding to UTF-16BE\n"
|
||||
" --utf16le Set text encoding to UTF-16LE\n"
|
||||
" --utf8 Set text encoding to UTF-8\n"
|
||||
*/
|
||||
;
|
||||
|
||||
static void usage(const char *argv0){
|
||||
printf(zHelp, argv0);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/*
|
||||
** The test schema is derived from the Fossil repository for SQLite itself.
|
||||
** The schema covers the repository, the local checkout database, and
|
||||
** the global configuration database.
|
||||
*/
|
||||
static const char zTestSchema[] =
|
||||
"CREATE TABLE repo_blob(\n"
|
||||
" rid INTEGER PRIMARY KEY,\n"
|
||||
" rcvid INTEGER,\n"
|
||||
" size INTEGER,\n"
|
||||
" uuid TEXT UNIQUE NOT NULL,\n"
|
||||
" content BLOB,\n"
|
||||
" CHECK( length(uuid)>=40 AND rid>0 )\n"
|
||||
");\n"
|
||||
"CREATE TABLE repo_delta(\n"
|
||||
" rid INTEGER PRIMARY KEY,\n"
|
||||
" srcid INTEGER NOT NULL REFERENCES blob\n"
|
||||
");\n"
|
||||
"CREATE TABLE repo_rcvfrom(\n"
|
||||
" rcvid INTEGER PRIMARY KEY,\n"
|
||||
" uid INTEGER REFERENCES user,\n"
|
||||
" mtime DATETIME,\n"
|
||||
" nonce TEXT UNIQUE,\n"
|
||||
" ipaddr TEXT\n"
|
||||
");\n"
|
||||
"CREATE TABLE repo_private(rid INTEGER PRIMARY KEY);\n"
|
||||
"CREATE TABLE repo_accesslog(\n"
|
||||
" uname TEXT,\n"
|
||||
" ipaddr TEXT,\n"
|
||||
" success BOOLEAN,\n"
|
||||
" mtime TIMESTAMP);\n"
|
||||
"CREATE TABLE repo_user(\n"
|
||||
" uid INTEGER PRIMARY KEY,\n"
|
||||
" login TEXT UNIQUE,\n"
|
||||
" pw TEXT,\n"
|
||||
" cap TEXT,\n"
|
||||
" cookie TEXT,\n"
|
||||
" ipaddr TEXT,\n"
|
||||
" cexpire DATETIME,\n"
|
||||
" info TEXT,\n"
|
||||
" mtime DATE,\n"
|
||||
" photo BLOB\n"
|
||||
");\n"
|
||||
"CREATE TABLE repo_reportfmt(\n"
|
||||
" rn INTEGER PRIMARY KEY,\n"
|
||||
" owner TEXT,\n"
|
||||
" title TEXT UNIQUE,\n"
|
||||
" mtime INTEGER,\n"
|
||||
" cols TEXT,\n"
|
||||
" sqlcode TEXT\n"
|
||||
");\n"
|
||||
"CREATE TABLE repo_sqlite_stat2(tbl,idx,sampleno,sample);\n"
|
||||
"CREATE TABLE repo_sqlite_stat1(tbl,idx,stat);\n"
|
||||
"CREATE TABLE repo_sqlite_stat3(tbl,idx,neq,nlt,ndlt,sample);\n"
|
||||
"CREATE TABLE repo_config(\n"
|
||||
" name TEXT PRIMARY KEY NOT NULL,\n"
|
||||
" value CLOB, mtime INTEGER,\n"
|
||||
" CHECK( typeof(name)='text' AND length(name)>=1 )\n"
|
||||
") WITHOUT ROWID;\n"
|
||||
"CREATE TABLE repo_shun(uuid PRIMARY KEY,\n"
|
||||
" mtime INTEGER,\n"
|
||||
" scom TEXT) WITHOUT ROWID;\n"
|
||||
"CREATE TABLE repo_concealed(\n"
|
||||
" hash TEXT PRIMARY KEY,\n"
|
||||
" content TEXT\n"
|
||||
", mtime INTEGER) WITHOUT ROWID;\n"
|
||||
"CREATE TABLE repo_admin_log(\n"
|
||||
" id INTEGER PRIMARY KEY,\n"
|
||||
" time INTEGER, -- Seconds since 1970\n"
|
||||
" page TEXT, -- path of page\n"
|
||||
" who TEXT, -- User who made the change\n"
|
||||
" what TEXT -- What changed\n"
|
||||
");\n"
|
||||
"CREATE TABLE repo_unversioned(\n"
|
||||
" name TEXT PRIMARY KEY,\n"
|
||||
" rcvid INTEGER,\n"
|
||||
" mtime DATETIME,\n"
|
||||
" hash TEXT,\n"
|
||||
" sz INTEGER,\n"
|
||||
" encoding INT,\n"
|
||||
" content BLOB\n"
|
||||
") WITHOUT ROWID;\n"
|
||||
"CREATE TABLE repo_subscriber(\n"
|
||||
" subscriberId INTEGER PRIMARY KEY,\n"
|
||||
" subscriberCode BLOB DEFAULT (randomblob(32)) UNIQUE,\n"
|
||||
" semail TEXT UNIQUE COLLATE nocase,\n"
|
||||
" suname TEXT,\n"
|
||||
" sverified BOOLEAN DEFAULT true,\n"
|
||||
" sdonotcall BOOLEAN,\n"
|
||||
" sdigest BOOLEAN,\n"
|
||||
" ssub TEXT,\n"
|
||||
" sctime INTDATE,\n"
|
||||
" mtime INTDATE,\n"
|
||||
" smip TEXT\n"
|
||||
");\n"
|
||||
"CREATE TABLE repo_pending_alert(\n"
|
||||
" eventid TEXT PRIMARY KEY,\n"
|
||||
" sentSep BOOLEAN DEFAULT false,\n"
|
||||
" sentDigest BOOLEAN DEFAULT false\n"
|
||||
", sentMod BOOLEAN DEFAULT false) WITHOUT ROWID;\n"
|
||||
"CREATE INDEX repo_delta_i1 ON repo_delta(srcid);\n"
|
||||
"CREATE INDEX repo_blob_rcvid ON repo_blob(rcvid);\n"
|
||||
"CREATE INDEX repo_subscriberUname\n"
|
||||
" ON repo_subscriber(suname) WHERE suname IS NOT NULL;\n"
|
||||
"CREATE VIEW repo_artifact(rid,rcvid,size,atype,srcid,hash,content) AS\n"
|
||||
" SELECT blob.rid,rcvid,size,1,srcid,uuid,content\n"
|
||||
" FROM repo_blob LEFT JOIN repo_delta ON (blob.rid=delta.rid);\n"
|
||||
"CREATE TABLE repo_filename(\n"
|
||||
" fnid INTEGER PRIMARY KEY,\n"
|
||||
" name TEXT UNIQUE\n"
|
||||
");\n"
|
||||
"CREATE TABLE repo_mlink(\n"
|
||||
" mid INTEGER,\n"
|
||||
" fid INTEGER,\n"
|
||||
" pmid INTEGER,\n"
|
||||
" pid INTEGER,\n"
|
||||
" fnid INTEGER REFERENCES filename,\n"
|
||||
" pfnid INTEGER,\n"
|
||||
" mperm INTEGER,\n"
|
||||
" isaux BOOLEAN DEFAULT 0\n"
|
||||
");\n"
|
||||
"CREATE INDEX repo_mlink_i1 ON repo_mlink(mid);\n"
|
||||
"CREATE INDEX repo_mlink_i2 ON repo_mlink(fnid);\n"
|
||||
"CREATE INDEX repo_mlink_i3 ON repo_mlink(fid);\n"
|
||||
"CREATE INDEX repo_mlink_i4 ON repo_mlink(pid);\n"
|
||||
"CREATE TABLE repo_plink(\n"
|
||||
" pid INTEGER REFERENCES blob,\n"
|
||||
" cid INTEGER REFERENCES blob,\n"
|
||||
" isprim BOOLEAN,\n"
|
||||
" mtime DATETIME,\n"
|
||||
" baseid INTEGER REFERENCES blob,\n"
|
||||
" UNIQUE(pid, cid)\n"
|
||||
");\n"
|
||||
"CREATE INDEX repo_plink_i2 ON repo_plink(cid,pid);\n"
|
||||
"CREATE TABLE repo_leaf(rid INTEGER PRIMARY KEY);\n"
|
||||
"CREATE TABLE repo_event(\n"
|
||||
" type TEXT,\n"
|
||||
" mtime DATETIME,\n"
|
||||
" objid INTEGER PRIMARY KEY,\n"
|
||||
" tagid INTEGER,\n"
|
||||
" uid INTEGER REFERENCES user,\n"
|
||||
" bgcolor TEXT,\n"
|
||||
" euser TEXT,\n"
|
||||
" user TEXT,\n"
|
||||
" ecomment TEXT,\n"
|
||||
" comment TEXT,\n"
|
||||
" brief TEXT,\n"
|
||||
" omtime DATETIME\n"
|
||||
");\n"
|
||||
"CREATE INDEX repo_event_i1 ON repo_event(mtime);\n"
|
||||
"CREATE TABLE repo_phantom(\n"
|
||||
" rid INTEGER PRIMARY KEY\n"
|
||||
");\n"
|
||||
"CREATE TABLE repo_orphan(\n"
|
||||
" rid INTEGER PRIMARY KEY,\n"
|
||||
" baseline INTEGER\n"
|
||||
");\n"
|
||||
"CREATE INDEX repo_orphan_baseline ON repo_orphan(baseline);\n"
|
||||
"CREATE TABLE repo_unclustered(\n"
|
||||
" rid INTEGER PRIMARY KEY\n"
|
||||
");\n"
|
||||
"CREATE TABLE repo_unsent(\n"
|
||||
" rid INTEGER PRIMARY KEY\n"
|
||||
");\n"
|
||||
"CREATE TABLE repo_tag(\n"
|
||||
" tagid INTEGER PRIMARY KEY,\n"
|
||||
" tagname TEXT UNIQUE\n"
|
||||
");\n"
|
||||
"CREATE TABLE repo_tagxref(\n"
|
||||
" tagid INTEGER REFERENCES tag,\n"
|
||||
" tagtype INTEGER,\n"
|
||||
" srcid INTEGER REFERENCES blob,\n"
|
||||
" origid INTEGER REFERENCES blob,\n"
|
||||
" value TEXT,\n"
|
||||
" mtime TIMESTAMP,\n"
|
||||
" rid INTEGER REFERENCE blob,\n"
|
||||
" UNIQUE(rid, tagid)\n"
|
||||
");\n"
|
||||
"CREATE INDEX repo_tagxref_i1 ON repo_tagxref(tagid, mtime);\n"
|
||||
"CREATE TABLE repo_backlink(\n"
|
||||
" target TEXT,\n"
|
||||
" srctype INT,\n"
|
||||
" srcid INT,\n"
|
||||
" mtime TIMESTAMP,\n"
|
||||
" UNIQUE(target, srctype, srcid)\n"
|
||||
");\n"
|
||||
"CREATE INDEX repo_backlink_src ON repo_backlink(srcid, srctype);\n"
|
||||
"CREATE TABLE repo_attachment(\n"
|
||||
" attachid INTEGER PRIMARY KEY,\n"
|
||||
" isLatest BOOLEAN DEFAULT 0,\n"
|
||||
" mtime TIMESTAMP,\n"
|
||||
" src TEXT,\n"
|
||||
" target TEXT,\n"
|
||||
" filename TEXT,\n"
|
||||
" comment TEXT,\n"
|
||||
" user TEXT\n"
|
||||
");\n"
|
||||
"CREATE INDEX repo_attachment_idx1\n"
|
||||
" ON repo_attachment(target, filename, mtime);\n"
|
||||
"CREATE INDEX repo_attachment_idx2 ON repo_attachment(src);\n"
|
||||
"CREATE TABLE repo_cherrypick(\n"
|
||||
" parentid INT,\n"
|
||||
" childid INT,\n"
|
||||
" isExclude BOOLEAN DEFAULT false,\n"
|
||||
" PRIMARY KEY(parentid, childid)\n"
|
||||
") WITHOUT ROWID;\n"
|
||||
"CREATE INDEX repo_cherrypick_cid ON repo_cherrypick(childid);\n"
|
||||
"CREATE TABLE repo_ticket(\n"
|
||||
" -- Do not change any column that begins with tkt_\n"
|
||||
" tkt_id INTEGER PRIMARY KEY,\n"
|
||||
" tkt_uuid TEXT UNIQUE,\n"
|
||||
" tkt_mtime DATE,\n"
|
||||
" tkt_ctime DATE,\n"
|
||||
" -- Add as many fields as required below this line\n"
|
||||
" type TEXT,\n"
|
||||
" status TEXT,\n"
|
||||
" subsystem TEXT,\n"
|
||||
" priority TEXT,\n"
|
||||
" severity TEXT,\n"
|
||||
" foundin TEXT,\n"
|
||||
" private_contact TEXT,\n"
|
||||
" resolution TEXT,\n"
|
||||
" title TEXT,\n"
|
||||
" comment TEXT\n"
|
||||
");\n"
|
||||
"CREATE TABLE repo_ticketchng(\n"
|
||||
" -- Do not change any column that begins with tkt_\n"
|
||||
" tkt_id INTEGER REFERENCES ticket,\n"
|
||||
" tkt_rid INTEGER REFERENCES blob,\n"
|
||||
" tkt_mtime DATE,\n"
|
||||
" -- Add as many fields as required below this line\n"
|
||||
" login TEXT,\n"
|
||||
" username TEXT,\n"
|
||||
" mimetype TEXT,\n"
|
||||
" icomment TEXT\n"
|
||||
");\n"
|
||||
"CREATE INDEX repo_ticketchng_idx1 ON repo_ticketchng(tkt_id, tkt_mtime);\n"
|
||||
"CREATE TRIGGER repo_alert_trigger1\n"
|
||||
"AFTER INSERT ON repo_event BEGIN\n"
|
||||
" INSERT INTO repo_pending_alert(eventid)\n"
|
||||
" SELECT printf('%.1c%d',new.type,new.objid) WHERE true\n"
|
||||
" ON CONFLICT(eventId) DO NOTHING;\n"
|
||||
"END;\n"
|
||||
"CREATE TABLE repo_vcache(\n"
|
||||
" vid INTEGER, -- check-in ID\n"
|
||||
" fname TEXT, -- filename\n"
|
||||
" rid INTEGER, -- artifact ID\n"
|
||||
" PRIMARY KEY(vid,fname)\n"
|
||||
") WITHOUT ROWID;\n"
|
||||
"CREATE TABLE localdb_vvar(\n"
|
||||
" name TEXT PRIMARY KEY NOT NULL,\n"
|
||||
" value CLOB,\n"
|
||||
" CHECK( typeof(name)='text' AND length(name)>=1 )\n"
|
||||
");\n"
|
||||
"CREATE TABLE localdb_vfile(\n"
|
||||
" id INTEGER PRIMARY KEY,\n"
|
||||
" vid INTEGER REFERENCES blob,\n"
|
||||
" chnged INT DEFAULT 0,\n"
|
||||
" deleted BOOLEAN DEFAULT 0,\n"
|
||||
" isexe BOOLEAN,\n"
|
||||
" islink BOOLEAN,\n"
|
||||
" rid INTEGER,\n"
|
||||
" mrid INTEGER,\n"
|
||||
" mtime INTEGER,\n"
|
||||
" pathname TEXT,\n"
|
||||
" origname TEXT, mhash,\n"
|
||||
" UNIQUE(pathname,vid)\n"
|
||||
");\n"
|
||||
"CREATE TABLE localdb_sqlite_stat1(tbl,idx,stat);\n"
|
||||
"CREATE TABLE localdb_vcache(\n"
|
||||
" vid INTEGER, -- check-in ID\n"
|
||||
" fname TEXT, -- filename\n"
|
||||
" rid INTEGER, -- artifact ID\n"
|
||||
" PRIMARY KEY(vid,fname)\n"
|
||||
") WITHOUT ROWID;\n"
|
||||
"CREATE TABLE localdb_stash(\n"
|
||||
" stashid INTEGER PRIMARY KEY,\n"
|
||||
" vid INTEGER,\n"
|
||||
" hash TEXT,\n"
|
||||
" comment TEXT,\n"
|
||||
" ctime TIMESTAMP\n"
|
||||
");\n"
|
||||
"CREATE TABLE localdb_stashfile(\n"
|
||||
" stashid INTEGER REFERENCES stash,\n"
|
||||
" isAdded BOOLEAN,\n"
|
||||
" isRemoved BOOLEAN,\n"
|
||||
" isExec BOOLEAN,\n"
|
||||
" isLink BOOLEAN,\n"
|
||||
" rid INTEGER,\n"
|
||||
" hash TEXT,\n"
|
||||
" origname TEXT,\n"
|
||||
" newname TEXT,\n"
|
||||
" delta BLOB,\n"
|
||||
" PRIMARY KEY(newname, stashid)\n"
|
||||
");\n"
|
||||
"CREATE TABLE localdb_vmerge(\n"
|
||||
" id INTEGER REFERENCES vfile,\n"
|
||||
" merge INTEGER,\n"
|
||||
" mhash TEXT\n"
|
||||
");\n"
|
||||
"CREATE UNIQUE INDEX localdb_vmergex1 ON localdb_vmerge(id,mhash);\n"
|
||||
"CREATE TRIGGER localdb_vmerge_ck1 AFTER INSERT ON localdb_vmerge\n"
|
||||
"WHEN new.mhash IS NULL BEGIN\n"
|
||||
" SELECT raise(FAIL,\n"
|
||||
" 'trying to update a newer checkout with an older version of Fossil');\n"
|
||||
"END;\n"
|
||||
"CREATE TABLE configdb_global_config(\n"
|
||||
" name TEXT PRIMARY KEY,\n"
|
||||
" value TEXT\n"
|
||||
");\n"
|
||||
"CREATE TABLE configdb_sqlite_stat1(tbl,idx,stat);\n"
|
||||
;
|
||||
|
||||
#ifdef __linux__
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/*
|
||||
** Attempt to display I/O stats on Linux using /proc/PID/io
|
||||
*/
|
||||
static void displayLinuxIoStats(FILE *out){
|
||||
FILE *in;
|
||||
char z[200];
|
||||
sqlite3_snprintf(sizeof(z), z, "/proc/%d/io", getpid());
|
||||
in = fopen(z, "rb");
|
||||
if( in==0 ) return;
|
||||
while( fgets(z, sizeof(z), in)!=0 ){
|
||||
static const struct {
|
||||
const char *zPattern;
|
||||
const char *zDesc;
|
||||
} aTrans[] = {
|
||||
{ "rchar: ", "Bytes received by read():" },
|
||||
{ "wchar: ", "Bytes sent to write():" },
|
||||
{ "syscr: ", "Read() system calls:" },
|
||||
{ "syscw: ", "Write() system calls:" },
|
||||
{ "read_bytes: ", "Bytes rcvd from storage:" },
|
||||
{ "write_bytes: ", "Bytes sent to storage:" },
|
||||
{ "cancelled_write_bytes: ", "Cancelled write bytes:" },
|
||||
};
|
||||
int i;
|
||||
for(i=0; i<sizeof(aTrans)/sizeof(aTrans[0]); i++){
|
||||
int n = (int)strlen(aTrans[i].zPattern);
|
||||
if( strncmp(aTrans[i].zPattern, z, n)==0 ){
|
||||
fprintf(out, "-- %-28s %s", aTrans[i].zDesc, &z[n]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose(in);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Return the value of a hexadecimal digit. Return -1 if the input
|
||||
** is not a hex digit.
|
||||
*/
|
||||
static int hexDigitValue(char c){
|
||||
if( c>='0' && c<='9' ) return c - '0';
|
||||
if( c>='a' && c<='f' ) return c - 'a' + 10;
|
||||
if( c>='A' && c<='F' ) return c - 'A' + 10;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
** Interpret zArg as an integer value, possibly with suffixes.
|
||||
*/
|
||||
static int integerValue(const char *zArg){
|
||||
sqlite3_int64 v = 0;
|
||||
static const struct { char *zSuffix; int iMult; } aMult[] = {
|
||||
{ "KiB", 1024 },
|
||||
{ "MiB", 1024*1024 },
|
||||
{ "GiB", 1024*1024*1024 },
|
||||
{ "KB", 1000 },
|
||||
{ "MB", 1000000 },
|
||||
{ "GB", 1000000000 },
|
||||
{ "K", 1000 },
|
||||
{ "M", 1000000 },
|
||||
{ "G", 1000000000 },
|
||||
};
|
||||
int i;
|
||||
int isNeg = 0;
|
||||
if( zArg[0]=='-' ){
|
||||
isNeg = 1;
|
||||
zArg++;
|
||||
}else if( zArg[0]=='+' ){
|
||||
zArg++;
|
||||
}
|
||||
if( zArg[0]=='0' && zArg[1]=='x' ){
|
||||
int x;
|
||||
zArg += 2;
|
||||
while( (x = hexDigitValue(zArg[0]))>=0 ){
|
||||
v = (v<<4) + x;
|
||||
zArg++;
|
||||
}
|
||||
}else{
|
||||
while( isdigit(zArg[0]) ){
|
||||
v = v*10 + zArg[0] - '0';
|
||||
zArg++;
|
||||
}
|
||||
}
|
||||
for(i=0; i<sizeof(aMult)/sizeof(aMult[0]); i++){
|
||||
if( sqlite3_stricmp(aMult[i].zSuffix, zArg)==0 ){
|
||||
v *= aMult[i].iMult;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( v>0x7fffffff ){
|
||||
printf("ERROR: parameter too large - max 2147483648\n");
|
||||
exit(1);
|
||||
}
|
||||
return (int)(isNeg? -v : v);
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char **argv){
|
||||
const char *zCmd = 0;
|
||||
int i;
|
||||
int bAutovac = 0;
|
||||
int showStats = 0;
|
||||
const char *zDbName = "./startup.db";
|
||||
int nHeap = 0;
|
||||
int mnHeap = 0;
|
||||
|
||||
for(i=1; i<argc; i++){
|
||||
const char *z = argv[i];
|
||||
if( z[0]!='-' ){
|
||||
if( zCmd ){
|
||||
usage(argv[0]);
|
||||
}
|
||||
zCmd = z;
|
||||
continue;
|
||||
}
|
||||
if( z[1]=='-' ) z++;
|
||||
if( strcmp(z, "-autovacuum")==0 ){
|
||||
bAutovac = 1;
|
||||
}else
|
||||
if( strcmp(z, "-dbname")==0 ){
|
||||
if( i==argc-1 ){
|
||||
printf("ERROR: missing argument on \"%s\"\n", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
zDbName = argv[++i];
|
||||
}else
|
||||
if( strcmp(z,"-heap")==0 ){
|
||||
if( i>=argc-2 ){
|
||||
printf("ERROR: missing arguments on %s\n", argv[i]);
|
||||
exit(1);
|
||||
}
|
||||
nHeap = integerValue(argv[i+1]);
|
||||
mnHeap = integerValue(argv[i+2]);
|
||||
i += 2;
|
||||
}else
|
||||
if( strcmp(z,"-stats")==0 ){
|
||||
showStats = 1;
|
||||
}else
|
||||
{
|
||||
printf("ERROR: unknown option \"%s\"\n", argv[i]);
|
||||
usage(argv[0]);
|
||||
}
|
||||
}
|
||||
if( zCmd==0 ){
|
||||
printf("ERROR: no COMMAND specified\n");
|
||||
usage(argv[0]);
|
||||
}
|
||||
if( strcmp(zCmd, "run")==0 ){
|
||||
sqlite3 *db;
|
||||
int rc;
|
||||
char *zErr = 0;
|
||||
void *pHeap = 0;
|
||||
if( nHeap>0 ){
|
||||
pHeap = malloc( nHeap );
|
||||
if( pHeap==0 ){
|
||||
printf("ERROR: cannot allocate %d-byte heap\n", nHeap);
|
||||
exit(1);
|
||||
}
|
||||
rc = sqlite3_config(SQLITE_CONFIG_HEAP, pHeap, nHeap, mnHeap);
|
||||
if( rc ){
|
||||
printf("ERROR: heap configuration failed: %d\n", rc);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
rc = sqlite3_open(zDbName, &db);
|
||||
if( rc ){
|
||||
printf("SQLite error: %s\n", sqlite3_errmsg(db));
|
||||
}else{
|
||||
sqlite3_exec(db, "PRAGMA synchronous", 0, 0, &zErr);
|
||||
}
|
||||
if( zErr ){
|
||||
printf("ERROR: %s\n", zErr);
|
||||
sqlite3_free(zErr);
|
||||
}
|
||||
if( showStats ){
|
||||
int iCur, iHi;
|
||||
sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_USED, &iCur, &iHi, 0);
|
||||
printf("-- Lookaside Slots Used: %d (max %d)\n", iCur,iHi);
|
||||
sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_HIT, &iCur, &iHi, 0);
|
||||
printf("-- Successful lookasides: %d\n", iHi);
|
||||
sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE, &iCur,&iHi,0);
|
||||
printf("-- Lookaside size faults: %d\n", iHi);
|
||||
sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL, &iCur,&iHi,0);
|
||||
printf("-- Lookaside OOM faults: %d\n", iHi);
|
||||
sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_USED, &iCur, &iHi, 0);
|
||||
printf("-- Pager Heap Usage: %d bytes\n", iCur);
|
||||
sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_HIT, &iCur, &iHi, 1);
|
||||
printf("-- Page cache hits: %d\n", iCur);
|
||||
sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_MISS, &iCur, &iHi, 1);
|
||||
printf("-- Page cache misses: %d\n", iCur);
|
||||
sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_WRITE, &iCur, &iHi, 1);
|
||||
printf("-- Page cache writes: %d\n", iCur);
|
||||
sqlite3_db_status(db, SQLITE_DBSTATUS_SCHEMA_USED, &iCur, &iHi, 0);
|
||||
printf("-- Schema Heap Usage: %d bytes\n", iCur);
|
||||
sqlite3_db_status(db, SQLITE_DBSTATUS_STMT_USED, &iCur, &iHi, 0);
|
||||
printf("-- Statement Heap Usage: %d bytes\n", iCur);
|
||||
}
|
||||
sqlite3_close(db);
|
||||
free(pHeap);
|
||||
/* Global memory usage statistics printed after the database connection
|
||||
** has closed. Memory usage should be zero at this point. */
|
||||
if( showStats ){
|
||||
int iCur, iHi;
|
||||
sqlite3_status(SQLITE_STATUS_MEMORY_USED, &iCur, &iHi, 0);
|
||||
printf("-- Memory Used (bytes): %d (max %d)\n", iCur,iHi);
|
||||
sqlite3_status(SQLITE_STATUS_MALLOC_COUNT, &iCur, &iHi, 0);
|
||||
printf("-- Outstanding Allocations: %d (max %d)\n", iCur,iHi);
|
||||
sqlite3_status(SQLITE_STATUS_PAGECACHE_OVERFLOW, &iCur, &iHi, 0);
|
||||
printf("-- Pcache Overflow Bytes: %d (max %d)\n", iCur,iHi);
|
||||
sqlite3_status(SQLITE_STATUS_MALLOC_SIZE, &iCur, &iHi, 0);
|
||||
printf("-- Largest Allocation: %d bytes\n",iHi);
|
||||
sqlite3_status(SQLITE_STATUS_PAGECACHE_SIZE, &iCur, &iHi, 0);
|
||||
printf("-- Largest Pcache Allocation: %d bytes\n",iHi);
|
||||
#ifdef __linux__
|
||||
displayLinuxIoStats(stdout);
|
||||
#endif
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
if( strcmp(zCmd, "init")==0 ){
|
||||
sqlite3 *db;
|
||||
char *zAux;
|
||||
char *zErr = 0;
|
||||
int rc;
|
||||
unlink(zDbName);
|
||||
zAux = sqlite3_mprintf("%s-journal", zDbName);
|
||||
unlink(zAux);
|
||||
sqlite3_free(zAux);
|
||||
zAux = sqlite3_mprintf("%s-wal", zDbName);
|
||||
unlink(zAux);
|
||||
sqlite3_free(zAux);
|
||||
rc = sqlite3_open(zDbName, &db);
|
||||
if( rc ){
|
||||
printf("SQLite error: %s\n", sqlite3_errmsg(db));
|
||||
}else{
|
||||
sqlite3_exec(db, "BEGIN", 0, 0, 0);
|
||||
sqlite3_exec(db, zTestSchema, 0, 0, &zErr);
|
||||
sqlite3_exec(db, "COMMIT", 0, 0, 0);
|
||||
}
|
||||
if( zErr ){
|
||||
printf("ERROR: %s\n", zErr);
|
||||
sqlite3_free(zErr);
|
||||
}
|
||||
sqlite3_close(db);
|
||||
return 0;
|
||||
|
||||
}
|
||||
}
|
||||
+11
-2
@@ -174,8 +174,14 @@ proc get_pwd {} {
|
||||
# case of the result to what Tcl considers canonical, which would
|
||||
# defeat the purpose of this procedure.
|
||||
#
|
||||
if {[info exists ::env(ComSpec)]} {
|
||||
set comSpec $::env(ComSpec)
|
||||
} else {
|
||||
# NOTE: Hard-code the typical default value.
|
||||
set comSpec {C:\Windows\system32\cmd.exe}
|
||||
}
|
||||
return [string map [list \\ /] \
|
||||
[string trim [exec -- $::env(ComSpec) /c echo %CD%]]]
|
||||
[string trim [exec -- $comSpec /c echo %CD%]]]
|
||||
} else {
|
||||
return [pwd]
|
||||
}
|
||||
@@ -1689,9 +1695,12 @@ proc crashsql {args} {
|
||||
set cfile [string map {\\ \\\\} [file nativename [file join [get_pwd] $crashfile]]]
|
||||
|
||||
set f [open crash.tcl w]
|
||||
puts $f "sqlite3_initialize ; sqlite3_shutdown"
|
||||
puts $f "catch { install_malloc_faultsim 1 }"
|
||||
puts $f "sqlite3_crash_enable 1 $dfltvfs"
|
||||
puts $f "sqlite3_crashparams $blocksize $dc $crashdelay $cfile"
|
||||
puts $f "sqlite3_test_control_pending_byte $::sqlite_pending_byte"
|
||||
puts $f "autoinstall_test_functions"
|
||||
|
||||
# This block sets the cache size of the main database to 10
|
||||
# pages. This is done in case the build is configured to omit
|
||||
@@ -1719,7 +1728,7 @@ proc crashsql {args} {
|
||||
}
|
||||
close $f
|
||||
set r [catch {
|
||||
exec [info nameofexec] crash.tcl >@stdout
|
||||
exec [info nameofexec] crash.tcl >@stdout 2>@stdout
|
||||
} msg]
|
||||
|
||||
# Windows/ActiveState TCL returns a slightly different
|
||||
|
||||
@@ -251,4 +251,83 @@ do_test trace3-11.2 {
|
||||
set ::stmtlist(record)
|
||||
} {/^-?\d+$/}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_test 12.1.0 {
|
||||
set ::STMT [sqlite3_prepare_v2 $DB \
|
||||
"SELECT ?1 || ?1 || ?1 || ?2 || ?3 || ?4 || ? || ?1 || ?" -1 TAIL
|
||||
]
|
||||
sqlite3_bind_parameter_count $::STMT
|
||||
} {6}
|
||||
|
||||
do_test 12.1.1 {
|
||||
sqlite3_bind_text $STMT 1 "A" 1
|
||||
sqlite3_bind_text $STMT 2 "B" 1
|
||||
sqlite3_bind_text $STMT 3 "C" 1
|
||||
sqlite3_bind_text $STMT 4 "D" 1
|
||||
sqlite3_bind_text $STMT 5 "E" 1
|
||||
sqlite3_bind_text $STMT 6 "F" 1
|
||||
sqlite3_expanded_sql $STMT
|
||||
} {SELECT 'A' || 'A' || 'A' || 'B' || 'C' || 'D' || 'E' || 'A' || 'F'}
|
||||
|
||||
do_test 12.1.2 {
|
||||
sqlite3_step $STMT
|
||||
sqlite3_column_text $STMT 0
|
||||
} {AAABCDEAF}
|
||||
|
||||
do_test 12.1.3 {
|
||||
sqlite3_finalize $STMT
|
||||
} {SQLITE_OK}
|
||||
|
||||
do_test 12.2.0 {
|
||||
execsql {
|
||||
CREATE TABLE nameFtsFuzzySearchTable(
|
||||
word, distance, langid, score, top, scope
|
||||
);
|
||||
}
|
||||
set ::STMT [sqlite3_prepare_v2 $DB {
|
||||
SELECT
|
||||
substr(word,1,length(?1)-1) AS term,
|
||||
distance,
|
||||
langid,
|
||||
score
|
||||
FROM
|
||||
nameFtsFuzzySearchTable
|
||||
WHERE
|
||||
word MATCH (?1) AND abs(?1) = abs(term)
|
||||
AND top = ?2 AND distance > ?3 AND scope = ?4 AND langid = ?
|
||||
GROUP BY term, langid
|
||||
HAVING (1.0 - ((distance / 100.0) / CAST( length(?1) - 1 AS REAL ))) >= ?
|
||||
} -1 TAIL]
|
||||
sqlite3_bind_parameter_count $::STMT
|
||||
} {6}
|
||||
|
||||
do_test 12.1.1 {
|
||||
sqlite3_bind_text $STMT 1 "A" 1
|
||||
sqlite3_bind_text $STMT 2 "B" 1
|
||||
sqlite3_bind_text $STMT 3 "C" 1
|
||||
sqlite3_bind_text $STMT 4 "D" 1
|
||||
sqlite3_bind_text $STMT 5 "E" 1
|
||||
sqlite3_bind_text $STMT 6 "F" 1
|
||||
sqlite3_expanded_sql $STMT
|
||||
} {
|
||||
SELECT
|
||||
substr(word,1,length('A')-1) AS term,
|
||||
distance,
|
||||
langid,
|
||||
score
|
||||
FROM
|
||||
nameFtsFuzzySearchTable
|
||||
WHERE
|
||||
word MATCH ('A') AND abs('A') = abs(term)
|
||||
AND top = 'B' AND distance > 'C' AND scope = 'D' AND langid = 'E'
|
||||
GROUP BY term, langid
|
||||
HAVING (1.0 - ((distance / 100.0) / CAST( length('A') - 1 AS REAL ))) >= 'F'
|
||||
}
|
||||
|
||||
do_test 12.1.2 {
|
||||
sqlite3_finalize $STMT
|
||||
} {SQLITE_OK}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -58,6 +58,8 @@ foreach {tn defn} {
|
||||
8 { BEFORE UPDATE ON t1 BEGIN UPDATE t2 SET c = ?; END; }
|
||||
9 { BEFORE UPDATE ON t1 BEGIN UPDATE t2 SET c = 1 WHERE d = ?; END; }
|
||||
10 { AFTER INSERT ON t1 BEGIN SELECT * FROM pragma_stats(?); END; }
|
||||
11 { BEFORE INSERT ON t1 BEGIN
|
||||
INSERT INTO t1 SELECT max(b) OVER(ORDER BY $1) FROM t1; END }
|
||||
} {
|
||||
catchsql {drop trigger tr1}
|
||||
do_catchsql_test 1.1.$tn "CREATE TRIGGER tr1 $defn" [list 1 $errmsg]
|
||||
|
||||
@@ -0,0 +1,329 @@
|
||||
# 2020-12-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 file is flattening UNION ALL sub-queries.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix unionall
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE TABLE t1_a(a INTEGER PRIMARY KEY, b TEXT);
|
||||
CREATE TABLE t1_b(c INTEGER PRIMARY KEY, d TEXT);
|
||||
CREATE TABLE t1_c(e INTEGER PRIMARY KEY, f TEXT);
|
||||
|
||||
INSERT INTO t1_a VALUES(1, 'one'), (4, 'four');
|
||||
INSERT INTO t1_b VALUES(2, 'two'), (5, 'five');
|
||||
INSERT INTO t1_c VALUES(3, 'three'), (6, 'six');
|
||||
|
||||
CREATE VIEW t1 AS
|
||||
SELECT a, b FROM t1_a UNION ALL
|
||||
SELECT c, d FROM t1_b UNION ALL
|
||||
SELECT e, f FROM t1_c;
|
||||
|
||||
CREATE TABLE i1(x);
|
||||
INSERT INTO i1 VALUES(2), (5), (6), (1);
|
||||
}
|
||||
|
||||
do_execsql_test 1.1 {
|
||||
SELECT a, b FROM (
|
||||
SELECT a, b FROM t1_a UNION ALL
|
||||
SELECT c, d FROM t1_b UNION ALL
|
||||
SELECT e, f FROM t1_c
|
||||
) ORDER BY a
|
||||
} {
|
||||
1 one 2 two 3 three 4 four 5 five 6 six
|
||||
}
|
||||
|
||||
do_execsql_test 1.2 {
|
||||
SELECT a, b FROM t1 ORDER BY a
|
||||
} {
|
||||
1 one 2 two 3 three 4 four 5 five 6 six
|
||||
}
|
||||
|
||||
do_execsql_test 1.3 {
|
||||
SELECT a, b FROM i1, t1 WHERE a=x ORDER BY a
|
||||
} {1 one 2 two 5 five 6 six}
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
|
||||
do_execsql_test 2.1.0 {
|
||||
CREATE TABLE t1(x, y);
|
||||
INSERT INTO t1 VALUES(1, 'one');
|
||||
INSERT INTO t1 VALUES(1, 'ONE');
|
||||
INSERT INTO t1 VALUES(2, 'two');
|
||||
INSERT INTO t1 VALUES(2, 'TWO');
|
||||
INSERT INTO t1 VALUES(3, 'three');
|
||||
INSERT INTO t1 VALUES(3, 'THREE');
|
||||
}
|
||||
|
||||
do_execsql_test 2.1.1 {
|
||||
WITH s(i) AS (
|
||||
SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<3
|
||||
)
|
||||
SELECT * FROM (
|
||||
SELECT 0 AS i UNION ALL SELECT i FROM s UNION ALL SELECT 0
|
||||
), t1 WHERE x=i;
|
||||
} {
|
||||
1 1 one 1 1 ONE 2 2 two 2 2 TWO 3 3 three 3 3 THREE
|
||||
}
|
||||
|
||||
do_catchsql_test 2.1.2 {
|
||||
WITH s(i) AS (
|
||||
SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<3 UNION ALL SELECT 4
|
||||
)
|
||||
SELECT * FROM s, t1 WHERE x=i;
|
||||
} {1 {circular reference: s}}
|
||||
|
||||
do_execsql_test 2.2.0 {
|
||||
CREATE TABLE t2_a(k INTEGER PRIMARY KEY, v TEXT);
|
||||
CREATE TABLE t2_b(k INTEGER PRIMARY KEY, v TEXT);
|
||||
|
||||
CREATE VIEW t2 AS
|
||||
SELECT * FROM t2_a
|
||||
UNION ALL
|
||||
SELECT * FROM t2_b;
|
||||
|
||||
CREATE TRIGGER t2_insert INSTEAD OF INSERT ON t2 BEGIN
|
||||
INSERT INTO t2_a SELECT new.k, new.v WHERE (new.k%2)==0;
|
||||
INSERT INTO t2_b SELECT new.k, new.v WHERE (new.k%2)==1;
|
||||
END;
|
||||
|
||||
INSERT INTO t2 VALUES(5, 'v'), (4, 'iv'), (3, 'iii'), (2, 'ii');
|
||||
}
|
||||
|
||||
do_execsql_test 2.2.1 {
|
||||
SELECT * FROM t1, t2 WHERE x=k;
|
||||
} {
|
||||
2 two 2 ii 2 TWO 2 ii 3 three 3 iii 3 THREE 3 iii
|
||||
}
|
||||
|
||||
do_execsql_test 2.2.2 {
|
||||
SELECT * FROM t1 LEFT JOIN t2 ON (x=k);
|
||||
} {
|
||||
1 one {} {}
|
||||
1 ONE {} {}
|
||||
2 two 2 ii 2 TWO 2 ii 3 three 3 iii 3 THREE 3 iii
|
||||
}
|
||||
|
||||
do_execsql_test 2.2.3 {
|
||||
SELECT x1.*, x2.* FROM t2 AS x1, t2 AS x2 WHERE x1.k=x2.k+1
|
||||
} {
|
||||
4 iv 3 iii
|
||||
3 iii 2 ii
|
||||
5 v 4 iv
|
||||
}
|
||||
|
||||
do_execsql_test 2.2.4 {
|
||||
SELECT * FROM t1, t2 WHERE x=k ORDER BY y;
|
||||
} {
|
||||
3 THREE 3 iii
|
||||
2 TWO 2 ii
|
||||
3 three 3 iii
|
||||
2 two 2 ii
|
||||
}
|
||||
do_execsql_test 2.2.5 {
|
||||
SELECT * FROM t1, t2 WHERE x=k ORDER BY y||'';
|
||||
} {
|
||||
3 THREE 3 iii
|
||||
2 TWO 2 ii
|
||||
3 three 3 iii
|
||||
2 two 2 ii
|
||||
}
|
||||
do_execsql_test 2.2.6 {
|
||||
SELECT * FROM t1, t2 WHERE x=k ORDER BY v
|
||||
} {
|
||||
2 two 2 ii
|
||||
2 TWO 2 ii
|
||||
3 three 3 iii
|
||||
3 THREE 3 iii
|
||||
}
|
||||
do_execsql_test 2.2.7 {
|
||||
SELECT * FROM t1, t2 WHERE x=k ORDER BY v||''
|
||||
} {
|
||||
2 two 2 ii
|
||||
2 TWO 2 ii
|
||||
3 three 3 iii
|
||||
3 THREE 3 iii
|
||||
}
|
||||
do_execsql_test 2.2.8 {
|
||||
SELECT * FROM t1, t2 WHERE x=k ORDER BY k,v||''
|
||||
} {
|
||||
2 two 2 ii
|
||||
2 TWO 2 ii
|
||||
3 three 3 iii
|
||||
3 THREE 3 iii
|
||||
}
|
||||
do_execsql_test 2.2.9a {
|
||||
SELECT * FROM t1, t2 ORDER BY +k
|
||||
} {
|
||||
1 one 2 ii 1 ONE 2 ii 2 two 2 ii
|
||||
2 TWO 2 ii 3 three 2 ii 3 THREE 2 ii
|
||||
|
||||
1 one 3 iii 1 ONE 3 iii 2 two 3 iii
|
||||
2 TWO 3 iii 3 three 3 iii 3 THREE 3 iii
|
||||
|
||||
1 one 4 iv 1 ONE 4 iv 2 two 4 iv
|
||||
2 TWO 4 iv 3 three 4 iv 3 THREE 4 iv
|
||||
|
||||
1 one 5 v 1 ONE 5 v 2 two 5 v
|
||||
2 TWO 5 v 3 three 5 v 3 THREE 5 v
|
||||
}
|
||||
|
||||
do_execsql_test 2.2.9b {
|
||||
SELECT * FROM t1, t2 ORDER BY k
|
||||
} {
|
||||
1 one 2 ii 1 ONE 2 ii 2 two 2 ii
|
||||
2 TWO 2 ii 3 three 2 ii 3 THREE 2 ii
|
||||
|
||||
1 one 3 iii 1 ONE 3 iii 2 two 3 iii
|
||||
2 TWO 3 iii 3 three 3 iii 3 THREE 3 iii
|
||||
|
||||
1 one 4 iv 1 ONE 4 iv 2 two 4 iv
|
||||
2 TWO 4 iv 3 three 4 iv 3 THREE 4 iv
|
||||
|
||||
1 one 5 v 1 ONE 5 v 2 two 5 v
|
||||
2 TWO 5 v 3 three 5 v 3 THREE 5 v
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_execsql_test 3.0 {
|
||||
CREATE TABLE t1(c INTEGER PRIMARY KEY, d TEXT);
|
||||
INSERT INTO t1 VALUES(1,2);
|
||||
CREATE TABLE t3_a(k INTEGER PRIMARY KEY, v TEXT);
|
||||
INSERT INTO t3_a VALUES(2,'ii');
|
||||
CREATE TABLE t3_b(k INTEGER PRIMARY KEY, v TEXT);
|
||||
CREATE VIEW t3 AS
|
||||
SELECT * FROM t3_a
|
||||
UNION ALL
|
||||
SELECT * FROM t3_b;
|
||||
} {}
|
||||
|
||||
do_execsql_test 3.1 {
|
||||
SELECT * FROM t1, t3 ORDER BY k;
|
||||
} {1 2 2 ii}
|
||||
|
||||
reset_db
|
||||
do_execsql_test 4.0 {
|
||||
|
||||
CREATE TABLE t1_a(a INTEGER PRIMARY KEY, b TEXT);
|
||||
INSERT INTO t1_a VALUES(123, 't1_a');
|
||||
CREATE TABLE t1_b(c INTEGER PRIMARY KEY, d TEXT);
|
||||
|
||||
CREATE VIEW t1 AS
|
||||
SELECT a, b FROM t1_a
|
||||
UNION ALL
|
||||
SELECT c, d FROM t1_b;
|
||||
|
||||
CREATE TABLE t3_a(k INTEGER PRIMARY KEY, v TEXT);
|
||||
INSERT INTO t3_a VALUES(456, 't3_a');
|
||||
CREATE TABLE t3_b(k INTEGER PRIMARY KEY, v TEXT);
|
||||
|
||||
CREATE VIEW t3 AS
|
||||
SELECT * FROM t3_a
|
||||
UNION ALL
|
||||
SELECT * FROM t3_b;
|
||||
}
|
||||
|
||||
do_execsql_test 4.1 {
|
||||
SELECT * FROM t1, t3 ORDER BY k;
|
||||
} {123 t1_a 456 t3_a}
|
||||
|
||||
do_execsql_test 4.2 {
|
||||
SELECT * FROM (SELECT * FROM t1, t3) ORDER BY k;
|
||||
} {123 t1_a 456 t3_a}
|
||||
|
||||
do_execsql_test 4.3 {
|
||||
SELECT * FROM (SELECT * FROM t1, t3), (
|
||||
SELECT max(a) OVER () FROM t1
|
||||
UNION ALL
|
||||
SELECT min(a) OVER () FROM t1
|
||||
)
|
||||
ORDER BY k;
|
||||
} {
|
||||
123 t1_a 456 t3_a 123
|
||||
123 t1_a 456 t3_a 123
|
||||
}
|
||||
|
||||
do_execsql_test 4.3 {
|
||||
SELECT * FROM (SELECT * FROM t1, t3), (
|
||||
SELECT group_concat(a) OVER (ORDER BY a),
|
||||
group_concat(a) OVER (ORDER BY a),
|
||||
group_concat(a) OVER (ORDER BY a),
|
||||
group_concat(a) OVER (ORDER BY a),
|
||||
group_concat(a) OVER (ORDER BY a),
|
||||
group_concat(a) OVER (ORDER BY a),
|
||||
group_concat(a) OVER (ORDER BY a),
|
||||
group_concat(a) OVER (ORDER BY a),
|
||||
group_concat(a) OVER (ORDER BY a)
|
||||
FROM t1
|
||||
)
|
||||
ORDER BY k;
|
||||
} {
|
||||
123 t1_a 456 t3_a 123 123 123 123 123 123 123 123 123
|
||||
}
|
||||
|
||||
do_execsql_test 4.3 {
|
||||
SELECT * FROM (SELECT * FROM t1, t3) AS o, (
|
||||
SELECT * FROM t1 LEFT JOIN t3 ON a=k
|
||||
);
|
||||
} {
|
||||
123 t1_a 456 t3_a 123 t1_a {} {}
|
||||
}
|
||||
|
||||
# 2020-12-30: dbsqlfuzz find
|
||||
reset_db
|
||||
do_execsql_test 5.1 {
|
||||
CREATE TABLE t1_a(a INTEGER PRIMARY KEY, b TEXT);
|
||||
INSERT INTO t1_a VALUES(1,'one');
|
||||
INSERT INTO t1_a VALUES(0,NULL);
|
||||
CREATE TABLE t1_b(c INTEGER PRIMARY KEY, d TEXT);
|
||||
INSERT INTO t1_b VALUES(2,'two');
|
||||
INSERT INTO t1_b VALUES(5,'five');
|
||||
CREATE TABLE t1_c(e INTEGER PRIMARY KEY, f TEXT);
|
||||
INSERT INTO t1_c VALUES(3,'three');
|
||||
INSERT INTO t1_c VALUES(6,'six');
|
||||
CREATE TABLE t2(k,v);
|
||||
INSERT INTO t2 VALUES(5,'v');
|
||||
INSERT INTO t2 VALUES(4,'iv');
|
||||
INSERT INTO t2 VALUES(3,'iii');
|
||||
INSERT INTO t2 VALUES(2,'ii');
|
||||
CREATE TABLE t3_a(k INTEGER PRIMARY KEY, v TEXT);
|
||||
INSERT INTO t3_a VALUES(2,'ii');
|
||||
INSERT INTO t3_a VALUES(4,'iv');
|
||||
CREATE TABLE t3_b(k INTEG5R PRIMARY KEY, v TEXT);
|
||||
INSERT INTO t3_b VALUES(NULL,'iii');
|
||||
INSERT INTO t3_b VALUES(NULL,'v');
|
||||
CREATE VIEW t1 AS
|
||||
SELECT a, b FROM t1_a UNION ALL
|
||||
SELECT c, d FROM t1_b UNION ALL
|
||||
SELECT e, f FROM t1_c;
|
||||
CREATE VIEW t3 AS
|
||||
SELECT * FROM t3_a
|
||||
UNION ALL
|
||||
SELECT * FROM t3_b;
|
||||
CREATE TRIGGER t3_insert INSTEAD OF INSERT ON t3 BEGIN
|
||||
INSERT INTO t3_a SELECT new.k, new.v WHERE (new.k%2)==0;
|
||||
INSERT INTO t3_b SELECT new.k, new.v WHERE (new.k%2)==1;
|
||||
END;
|
||||
} {}
|
||||
do_execsql_test 5.10 {
|
||||
SELECT *, '+' FROM t1 LEFT JOIN t2 ON (a NOT IN(SELECT v FROM t1, t3 WHERE a=k)=NOT EXISTS(SELECT 1 FROM t1 LEFT JOIN t3 ON (a=k)));
|
||||
} {0 {} {} {} + 1 one {} {} + 2 two {} {} + 5 five {} {} + 3 three {} {} + 6 six {} {} +}
|
||||
do_execsql_test 5.20 {
|
||||
SELECT *, '+' FROM t1 LEFT JOIN t3 ON (a NOT IN(SELECT v FROM t1 LEFT JOIN t2 ON (a=k))=k);
|
||||
} {0 {} {} {} + 1 one {} {} + 2 two {} {} + 5 five {} {} + 3 three {} {} + 6 six {} {} +}
|
||||
|
||||
finish_test
|
||||
@@ -0,0 +1,39 @@
|
||||
# 2020-12-22
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
# This file implements regression tests for SQLite library. The
|
||||
# focus of this file is flattening UNION ALL sub-queries.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix unionall2
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE TABLE t1(a, b);
|
||||
CREATE TABLE t2(c, d);
|
||||
|
||||
CREATE VIEW v1 AS SELECT * FROM t1, t2;
|
||||
CREATE VIEW v2 AS SELECT * FROM t1, t2;
|
||||
|
||||
CREATE VIEW vA AS
|
||||
SELECT * FROM v1, (
|
||||
SELECT * FROM t1 LEFT JOIN t2 ON (a=c)
|
||||
)
|
||||
UNION ALL
|
||||
SELECT * FROM v1, v2
|
||||
}
|
||||
|
||||
do_execsql_test 1.1 {
|
||||
SELECT 1 FROM vA, vA, vA, vA, vA, vA, vA, vA, vA, vA
|
||||
}
|
||||
|
||||
|
||||
finish_test
|
||||
@@ -0,0 +1,36 @@
|
||||
# 2020-12-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.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix unionallfault
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE TABLE t1(x,y,z);
|
||||
CREATE TABLE t3(x,y,z);
|
||||
}
|
||||
faultsim_save_and_close
|
||||
|
||||
|
||||
do_faultsim_test 1 -faults oom-t* -prep {
|
||||
faultsim_restore_and_reopen
|
||||
} -body {
|
||||
execsql {
|
||||
SELECT * FROM t1, (
|
||||
SELECT x FROM t1 UNION ALL SELECT y FROM t1
|
||||
), t3
|
||||
}
|
||||
} -test {
|
||||
faultsim_test_result {0 {}}
|
||||
}
|
||||
|
||||
finish_test
|
||||
@@ -0,0 +1,397 @@
|
||||
# 2020-12-11
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
# Test cases for generalized UPSERT
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix upsert5
|
||||
|
||||
foreach {tn sql} {
|
||||
1 { CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c UNIQUE, d UNIQUE, e UNIQUE) }
|
||||
2 { CREATE TABLE t1(a INT PRIMARY KEY, b, c UNIQUE, d UNIQUE, e UNIQUE) }
|
||||
3 { CREATE TABLE t1(a INT PRIMARY KEY, b, c UNIQUE, d UNIQUE, e UNIQUE) WITHOUT ROWID}
|
||||
4 { CREATE TABLE t1(e UNIQUE, d UNIQUE, c UNIQUE, a INTEGER PRIMARY KEY, b) }
|
||||
5 { CREATE TABLE t1(e UNIQUE, d UNIQUE, c UNIQUE, a INT PRIMARY KEY, b) }
|
||||
6 { CREATE TABLE t1(e UNIQUE, d UNIQUE, c UNIQUE, a INT PRIMARY KEY, b) WITHOUT ROWID}
|
||||
} {
|
||||
reset_db
|
||||
execsql $sql
|
||||
|
||||
do_execsql_test 1.$tn.100 {
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5);
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,NULL,3,4,5)
|
||||
ON CONFLICT(a) DO UPDATE SET b='a'
|
||||
ON CONFLICT(c) DO UPDATE SET b='c'
|
||||
ON CONFLICT(d) DO UPDATE SET b='d'
|
||||
ON CONFLICT(e) DO UPDATE SET b='e';
|
||||
SELECT a,b,c,d,e FROM t1;
|
||||
} {1 a 3 4 5}
|
||||
do_execsql_test 1.$tn.101 {
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5);
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(91,NULL,3,4,5)
|
||||
ON CONFLICT(a) DO UPDATE SET b='a'
|
||||
ON CONFLICT(c) DO UPDATE SET b='c'
|
||||
ON CONFLICT(d) DO UPDATE SET b='d'
|
||||
ON CONFLICT(e) DO UPDATE SET b='e';
|
||||
SELECT a,b,c,d,e FROM t1;
|
||||
} {1 c 3 4 5}
|
||||
do_execsql_test 1.$tn.102 {
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5);
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(91,NULL,93,4,5)
|
||||
ON CONFLICT(a) DO UPDATE SET b='a'
|
||||
ON CONFLICT(c) DO UPDATE SET b='c'
|
||||
ON CONFLICT(d) DO UPDATE SET b='d'
|
||||
ON CONFLICT(e) DO UPDATE SET b='e';
|
||||
SELECT a,b,c,d,e FROM t1;
|
||||
} {1 d 3 4 5}
|
||||
do_execsql_test 1.$tn.103 {
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5);
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(91,NULL,93,94,5)
|
||||
ON CONFLICT(a) DO UPDATE SET b='a'
|
||||
ON CONFLICT(c) DO UPDATE SET b='c'
|
||||
ON CONFLICT(d) DO UPDATE SET b='d'
|
||||
ON CONFLICT(e) DO UPDATE SET b='e';
|
||||
SELECT a,b,c,d,e FROM t1;
|
||||
} {1 e 3 4 5}
|
||||
do_execsql_test 1.$tn.200 {
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5);
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,NULL,93,94,95)
|
||||
ON CONFLICT(c) DO UPDATE SET b='c'
|
||||
ON CONFLICT(a) DO UPDATE SET b='a'
|
||||
ON CONFLICT(d) DO UPDATE SET b='d'
|
||||
ON CONFLICT(e) DO UPDATE SET b='e';
|
||||
SELECT a,b,c,d,e FROM t1;
|
||||
} {1 a 3 4 5}
|
||||
do_execsql_test 1.$tn.201 {
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5);
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,NULL,3,94,95)
|
||||
ON CONFLICT(c) DO UPDATE SET b='c'
|
||||
ON CONFLICT(a) DO UPDATE SET b='a'
|
||||
ON CONFLICT(d) DO UPDATE SET b='d'
|
||||
ON CONFLICT(e) DO UPDATE SET b='e';
|
||||
SELECT a,b,c,d,e FROM t1;
|
||||
} {1 c 3 4 5}
|
||||
do_execsql_test 1.$tn.202 {
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5);
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,NULL,3,4,5)
|
||||
ON CONFLICT(c) DO UPDATE SET b='c'
|
||||
ON CONFLICT(a) DO UPDATE SET b='a'
|
||||
ON CONFLICT(d) DO UPDATE SET b='d'
|
||||
ON CONFLICT(e) DO UPDATE SET b='e';
|
||||
SELECT a,b,c,d,e FROM t1;
|
||||
} {1 c 3 4 5}
|
||||
do_execsql_test 1.$tn.203 {
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5);
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,NULL,93,94,5)
|
||||
ON CONFLICT(c) DO UPDATE SET b='c'
|
||||
ON CONFLICT(a) DO UPDATE SET b='a'
|
||||
ON CONFLICT(d) DO UPDATE SET b='d'
|
||||
ON CONFLICT(e) DO UPDATE SET b='e';
|
||||
SELECT a,b,c,d,e FROM t1;
|
||||
} {1 a 3 4 5}
|
||||
do_execsql_test 1.$tn.204 {
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5);
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,NULL,93,4,95)
|
||||
ON CONFLICT(c) DO UPDATE SET b='c'
|
||||
ON CONFLICT(a) DO UPDATE SET b='a'
|
||||
ON CONFLICT(d) DO UPDATE SET b='d'
|
||||
ON CONFLICT(e) DO UPDATE SET b='e';
|
||||
SELECT a,b,c,d,e FROM t1;
|
||||
} {1 a 3 4 5}
|
||||
do_execsql_test 1.$tn.210 {
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5);
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,NULL,93,94,95)
|
||||
ON CONFLICT(c) DO UPDATE SET b='c'
|
||||
ON CONFLICT(d) DO UPDATE SET b='d'
|
||||
ON CONFLICT(a) DO UPDATE SET b='a'
|
||||
ON CONFLICT(e) DO UPDATE SET b='e';
|
||||
SELECT a,b,c,d,e FROM t1;
|
||||
} {1 a 3 4 5}
|
||||
do_execsql_test 1.$tn.211 {
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5);
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,NULL,93,4,95)
|
||||
ON CONFLICT(c) DO UPDATE SET b='c'
|
||||
ON CONFLICT(d) DO UPDATE SET b='d'
|
||||
ON CONFLICT(a) DO UPDATE SET b='a'
|
||||
ON CONFLICT(e) DO UPDATE SET b='e';
|
||||
SELECT a,b,c,d,e FROM t1;
|
||||
} {1 d 3 4 5}
|
||||
do_execsql_test 1.$tn.212 {
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5);
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,NULL,93,94,5)
|
||||
ON CONFLICT(c) DO UPDATE SET b='c'
|
||||
ON CONFLICT(d) DO UPDATE SET b='d'
|
||||
ON CONFLICT(a) DO UPDATE SET b='a'
|
||||
ON CONFLICT(e) DO UPDATE SET b='e';
|
||||
SELECT a,b,c,d,e FROM t1;
|
||||
} {1 a 3 4 5}
|
||||
do_execsql_test 1.$tn.213 {
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5);
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(91,NULL,93,94,5)
|
||||
ON CONFLICT(c) DO UPDATE SET b='c'
|
||||
ON CONFLICT(d) DO UPDATE SET b='d'
|
||||
ON CONFLICT(a) DO UPDATE SET b='a'
|
||||
ON CONFLICT(e) DO UPDATE SET b='e';
|
||||
SELECT a,b,c,d,e FROM t1;
|
||||
} {1 e 3 4 5}
|
||||
do_execsql_test 1.$tn.214 {
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5);
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(91,NULL,93,94,5)
|
||||
ON CONFLICT(c) DO UPDATE SET b='c'
|
||||
ON CONFLICT(d) DO UPDATE SET b='d'
|
||||
ON CONFLICT(e) DO UPDATE SET b='e'
|
||||
ON CONFLICT(a) DO UPDATE SET b='a';
|
||||
SELECT a,b,c,d,e FROM t1;
|
||||
} {1 e 3 4 5}
|
||||
do_execsql_test 1.$tn.215 {
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5);
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,NULL,93,94,5)
|
||||
ON CONFLICT(c) DO UPDATE SET b='c'
|
||||
ON CONFLICT(d) DO UPDATE SET b='d'
|
||||
ON CONFLICT(e) DO UPDATE SET b='e'
|
||||
ON CONFLICT(a) DO UPDATE SET b='a';
|
||||
SELECT a,b,c,d,e FROM t1;
|
||||
} {1 e 3 4 5}
|
||||
do_execsql_test 1.$tn.216 {
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5);
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,NULL,93,94,95)
|
||||
ON CONFLICT(c) DO UPDATE SET b='c'
|
||||
ON CONFLICT(d) DO UPDATE SET b='d'
|
||||
ON CONFLICT(e) DO UPDATE SET b='e'
|
||||
ON CONFLICT(a) DO UPDATE SET b='a';
|
||||
SELECT a,b,c,d,e FROM t1;
|
||||
} {1 a 3 4 5}
|
||||
|
||||
do_execsql_test 1.$tn.300 {
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5);
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,NULL,93,94,95)
|
||||
ON CONFLICT(c) DO UPDATE SET b='c'
|
||||
ON CONFLICT(d) DO UPDATE SET b='d'
|
||||
ON CONFLICT(a) DO UPDATE SET b='a1'
|
||||
ON CONFLICT(a) DO UPDATE SET b='a2'
|
||||
ON CONFLICT(a) DO UPDATE SET b='a3'
|
||||
ON CONFLICT(a) DO UPDATE SET b='a4'
|
||||
ON CONFLICT(a) DO UPDATE SET b='a5'
|
||||
ON CONFLICT(e) DO UPDATE SET b='e';
|
||||
SELECT a,b,c,d,e FROM t1;
|
||||
} {1 a1 3 4 5}
|
||||
do_execsql_test 1.$tn.301 {
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5);
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(91,NULL,93,94,5)
|
||||
ON CONFLICT(c) DO UPDATE SET b='c'
|
||||
ON CONFLICT(d) DO UPDATE SET b='d'
|
||||
ON CONFLICT(a) DO UPDATE SET b='a1'
|
||||
ON CONFLICT(a) DO UPDATE SET b='a2'
|
||||
ON CONFLICT(a) DO UPDATE SET b='a3'
|
||||
ON CONFLICT(a) DO UPDATE SET b='a4'
|
||||
ON CONFLICT(a) DO UPDATE SET b='a5'
|
||||
ON CONFLICT(e) DO UPDATE SET b='e';
|
||||
SELECT a,b,c,d,e FROM t1;
|
||||
} {1 e 3 4 5}
|
||||
|
||||
do_execsql_test 1.$tn.400 {
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5);
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,NULL,93,94,95)
|
||||
ON CONFLICT(c) DO UPDATE SET b='c'
|
||||
ON CONFLICT(d) DO UPDATE SET b='d'
|
||||
ON CONFLICT DO UPDATE set b='x';
|
||||
SELECT a,b,c,d,e FROM t1;
|
||||
} {1 x 3 4 5}
|
||||
do_execsql_test 1.$tn.401 {
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5);
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(91,NULL,93,94,5)
|
||||
ON CONFLICT(c) DO UPDATE SET b='c'
|
||||
ON CONFLICT(d) DO UPDATE SET b='d'
|
||||
ON CONFLICT DO UPDATE set b='x';
|
||||
SELECT a,b,c,d,e FROM t1;
|
||||
} {1 x 3 4 5}
|
||||
do_execsql_test 1.$tn.402 {
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5);
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,NULL,93,94,95)
|
||||
ON CONFLICT(c) DO UPDATE SET b='c'
|
||||
ON CONFLICT(d) DO UPDATE SET b='d'
|
||||
ON CONFLICT DO UPDATE set b='x';
|
||||
SELECT a,b,c,d,e FROM t1;
|
||||
} {1 x 3 4 5}
|
||||
do_execsql_test 1.$tn.403 {
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5);
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(91,NULL,3,94,95)
|
||||
ON CONFLICT(c) DO UPDATE SET b='c'
|
||||
ON CONFLICT(d) DO UPDATE SET b='d'
|
||||
ON CONFLICT DO UPDATE set b='x';
|
||||
SELECT a,b,c,d,e FROM t1;
|
||||
} {1 c 3 4 5}
|
||||
do_execsql_test 1.$tn.404 {
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5);
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(91,NULL,3,4,95)
|
||||
ON CONFLICT(c) DO UPDATE SET b='c'
|
||||
ON CONFLICT(d) DO UPDATE SET b='d'
|
||||
ON CONFLICT DO UPDATE set b='x';
|
||||
SELECT a,b,c,d,e FROM t1;
|
||||
} {1 c 3 4 5}
|
||||
do_execsql_test 1.$tn.405 {
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5);
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,NULL,93,4,5)
|
||||
ON CONFLICT(c) DO UPDATE SET b='c'
|
||||
ON CONFLICT(d) DO UPDATE SET b='d'
|
||||
ON CONFLICT DO UPDATE set b='x';
|
||||
SELECT a,b,c,d,e FROM t1;
|
||||
} {1 d 3 4 5}
|
||||
|
||||
do_execsql_test 1.$tn.410 {
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5);
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,NULL,93,94,95)
|
||||
ON CONFLICT DO UPDATE set b='x';
|
||||
SELECT a,b,c,d,e FROM t1;
|
||||
} {1 x 3 4 5}
|
||||
do_execsql_test 1.$tn.411 {
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5);
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(91,NULL,93,94,5)
|
||||
ON CONFLICT DO UPDATE set b='x';
|
||||
SELECT a,b,c,d,e FROM t1;
|
||||
} {1 x 3 4 5}
|
||||
do_execsql_test 1.$tn.412 {
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5);
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(91,NULL,93,4,95)
|
||||
ON CONFLICT DO UPDATE set b='x';
|
||||
SELECT a,b,c,d,e FROM t1;
|
||||
} {1 x 3 4 5}
|
||||
do_execsql_test 1.$tn.413 {
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5);
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(91,NULL,3,94,95)
|
||||
ON CONFLICT DO UPDATE set b='x';
|
||||
SELECT a,b,c,d,e FROM t1;
|
||||
} {1 x 3 4 5}
|
||||
|
||||
do_execsql_test 1.$tn.420 {
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5);
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,NULL,93,94,95)
|
||||
ON CONFLICT(c) DO NOTHING
|
||||
ON CONFLICT(d) DO NOTHING
|
||||
ON CONFLICT DO UPDATE set b='x';
|
||||
SELECT a,b,c,d,e FROM t1;
|
||||
} {1 x 3 4 5}
|
||||
do_execsql_test 1.$tn.421 {
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5);
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(91,NULL,93,94,5)
|
||||
ON CONFLICT(c) DO NOTHING
|
||||
ON CONFLICT(d) DO NOTHING
|
||||
ON CONFLICT DO UPDATE set b='x';
|
||||
SELECT a,b,c,d,e FROM t1;
|
||||
} {1 x 3 4 5}
|
||||
do_execsql_test 1.$tn.422 {
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5);
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(91,NULL,93,4,95)
|
||||
ON CONFLICT(c) DO NOTHING
|
||||
ON CONFLICT(d) DO NOTHING
|
||||
ON CONFLICT DO UPDATE set b='x';
|
||||
SELECT a,b,c,d,e FROM t1;
|
||||
} {1 2 3 4 5}
|
||||
do_execsql_test 1.$tn.423 {
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5);
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(91,NULL,3,94,95)
|
||||
ON CONFLICT(c) DO NOTHING
|
||||
ON CONFLICT(d) DO NOTHING
|
||||
ON CONFLICT DO UPDATE set b='x';
|
||||
SELECT a,b,c,d,e FROM t1;
|
||||
} {1 2 3 4 5}
|
||||
|
||||
do_execsql_test 1.$tn.500 {
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5);
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,NULL,93,94,95)
|
||||
ON CONFLICT(c) DO UPDATE SET b='c'
|
||||
ON CONFLICT(d) DO UPDATE SET b='d'
|
||||
ON CONFLICT DO NOTHING;
|
||||
SELECT a,b,c,d,e FROM t1;
|
||||
} {1 2 3 4 5}
|
||||
do_execsql_test 1.$tn.501 {
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5);
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(91,NULL,93,94,5)
|
||||
ON CONFLICT(c) DO UPDATE SET b='c'
|
||||
ON CONFLICT(d) DO UPDATE SET b='d'
|
||||
ON CONFLICT DO NOTHING;
|
||||
SELECT a,b,c,d,e FROM t1;
|
||||
} {1 2 3 4 5}
|
||||
do_execsql_test 1.$tn.502 {
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5);
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,NULL,93,94,95)
|
||||
ON CONFLICT(c) DO UPDATE SET b='c'
|
||||
ON CONFLICT(d) DO UPDATE SET b='d'
|
||||
ON CONFLICT DO NOTHING;
|
||||
SELECT a,b,c,d,e FROM t1;
|
||||
} {1 2 3 4 5}
|
||||
do_execsql_test 1.$tn.503 {
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5);
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(91,NULL,3,94,95)
|
||||
ON CONFLICT(c) DO UPDATE SET b='c'
|
||||
ON CONFLICT(d) DO UPDATE SET b='d'
|
||||
ON CONFLICT DO NOTHING;
|
||||
SELECT a,b,c,d,e FROM t1;
|
||||
} {1 c 3 4 5}
|
||||
do_execsql_test 1.$tn.504 {
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5);
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(91,NULL,3,4,95)
|
||||
ON CONFLICT(c) DO UPDATE SET b='c'
|
||||
ON CONFLICT(d) DO UPDATE SET b='d'
|
||||
ON CONFLICT DO NOTHING;
|
||||
SELECT a,b,c,d,e FROM t1;
|
||||
} {1 c 3 4 5}
|
||||
do_execsql_test 1.$tn.505 {
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5);
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,NULL,93,4,5)
|
||||
ON CONFLICT(c) DO UPDATE SET b='c'
|
||||
ON CONFLICT(d) DO UPDATE SET b='d'
|
||||
ON CONFLICT DO NOTHING;
|
||||
SELECT a,b,c,d,e FROM t1;
|
||||
} {1 d 3 4 5}
|
||||
|
||||
}
|
||||
|
||||
finish_test
|
||||
+1
-1
@@ -56,7 +56,7 @@ do_test vacuum2-2.1 {
|
||||
}
|
||||
hexio_get_int [hexio_read test.db 24 4]
|
||||
} [expr {[hexio_get_int [hexio_read test.db 24 4]]+3}]
|
||||
do_test vacuum2-2.1 {
|
||||
do_test vacuum2-2.2 {
|
||||
execsql {
|
||||
VACUUM
|
||||
}
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
# 2016-08-19
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
# This file implements a test for VACUUM on attached databases.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix vacuum6
|
||||
|
||||
# If the VACUUM statement is disabled in the current build, skip all
|
||||
# the tests in this file.
|
||||
#
|
||||
ifcapable !vacuum {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE TABLE t1(x INTEGER PRIMARY KEY, y);
|
||||
INSERT INTO t1 VALUES(1, 1);
|
||||
} {}
|
||||
|
||||
do_execsql_test 1.1 {
|
||||
VACUUM
|
||||
}
|
||||
|
||||
reset_db
|
||||
do_execsql_test 1.2 {
|
||||
CREATE TABLE t1(x,b);
|
||||
CREATE INDEX x1 ON t1(x);
|
||||
CREATE INDEX x2 ON t1(x);
|
||||
CREATE INDEX x3 ON t1(x);
|
||||
INSERT INTO t1 SELECT 2,'';
|
||||
VACUUM;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
reset_db
|
||||
foreach {tn sz} {1 400 2 4000 3 9999} {
|
||||
reset_db
|
||||
do_execsql_test 2.$tn.1 {
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
|
||||
WITH s(i) AS (
|
||||
SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<100
|
||||
)
|
||||
INSERT INTO t1 SELECT i, randomblob($sz) FROM s;
|
||||
}
|
||||
|
||||
do_execsql_test 2.$tn.2 {
|
||||
vacuum;
|
||||
}
|
||||
|
||||
do_execsql_test 2.$tn.3 {
|
||||
PRAGMA integrity_check;
|
||||
} {ok}
|
||||
}
|
||||
|
||||
reset_db
|
||||
do_execsql_test 3.0 {
|
||||
PRAGMA page_size = 1024;
|
||||
CREATE TABLE t1(x INTEGER PRIMARY KEY, y);
|
||||
INSERT INTO t1 VALUES(2, randomblob(1200));
|
||||
} {}
|
||||
do_execsql_test 3.1 {
|
||||
PRAGMA page_size = 512;
|
||||
VACUUM;
|
||||
}
|
||||
do_execsql_test 3.2 {
|
||||
PRAGMA integrity_check
|
||||
} {ok}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 4.0 {
|
||||
CREATE TABLE tx(a, b);
|
||||
CREATE INDEX i1 ON tx(b);
|
||||
WITH s(i) AS (
|
||||
SELECT 8000 UNION ALL SELECT i+1 FROM s WHERE i<10000
|
||||
)
|
||||
INSERT INTO tx SELECT i, randomblob(i) FROM s;
|
||||
|
||||
SELECT sum(length(b)) FROM tx;
|
||||
} {18009000}
|
||||
foreach {tn pgsz av} {
|
||||
1 2048 0
|
||||
2 1024 1
|
||||
3 65536 0
|
||||
4 8192 1
|
||||
5 512 0
|
||||
6 4096 1
|
||||
} {
|
||||
do_execsql_test 4.1.$tn.1 "
|
||||
PRAGMA page_size = $pgsz;
|
||||
PRAGMA auto_vacuum = $av;
|
||||
"
|
||||
do_execsql_test 4.1.$tn.2 VACUUM
|
||||
integrity_check 4.1.$tn.3
|
||||
}
|
||||
|
||||
finish_test
|
||||
+8
-1
@@ -146,16 +146,23 @@ proc xWrite {method file args} {
|
||||
incr ::cnt -1
|
||||
if {$::cnt==0} {
|
||||
sqlite3_memdebug_fail 1 -repeat 0
|
||||
catchsql { SELECT 'a big long string!' }
|
||||
# For this test to pass, the following statement must call malloc() at
|
||||
# least once. Even if the lookaside is enabled.
|
||||
set ::xwrite_stmt_res [catchsql { SELECT hex(randomblob(4000)) }]
|
||||
sqlite3_interrupt db
|
||||
}
|
||||
}
|
||||
return SQLITE_OK
|
||||
}
|
||||
|
||||
set ::xwrite_stmt_res ""
|
||||
do_catchsql_test 3.2 {
|
||||
PRAGMA wal_checkpoint
|
||||
} {1 {out of memory}}
|
||||
do_test 3.2.2 {
|
||||
set ::xwrite_stmt_res
|
||||
} {1 {out of memory}}
|
||||
unset ::xwrite_stmt_res
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
|
||||
+7
-8
@@ -26,14 +26,13 @@ do_eqp_test 110 {
|
||||
SELECT * FROM t1, v4 WHERE t1.a=?1 AND v4.a=t1.a;
|
||||
} {
|
||||
QUERY PLAN
|
||||
|--MATERIALIZE xxxxxx
|
||||
| `--COMPOUND QUERY
|
||||
| |--LEFT-MOST SUBQUERY
|
||||
| | `--SEARCH TABLE t2 USING INDEX sqlite_autoindex_t2_1 (a=?)
|
||||
| `--UNION ALL
|
||||
| `--SEARCH TABLE t3 USING INDEX sqlite_autoindex_t3_1 (a=?)
|
||||
|--SCAN SUBQUERY xxxxxx
|
||||
`--SEARCH TABLE t1 USING INDEX sqlite_autoindex_t1_1 (a=?)
|
||||
`--COMPOUND QUERY
|
||||
|--LEFT-MOST SUBQUERY
|
||||
| |--SEARCH TABLE t2 USING INDEX sqlite_autoindex_t2_1 (a=?)
|
||||
| `--SEARCH TABLE t1 USING INDEX sqlite_autoindex_t1_1 (a=?)
|
||||
`--UNION ALL
|
||||
|--SEARCH TABLE t3 USING INDEX sqlite_autoindex_t3_1 (a=?)
|
||||
`--SEARCH TABLE t1 USING INDEX sqlite_autoindex_t1_1 (a=?)
|
||||
}
|
||||
|
||||
# The scan of the t1 table goes first since that enables the ORDER BY
|
||||
|
||||
+6
-6
@@ -401,7 +401,7 @@ struct lemon {
|
||||
struct symbol *errsym; /* The error symbol */
|
||||
struct symbol *wildcard; /* Token that matches anything */
|
||||
char *name; /* Name of the generated parser */
|
||||
char *arg; /* Declaration of the 3th argument to parser */
|
||||
char *arg; /* Declaration of the 3rd argument to parser */
|
||||
char *ctx; /* Declaration of 2nd argument to constructor */
|
||||
char *tokentype; /* Type of terminal symbols in the parser stack */
|
||||
char *vartype; /* The default type of non-terminal symbols */
|
||||
@@ -1027,7 +1027,7 @@ PRIVATE void buildshifts(struct lemon *lemp, struct state *stp)
|
||||
struct symbol *bsp; /* Symbol following the dot in configuration "bcfp" */
|
||||
struct state *newstp; /* A pointer to a successor state */
|
||||
|
||||
/* Each configuration becomes complete after it contibutes to a successor
|
||||
/* Each configuration becomes complete after it contributes to a successor
|
||||
** state. Initially, all configurations are incomplete */
|
||||
for(cfp=stp->cfp; cfp; cfp=cfp->next) cfp->status = INCOMPLETE;
|
||||
|
||||
@@ -1887,7 +1887,7 @@ static char *merge(
|
||||
**
|
||||
** Return Value:
|
||||
** A pointer to the head of a sorted list containing the elements
|
||||
** orginally in list.
|
||||
** originally in list.
|
||||
**
|
||||
** Side effects:
|
||||
** The "next" pointers for elements in list are changed.
|
||||
@@ -3513,7 +3513,7 @@ void ReportOutput(struct lemon *lemp)
|
||||
}
|
||||
|
||||
/* Search for the file "name" which is in the same directory as
|
||||
** the exacutable */
|
||||
** the executable */
|
||||
PRIVATE char *pathsearch(char *argv0, char *name, int modemask)
|
||||
{
|
||||
const char *pathlist;
|
||||
@@ -3868,7 +3868,7 @@ PRIVATE int translate_code(struct lemon *lemp, struct rule *rp){
|
||||
lhsdirect = 1;
|
||||
}else if( rp->rhsalias[0]==0 ){
|
||||
/* The left-most RHS symbol has no value. LHS direct is ok. But
|
||||
** we have to call the distructor on the RHS symbol first. */
|
||||
** we have to call the destructor on the RHS symbol first. */
|
||||
lhsdirect = 1;
|
||||
if( has_destructor(rp->rhs[0],lemp) ){
|
||||
append_str(0,0,0,0);
|
||||
@@ -4849,7 +4849,7 @@ void ReportTable(
|
||||
** yyRuleInfoNRhs[].
|
||||
**
|
||||
** Note: This code depends on the fact that rules are number
|
||||
** sequentually beginning with 0.
|
||||
** sequentially beginning with 0.
|
||||
*/
|
||||
for(i=0, rp=lemp->rule; rp; rp=rp->next, i++){
|
||||
fprintf(out," %4d, /* (%d) ", rp->lhs->index, i);
|
||||
|
||||
+48
-53
@@ -718,55 +718,6 @@ static YYACTIONTYPE yy_reduce(
|
||||
(void)yyLookahead;
|
||||
(void)yyLookaheadToken;
|
||||
yymsp = yypParser->yytos;
|
||||
assert( yyruleno<(int)(sizeof(yyRuleName)/sizeof(yyRuleName[0])) );
|
||||
#ifndef NDEBUG
|
||||
if( yyTraceFILE ){
|
||||
yysize = yyRuleInfoNRhs[yyruleno];
|
||||
if( yysize ){
|
||||
fprintf(yyTraceFILE, "%sReduce %d [%s]%s, pop back to state %d.\n",
|
||||
yyTracePrompt,
|
||||
yyruleno, yyRuleName[yyruleno],
|
||||
yyruleno<YYNRULE_WITH_ACTION ? "" : " without external action",
|
||||
yymsp[yysize].stateno);
|
||||
}else{
|
||||
fprintf(yyTraceFILE, "%sReduce %d [%s]%s.\n",
|
||||
yyTracePrompt, yyruleno, yyRuleName[yyruleno],
|
||||
yyruleno<YYNRULE_WITH_ACTION ? "" : " without external action");
|
||||
}
|
||||
}
|
||||
#endif /* NDEBUG */
|
||||
|
||||
/* Check that the stack is large enough to grow by a single entry
|
||||
** if the RHS of the rule is empty. This ensures that there is room
|
||||
** enough on the stack to push the LHS value */
|
||||
if( yyRuleInfoNRhs[yyruleno]==0 ){
|
||||
#ifdef YYTRACKMAXSTACKDEPTH
|
||||
if( (int)(yypParser->yytos - yypParser->yystack)>yypParser->yyhwm ){
|
||||
yypParser->yyhwm++;
|
||||
assert( yypParser->yyhwm == (int)(yypParser->yytos - yypParser->yystack));
|
||||
}
|
||||
#endif
|
||||
#if YYSTACKDEPTH>0
|
||||
if( yypParser->yytos>=yypParser->yystackEnd ){
|
||||
yyStackOverflow(yypParser);
|
||||
/* The call to yyStackOverflow() above pops the stack until it is
|
||||
** empty, causing the main parser loop to exit. So the return value
|
||||
** is never used and does not matter. */
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
if( yypParser->yytos>=&yypParser->yystack[yypParser->yystksz-1] ){
|
||||
if( yyGrowStack(yypParser) ){
|
||||
yyStackOverflow(yypParser);
|
||||
/* The call to yyStackOverflow() above pops the stack until it is
|
||||
** empty, causing the main parser loop to exit. So the return value
|
||||
** is never used and does not matter. */
|
||||
return 0;
|
||||
}
|
||||
yymsp = yypParser->yytos;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
switch( yyruleno ){
|
||||
/* Beginning here are the reduction cases. A typical example
|
||||
@@ -925,12 +876,56 @@ void Parse(
|
||||
}
|
||||
#endif
|
||||
|
||||
do{
|
||||
while(1){ /* Exit by "break" */
|
||||
assert( yypParser->yytos>=yypParser->yystack );
|
||||
assert( yyact==yypParser->yytos->stateno );
|
||||
yyact = yy_find_shift_action((YYCODETYPE)yymajor,yyact);
|
||||
if( yyact >= YY_MIN_REDUCE ){
|
||||
yyact = yy_reduce(yypParser,yyact-YY_MIN_REDUCE,yymajor,
|
||||
yyminor ParseCTX_PARAM);
|
||||
unsigned int yyruleno = yyact - YY_MIN_REDUCE; /* Reduce by this rule */
|
||||
assert( yyruleno<(int)(sizeof(yyRuleName)/sizeof(yyRuleName[0])) );
|
||||
#ifndef NDEBUG
|
||||
if( yyTraceFILE ){
|
||||
int yysize = yyRuleInfoNRhs[yyruleno];
|
||||
if( yysize ){
|
||||
fprintf(yyTraceFILE, "%sReduce %d [%s]%s, pop back to state %d.\n",
|
||||
yyTracePrompt,
|
||||
yyruleno, yyRuleName[yyruleno],
|
||||
yyruleno<YYNRULE_WITH_ACTION ? "" : " without external action",
|
||||
yypParser->yytos[yysize].stateno);
|
||||
}else{
|
||||
fprintf(yyTraceFILE, "%sReduce %d [%s]%s.\n",
|
||||
yyTracePrompt, yyruleno, yyRuleName[yyruleno],
|
||||
yyruleno<YYNRULE_WITH_ACTION ? "" : " without external action");
|
||||
}
|
||||
}
|
||||
#endif /* NDEBUG */
|
||||
|
||||
/* Check that the stack is large enough to grow by a single entry
|
||||
** if the RHS of the rule is empty. This ensures that there is room
|
||||
** enough on the stack to push the LHS value */
|
||||
if( yyRuleInfoNRhs[yyruleno]==0 ){
|
||||
#ifdef YYTRACKMAXSTACKDEPTH
|
||||
if( (int)(yypParser->yytos - yypParser->yystack)>yypParser->yyhwm ){
|
||||
yypParser->yyhwm++;
|
||||
assert( yypParser->yyhwm ==
|
||||
(int)(yypParser->yytos - yypParser->yystack));
|
||||
}
|
||||
#endif
|
||||
#if YYSTACKDEPTH>0
|
||||
if( yypParser->yytos>=yypParser->yystackEnd ){
|
||||
yyStackOverflow(yypParser);
|
||||
break;
|
||||
}
|
||||
#else
|
||||
if( yypParser->yytos>=&yypParser->yystack[yypParser->yystksz-1] ){
|
||||
if( yyGrowStack(yypParser) ){
|
||||
yyStackOverflow(yypParser);
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
yyact = yy_reduce(yypParser,yyruleno,yymajor,yyminor ParseCTX_PARAM);
|
||||
}else if( yyact <= YY_MAX_SHIFTREDUCE ){
|
||||
yy_shift(yypParser,yyact,(YYCODETYPE)yymajor,yyminor);
|
||||
#ifndef YYNOERRORRECOVERY
|
||||
@@ -1043,7 +1038,7 @@ void Parse(
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}while( yypParser->yytos>yypParser->yystack );
|
||||
}
|
||||
#ifndef NDEBUG
|
||||
if( yyTraceFILE ){
|
||||
yyStackEntry *i;
|
||||
|
||||
+14
-4
@@ -381,6 +381,14 @@ static void reorder(int *pFrom){
|
||||
reorder(&aKeywordTable[i].iNext);
|
||||
}
|
||||
|
||||
/* Parameter to the hash function
|
||||
*/
|
||||
#define HASH_OP ^
|
||||
#define HASH_CC '^'
|
||||
#define HASH_C0 4
|
||||
#define HASH_C1 3
|
||||
#define HASH_C2 1
|
||||
|
||||
/*
|
||||
** This routine does the work. The generated code is printed on standard
|
||||
** output.
|
||||
@@ -411,8 +419,9 @@ int main(int argc, char **argv){
|
||||
assert( p->len<sizeof(p->zOrigName) );
|
||||
memcpy(p->zOrigName, p->zName, p->len+1);
|
||||
totalLen += p->len;
|
||||
p->hash = (charMap(p->zName[0])*4) ^
|
||||
(charMap(p->zName[p->len-1])*3) ^ (p->len*1);
|
||||
p->hash = (charMap(p->zName[0])*HASH_C0) HASH_OP
|
||||
(charMap(p->zName[p->len-1])*HASH_C1) HASH_OP
|
||||
(p->len*HASH_C2);
|
||||
p->id = i+1;
|
||||
}
|
||||
|
||||
@@ -648,8 +657,9 @@ int main(int argc, char **argv){
|
||||
printf(" int i, j;\n");
|
||||
printf(" const char *zKW;\n");
|
||||
printf(" if( n>=2 ){\n");
|
||||
printf(" i = ((charMap(z[0])*4) ^ (charMap(z[n-1])*3) ^ n) %% %d;\n",
|
||||
bestSize);
|
||||
printf(" i = ((charMap(z[0])*%d) %c", HASH_C0, HASH_CC);
|
||||
printf(" (charMap(z[n-1])*%d) %c", HASH_C1, HASH_CC);
|
||||
printf(" n*%d) %% %d;\n", HASH_C2, bestSize);
|
||||
printf(" for(i=((int)aKWHash[i])-1; i>=0; i=((int)aKWNext[i])-1){\n");
|
||||
printf(" if( aKWLen[i]!=n ) continue;\n");
|
||||
printf(" zKW = &zKWText[aKWOffset[i]];\n");
|
||||
|
||||
Reference in New Issue
Block a user