Compare commits
142 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1e1c4226ee | |||
| 9ea258d712 | |||
| dd1bb43ab5 | |||
| 96a27f4cbb | |||
| c8d3e836ca | |||
| ee3333b202 | |||
| 9715f0e544 | |||
| 6b4fbabd6a | |||
| 3fb153cb29 | |||
| f7fa4e71f4 | |||
| 9418921c59 | |||
| ee92eb80db | |||
| 2336c935af | |||
| e694139788 | |||
| 0d236a8bb0 | |||
| 701caf1eb1 | |||
| 7b458519f2 | |||
| e4eb0497d8 | |||
| 614c6a09f7 | |||
| 2617c9bdd8 | |||
| ffe280596e | |||
| f8a2e8c2d2 | |||
| 050b124ce2 | |||
| 30f01249a3 | |||
| 313e6fd222 | |||
| ad012d09dc | |||
| e780764b4e | |||
| 3f4df4c6f3 | |||
| a1f5c0c90b | |||
| ab314001b8 | |||
| 8d5cee166e | |||
| c478c8daec | |||
| 4b2667c8b8 | |||
| 874080bbb6 | |||
| ed71298085 | |||
| 33543c237b | |||
| e08e8d6b61 | |||
| 181a1167dc | |||
| ab31a8450b | |||
| 7555581fc1 | |||
| bb6783b86f | |||
| bc43995f99 | |||
| 6ab3eb5d0e | |||
| 6f654a40e8 | |||
| 4b17369579 | |||
| b9e6a73866 | |||
| 69bfa55279 | |||
| a1188d6d93 | |||
| 0c3233be0b | |||
| 39c9d3a367 | |||
| 0619838c55 | |||
| dc62daca86 | |||
| a059e99ca8 | |||
| 0027e98b85 | |||
| bff6fe1f40 | |||
| bda00fbdb7 | |||
| cfcca02765 | |||
| e2bc6552fe | |||
| 4bee5599c0 | |||
| 940464b1dc | |||
| 624edacf6a | |||
| ddf4747053 | |||
| 6887e8facd | |||
| b6d5a43b8a | |||
| b65b3e429a | |||
| 147fd88268 | |||
| a2e2d92b21 | |||
| 06f60d8e87 | |||
| 14d8855b8f | |||
| 31d6fd5507 | |||
| 1a17b44231 | |||
| 399c7e21e4 | |||
| b1ed717f18 | |||
| d97cda43ab | |||
| 46967de2ec | |||
| 7c88bcd473 | |||
| 571311502d | |||
| 172806e489 | |||
| c04ea80f64 | |||
| a74f5c2923 | |||
| d0a537100c | |||
| 44ae27ac32 | |||
| 839fa6d814 | |||
| 929b695111 | |||
| 8489bf5aff | |||
| 8671538cad | |||
| 03155f659f | |||
| 26849e14c2 | |||
| 15e0f3d901 | |||
| 940b5eaa5e | |||
| ff6d50e973 | |||
| e97c9ff49a | |||
| ef90a6b8dd | |||
| cbae543a5c | |||
| b8d29c2f75 | |||
| d6e992cb1e | |||
| eac5fc0476 | |||
| 2f8b37850c | |||
| 0415d826c0 | |||
| 4c6463cc29 | |||
| 2ac702d8c0 | |||
| e12e24ded8 | |||
| 7a6ea93fd8 | |||
| 9fa866a8d9 | |||
| a34adaf667 | |||
| 5b09d13a58 | |||
| 13fe138b0a | |||
| be0bc8bb4d | |||
| 297e2bdb8e | |||
| 72507d431b | |||
| 98368eeb2c | |||
| f1824a77b0 | |||
| aca19e19a8 | |||
| 6193d49cdf | |||
| 54e2efcd2f | |||
| 50da9382f9 | |||
| 6948ed5977 | |||
| dbd6a7dc06 | |||
| ac48b751e2 | |||
| f4dd26c5a0 | |||
| 43606175e2 | |||
| 32d0eba4c2 | |||
| 75f9558808 | |||
| 628dfe163f | |||
| cfb3235752 | |||
| 761f691d0e | |||
| 1cc3a36d90 | |||
| caab5f42db | |||
| 8e633b3ba9 | |||
| 662c50e067 | |||
| 96a7e28df6 | |||
| b808d77771 | |||
| b6017a44c5 | |||
| 75e96b3100 | |||
| 53b2459a36 | |||
| 52105783fd | |||
| ecc0f84d08 | |||
| b3d3bea31d | |||
| 9ca431aef8 | |||
| 4eb8d7fa89 | |||
| 9f549d548d | |||
| bf96228754 |
+6
-3
@@ -21,7 +21,7 @@ USE_AMALGAMATION = 1
|
||||
# Set this non-0 to enable full warnings (-W4, etc) when compiling.
|
||||
#
|
||||
!IFNDEF USE_FULLWARN
|
||||
USE_FULLWARN = 0
|
||||
USE_FULLWARN = 1
|
||||
!ENDIF
|
||||
|
||||
# Set this non-0 to enable treating warnings as errors (-WX, etc) when
|
||||
@@ -745,8 +745,11 @@ RCC = $(RCC) -DSQLITE_ENABLE_API_ARMOR=1
|
||||
|
||||
!IF $(DEBUG)>2
|
||||
TCC = $(TCC) -DSQLITE_DEBUG=1
|
||||
TCC = $(TCC) -DSQLITE_ENABLE_WHERETRACE -DSQLITE_ENABLE_SELECTTRACE
|
||||
RCC = $(RCC) -DSQLITE_DEBUG=1
|
||||
!IF $(DYNAMIC_SHELL)==0
|
||||
TCC = $(TCC) -DSQLITE_ENABLE_WHERETRACE -DSQLITE_ENABLE_SELECTTRACE
|
||||
RCC = $(RCC) -DSQLITE_ENABLE_WHERETRACE -DSQLITE_ENABLE_SELECTTRACE
|
||||
!ENDIF
|
||||
!ENDIF
|
||||
|
||||
!IF $(DEBUG)>4 || $(OSTRACE)!=0
|
||||
@@ -1559,7 +1562,7 @@ $(SQLITE3DLL): $(LIBOBJ) $(LIBRESOBJS) $(CORE_LINK_DEP)
|
||||
sqlite3.def: libsqlite3.lib
|
||||
echo EXPORTS > sqlite3.def
|
||||
dumpbin /all libsqlite3.lib \
|
||||
| $(TCLSH_CMD) $(TOP)\tool\replace.tcl include "^\s+1 _?(sqlite3(?:session|changeset)?_[^@]*)(?:@\d+)?$$" \1 \
|
||||
| $(TCLSH_CMD) $(TOP)\tool\replace.tcl include "^\s+1 _?(sqlite3(?:session|changeset|changegroup)?_[^@]*)(?:@\d+)?$$" \1 \
|
||||
| sort >> sqlite3.def
|
||||
# <</block2>>
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ TOP = .
|
||||
# Set this non-0 to enable full warnings (-W4, etc) when compiling.
|
||||
#
|
||||
!IFNDEF USE_FULLWARN
|
||||
USE_FULLWARN = 0
|
||||
USE_FULLWARN = 1
|
||||
!ENDIF
|
||||
|
||||
# Set this non-0 to enable treating warnings as errors (-WX, etc) when
|
||||
@@ -644,8 +644,11 @@ RCC = $(RCC) -DSQLITE_ENABLE_API_ARMOR=1
|
||||
|
||||
!IF $(DEBUG)>2
|
||||
TCC = $(TCC) -DSQLITE_DEBUG=1
|
||||
TCC = $(TCC) -DSQLITE_ENABLE_WHERETRACE -DSQLITE_ENABLE_SELECTTRACE
|
||||
RCC = $(RCC) -DSQLITE_DEBUG=1
|
||||
!IF $(DYNAMIC_SHELL)==0
|
||||
TCC = $(TCC) -DSQLITE_ENABLE_WHERETRACE -DSQLITE_ENABLE_SELECTTRACE
|
||||
RCC = $(RCC) -DSQLITE_ENABLE_WHERETRACE -DSQLITE_ENABLE_SELECTTRACE
|
||||
!ENDIF
|
||||
!ENDIF
|
||||
|
||||
!IF $(DEBUG)>4 || $(OSTRACE)!=0
|
||||
@@ -951,7 +954,7 @@ Replace.exe:
|
||||
sqlite3.def: Replace.exe $(LIBOBJ)
|
||||
echo EXPORTS > sqlite3.def
|
||||
dumpbin /all $(LIBOBJ) \
|
||||
| .\Replace.exe "^\s+/EXPORT:_?(sqlite3(?:session|changeset)?_[^@,]*)(?:@\d+|,DATA)?$$" $$1 true \
|
||||
| .\Replace.exe "^\s+/EXPORT:_?(sqlite3(?:session|changeset|changegroup)?_[^@,]*)(?:@\d+|,DATA)?$$" $$1 true \
|
||||
| sort >> sqlite3.def
|
||||
|
||||
$(SQLITE3EXE): $(TOP)\shell.c $(SHELL_CORE_DEP) $(LIBRESOBJS) $(SHELL_CORE_SRC) $(SQLITE3H)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#! /bin/sh
|
||||
# Guess values for system-dependent variables and create Makefiles.
|
||||
# Generated by GNU Autoconf 2.69 for sqlite 3.18.0.
|
||||
# Generated by GNU Autoconf 2.69 for sqlite 3.19.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.18.0'
|
||||
PACKAGE_STRING='sqlite 3.18.0'
|
||||
PACKAGE_VERSION='3.19.0'
|
||||
PACKAGE_STRING='sqlite 3.19.0'
|
||||
PACKAGE_BUGREPORT=''
|
||||
PACKAGE_URL=''
|
||||
|
||||
@@ -1463,7 +1463,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.18.0 to adapt to many kinds of systems.
|
||||
\`configure' configures sqlite 3.19.0 to adapt to many kinds of systems.
|
||||
|
||||
Usage: $0 [OPTION]... [VAR=VALUE]...
|
||||
|
||||
@@ -1528,7 +1528,7 @@ fi
|
||||
|
||||
if test -n "$ac_init_help"; then
|
||||
case $ac_init_help in
|
||||
short | recursive ) echo "Configuration of sqlite 3.18.0:";;
|
||||
short | recursive ) echo "Configuration of sqlite 3.19.0:";;
|
||||
esac
|
||||
cat <<\_ACEOF
|
||||
|
||||
@@ -1652,7 +1652,7 @@ fi
|
||||
test -n "$ac_init_help" && exit $ac_status
|
||||
if $ac_init_version; then
|
||||
cat <<\_ACEOF
|
||||
sqlite configure 3.18.0
|
||||
sqlite configure 3.19.0
|
||||
generated by GNU Autoconf 2.69
|
||||
|
||||
Copyright (C) 2012 Free Software Foundation, Inc.
|
||||
@@ -2071,7 +2071,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.18.0, which was
|
||||
It was created by sqlite $as_me 3.19.0, which was
|
||||
generated by GNU Autoconf 2.69. Invocation command line was
|
||||
|
||||
$ $0 $@
|
||||
@@ -11252,7 +11252,7 @@ else
|
||||
fi
|
||||
|
||||
if test "${use_debug}" = "yes" ; then
|
||||
TARGET_DEBUG="-DSQLITE_DEBUG=1 -DSQLITE_ENABLE_SELECTTRACE -DSQLITE_ENABLE_WHERETRACE"
|
||||
TARGET_DEBUG="-DSQLITE_DEBUG=1 -DSQLITE_ENABLE_SELECTTRACE -DSQLITE_ENABLE_WHERETRACE -O0"
|
||||
else
|
||||
TARGET_DEBUG="-DNDEBUG"
|
||||
fi
|
||||
@@ -11356,7 +11356,7 @@ fi
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to support MEMSYS5" >&5
|
||||
$as_echo_n "checking whether to support MEMSYS5... " >&6; }
|
||||
if test "${enable_memsys5}" = "yes"; then
|
||||
OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_MEMSYS5"
|
||||
OPT_FEATURE_FLAGS="$(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_MEMSYS5"
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
|
||||
$as_echo "yes" >&6; }
|
||||
else
|
||||
@@ -11373,7 +11373,7 @@ fi
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to support MEMSYS3" >&5
|
||||
$as_echo_n "checking whether to support MEMSYS3... " >&6; }
|
||||
if test "${enable_memsys3}" = "yes" -a "${enable_memsys5}" = "no"; then
|
||||
OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_MEMSYS3"
|
||||
OPT_FEATURE_FLAGS="$(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_MEMSYS3"
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
|
||||
$as_echo "yes" >&6; }
|
||||
else
|
||||
@@ -11391,7 +11391,7 @@ else
|
||||
fi
|
||||
|
||||
if test "${enable_fts3}" = "yes" ; then
|
||||
OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_FTS3"
|
||||
OPT_FEATURE_FLAGS="$(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_FTS3"
|
||||
fi
|
||||
# Check whether --enable-fts4 was given.
|
||||
if test "${enable_fts4+set}" = set; then :
|
||||
@@ -11401,7 +11401,7 @@ else
|
||||
fi
|
||||
|
||||
if test "${enable_fts4}" = "yes" ; then
|
||||
OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_FTS4"
|
||||
OPT_FEATURE_FLAGS="$(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_FTS4"
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing log" >&5
|
||||
$as_echo_n "checking for library containing log... " >&6; }
|
||||
if ${ac_cv_search_log+:} false; then :
|
||||
@@ -11467,7 +11467,7 @@ else
|
||||
fi
|
||||
|
||||
if test "${enable_fts5}" = "yes" ; then
|
||||
OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_FTS5"
|
||||
OPT_FEATURE_FLAGS="$(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_FTS5"
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing log" >&5
|
||||
$as_echo_n "checking for library containing log... " >&6; }
|
||||
if ${ac_cv_search_log+:} false; then :
|
||||
@@ -11536,7 +11536,7 @@ else
|
||||
fi
|
||||
|
||||
if test "${enable_json1}" = "yes" ; then
|
||||
OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_JSON1"
|
||||
OPT_FEATURE_FLAGS="$(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_JSON1"
|
||||
fi
|
||||
|
||||
#########
|
||||
@@ -11549,7 +11549,7 @@ else
|
||||
fi
|
||||
|
||||
if test "${enable_rtree}" = "yes" ; then
|
||||
OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_RTREE"
|
||||
OPT_FEATURE_FLAGS="$(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_RTREE"
|
||||
fi
|
||||
|
||||
#########
|
||||
@@ -11562,8 +11562,8 @@ else
|
||||
fi
|
||||
|
||||
if test "${enable_session}" = "yes" ; then
|
||||
OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_SESSION"
|
||||
OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_PREUPDATE_HOOK"
|
||||
OPT_FEATURE_FLAGS="$(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_SESSION"
|
||||
OPT_FEATURE_FLAGS="$(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_PREUPDATE_HOOK"
|
||||
fi
|
||||
|
||||
#########
|
||||
@@ -12151,7 +12151,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.18.0, which was
|
||||
This file was extended by sqlite $as_me 3.19.0, which was
|
||||
generated by GNU Autoconf 2.69. Invocation command line was
|
||||
|
||||
CONFIG_FILES = $CONFIG_FILES
|
||||
@@ -12217,7 +12217,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.18.0
|
||||
sqlite config.status 3.19.0
|
||||
configured by $0, generated by GNU Autoconf 2.69,
|
||||
with options \\"\$ac_cs_config\\"
|
||||
|
||||
|
||||
+10
-10
@@ -560,7 +560,7 @@ AC_SEARCH_LIBS(fdatasync, [rt])
|
||||
AC_ARG_ENABLE(debug, AC_HELP_STRING([--enable-debug],[enable debugging & verbose explain]),
|
||||
[use_debug=$enableval],[use_debug=no])
|
||||
if test "${use_debug}" = "yes" ; then
|
||||
TARGET_DEBUG="-DSQLITE_DEBUG=1 -DSQLITE_ENABLE_SELECTTRACE -DSQLITE_ENABLE_WHERETRACE"
|
||||
TARGET_DEBUG="-DSQLITE_DEBUG=1 -DSQLITE_ENABLE_SELECTTRACE -DSQLITE_ENABLE_WHERETRACE -O0"
|
||||
else
|
||||
TARGET_DEBUG="-DNDEBUG"
|
||||
fi
|
||||
@@ -596,7 +596,7 @@ AC_ARG_ENABLE(memsys5,
|
||||
[enable_memsys5=yes],[enable_memsys5=no])
|
||||
AC_MSG_CHECKING([whether to support MEMSYS5])
|
||||
if test "${enable_memsys5}" = "yes"; then
|
||||
OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_MEMSYS5"
|
||||
OPT_FEATURE_FLAGS="$(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_MEMSYS5"
|
||||
AC_MSG_RESULT([yes])
|
||||
else
|
||||
AC_MSG_RESULT([no])
|
||||
@@ -606,7 +606,7 @@ AC_ARG_ENABLE(memsys3,
|
||||
[enable_memsys3=yes],[enable_memsys3=no])
|
||||
AC_MSG_CHECKING([whether to support MEMSYS3])
|
||||
if test "${enable_memsys3}" = "yes" -a "${enable_memsys5}" = "no"; then
|
||||
OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_MEMSYS3"
|
||||
OPT_FEATURE_FLAGS="$(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_MEMSYS3"
|
||||
AC_MSG_RESULT([yes])
|
||||
else
|
||||
AC_MSG_RESULT([no])
|
||||
@@ -618,20 +618,20 @@ AC_ARG_ENABLE(fts3, AC_HELP_STRING([--enable-fts3],
|
||||
[Enable the FTS3 extension]),
|
||||
[enable_fts3=yes],[enable_fts3=no])
|
||||
if test "${enable_fts3}" = "yes" ; then
|
||||
OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_FTS3"
|
||||
OPT_FEATURE_FLAGS="$(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_FTS3"
|
||||
fi
|
||||
AC_ARG_ENABLE(fts4, AC_HELP_STRING([--enable-fts4],
|
||||
[Enable the FTS4 extension]),
|
||||
[enable_fts4=yes],[enable_fts4=no])
|
||||
if test "${enable_fts4}" = "yes" ; then
|
||||
OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_FTS4"
|
||||
OPT_FEATURE_FLAGS="$(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_FTS4"
|
||||
AC_SEARCH_LIBS([log],[m])
|
||||
fi
|
||||
AC_ARG_ENABLE(fts5, AC_HELP_STRING([--enable-fts5],
|
||||
[Enable the FTS5 extension]),
|
||||
[enable_fts5=yes],[enable_fts5=no])
|
||||
if test "${enable_fts5}" = "yes" ; then
|
||||
OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_FTS5"
|
||||
OPT_FEATURE_FLAGS="$(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_FTS5"
|
||||
AC_SEARCH_LIBS([log],[m])
|
||||
fi
|
||||
|
||||
@@ -641,7 +641,7 @@ AC_ARG_ENABLE(json1, AC_HELP_STRING([--enable-json1],
|
||||
[Enable the JSON1 extension]),
|
||||
[enable_json1=yes],[enable_json1=no])
|
||||
if test "${enable_json1}" = "yes" ; then
|
||||
OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_JSON1"
|
||||
OPT_FEATURE_FLAGS="$(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_JSON1"
|
||||
fi
|
||||
|
||||
#########
|
||||
@@ -650,7 +650,7 @@ AC_ARG_ENABLE(rtree, AC_HELP_STRING([--enable-rtree],
|
||||
[Enable the RTREE extension]),
|
||||
[enable_rtree=yes],[enable_rtree=no])
|
||||
if test "${enable_rtree}" = "yes" ; then
|
||||
OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_RTREE"
|
||||
OPT_FEATURE_FLAGS="$(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_RTREE"
|
||||
fi
|
||||
|
||||
#########
|
||||
@@ -659,8 +659,8 @@ AC_ARG_ENABLE(session, AC_HELP_STRING([--enable-session],
|
||||
[Enable the SESSION extension]),
|
||||
[enable_session=yes],[enable_session=no])
|
||||
if test "${enable_session}" = "yes" ; then
|
||||
OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_SESSION"
|
||||
OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_PREUPDATE_HOOK"
|
||||
OPT_FEATURE_FLAGS="$(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_SESSION"
|
||||
OPT_FEATURE_FLAGS="$(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_PREUPDATE_HOOK"
|
||||
fi
|
||||
|
||||
#########
|
||||
|
||||
+132
-135
@@ -372,8 +372,8 @@ int sqlite3Fts3GetVarint(const char *pBuf, sqlite_int64 *v){
|
||||
}
|
||||
|
||||
/*
|
||||
** Similar to sqlite3Fts3GetVarint(), except that the output is truncated to a
|
||||
** 32-bit integer before it is returned.
|
||||
** Similar to sqlite3Fts3GetVarint(), except that the output is truncated to
|
||||
** a non-negative 32-bit integer before it is returned.
|
||||
*/
|
||||
int sqlite3Fts3GetVarint32(const char *p, int *pi){
|
||||
u32 a;
|
||||
@@ -389,7 +389,9 @@ int sqlite3Fts3GetVarint32(const char *p, int *pi){
|
||||
GETVARINT_STEP(a, p, 14, 0x3FFF, 0x200000, *pi, 3);
|
||||
GETVARINT_STEP(a, p, 21, 0x1FFFFF, 0x10000000, *pi, 4);
|
||||
a = (a & 0x0FFFFFFF );
|
||||
*pi = (int)(a | ((u32)(*p & 0x0F) << 28));
|
||||
*pi = (int)(a | ((u32)(*p & 0x07) << 28));
|
||||
assert( 0==(a & 0x80000000) );
|
||||
assert( *pi>=0 );
|
||||
return 5;
|
||||
}
|
||||
|
||||
@@ -1219,65 +1221,66 @@ static int fts3InitVtab(
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( iOpt==SizeofArray(aFts4Opt) ){
|
||||
sqlite3Fts3ErrMsg(pzErr, "unrecognized parameter: %s", z);
|
||||
rc = SQLITE_ERROR;
|
||||
}else{
|
||||
switch( iOpt ){
|
||||
case 0: /* MATCHINFO */
|
||||
if( strlen(zVal)!=4 || sqlite3_strnicmp(zVal, "fts3", 4) ){
|
||||
sqlite3Fts3ErrMsg(pzErr, "unrecognized matchinfo: %s", zVal);
|
||||
rc = SQLITE_ERROR;
|
||||
}
|
||||
bNoDocsize = 1;
|
||||
break;
|
||||
switch( iOpt ){
|
||||
case 0: /* MATCHINFO */
|
||||
if( strlen(zVal)!=4 || sqlite3_strnicmp(zVal, "fts3", 4) ){
|
||||
sqlite3Fts3ErrMsg(pzErr, "unrecognized matchinfo: %s", zVal);
|
||||
rc = SQLITE_ERROR;
|
||||
}
|
||||
bNoDocsize = 1;
|
||||
break;
|
||||
|
||||
case 1: /* PREFIX */
|
||||
sqlite3_free(zPrefix);
|
||||
zPrefix = zVal;
|
||||
zVal = 0;
|
||||
break;
|
||||
case 1: /* PREFIX */
|
||||
sqlite3_free(zPrefix);
|
||||
zPrefix = zVal;
|
||||
zVal = 0;
|
||||
break;
|
||||
|
||||
case 2: /* COMPRESS */
|
||||
sqlite3_free(zCompress);
|
||||
zCompress = zVal;
|
||||
zVal = 0;
|
||||
break;
|
||||
case 2: /* COMPRESS */
|
||||
sqlite3_free(zCompress);
|
||||
zCompress = zVal;
|
||||
zVal = 0;
|
||||
break;
|
||||
|
||||
case 3: /* UNCOMPRESS */
|
||||
sqlite3_free(zUncompress);
|
||||
zUncompress = zVal;
|
||||
zVal = 0;
|
||||
break;
|
||||
case 3: /* UNCOMPRESS */
|
||||
sqlite3_free(zUncompress);
|
||||
zUncompress = zVal;
|
||||
zVal = 0;
|
||||
break;
|
||||
|
||||
case 4: /* ORDER */
|
||||
if( (strlen(zVal)!=3 || sqlite3_strnicmp(zVal, "asc", 3))
|
||||
&& (strlen(zVal)!=4 || sqlite3_strnicmp(zVal, "desc", 4))
|
||||
){
|
||||
sqlite3Fts3ErrMsg(pzErr, "unrecognized order: %s", zVal);
|
||||
rc = SQLITE_ERROR;
|
||||
}
|
||||
bDescIdx = (zVal[0]=='d' || zVal[0]=='D');
|
||||
break;
|
||||
case 4: /* ORDER */
|
||||
if( (strlen(zVal)!=3 || sqlite3_strnicmp(zVal, "asc", 3))
|
||||
&& (strlen(zVal)!=4 || sqlite3_strnicmp(zVal, "desc", 4))
|
||||
){
|
||||
sqlite3Fts3ErrMsg(pzErr, "unrecognized order: %s", zVal);
|
||||
rc = SQLITE_ERROR;
|
||||
}
|
||||
bDescIdx = (zVal[0]=='d' || zVal[0]=='D');
|
||||
break;
|
||||
|
||||
case 5: /* CONTENT */
|
||||
sqlite3_free(zContent);
|
||||
zContent = zVal;
|
||||
zVal = 0;
|
||||
break;
|
||||
case 5: /* CONTENT */
|
||||
sqlite3_free(zContent);
|
||||
zContent = zVal;
|
||||
zVal = 0;
|
||||
break;
|
||||
|
||||
case 6: /* LANGUAGEID */
|
||||
assert( iOpt==6 );
|
||||
sqlite3_free(zLanguageid);
|
||||
zLanguageid = zVal;
|
||||
zVal = 0;
|
||||
break;
|
||||
case 6: /* LANGUAGEID */
|
||||
assert( iOpt==6 );
|
||||
sqlite3_free(zLanguageid);
|
||||
zLanguageid = zVal;
|
||||
zVal = 0;
|
||||
break;
|
||||
|
||||
case 7: /* NOTINDEXED */
|
||||
azNotindexed[nNotindexed++] = zVal;
|
||||
zVal = 0;
|
||||
break;
|
||||
}
|
||||
case 7: /* NOTINDEXED */
|
||||
azNotindexed[nNotindexed++] = zVal;
|
||||
zVal = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
assert( iOpt==SizeofArray(aFts4Opt) );
|
||||
sqlite3Fts3ErrMsg(pzErr, "unrecognized parameter: %s", z);
|
||||
rc = SQLITE_ERROR;
|
||||
break;
|
||||
}
|
||||
sqlite3_free(zVal);
|
||||
}
|
||||
@@ -1846,7 +1849,8 @@ static int fts3ScanInteriorNode(
|
||||
isFirstTerm = 0;
|
||||
zCsr += fts3GetVarint32(zCsr, &nSuffix);
|
||||
|
||||
if( nPrefix<0 || nSuffix<0 || &zCsr[nSuffix]>zEnd ){
|
||||
assert( nPrefix>=0 && nSuffix>=0 );
|
||||
if( &zCsr[nSuffix]>zEnd ){
|
||||
rc = FTS_CORRUPT_VTAB;
|
||||
goto finish_scan;
|
||||
}
|
||||
@@ -2656,7 +2660,7 @@ int sqlite3Fts3FirstFilter(
|
||||
fts3ColumnlistCopy(0, &p);
|
||||
}
|
||||
|
||||
while( p<pEnd && *p==0x01 ){
|
||||
while( p<pEnd ){
|
||||
sqlite3_int64 iCol;
|
||||
p++;
|
||||
p += sqlite3Fts3GetVarint(p, &iCol);
|
||||
@@ -3336,33 +3340,38 @@ static int fts3ColumnMethod(
|
||||
/* The column value supplied by SQLite must be in range. */
|
||||
assert( iCol>=0 && iCol<=p->nColumn+2 );
|
||||
|
||||
if( iCol==p->nColumn+1 ){
|
||||
/* This call is a request for the "docid" column. Since "docid" is an
|
||||
** alias for "rowid", use the xRowid() method to obtain the value.
|
||||
*/
|
||||
sqlite3_result_int64(pCtx, pCsr->iPrevId);
|
||||
}else if( iCol==p->nColumn ){
|
||||
/* The extra column whose name is the same as the table.
|
||||
** Return a blob which is a pointer to the cursor. */
|
||||
sqlite3_result_blob(pCtx, &pCsr, sizeof(pCsr), SQLITE_TRANSIENT);
|
||||
}else if( iCol==p->nColumn+2 && pCsr->pExpr ){
|
||||
sqlite3_result_int64(pCtx, pCsr->iLangid);
|
||||
}else{
|
||||
/* The requested column is either a user column (one that contains
|
||||
** indexed data), or the language-id column. */
|
||||
rc = fts3CursorSeek(0, pCsr);
|
||||
switch( iCol-p->nColumn ){
|
||||
case 0:
|
||||
/* The special 'table-name' column */
|
||||
sqlite3_result_blob(pCtx, &pCsr, sizeof(Fts3Cursor*), SQLITE_TRANSIENT);
|
||||
sqlite3_result_subtype(pCtx, SQLITE_BLOB);
|
||||
break;
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
if( iCol==p->nColumn+2 ){
|
||||
int iLangid = 0;
|
||||
if( p->zLanguageid ){
|
||||
iLangid = sqlite3_column_int(pCsr->pStmt, p->nColumn+1);
|
||||
}
|
||||
sqlite3_result_int(pCtx, iLangid);
|
||||
}else if( sqlite3_data_count(pCsr->pStmt)>(iCol+1) ){
|
||||
case 1:
|
||||
/* The docid column */
|
||||
sqlite3_result_int64(pCtx, pCsr->iPrevId);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
if( pCsr->pExpr ){
|
||||
sqlite3_result_int64(pCtx, pCsr->iLangid);
|
||||
break;
|
||||
}else if( p->zLanguageid==0 ){
|
||||
sqlite3_result_int(pCtx, 0);
|
||||
break;
|
||||
}else{
|
||||
iCol = p->nColumn;
|
||||
/* fall-through */
|
||||
}
|
||||
|
||||
default:
|
||||
/* A user column. Or, if this is a full-table scan, possibly the
|
||||
** language-id column. Seek the cursor. */
|
||||
rc = fts3CursorSeek(0, pCsr);
|
||||
if( rc==SQLITE_OK && sqlite3_data_count(pCsr->pStmt)-1>iCol ){
|
||||
sqlite3_result_value(pCtx, sqlite3_column_value(pCsr->pStmt, iCol+1));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
assert( ((Fts3Table *)pCsr->base.pVtab)->pSegments==0 );
|
||||
@@ -3442,17 +3451,11 @@ static int fts3SyncMethod(sqlite3_vtab *pVtab){
|
||||
static int fts3SetHasStat(Fts3Table *p){
|
||||
int rc = SQLITE_OK;
|
||||
if( p->bHasStat==2 ){
|
||||
const char *zFmt ="SELECT 1 FROM %Q.sqlite_master WHERE tbl_name='%q_stat'";
|
||||
char *zSql = sqlite3_mprintf(zFmt, p->zDb, p->zName);
|
||||
if( zSql ){
|
||||
sqlite3_stmt *pStmt = 0;
|
||||
rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
int bHasStat = (sqlite3_step(pStmt)==SQLITE_ROW);
|
||||
rc = sqlite3_finalize(pStmt);
|
||||
if( rc==SQLITE_OK ) p->bHasStat = (u8)bHasStat;
|
||||
}
|
||||
sqlite3_free(zSql);
|
||||
char *zTbl = sqlite3_mprintf("%s_stat", p->zName);
|
||||
if( zTbl ){
|
||||
int res = sqlite3_table_column_metadata(p->db, p->zDb, zTbl, 0,0,0,0,0,0);
|
||||
sqlite3_free(zTbl);
|
||||
p->bHasStat = (res==SQLITE_OK);
|
||||
}else{
|
||||
rc = SQLITE_NOMEM;
|
||||
}
|
||||
@@ -3559,18 +3562,16 @@ static int fts3FunctionArg(
|
||||
sqlite3_value *pVal, /* argv[0] passed to function */
|
||||
Fts3Cursor **ppCsr /* OUT: Store cursor handle here */
|
||||
){
|
||||
Fts3Cursor *pRet;
|
||||
if( sqlite3_value_type(pVal)!=SQLITE_BLOB
|
||||
|| sqlite3_value_bytes(pVal)!=sizeof(Fts3Cursor *)
|
||||
){
|
||||
int rc = SQLITE_OK;
|
||||
if( sqlite3_value_subtype(pVal)==SQLITE_BLOB ){
|
||||
*ppCsr = *(Fts3Cursor**)sqlite3_value_blob(pVal);
|
||||
}else{
|
||||
char *zErr = sqlite3_mprintf("illegal first argument to %s", zFunc);
|
||||
sqlite3_result_error(pContext, zErr, -1);
|
||||
sqlite3_free(zErr);
|
||||
return SQLITE_ERROR;
|
||||
rc = SQLITE_ERROR;
|
||||
}
|
||||
memcpy(&pRet, sqlite3_value_blob(pVal), sizeof(Fts3Cursor *));
|
||||
*ppCsr = pRet;
|
||||
return SQLITE_OK;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -3957,7 +3958,7 @@ int sqlite3Fts3Init(sqlite3 *db){
|
||||
#endif
|
||||
|
||||
/* Create the virtual table wrapper around the hash-table and overload
|
||||
** the two scalar functions. If this is successful, register the
|
||||
** the four scalar functions. If this is successful, register the
|
||||
** module with sqlite.
|
||||
*/
|
||||
if( SQLITE_OK==rc
|
||||
@@ -4540,7 +4541,7 @@ static int fts3EvalIncrPhraseNext(
|
||||
** one incremental token. In which case the bIncr flag is set. */
|
||||
assert( p->bIncr==1 );
|
||||
|
||||
if( p->nToken==1 && p->bIncr ){
|
||||
if( p->nToken==1 ){
|
||||
rc = sqlite3Fts3MsrIncrNext(pTab, p->aToken[0].pSegcsr,
|
||||
&pDL->iDocid, &pDL->pList, &pDL->nList
|
||||
);
|
||||
@@ -4773,6 +4774,7 @@ static void fts3EvalTokenCosts(
|
||||
** the number of overflow pages consumed by a record B bytes in size.
|
||||
*/
|
||||
static int fts3EvalAverageDocsize(Fts3Cursor *pCsr, int *pnPage){
|
||||
int rc = SQLITE_OK;
|
||||
if( pCsr->nRowAvg==0 ){
|
||||
/* The average document size, which is required to calculate the cost
|
||||
** of each doclist, has not yet been determined. Read the required
|
||||
@@ -4785,7 +4787,6 @@ static int fts3EvalAverageDocsize(Fts3Cursor *pCsr, int *pnPage){
|
||||
** data stored in all rows of each column of the table, from left
|
||||
** to right.
|
||||
*/
|
||||
int rc;
|
||||
Fts3Table *p = (Fts3Table*)pCsr->base.pVtab;
|
||||
sqlite3_stmt *pStmt;
|
||||
sqlite3_int64 nDoc = 0;
|
||||
@@ -4812,11 +4813,10 @@ static int fts3EvalAverageDocsize(Fts3Cursor *pCsr, int *pnPage){
|
||||
pCsr->nRowAvg = (int)(((nByte / nDoc) + p->nPgsz) / p->nPgsz);
|
||||
assert( pCsr->nRowAvg>0 );
|
||||
rc = sqlite3_reset(pStmt);
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
}
|
||||
|
||||
*pnPage = pCsr->nRowAvg;
|
||||
return SQLITE_OK;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -5166,7 +5166,8 @@ static void fts3EvalNextRow(
|
||||
pExpr->iDocid = pLeft->iDocid;
|
||||
pExpr->bEof = (pLeft->bEof || pRight->bEof);
|
||||
if( pExpr->eType==FTSQUERY_NEAR && pExpr->bEof ){
|
||||
if( pRight->pPhrase && pRight->pPhrase->doclist.aAll ){
|
||||
assert( pRight->eType==FTSQUERY_PHRASE );
|
||||
if( pRight->pPhrase->doclist.aAll ){
|
||||
Fts3Doclist *pDl = &pRight->pPhrase->doclist;
|
||||
while( *pRc==SQLITE_OK && pRight->bEof==0 ){
|
||||
memset(pDl->pList, 0, pDl->nList);
|
||||
@@ -5195,7 +5196,7 @@ static void fts3EvalNextRow(
|
||||
|
||||
if( pRight->bEof || (pLeft->bEof==0 && iCmp<0) ){
|
||||
fts3EvalNextRow(pCsr, pLeft, pRc);
|
||||
}else if( pLeft->bEof || (pRight->bEof==0 && iCmp>0) ){
|
||||
}else if( pLeft->bEof || iCmp>0 ){
|
||||
fts3EvalNextRow(pCsr, pRight, pRc);
|
||||
}else{
|
||||
fts3EvalNextRow(pCsr, pLeft, pRc);
|
||||
@@ -5287,7 +5288,6 @@ static int fts3EvalNearTest(Fts3Expr *pExpr, int *pRc){
|
||||
*/
|
||||
if( *pRc==SQLITE_OK
|
||||
&& pExpr->eType==FTSQUERY_NEAR
|
||||
&& pExpr->bEof==0
|
||||
&& (pExpr->pParent==0 || pExpr->pParent->eType!=FTSQUERY_NEAR)
|
||||
){
|
||||
Fts3Expr *p;
|
||||
@@ -5296,42 +5296,39 @@ static int fts3EvalNearTest(Fts3Expr *pExpr, int *pRc){
|
||||
|
||||
/* Allocate temporary working space. */
|
||||
for(p=pExpr; p->pLeft; p=p->pLeft){
|
||||
assert( p->pRight->pPhrase->doclist.nList>0 );
|
||||
nTmp += p->pRight->pPhrase->doclist.nList;
|
||||
}
|
||||
nTmp += p->pPhrase->doclist.nList;
|
||||
if( nTmp==0 ){
|
||||
aTmp = sqlite3_malloc(nTmp*2);
|
||||
if( !aTmp ){
|
||||
*pRc = SQLITE_NOMEM;
|
||||
res = 0;
|
||||
}else{
|
||||
aTmp = sqlite3_malloc(nTmp*2);
|
||||
if( !aTmp ){
|
||||
*pRc = SQLITE_NOMEM;
|
||||
res = 0;
|
||||
}else{
|
||||
char *aPoslist = p->pPhrase->doclist.pList;
|
||||
int nToken = p->pPhrase->nToken;
|
||||
char *aPoslist = p->pPhrase->doclist.pList;
|
||||
int nToken = p->pPhrase->nToken;
|
||||
|
||||
for(p=p->pParent;res && p && p->eType==FTSQUERY_NEAR; p=p->pParent){
|
||||
Fts3Phrase *pPhrase = p->pRight->pPhrase;
|
||||
int nNear = p->nNear;
|
||||
res = fts3EvalNearTrim(nNear, aTmp, &aPoslist, &nToken, pPhrase);
|
||||
}
|
||||
|
||||
aPoslist = pExpr->pRight->pPhrase->doclist.pList;
|
||||
nToken = pExpr->pRight->pPhrase->nToken;
|
||||
for(p=pExpr->pLeft; p && res; p=p->pLeft){
|
||||
int nNear;
|
||||
Fts3Phrase *pPhrase;
|
||||
assert( p->pParent && p->pParent->pLeft==p );
|
||||
nNear = p->pParent->nNear;
|
||||
pPhrase = (
|
||||
p->eType==FTSQUERY_NEAR ? p->pRight->pPhrase : p->pPhrase
|
||||
);
|
||||
res = fts3EvalNearTrim(nNear, aTmp, &aPoslist, &nToken, pPhrase);
|
||||
}
|
||||
for(p=p->pParent;res && p && p->eType==FTSQUERY_NEAR; p=p->pParent){
|
||||
Fts3Phrase *pPhrase = p->pRight->pPhrase;
|
||||
int nNear = p->nNear;
|
||||
res = fts3EvalNearTrim(nNear, aTmp, &aPoslist, &nToken, pPhrase);
|
||||
}
|
||||
|
||||
sqlite3_free(aTmp);
|
||||
aPoslist = pExpr->pRight->pPhrase->doclist.pList;
|
||||
nToken = pExpr->pRight->pPhrase->nToken;
|
||||
for(p=pExpr->pLeft; p && res; p=p->pLeft){
|
||||
int nNear;
|
||||
Fts3Phrase *pPhrase;
|
||||
assert( p->pParent && p->pParent->pLeft==p );
|
||||
nNear = p->pParent->nNear;
|
||||
pPhrase = (
|
||||
p->eType==FTSQUERY_NEAR ? p->pRight->pPhrase : p->pPhrase
|
||||
);
|
||||
res = fts3EvalNearTrim(nNear, aTmp, &aPoslist, &nToken, pPhrase);
|
||||
}
|
||||
}
|
||||
|
||||
sqlite3_free(aTmp);
|
||||
}
|
||||
|
||||
return res;
|
||||
|
||||
+5
-4
@@ -446,9 +446,9 @@ int sqlite3Fts5IndexBeginWrite(
|
||||
|
||||
/*
|
||||
** Flush any data stored in the in-memory hash tables to the database.
|
||||
** If the bCommit flag is true, also close any open blob handles.
|
||||
** Also close any open blob handles.
|
||||
*/
|
||||
int sqlite3Fts5IndexSync(Fts5Index *p, int bCommit);
|
||||
int sqlite3Fts5IndexSync(Fts5Index *p);
|
||||
|
||||
/*
|
||||
** Discard any data stored in the in-memory hash tables. Do not write it
|
||||
@@ -618,7 +618,7 @@ int sqlite3Fts5StorageDocsize(Fts5Storage *p, i64 iRowid, int *aCol);
|
||||
int sqlite3Fts5StorageSize(Fts5Storage *p, int iCol, i64 *pnAvg);
|
||||
int sqlite3Fts5StorageRowCount(Fts5Storage *p, i64 *pnRow);
|
||||
|
||||
int sqlite3Fts5StorageSync(Fts5Storage *p, int bCommit);
|
||||
int sqlite3Fts5StorageSync(Fts5Storage *p);
|
||||
int sqlite3Fts5StorageRollback(Fts5Storage *p);
|
||||
|
||||
int sqlite3Fts5StorageConfigValue(
|
||||
@@ -654,6 +654,7 @@ struct Fts5Token {
|
||||
/* Parse a MATCH expression. */
|
||||
int sqlite3Fts5ExprNew(
|
||||
Fts5Config *pConfig,
|
||||
int iCol, /* Column on LHS of MATCH operator */
|
||||
const char *zExpr,
|
||||
Fts5Expr **ppNew,
|
||||
char **pzErr
|
||||
@@ -738,7 +739,7 @@ void sqlite3Fts5ParseNearsetFree(Fts5ExprNearset*);
|
||||
void sqlite3Fts5ParseNodeFree(Fts5ExprNode*);
|
||||
|
||||
void sqlite3Fts5ParseSetDistance(Fts5Parse*, Fts5ExprNearset*, Fts5Token*);
|
||||
void sqlite3Fts5ParseSetColset(Fts5Parse*, Fts5ExprNearset*, Fts5Colset*);
|
||||
void sqlite3Fts5ParseSetColset(Fts5Parse*, Fts5ExprNode*, Fts5Colset*);
|
||||
Fts5Colset *sqlite3Fts5ParseColsetInvert(Fts5Parse*, Fts5Colset*);
|
||||
void sqlite3Fts5ParseFinished(Fts5Parse *pParse, Fts5ExprNode *p);
|
||||
void sqlite3Fts5ParseNear(Fts5Parse *pParse, Fts5Token*);
|
||||
|
||||
+107
-9
@@ -213,6 +213,7 @@ static void fts5ParseFree(void *p){ sqlite3_free(p); }
|
||||
|
||||
int sqlite3Fts5ExprNew(
|
||||
Fts5Config *pConfig, /* FTS5 Configuration */
|
||||
int iCol,
|
||||
const char *zExpr, /* Expression text */
|
||||
Fts5Expr **ppNew,
|
||||
char **pzErr
|
||||
@@ -237,6 +238,18 @@ int sqlite3Fts5ExprNew(
|
||||
}while( sParse.rc==SQLITE_OK && t!=FTS5_EOF );
|
||||
sqlite3Fts5ParserFree(pEngine, fts5ParseFree);
|
||||
|
||||
/* If the LHS of the MATCH expression was a user column, apply the
|
||||
** implicit column-filter. */
|
||||
if( iCol<pConfig->nCol && sParse.pExpr && sParse.rc==SQLITE_OK ){
|
||||
int n = sizeof(Fts5Colset);
|
||||
Fts5Colset *pColset = (Fts5Colset*)sqlite3Fts5MallocZero(&sParse.rc, n);
|
||||
if( pColset ){
|
||||
pColset->nCol = 1;
|
||||
pColset->aiCol[0] = iCol;
|
||||
sqlite3Fts5ParseSetColset(&sParse, sParse.pExpr, pColset);
|
||||
}
|
||||
}
|
||||
|
||||
assert( sParse.rc!=SQLITE_OK || sParse.zErr==0 );
|
||||
if( sParse.rc==SQLITE_OK ){
|
||||
*ppNew = pNew = sqlite3_malloc(sizeof(Fts5Expr));
|
||||
@@ -1886,25 +1899,110 @@ Fts5Colset *sqlite3Fts5ParseColset(
|
||||
return pRet;
|
||||
}
|
||||
|
||||
/*
|
||||
** If argument pOrig is NULL, or if (*pRc) is set to anything other than
|
||||
** SQLITE_OK when this function is called, NULL is returned.
|
||||
**
|
||||
** Otherwise, a copy of (*pOrig) is made into memory obtained from
|
||||
** sqlite3Fts5MallocZero() and a pointer to it returned. If the allocation
|
||||
** fails, (*pRc) is set to SQLITE_NOMEM and NULL is returned.
|
||||
*/
|
||||
static Fts5Colset *fts5CloneColset(int *pRc, Fts5Colset *pOrig){
|
||||
Fts5Colset *pRet;
|
||||
if( pOrig ){
|
||||
int nByte = sizeof(Fts5Colset) + (pOrig->nCol-1) * sizeof(int);
|
||||
pRet = (Fts5Colset*)sqlite3Fts5MallocZero(pRc, nByte);
|
||||
if( pRet ){
|
||||
memcpy(pRet, pOrig, nByte);
|
||||
}
|
||||
}else{
|
||||
pRet = 0;
|
||||
}
|
||||
return pRet;
|
||||
}
|
||||
|
||||
/*
|
||||
** Remove from colset pColset any columns that are not also in colset pMerge.
|
||||
*/
|
||||
static void fts5MergeColset(Fts5Colset *pColset, Fts5Colset *pMerge){
|
||||
int iIn = 0; /* Next input in pColset */
|
||||
int iMerge = 0; /* Next input in pMerge */
|
||||
int iOut = 0; /* Next output slot in pColset */
|
||||
|
||||
while( iIn<pColset->nCol && iMerge<pMerge->nCol ){
|
||||
int iDiff = pColset->aiCol[iIn] - pMerge->aiCol[iMerge];
|
||||
if( iDiff==0 ){
|
||||
pColset->aiCol[iOut++] = pMerge->aiCol[iMerge];
|
||||
iMerge++;
|
||||
iIn++;
|
||||
}else if( iDiff>0 ){
|
||||
iMerge++;
|
||||
}else{
|
||||
iIn++;
|
||||
}
|
||||
}
|
||||
pColset->nCol = iOut;
|
||||
}
|
||||
|
||||
/*
|
||||
** Recursively apply colset pColset to expression node pNode and all of
|
||||
** its decendents. If (*ppFree) is not NULL, it contains a spare copy
|
||||
** of pColset. This function may use the spare copy and set (*ppFree) to
|
||||
** zero, or it may create copies of pColset using fts5CloneColset().
|
||||
*/
|
||||
static void fts5ParseSetColset(
|
||||
Fts5Parse *pParse,
|
||||
Fts5ExprNode *pNode,
|
||||
Fts5Colset *pColset,
|
||||
Fts5Colset **ppFree
|
||||
){
|
||||
if( pParse->rc==SQLITE_OK ){
|
||||
assert( pNode->eType==FTS5_TERM || pNode->eType==FTS5_STRING
|
||||
|| pNode->eType==FTS5_AND || pNode->eType==FTS5_OR
|
||||
|| pNode->eType==FTS5_NOT || pNode->eType==FTS5_EOF
|
||||
);
|
||||
if( pNode->eType==FTS5_STRING || pNode->eType==FTS5_TERM ){
|
||||
Fts5ExprNearset *pNear = pNode->pNear;
|
||||
if( pNear->pColset ){
|
||||
fts5MergeColset(pNear->pColset, pColset);
|
||||
if( pNear->pColset->nCol==0 ){
|
||||
pNode->eType = FTS5_EOF;
|
||||
pNode->xNext = 0;
|
||||
}
|
||||
}else if( *ppFree ){
|
||||
pNear->pColset = pColset;
|
||||
*ppFree = 0;
|
||||
}else{
|
||||
pNear->pColset = fts5CloneColset(&pParse->rc, pColset);
|
||||
}
|
||||
}else{
|
||||
int i;
|
||||
assert( pNode->eType!=FTS5_EOF || pNode->nChild==0 );
|
||||
for(i=0; i<pNode->nChild; i++){
|
||||
fts5ParseSetColset(pParse, pNode->apChild[i], pColset, ppFree);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Apply colset pColset to expression node pExpr and all of its descendents.
|
||||
*/
|
||||
void sqlite3Fts5ParseSetColset(
|
||||
Fts5Parse *pParse,
|
||||
Fts5ExprNearset *pNear,
|
||||
Fts5ExprNode *pExpr,
|
||||
Fts5Colset *pColset
|
||||
){
|
||||
Fts5Colset *pFree = pColset;
|
||||
if( pParse->pConfig->eDetail==FTS5_DETAIL_NONE ){
|
||||
pParse->rc = SQLITE_ERROR;
|
||||
pParse->zErr = sqlite3_mprintf(
|
||||
"fts5: column queries are not supported (detail=none)"
|
||||
);
|
||||
sqlite3_free(pColset);
|
||||
return;
|
||||
}
|
||||
|
||||
if( pNear ){
|
||||
pNear->pColset = pColset;
|
||||
}else{
|
||||
sqlite3_free(pColset);
|
||||
fts5ParseSetColset(pParse, pExpr, pColset, &pFree);
|
||||
}
|
||||
sqlite3_free(pFree);
|
||||
}
|
||||
|
||||
static void fts5ExprAssignXNext(Fts5ExprNode *pNode){
|
||||
@@ -2358,7 +2456,7 @@ static void fts5ExprFunction(
|
||||
|
||||
rc = sqlite3Fts5ConfigParse(pGlobal, db, nConfig, azConfig, &pConfig, &zErr);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3Fts5ExprNew(pConfig, zExpr, &pExpr, &zErr);
|
||||
rc = sqlite3Fts5ExprNew(pConfig, pConfig->nCol, zExpr, &pExpr, &zErr);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
char *zText;
|
||||
|
||||
+26
-25
@@ -628,7 +628,6 @@ static void fts5CloseReader(Fts5Index *p){
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Retrieve a record from the %_data table.
|
||||
**
|
||||
@@ -2879,7 +2878,8 @@ static void fts5MultiIterNext2(
|
||||
){
|
||||
assert( pIter->bSkipEmpty );
|
||||
if( p->rc==SQLITE_OK ){
|
||||
do {
|
||||
*pbNewTerm = 0;
|
||||
do{
|
||||
int iFirst = pIter->aFirst[1].iFirst;
|
||||
Fts5SegIter *pSeg = &pIter->aSeg[iFirst];
|
||||
int bNewTerm = 0;
|
||||
@@ -2892,8 +2892,6 @@ static void fts5MultiIterNext2(
|
||||
fts5MultiIterAdvanced(p, pIter, iFirst, 1);
|
||||
fts5MultiIterSetEof(pIter);
|
||||
*pbNewTerm = 1;
|
||||
}else{
|
||||
*pbNewTerm = 0;
|
||||
}
|
||||
fts5AssertMultiIterSetup(p, pIter);
|
||||
|
||||
@@ -3159,23 +3157,23 @@ static int fts5IndexExtractCol(
|
||||
return p - (*pa);
|
||||
}
|
||||
|
||||
static int fts5IndexExtractColset (
|
||||
static void fts5IndexExtractColset(
|
||||
int *pRc,
|
||||
Fts5Colset *pColset, /* Colset to filter on */
|
||||
const u8 *pPos, int nPos, /* Position list */
|
||||
Fts5Buffer *pBuf /* Output buffer */
|
||||
){
|
||||
int rc = 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(&rc, pBuf, nSub, pSub);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -3299,8 +3297,9 @@ static void fts5IterSetOutputs_Full(Fts5Iter *pIter, Fts5SegIter *pSeg){
|
||||
pIter->base.nData = fts5IndexExtractCol(&a, pSeg->nPos,pColset->aiCol[0]);
|
||||
pIter->base.pData = a;
|
||||
}else{
|
||||
int *pRc = &pIter->pIndex->rc;
|
||||
fts5BufferZero(&pIter->poslist);
|
||||
fts5IndexExtractColset(pColset, a, pSeg->nPos, &pIter->poslist);
|
||||
fts5IndexExtractColset(pRc, pColset, a, pSeg->nPos, &pIter->poslist);
|
||||
pIter->base.pData = pIter->poslist.p;
|
||||
pIter->base.nData = pIter->poslist.n;
|
||||
}
|
||||
@@ -3845,9 +3844,6 @@ static void fts5WriteFlushLeaf(Fts5Index *p, Fts5SegWriter *pWriter){
|
||||
Fts5PageWriter *pPage = &pWriter->writer;
|
||||
i64 iRowid;
|
||||
|
||||
static int nCall = 0;
|
||||
nCall++;
|
||||
|
||||
assert( (pPage->pgidx.n==0)==(pWriter->bFirstTermInPage) );
|
||||
|
||||
/* Set the szLeaf header field. */
|
||||
@@ -4196,6 +4192,7 @@ static void fts5IndexMergeLevel(
|
||||
int bOldest; /* True if the output segment is the oldest */
|
||||
int eDetail = p->pConfig->eDetail;
|
||||
const int flags = FTS5INDEX_QUERY_NOOUTPUT;
|
||||
int bTermWritten = 0; /* True if current term already output */
|
||||
|
||||
assert( iLvl<pStruct->nLevel );
|
||||
assert( pLvl->nMerge<=pLvl->nSeg );
|
||||
@@ -4249,18 +4246,22 @@ static void fts5IndexMergeLevel(
|
||||
int nTerm;
|
||||
const u8 *pTerm;
|
||||
|
||||
/* Check for key annihilation. */
|
||||
if( pSegIter->nPos==0 && (bOldest || pSegIter->bDel==0) ) continue;
|
||||
|
||||
pTerm = fts5MultiIterTerm(pIter, &nTerm);
|
||||
if( nTerm!=term.n || memcmp(pTerm, term.p, nTerm) ){
|
||||
if( pnRem && writer.nLeafWritten>nRem ){
|
||||
break;
|
||||
}
|
||||
fts5BufferSet(&p->rc, &term, nTerm, pTerm);
|
||||
bTermWritten =0;
|
||||
}
|
||||
|
||||
/* Check for key annihilation. */
|
||||
if( pSegIter->nPos==0 && (bOldest || pSegIter->bDel==0) ) continue;
|
||||
|
||||
if( p->rc==SQLITE_OK && bTermWritten==0 ){
|
||||
/* This is a new term. Append a term to the output segment. */
|
||||
fts5WriteAppendTerm(p, &writer, nTerm, pTerm);
|
||||
fts5BufferSet(&p->rc, &term, nTerm, pTerm);
|
||||
bTermWritten = 1;
|
||||
}
|
||||
|
||||
/* Append the rowid to the output */
|
||||
@@ -5131,10 +5132,10 @@ int sqlite3Fts5IndexBeginWrite(Fts5Index *p, int bDelete, i64 iRowid){
|
||||
/*
|
||||
** Commit data to disk.
|
||||
*/
|
||||
int sqlite3Fts5IndexSync(Fts5Index *p, int bCommit){
|
||||
int sqlite3Fts5IndexSync(Fts5Index *p){
|
||||
assert( p->rc==SQLITE_OK );
|
||||
fts5IndexFlush(p);
|
||||
if( bCommit ) fts5CloseReader(p);
|
||||
fts5CloseReader(p);
|
||||
return fts5IndexReturn(p);
|
||||
}
|
||||
|
||||
|
||||
+30
-16
@@ -506,6 +506,7 @@ static void fts5SetUniqueFlag(sqlite3_index_info *pIdxInfo){
|
||||
static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
|
||||
Fts5Table *pTab = (Fts5Table*)pVTab;
|
||||
Fts5Config *pConfig = pTab->pConfig;
|
||||
const int nCol = pConfig->nCol;
|
||||
int idxFlags = 0; /* Parameter passed through to xFilter() */
|
||||
int bHasMatch;
|
||||
int iNext;
|
||||
@@ -531,24 +532,34 @@ static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
|
||||
|
||||
int aColMap[3];
|
||||
aColMap[0] = -1;
|
||||
aColMap[1] = pConfig->nCol;
|
||||
aColMap[2] = pConfig->nCol+1;
|
||||
aColMap[1] = nCol;
|
||||
aColMap[2] = nCol+1;
|
||||
|
||||
/* Set idxFlags flags for all WHERE clause terms that will be used. */
|
||||
for(i=0; i<pInfo->nConstraint; i++){
|
||||
struct sqlite3_index_constraint *p = &pInfo->aConstraint[i];
|
||||
int j;
|
||||
for(j=0; j<ArraySize(aConstraint); j++){
|
||||
struct Constraint *pC = &aConstraint[j];
|
||||
if( p->iColumn==aColMap[pC->iCol] && p->op & pC->op ){
|
||||
if( p->usable ){
|
||||
int iCol = p->iColumn;
|
||||
|
||||
if( (p->op==SQLITE_INDEX_CONSTRAINT_MATCH && iCol>=0 && iCol<=nCol)
|
||||
|| (p->op==SQLITE_INDEX_CONSTRAINT_EQ && iCol==nCol)
|
||||
){
|
||||
/* A MATCH operator or equivalent */
|
||||
if( p->usable ){
|
||||
idxFlags = (idxFlags & 0xFFFF) | FTS5_BI_MATCH | (iCol << 16);
|
||||
aConstraint[0].iConsIndex = i;
|
||||
}else{
|
||||
/* As there exists an unusable MATCH constraint this is an
|
||||
** unusable plan. Set a prohibitively high cost. */
|
||||
pInfo->estimatedCost = 1e50;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
}else{
|
||||
int j;
|
||||
for(j=1; j<ArraySize(aConstraint); j++){
|
||||
struct Constraint *pC = &aConstraint[j];
|
||||
if( iCol==aColMap[pC->iCol] && p->op & pC->op && p->usable ){
|
||||
pC->iConsIndex = i;
|
||||
idxFlags |= pC->fts5op;
|
||||
}else if( j==0 ){
|
||||
/* As there exists an unusable MATCH constraint this is an
|
||||
** unusable plan. Set a prohibitively high cost. */
|
||||
pInfo->estimatedCost = 1e50;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1123,6 +1134,7 @@ static int fts5FilterMethod(
|
||||
sqlite3_value *pRowidEq = 0; /* rowid = ? expression (or NULL) */
|
||||
sqlite3_value *pRowidLe = 0; /* rowid <= ? expression (or NULL) */
|
||||
sqlite3_value *pRowidGe = 0; /* rowid >= ? expression (or NULL) */
|
||||
int iCol; /* Column on LHS of MATCH operator */
|
||||
char **pzErrmsg = pConfig->pzErrmsg;
|
||||
|
||||
UNUSED_PARAM(zUnused);
|
||||
@@ -1153,6 +1165,8 @@ static int fts5FilterMethod(
|
||||
if( BitFlagTest(idxNum, FTS5_BI_ROWID_EQ) ) pRowidEq = apVal[iVal++];
|
||||
if( BitFlagTest(idxNum, FTS5_BI_ROWID_LE) ) pRowidLe = apVal[iVal++];
|
||||
if( BitFlagTest(idxNum, FTS5_BI_ROWID_GE) ) pRowidGe = apVal[iVal++];
|
||||
iCol = (idxNum>>16);
|
||||
assert( iCol>=0 && iCol<=pConfig->nCol );
|
||||
assert( iVal==nVal );
|
||||
bOrderByRank = ((idxNum & FTS5_BI_ORDER_RANK) ? 1 : 0);
|
||||
pCsr->bDesc = bDesc = ((idxNum & FTS5_BI_ORDER_DESC) ? 1 : 0);
|
||||
@@ -1199,7 +1213,7 @@ static int fts5FilterMethod(
|
||||
rc = fts5SpecialMatch(pTab, pCsr, &zExpr[1]);
|
||||
}else{
|
||||
char **pzErr = &pTab->base.zErrMsg;
|
||||
rc = sqlite3Fts5ExprNew(pConfig, zExpr, &pCsr->pExpr, pzErr);
|
||||
rc = sqlite3Fts5ExprNew(pConfig, iCol, zExpr, &pCsr->pExpr, pzErr);
|
||||
if( rc==SQLITE_OK ){
|
||||
if( bOrderByRank ){
|
||||
pCsr->ePlan = FTS5_PLAN_SORTED_MATCH;
|
||||
@@ -1579,7 +1593,7 @@ static int fts5SyncMethod(sqlite3_vtab *pVtab){
|
||||
fts5CheckTransactionState(pTab, FTS5_SYNC, 0);
|
||||
pTab->pConfig->pzErrmsg = &pTab->base.zErrMsg;
|
||||
fts5TripCursors(pTab);
|
||||
rc = sqlite3Fts5StorageSync(pTab->pStorage, 1);
|
||||
rc = sqlite3Fts5StorageSync(pTab->pStorage);
|
||||
pTab->pConfig->pzErrmsg = 0;
|
||||
return rc;
|
||||
}
|
||||
@@ -2390,7 +2404,7 @@ static int fts5SavepointMethod(sqlite3_vtab *pVtab, int iSavepoint){
|
||||
UNUSED_PARAM(iSavepoint); /* Call below is a no-op for NDEBUG builds */
|
||||
fts5CheckTransactionState(pTab, FTS5_SAVEPOINT, iSavepoint);
|
||||
fts5TripCursors(pTab);
|
||||
return sqlite3Fts5StorageSync(pTab->pStorage, 0);
|
||||
return sqlite3Fts5StorageSync(pTab->pStorage);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2403,7 +2417,7 @@ static int fts5ReleaseMethod(sqlite3_vtab *pVtab, int iSavepoint){
|
||||
UNUSED_PARAM(iSavepoint); /* Call below is a no-op for NDEBUG builds */
|
||||
fts5CheckTransactionState(pTab, FTS5_RELEASE, iSavepoint);
|
||||
fts5TripCursors(pTab);
|
||||
return sqlite3Fts5StorageSync(pTab->pStorage, 0);
|
||||
return sqlite3Fts5StorageSync(pTab->pStorage);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -218,7 +218,7 @@ static void fts5StorageRenameOne(
|
||||
|
||||
int sqlite3Fts5StorageRename(Fts5Storage *pStorage, const char *zName){
|
||||
Fts5Config *pConfig = pStorage->pConfig;
|
||||
int rc = sqlite3Fts5StorageSync(pStorage, 1);
|
||||
int rc = sqlite3Fts5StorageSync(pStorage);
|
||||
|
||||
fts5StorageRenameOne(pConfig, &rc, "data", zName);
|
||||
fts5StorageRenameOne(pConfig, &rc, "idx", zName);
|
||||
@@ -1081,15 +1081,15 @@ int sqlite3Fts5StorageRowCount(Fts5Storage *p, i64 *pnRow){
|
||||
/*
|
||||
** Flush any data currently held in-memory to disk.
|
||||
*/
|
||||
int sqlite3Fts5StorageSync(Fts5Storage *p, int bCommit){
|
||||
int sqlite3Fts5StorageSync(Fts5Storage *p){
|
||||
int rc = SQLITE_OK;
|
||||
i64 iLastRowid = sqlite3_last_insert_rowid(p->pConfig->db);
|
||||
if( p->bTotalsValid ){
|
||||
rc = fts5StorageSaveTotals(p);
|
||||
if( bCommit ) p->bTotalsValid = 0;
|
||||
p->bTotalsValid = 0;
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3Fts5IndexSync(p->pIndex, bCommit);
|
||||
rc = sqlite3Fts5IndexSync(p->pIndex);
|
||||
}
|
||||
sqlite3_set_last_insert_rowid(p->pConfig->db, iLastRowid);
|
||||
return rc;
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
*/
|
||||
#if defined(SQLITE_TEST) && defined(SQLITE_ENABLE_FTS5)
|
||||
|
||||
#include <fts5.h>
|
||||
#include "fts5.h"
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
|
||||
+31
-26
@@ -89,32 +89,6 @@ input ::= expr(X). { sqlite3Fts5ParseFinished(pParse, X); }
|
||||
%destructor expr { sqlite3Fts5ParseNodeFree($$); }
|
||||
%destructor exprlist { sqlite3Fts5ParseNodeFree($$); }
|
||||
|
||||
expr(A) ::= expr(X) AND expr(Y). {
|
||||
A = sqlite3Fts5ParseNode(pParse, FTS5_AND, X, Y, 0);
|
||||
}
|
||||
expr(A) ::= expr(X) OR expr(Y). {
|
||||
A = sqlite3Fts5ParseNode(pParse, FTS5_OR, X, Y, 0);
|
||||
}
|
||||
expr(A) ::= expr(X) NOT expr(Y). {
|
||||
A = sqlite3Fts5ParseNode(pParse, FTS5_NOT, X, Y, 0);
|
||||
}
|
||||
|
||||
expr(A) ::= LP expr(X) RP. {A = X;}
|
||||
expr(A) ::= exprlist(X). {A = X;}
|
||||
|
||||
exprlist(A) ::= cnearset(X). {A = X;}
|
||||
exprlist(A) ::= exprlist(X) cnearset(Y). {
|
||||
A = sqlite3Fts5ParseImplicitAnd(pParse, X, Y);
|
||||
}
|
||||
|
||||
cnearset(A) ::= nearset(X). {
|
||||
A = sqlite3Fts5ParseNode(pParse, FTS5_STRING, 0, 0, X);
|
||||
}
|
||||
cnearset(A) ::= colset(X) COLON nearset(Y). {
|
||||
sqlite3Fts5ParseSetColset(pParse, Y, X);
|
||||
A = sqlite3Fts5ParseNode(pParse, FTS5_STRING, 0, 0, Y);
|
||||
}
|
||||
|
||||
%type colset {Fts5Colset*}
|
||||
%destructor colset { sqlite3_free($$); }
|
||||
%type colsetlist {Fts5Colset*}
|
||||
@@ -138,6 +112,37 @@ colsetlist(A) ::= STRING(X). {
|
||||
A = sqlite3Fts5ParseColset(pParse, 0, &X);
|
||||
}
|
||||
|
||||
expr(A) ::= expr(X) AND expr(Y). {
|
||||
A = sqlite3Fts5ParseNode(pParse, FTS5_AND, X, Y, 0);
|
||||
}
|
||||
expr(A) ::= expr(X) OR expr(Y). {
|
||||
A = sqlite3Fts5ParseNode(pParse, FTS5_OR, X, Y, 0);
|
||||
}
|
||||
expr(A) ::= expr(X) NOT expr(Y). {
|
||||
A = sqlite3Fts5ParseNode(pParse, FTS5_NOT, X, Y, 0);
|
||||
}
|
||||
|
||||
expr(A) ::= colset(X) COLON LP expr(Y) RP. {
|
||||
sqlite3Fts5ParseSetColset(pParse, Y, X);
|
||||
A = Y;
|
||||
}
|
||||
expr(A) ::= LP expr(X) RP. {A = X;}
|
||||
expr(A) ::= exprlist(X). {A = X;}
|
||||
|
||||
exprlist(A) ::= cnearset(X). {A = X;}
|
||||
exprlist(A) ::= exprlist(X) cnearset(Y). {
|
||||
A = sqlite3Fts5ParseImplicitAnd(pParse, X, Y);
|
||||
}
|
||||
|
||||
cnearset(A) ::= nearset(X). {
|
||||
A = sqlite3Fts5ParseNode(pParse, FTS5_STRING, 0, 0, X);
|
||||
}
|
||||
cnearset(A) ::= colset(X) COLON nearset(Y). {
|
||||
A = sqlite3Fts5ParseNode(pParse, FTS5_STRING, 0, 0, Y);
|
||||
sqlite3Fts5ParseSetColset(pParse, A, X);
|
||||
}
|
||||
|
||||
|
||||
%type nearset {Fts5ExprNearset*}
|
||||
%type nearphrases {Fts5ExprNearset*}
|
||||
%destructor nearset { sqlite3Fts5ParseNearsetFree($$); }
|
||||
|
||||
@@ -561,6 +561,36 @@ do_test 20.1 {
|
||||
execsql { SELECT rowid FROM tmp WHERE tmp MATCH 'y' }
|
||||
} $::ids
|
||||
|
||||
#--------------------------------------------------------------------
|
||||
# Test that a DROP TABLE may be executed within a transaction that
|
||||
# writes to an FTS5 table.
|
||||
#
|
||||
do_execsql_test 21.0 {
|
||||
CREATE TEMP TABLE t8(a, b);
|
||||
CREATE VIRTUAL TABLE ft USING fts5(x, detail=%DETAIL%);
|
||||
}
|
||||
|
||||
do_execsql_test 21.1 {
|
||||
BEGIN;
|
||||
INSERT INTO ft VALUES('a b c');
|
||||
DROP TABLE t8;
|
||||
COMMIT;
|
||||
}
|
||||
|
||||
do_execsql_test 22.0 {
|
||||
CREATE VIRTUAL TABLE t9 USING fts5(x, detail=%DETAIL%);
|
||||
INSERT INTO t9(rowid, x) VALUES(2, 'bbb');
|
||||
BEGIN;
|
||||
INSERT INTO t9(rowid, x) VALUES(1, 'aaa');
|
||||
DELETE FROM t9 WHERE rowid = 2;
|
||||
INSERT INTO t9(rowid, x) VALUES(3, 'bbb');
|
||||
COMMIT;
|
||||
}
|
||||
|
||||
do_execsql_test 22.1 {
|
||||
SELECT rowid FROM t9('a*')
|
||||
} {1}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -44,13 +44,42 @@ foreach_detail_mode $::testprefix {
|
||||
9 "-c : a" {1 2 4}
|
||||
10 "-\"c\" : a" {1 2 4}
|
||||
} {
|
||||
breakpoint
|
||||
do_execsql_test 1.$tn {
|
||||
SELECT rowid FROM t1($q)
|
||||
} $res
|
||||
}
|
||||
|
||||
foreach {tn q res} {
|
||||
0 {{a} : (a AND ":")} {}
|
||||
1 "{a b c} : (a AND d)" {2 3}
|
||||
2 "{a b c} : (a AND b:d)" {3}
|
||||
3 "{a b c} : (a AND d:d)" {}
|
||||
4 "{b} : ( {b a} : ( {c b a} : ( {d b c a} : ( d OR c ) ) ) )" {3 4}
|
||||
5 "{a} : ( {b a} : ( {c b a} : ( {d b c a} : ( d OR c ) ) ) )" {2 3}
|
||||
6 "{a} : ( {b a} : ( {c b} : ( {d b c a} : ( d OR c ) ) ) )" {}
|
||||
7 "{a b c} : (b:a AND c:b)" {2}
|
||||
} {
|
||||
do_execsql_test 2.$tn {
|
||||
SELECT rowid FROM t1($q)
|
||||
} $res
|
||||
}
|
||||
|
||||
foreach {tn w res} {
|
||||
0 "a MATCH 'a'" {1}
|
||||
1 "b MATCH 'a'" {2}
|
||||
2 "b MATCH '{a b c} : a'" {2}
|
||||
3 "b MATCH 'a OR b'" {1 2}
|
||||
4 "b MATCH 'a OR a:b'" {2}
|
||||
5 "b MATCH 'a OR b:b'" {1 2}
|
||||
} {
|
||||
do_execsql_test 3.$tn "
|
||||
SELECT rowid FROM t1 WHERE $w
|
||||
" $res
|
||||
}
|
||||
|
||||
do_catchsql_test 4.1 {
|
||||
SELECT * FROM t1 WHERE rowid MATCH 'a'
|
||||
} {1 {unable to use function MATCH in the requested context}}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
# 2017 May 12
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#*************************************************************************
|
||||
# This file implements regression tests for SQLite library. The
|
||||
# focus of this script is testing the FTS5 module.
|
||||
#
|
||||
|
||||
source [file join [file dirname [info script]] fts5_common.tcl]
|
||||
set testprefix fts5delete
|
||||
|
||||
# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
|
||||
ifcapable !fts5 {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
fts5_aux_test_functions db
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE VIRTUAL TABLE t1 USING fts5(x);
|
||||
WITH s(i) AS (
|
||||
SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<5000
|
||||
)
|
||||
INSERT INTO t1(rowid, x) SELECT i, (i/2)*2 FROM s;
|
||||
}
|
||||
|
||||
do_test 1.1 {
|
||||
execsql BEGIN
|
||||
for {set i 1} {$i<=5000} {incr i} {
|
||||
if {$i % 2} {
|
||||
execsql { INSERT INTO t1 VALUES($i) }
|
||||
} else {
|
||||
execsql { DELETE FROM t1 WHERE rowid = $i }
|
||||
}
|
||||
}
|
||||
execsql COMMIT
|
||||
} {}
|
||||
|
||||
do_test 1.2 {
|
||||
execsql { INSERT INTO t1(t1, rank) VALUES('usermerge', 2); }
|
||||
for {set i 0} {$i < 5} {incr i} {
|
||||
execsql { INSERT INTO t1(t1, rank) VALUES('merge', 1) }
|
||||
execsql { INSERT INTO t1(t1) VALUES('integrity-check') }
|
||||
}
|
||||
} {}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -107,5 +107,29 @@ do_faultsim_test 3.3 -faults oom* -body {
|
||||
faultsim_test_result {0 {2 3}}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test OOM injection with nested colsets.
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 4.0 {
|
||||
CREATE VIRTUAL TABLE t1 USING fts5(a, b, c, d);
|
||||
INSERT INTO t1 VALUES('a', 'b', 'c', 'd'); -- 1
|
||||
INSERT INTO t1 VALUES('d', 'a', 'b', 'c'); -- 2
|
||||
INSERT INTO t1 VALUES('c', 'd', 'a', 'b'); -- 3
|
||||
INSERT INTO t1 VALUES('b', 'c', 'd', 'a'); -- 4
|
||||
}
|
||||
do_faultsim_test 4.1 -faults oom* -body {
|
||||
execsql { SELECT rowid FROM t1('{a b c} : (b:a AND c:b)'); }
|
||||
} -test {
|
||||
faultsim_test_result {0 2}
|
||||
}
|
||||
|
||||
do_faultsim_test 4.2 -faults oom* -body {
|
||||
execsql { SELECT rowid FROM t1('{a b c} : (a AND d)') }
|
||||
} -test {
|
||||
faultsim_test_result {0 {2 3}}
|
||||
}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ do_eqp_test 1.1 {
|
||||
SELECT * FROM t1, f1 WHERE f1 MATCH t1.x
|
||||
} {
|
||||
0 0 0 {SCAN TABLE t1}
|
||||
0 1 1 {SCAN TABLE f1 VIRTUAL TABLE INDEX 1:}
|
||||
0 1 1 {SCAN TABLE f1 VIRTUAL TABLE INDEX 65537:}
|
||||
}
|
||||
|
||||
do_eqp_test 1.2 {
|
||||
@@ -43,7 +43,7 @@ do_eqp_test 1.2 {
|
||||
do_eqp_test 1.3 {
|
||||
SELECT * FROM f1 WHERE f1 MATCH ? ORDER BY ff
|
||||
} {
|
||||
0 0 0 {SCAN TABLE f1 VIRTUAL TABLE INDEX 1:}
|
||||
0 0 0 {SCAN TABLE f1 VIRTUAL TABLE INDEX 65537:}
|
||||
0 0 0 {USE TEMP B-TREE FOR ORDER BY}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
** 2017-04-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 a run-time loadable extension to SQLite that
|
||||
** registers a sqlite3_collation_needed() callback to register a fake
|
||||
** collating function for any unknown collating sequence. The fake
|
||||
** collating function works like BINARY.
|
||||
**
|
||||
** This extension can be used to load schemas that contain one or more
|
||||
** unknown collating sequences.
|
||||
*/
|
||||
#include "sqlite3ext.h"
|
||||
SQLITE_EXTENSION_INIT1
|
||||
#include <string.h>
|
||||
|
||||
static int anyCollFunc(
|
||||
void *NotUsed,
|
||||
int nKey1, const void *pKey1,
|
||||
int nKey2, const void *pKey2
|
||||
){
|
||||
int rc, n;
|
||||
n = nKey1<nKey2 ? nKey1 : nKey2;
|
||||
rc = memcmp(pKey1, pKey2, n);
|
||||
if( rc==0 ) rc = nKey1 - nKey2;
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void anyCollNeeded(
|
||||
void *NotUsed,
|
||||
sqlite3 *db,
|
||||
int eTextRep,
|
||||
const char *zCollName
|
||||
){
|
||||
sqlite3_create_collation(db, zCollName, eTextRep, 0, anyCollFunc);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
__declspec(dllexport)
|
||||
#endif
|
||||
int sqlite3_anycollseq_init(
|
||||
sqlite3 *db,
|
||||
char **pzErrMsg,
|
||||
const sqlite3_api_routines *pApi
|
||||
){
|
||||
int rc = SQLITE_OK;
|
||||
SQLITE_EXTENSION_INIT2(pApi);
|
||||
rc = sqlite3_collation_needed(db, 0, anyCollNeeded);
|
||||
return rc;
|
||||
}
|
||||
+71
-38
@@ -324,54 +324,86 @@ static void output_formatted(DState *p, const char *zFormat, ...){
|
||||
}
|
||||
|
||||
/*
|
||||
** Output the given string as a quoted string using SQL quoting conventions.
|
||||
** Find a string that is not found anywhere in z[]. Return a pointer
|
||||
** to that string.
|
||||
**
|
||||
** The "\n" and "\r" characters are converted to char(10) and char(13)
|
||||
** to prevent them from being transformed by end-of-line translators.
|
||||
** Try to use zA and zB first. If both of those are already found in z[]
|
||||
** then make up some string and store it in the buffer zBuf.
|
||||
*/
|
||||
static void output_quoted_string(DState *p, const unsigned char *z){
|
||||
static const char *unused_string(
|
||||
const char *z, /* Result must not appear anywhere in z */
|
||||
const char *zA, const char *zB, /* Try these first */
|
||||
char *zBuf /* Space to store a generated string */
|
||||
){
|
||||
unsigned i = 0;
|
||||
if( strstr(z, zA)==0 ) return zA;
|
||||
if( strstr(z, zB)==0 ) return zB;
|
||||
do{
|
||||
sqlite3_snprintf(20,zBuf,"(%s%u)", zA, i++);
|
||||
}while( strstr(z,zBuf)!=0 );
|
||||
return zBuf;
|
||||
}
|
||||
|
||||
/*
|
||||
** Output the given string as a quoted string using SQL quoting conventions.
|
||||
** Additionallly , escape the "\n" and "\r" characters so that they do not
|
||||
** get corrupted by end-of-line translation facilities in some operating
|
||||
** systems.
|
||||
*/
|
||||
static void output_quoted_escaped_string(DState *p, const char *z){
|
||||
int i;
|
||||
char c;
|
||||
int inQuote = 0;
|
||||
int bStarted = 0;
|
||||
|
||||
for(i=0; (c = z[i])!=0 && c!='\'' && c!='\n' && c!='\r'; i++){}
|
||||
if( c==0 ){
|
||||
output_formatted(p, "'%s'", z);
|
||||
return;
|
||||
}
|
||||
while( *z ){
|
||||
for(i=0; (c = z[i])!=0 && c!='\n' && c!='\r' && c!='\''; i++){}
|
||||
if( c=='\'' ) i++;
|
||||
if( i ){
|
||||
if( !inQuote ){
|
||||
if( bStarted ) p->xCallback("||", p->pArg);
|
||||
p->xCallback("'", p->pArg);
|
||||
inQuote = 1;
|
||||
output_formatted(p,"'%s'",z);
|
||||
}else{
|
||||
const char *zNL = 0;
|
||||
const char *zCR = 0;
|
||||
int nNL = 0;
|
||||
int nCR = 0;
|
||||
char zBuf1[20], zBuf2[20];
|
||||
for(i=0; z[i]; i++){
|
||||
if( z[i]=='\n' ) nNL++;
|
||||
if( z[i]=='\r' ) nCR++;
|
||||
}
|
||||
if( nNL ){
|
||||
p->xCallback("replace(", p->pArg);
|
||||
zNL = unused_string(z, "\\n", "\\012", zBuf1);
|
||||
}
|
||||
if( nCR ){
|
||||
p->xCallback("replace(", p->pArg);
|
||||
zCR = unused_string(z, "\\r", "\\015", zBuf2);
|
||||
}
|
||||
p->xCallback("'", p->pArg);
|
||||
while( *z ){
|
||||
for(i=0; (c = z[i])!=0 && c!='\n' && c!='\r' && c!='\''; i++){}
|
||||
if( c=='\'' ) i++;
|
||||
if( i ){
|
||||
output_formatted(p, "%.*s", i, z);
|
||||
z += i;
|
||||
}
|
||||
output_formatted(p, "%.*s", i, z);
|
||||
z += i;
|
||||
bStarted = 1;
|
||||
if( c=='\'' ){
|
||||
p->xCallback("'", p->pArg);
|
||||
continue;
|
||||
}
|
||||
if( c==0 ){
|
||||
break;
|
||||
}
|
||||
z++;
|
||||
if( c=='\n' ){
|
||||
p->xCallback(zNL, p->pArg);
|
||||
continue;
|
||||
}
|
||||
p->xCallback(zCR, p->pArg);
|
||||
}
|
||||
if( c=='\'' ){
|
||||
p->xCallback("'", p->pArg);
|
||||
continue;
|
||||
p->xCallback("'", p->pArg);
|
||||
if( nCR ){
|
||||
output_formatted(p, ",'%s',char(13))", zCR);
|
||||
}
|
||||
if( inQuote ){
|
||||
p->xCallback("'", p->pArg);
|
||||
inQuote = 0;
|
||||
if( nNL ){
|
||||
output_formatted(p, ",'%s',char(10))", zNL);
|
||||
}
|
||||
if( c==0 ){
|
||||
break;
|
||||
}
|
||||
for(i=0; (c = z[i])=='\r' || c=='\n'; i++){
|
||||
if( bStarted ) p->xCallback("||", p->pArg);
|
||||
output_formatted(p, "char(%d)", c);
|
||||
bStarted = 1;
|
||||
}
|
||||
z += i;
|
||||
}
|
||||
if( inQuote ) p->xCallback("'", p->pArg);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -495,7 +527,8 @@ static int dump_callback(void *pArg, int nArg, char **azArg, char **azCol){
|
||||
break;
|
||||
}
|
||||
case SQLITE_TEXT: {
|
||||
output_quoted_string(p, sqlite3_column_text(pStmt,i));
|
||||
output_quoted_escaped_string(p,
|
||||
(const char*)sqlite3_column_text(pStmt,i));
|
||||
break;
|
||||
}
|
||||
case SQLITE_BLOB: {
|
||||
|
||||
+122
-43
@@ -90,6 +90,7 @@ static const char jsonIsSpace[] = {
|
||||
** but the definitions need to be repeated for separate compilation. */
|
||||
typedef sqlite3_uint64 u64;
|
||||
typedef unsigned int u32;
|
||||
typedef unsigned short int u16;
|
||||
typedef unsigned char u8;
|
||||
#endif
|
||||
|
||||
@@ -169,8 +170,19 @@ struct JsonParse {
|
||||
u32 *aUp; /* Index of parent of each node */
|
||||
u8 oom; /* Set to true if out of memory */
|
||||
u8 nErr; /* Number of errors seen */
|
||||
u16 iDepth; /* Nesting depth */
|
||||
int nJson; /* Length of the zJson string in bytes */
|
||||
};
|
||||
|
||||
/*
|
||||
** Maximum nesting depth of JSON for this implementation.
|
||||
**
|
||||
** This limit is needed to avoid a stack overflow in the recursive
|
||||
** descent parser. A depth of 2000 is far deeper than any sane JSON
|
||||
** should go.
|
||||
*/
|
||||
#define JSON_MAX_DEPTH 2000
|
||||
|
||||
/**************************************************************************
|
||||
** Utility routines for dealing with JsonString objects
|
||||
**************************************************************************/
|
||||
@@ -402,6 +414,14 @@ static void jsonParseReset(JsonParse *pParse){
|
||||
pParse->aUp = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Free a JsonParse object that was obtained from sqlite3_malloc().
|
||||
*/
|
||||
static void jsonParseFree(JsonParse *pParse){
|
||||
jsonParseReset(pParse);
|
||||
sqlite3_free(pParse);
|
||||
}
|
||||
|
||||
/*
|
||||
** Convert the JsonNode pNode into a pure JSON string and
|
||||
** append to pOut. Subsubstructure is also included. Return
|
||||
@@ -727,15 +747,18 @@ static int jsonParseValue(JsonParse *pParse, u32 i){
|
||||
int iThis;
|
||||
int x;
|
||||
JsonNode *pNode;
|
||||
while( safe_isspace(pParse->zJson[i]) ){ i++; }
|
||||
if( (c = pParse->zJson[i])=='{' ){
|
||||
const char *z = pParse->zJson;
|
||||
while( safe_isspace(z[i]) ){ i++; }
|
||||
if( (c = z[i])=='{' ){
|
||||
/* Parse object */
|
||||
iThis = jsonParseAddNode(pParse, JSON_OBJECT, 0, 0);
|
||||
if( iThis<0 ) return -1;
|
||||
for(j=i+1;;j++){
|
||||
while( safe_isspace(pParse->zJson[j]) ){ j++; }
|
||||
while( safe_isspace(z[j]) ){ j++; }
|
||||
if( ++pParse->iDepth > JSON_MAX_DEPTH ) return -1;
|
||||
x = jsonParseValue(pParse, j);
|
||||
if( x<0 ){
|
||||
pParse->iDepth--;
|
||||
if( x==(-2) && pParse->nNode==(u32)iThis+1 ) return j+1;
|
||||
return -1;
|
||||
}
|
||||
@@ -744,14 +767,15 @@ static int jsonParseValue(JsonParse *pParse, u32 i){
|
||||
if( pNode->eType!=JSON_STRING ) return -1;
|
||||
pNode->jnFlags |= JNODE_LABEL;
|
||||
j = x;
|
||||
while( safe_isspace(pParse->zJson[j]) ){ j++; }
|
||||
if( pParse->zJson[j]!=':' ) return -1;
|
||||
while( safe_isspace(z[j]) ){ j++; }
|
||||
if( z[j]!=':' ) return -1;
|
||||
j++;
|
||||
x = jsonParseValue(pParse, j);
|
||||
pParse->iDepth--;
|
||||
if( x<0 ) return -1;
|
||||
j = x;
|
||||
while( safe_isspace(pParse->zJson[j]) ){ j++; }
|
||||
c = pParse->zJson[j];
|
||||
while( safe_isspace(z[j]) ){ j++; }
|
||||
c = z[j];
|
||||
if( c==',' ) continue;
|
||||
if( c!='}' ) return -1;
|
||||
break;
|
||||
@@ -763,15 +787,17 @@ static int jsonParseValue(JsonParse *pParse, u32 i){
|
||||
iThis = jsonParseAddNode(pParse, JSON_ARRAY, 0, 0);
|
||||
if( iThis<0 ) return -1;
|
||||
for(j=i+1;;j++){
|
||||
while( safe_isspace(pParse->zJson[j]) ){ j++; }
|
||||
while( safe_isspace(z[j]) ){ j++; }
|
||||
if( ++pParse->iDepth > JSON_MAX_DEPTH ) return -1;
|
||||
x = jsonParseValue(pParse, j);
|
||||
pParse->iDepth--;
|
||||
if( x<0 ){
|
||||
if( x==(-3) && pParse->nNode==(u32)iThis+1 ) return j+1;
|
||||
return -1;
|
||||
}
|
||||
j = x;
|
||||
while( safe_isspace(pParse->zJson[j]) ){ j++; }
|
||||
c = pParse->zJson[j];
|
||||
while( safe_isspace(z[j]) ){ j++; }
|
||||
c = z[j];
|
||||
if( c==',' ) continue;
|
||||
if( c!=']' ) return -1;
|
||||
break;
|
||||
@@ -783,13 +809,16 @@ static int jsonParseValue(JsonParse *pParse, u32 i){
|
||||
u8 jnFlags = 0;
|
||||
j = i+1;
|
||||
for(;;){
|
||||
c = pParse->zJson[j];
|
||||
if( c==0 ) return -1;
|
||||
c = z[j];
|
||||
if( (c & ~0x1f)==0 ){
|
||||
/* Control characters are not allowed in strings */
|
||||
return -1;
|
||||
}
|
||||
if( c=='\\' ){
|
||||
c = pParse->zJson[++j];
|
||||
c = z[++j];
|
||||
if( c=='"' || c=='\\' || c=='/' || c=='b' || c=='f'
|
||||
|| c=='n' || c=='r' || c=='t'
|
||||
|| (c=='u' && jsonIs4Hex(pParse->zJson+j+1)) ){
|
||||
|| (c=='u' && jsonIs4Hex(z+j+1)) ){
|
||||
jnFlags = JNODE_ESCAPE;
|
||||
}else{
|
||||
return -1;
|
||||
@@ -799,55 +828,60 @@ static int jsonParseValue(JsonParse *pParse, u32 i){
|
||||
}
|
||||
j++;
|
||||
}
|
||||
jsonParseAddNode(pParse, JSON_STRING, j+1-i, &pParse->zJson[i]);
|
||||
jsonParseAddNode(pParse, JSON_STRING, j+1-i, &z[i]);
|
||||
if( !pParse->oom ) pParse->aNode[pParse->nNode-1].jnFlags = jnFlags;
|
||||
return j+1;
|
||||
}else if( c=='n'
|
||||
&& strncmp(pParse->zJson+i,"null",4)==0
|
||||
&& !safe_isalnum(pParse->zJson[i+4]) ){
|
||||
&& strncmp(z+i,"null",4)==0
|
||||
&& !safe_isalnum(z[i+4]) ){
|
||||
jsonParseAddNode(pParse, JSON_NULL, 0, 0);
|
||||
return i+4;
|
||||
}else if( c=='t'
|
||||
&& strncmp(pParse->zJson+i,"true",4)==0
|
||||
&& !safe_isalnum(pParse->zJson[i+4]) ){
|
||||
&& strncmp(z+i,"true",4)==0
|
||||
&& !safe_isalnum(z[i+4]) ){
|
||||
jsonParseAddNode(pParse, JSON_TRUE, 0, 0);
|
||||
return i+4;
|
||||
}else if( c=='f'
|
||||
&& strncmp(pParse->zJson+i,"false",5)==0
|
||||
&& !safe_isalnum(pParse->zJson[i+5]) ){
|
||||
&& strncmp(z+i,"false",5)==0
|
||||
&& !safe_isalnum(z[i+5]) ){
|
||||
jsonParseAddNode(pParse, JSON_FALSE, 0, 0);
|
||||
return i+5;
|
||||
}else if( c=='-' || (c>='0' && c<='9') ){
|
||||
/* Parse number */
|
||||
u8 seenDP = 0;
|
||||
u8 seenE = 0;
|
||||
assert( '-' < '0' );
|
||||
if( c<='0' ){
|
||||
j = c=='-' ? i+1 : i;
|
||||
if( z[j]=='0' && z[j+1]>='0' && z[j+1]<='9' ) return -1;
|
||||
}
|
||||
j = i+1;
|
||||
for(;; j++){
|
||||
c = pParse->zJson[j];
|
||||
c = z[j];
|
||||
if( c>='0' && c<='9' ) continue;
|
||||
if( c=='.' ){
|
||||
if( pParse->zJson[j-1]=='-' ) return -1;
|
||||
if( z[j-1]=='-' ) return -1;
|
||||
if( seenDP ) return -1;
|
||||
seenDP = 1;
|
||||
continue;
|
||||
}
|
||||
if( c=='e' || c=='E' ){
|
||||
if( pParse->zJson[j-1]<'0' ) return -1;
|
||||
if( z[j-1]<'0' ) return -1;
|
||||
if( seenE ) return -1;
|
||||
seenDP = seenE = 1;
|
||||
c = pParse->zJson[j+1];
|
||||
c = z[j+1];
|
||||
if( c=='+' || c=='-' ){
|
||||
j++;
|
||||
c = pParse->zJson[j+1];
|
||||
c = z[j+1];
|
||||
}
|
||||
if( c<'0' || c>'9' ) return -1;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if( pParse->zJson[j-1]<'0' ) return -1;
|
||||
if( z[j-1]<'0' ) return -1;
|
||||
jsonParseAddNode(pParse, seenDP ? JSON_REAL : JSON_INT,
|
||||
j - i, &pParse->zJson[i]);
|
||||
j - i, &z[i]);
|
||||
return j;
|
||||
}else if( c=='}' ){
|
||||
return -2; /* End of {...} */
|
||||
@@ -879,6 +913,7 @@ static int jsonParse(
|
||||
i = jsonParseValue(pParse, 0);
|
||||
if( pParse->oom ) i = -1;
|
||||
if( i>0 ){
|
||||
assert( pParse->iDepth==0 );
|
||||
while( safe_isspace(zJson[i]) ) i++;
|
||||
if( zJson[i] ) i = -1;
|
||||
}
|
||||
@@ -938,6 +973,49 @@ static int jsonParseFindParents(JsonParse *pParse){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Magic number used for the JSON parse cache in sqlite3_get_auxdata()
|
||||
*/
|
||||
#define JSON_CACHE_ID (-429938)
|
||||
|
||||
/*
|
||||
** Obtain a complete parse of the JSON found in the first argument
|
||||
** of the argv array. Use the sqlite3_get_auxdata() cache for this
|
||||
** parse if it is available. If the cache is not available or if it
|
||||
** is no longer valid, parse the JSON again and return the new parse,
|
||||
** and also register the new parse so that it will be available for
|
||||
** future sqlite3_get_auxdata() calls.
|
||||
*/
|
||||
static JsonParse *jsonParseCached(
|
||||
sqlite3_context *pCtx,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
const char *zJson = (const char*)sqlite3_value_text(argv[0]);
|
||||
int nJson = sqlite3_value_bytes(argv[0]);
|
||||
JsonParse *p;
|
||||
if( zJson==0 ) return 0;
|
||||
p = (JsonParse*)sqlite3_get_auxdata(pCtx, JSON_CACHE_ID);
|
||||
if( p && p->nJson==nJson && memcmp(p->zJson,zJson,nJson)==0 ){
|
||||
p->nErr = 0;
|
||||
return p; /* The cached entry matches, so return it */
|
||||
}
|
||||
p = sqlite3_malloc( sizeof(*p) + nJson + 1 );
|
||||
if( p==0 ){
|
||||
sqlite3_result_error_nomem(pCtx);
|
||||
return 0;
|
||||
}
|
||||
memset(p, 0, sizeof(*p));
|
||||
p->zJson = (char*)&p[1];
|
||||
memcpy((char*)p->zJson, zJson, nJson+1);
|
||||
if( jsonParse(p, pCtx, p->zJson) ){
|
||||
sqlite3_free(p);
|
||||
return 0;
|
||||
}
|
||||
p->nJson = nJson;
|
||||
sqlite3_set_auxdata(pCtx, JSON_CACHE_ID, p, (void(*)(void*))jsonParseFree);
|
||||
return (JsonParse*)sqlite3_get_auxdata(pCtx, JSON_CACHE_ID);
|
||||
}
|
||||
|
||||
/*
|
||||
** Compare the OBJECT label at pNode against zKey,nKey. Return true on
|
||||
** a match.
|
||||
@@ -1303,29 +1381,30 @@ static void jsonArrayLengthFunc(
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
JsonParse x; /* The parse */
|
||||
JsonParse *p; /* The parse */
|
||||
sqlite3_int64 n = 0;
|
||||
u32 i;
|
||||
JsonNode *pNode;
|
||||
|
||||
if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return;
|
||||
assert( x.nNode );
|
||||
p = jsonParseCached(ctx, argv);
|
||||
if( p==0 ) return;
|
||||
assert( p->nNode );
|
||||
if( argc==2 ){
|
||||
const char *zPath = (const char*)sqlite3_value_text(argv[1]);
|
||||
pNode = jsonLookup(&x, zPath, 0, ctx);
|
||||
pNode = jsonLookup(p, zPath, 0, ctx);
|
||||
}else{
|
||||
pNode = x.aNode;
|
||||
pNode = p->aNode;
|
||||
}
|
||||
if( pNode==0 ){
|
||||
x.nErr = 1;
|
||||
}else if( pNode->eType==JSON_ARRAY ){
|
||||
return;
|
||||
}
|
||||
if( pNode->eType==JSON_ARRAY ){
|
||||
assert( (pNode->jnFlags & JNODE_APPEND)==0 );
|
||||
for(i=1; i<=pNode->n; n++){
|
||||
i += jsonNodeSize(&pNode[i]);
|
||||
}
|
||||
}
|
||||
if( x.nErr==0 ) sqlite3_result_int64(ctx, n);
|
||||
jsonParseReset(&x);
|
||||
sqlite3_result_int64(ctx, n);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1341,20 +1420,21 @@ static void jsonExtractFunc(
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
JsonParse x; /* The parse */
|
||||
JsonParse *p; /* The parse */
|
||||
JsonNode *pNode;
|
||||
const char *zPath;
|
||||
JsonString jx;
|
||||
int i;
|
||||
|
||||
if( argc<2 ) return;
|
||||
if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return;
|
||||
p = jsonParseCached(ctx, argv);
|
||||
if( p==0 ) return;
|
||||
jsonInit(&jx, ctx);
|
||||
jsonAppendChar(&jx, '[');
|
||||
for(i=1; i<argc; i++){
|
||||
zPath = (const char*)sqlite3_value_text(argv[i]);
|
||||
pNode = jsonLookup(&x, zPath, 0, ctx);
|
||||
if( x.nErr ) break;
|
||||
pNode = jsonLookup(p, zPath, 0, ctx);
|
||||
if( p->nErr ) break;
|
||||
if( argc>2 ){
|
||||
jsonAppendSeparator(&jx);
|
||||
if( pNode ){
|
||||
@@ -1372,14 +1452,13 @@ static void jsonExtractFunc(
|
||||
sqlite3_result_subtype(ctx, JSON_SUBTYPE);
|
||||
}
|
||||
jsonReset(&jx);
|
||||
jsonParseReset(&x);
|
||||
}
|
||||
|
||||
/* This is the RFC 7396 MergePatch algorithm.
|
||||
*/
|
||||
static JsonNode *jsonMergePatch(
|
||||
JsonParse *pParse, /* The JSON parser that contains the TARGET */
|
||||
int iTarget, /* Node of the TARGET in pParse */
|
||||
u32 iTarget, /* Node of the TARGET in pParse */
|
||||
JsonNode *pPatch /* The PATCH */
|
||||
){
|
||||
u32 i, j;
|
||||
|
||||
+2
-2
@@ -82,10 +82,10 @@ int main(int argc, char **argv){
|
||||
int bVacuum = 0;
|
||||
int rc;
|
||||
sqlite3_int64 nProgress = 0;
|
||||
int nArg = argc-2;
|
||||
int nArgc = argc-2;
|
||||
|
||||
if( argc<3 ) usage(argv[0]);
|
||||
for(i=1; i<nArg; i++){
|
||||
for(i=1; i<nArgc; i++){
|
||||
const char *zArg = argv[i];
|
||||
int nArg = strlen(zArg);
|
||||
if( nArg>1 && nArg<=8 && 0==memcmp(zArg, "-vacuum", nArg) ){
|
||||
|
||||
+26
-2
@@ -3198,12 +3198,36 @@ static int rtreeRename(sqlite3_vtab *pVtab, const char *zNewName){
|
||||
, pRtree->zDb, pRtree->zName, zNewName
|
||||
);
|
||||
if( zSql ){
|
||||
nodeBlobReset(pRtree);
|
||||
rc = sqlite3_exec(pRtree->db, zSql, 0, 0, 0);
|
||||
sqlite3_free(zSql);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** The xSavepoint method.
|
||||
**
|
||||
** This module does not need to do anything to support savepoints. However,
|
||||
** it uses this hook to close any open blob handle. This is done because a
|
||||
** DROP TABLE command - which fortunately always opens a savepoint - cannot
|
||||
** succeed if there are any open blob handles. i.e. if the blob handle were
|
||||
** not closed here, the following would fail:
|
||||
**
|
||||
** BEGIN;
|
||||
** INSERT INTO rtree...
|
||||
** DROP TABLE <tablename>; -- Would fail with SQLITE_LOCKED
|
||||
** COMMIT;
|
||||
*/
|
||||
static int rtreeSavepoint(sqlite3_vtab *pVtab, int iSavepoint){
|
||||
Rtree *pRtree = (Rtree *)pVtab;
|
||||
int iwt = pRtree->inWrTrans;
|
||||
UNUSED_PARAMETER(iSavepoint);
|
||||
pRtree->inWrTrans = 0;
|
||||
nodeBlobReset(pRtree);
|
||||
pRtree->inWrTrans = iwt;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** This function populates the pRtree->nRowEst variable with an estimate
|
||||
@@ -3250,7 +3274,7 @@ static int rtreeQueryStat1(sqlite3 *db, Rtree *pRtree){
|
||||
}
|
||||
|
||||
static sqlite3_module rtreeModule = {
|
||||
0, /* iVersion */
|
||||
2, /* iVersion */
|
||||
rtreeCreate, /* xCreate - create a table */
|
||||
rtreeConnect, /* xConnect - connect to an existing table */
|
||||
rtreeBestIndex, /* xBestIndex - Determine search strategy */
|
||||
@@ -3270,7 +3294,7 @@ static sqlite3_module rtreeModule = {
|
||||
rtreeEndTransaction, /* xRollback - rollback transaction */
|
||||
0, /* xFindFunction - function overloading */
|
||||
rtreeRename, /* xRename - rename the table */
|
||||
0, /* xSavepoint */
|
||||
rtreeSavepoint, /* xSavepoint */
|
||||
0, /* xRelease */
|
||||
0, /* xRollbackTo */
|
||||
};
|
||||
|
||||
@@ -39,6 +39,8 @@ set testprefix rtree1
|
||||
# inserted. Also that if a non-numeric is inserted into one
|
||||
# of the min/max dimension columns, it is converted to the
|
||||
# required type before being inserted.
|
||||
# rtree-15.*: Check that DROP TABLE works within a transaction that
|
||||
# writes to an r-tree table.
|
||||
#
|
||||
|
||||
ifcapable !rtree {
|
||||
@@ -592,4 +594,20 @@ do_execsql_test 14.5 {
|
||||
3 42 49
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
do_execsql_test 15.0 {
|
||||
CREATE VIRTUAL TABLE rt USING rtree(id, x1,x2, y1,y2);
|
||||
CREATE TEMP TABLE t13(a, b, c);
|
||||
}
|
||||
do_execsql_test 15.1 {
|
||||
BEGIN;
|
||||
INSERT INTO rt VALUES(1,2,3,4,5);
|
||||
}
|
||||
breakpoint
|
||||
do_execsql_test 15.2 {
|
||||
DROP TABLE t13;
|
||||
COMMIT;
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
C Version\s3.18.0\sRelease\sCandidate
|
||||
D 2017-03-28T18:48:43.315
|
||||
C Fix\sa\sdocumentation\stypo.\s\sNo\schanges\sto\scode.
|
||||
D 2017-05-18T18:17:55.135
|
||||
F Makefile.in 1cc758ce3374a32425e4d130c2fe7b026b20de5b8843243de75f087c0a2661fb
|
||||
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
|
||||
F Makefile.msc 1faf9f06aadc9284c212dea7bbc7c0dea7e8337f0287c81001eff500912c790a
|
||||
F Makefile.msc 8eeb80162074004e906b53d7340a12a14c471a83743aab975947e95ce061efcc
|
||||
F README.md 2b15fae33852f2f53996774c21fb41e1d94181c4401a0e43ac93e11f2cc901b9
|
||||
F VERSION 3605fa447e4623f5ff4a6adc97b1fde9a257b8f2
|
||||
F VERSION 0a0e02e16b44ea735b40118fc844311b2ab0d35b25fbeda5120aee62f973f663
|
||||
F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50
|
||||
F art/sqlite370.eps aa97a671332b432a54e1d74ff5e8775be34200c2
|
||||
F art/sqlite370.ico af56c1d00fee7cd4753e8631ed60703ed0fc6e90
|
||||
F art/sqlite370.jpg d512473dae7e378a67e28ff96a34da7cb331def2
|
||||
F autoconf/INSTALL 83e4a25da9fd053c7b3665eaaaf7919707915903
|
||||
F autoconf/Makefile.am 1a47d071e3d5435f8f7ebff7eb6703848bbd65d4
|
||||
F autoconf/Makefile.msc 92e3d7fd64dc5c23a23d33824ee4709aaea00a6331c4bb41a1aadcf6600a49f7
|
||||
F autoconf/Makefile.msc 1014be616b420a5f48611d21b62ca2f50ec97ee795087ecb8a4d6bf6375ba11d
|
||||
F autoconf/README.first 6c4f34fe115ff55d4e8dbfa3cecf04a0188292f7
|
||||
F autoconf/README.txt 4f04b0819303aabaa35fff5f7b257fb0c1ef95f1
|
||||
F autoconf/configure.ac 2893b823ecc86cea13739f6c8109a41392254d1db08235c5615e0af5722c8578
|
||||
@@ -30,8 +30,8 @@ F autoconf/tea/win/rules.vc c511f222b80064096b705dbeb97060ee1d6b6d63
|
||||
F config.guess 226d9a188c6196f3033ffc651cbc9dcee1a42977
|
||||
F config.h.in 6376abec766e9a0785178b1823b5a587e9f1ccbc
|
||||
F config.sub 9ebe4c3b3dab6431ece34f16828b594fb420da55
|
||||
F configure b15d030a8ae2e672d76c97b6667dacb98934a467 x
|
||||
F configure.ac 605173e829ab64514ed89f9b53d0da1739d7b0a0
|
||||
F configure bddf7d1d945894b724e2b16a1266359a40abec2c798c95b4409a7ebf771c38ef x
|
||||
F configure.ac 901e8db2c211e8b655e51ee24f2b8faa33407acde87effc47f70380f3b04e452
|
||||
F contrib/sqlitecon.tcl 210a913ad63f9f991070821e599d600bd913e0ad
|
||||
F doc/lemon.html b5a3c07d33ecb8e019ce8f7660fe2dbbad9d7977
|
||||
F doc/pager-invariants.txt 27fed9a70ddad2088750c4a2b493b63853da2710
|
||||
@@ -70,7 +70,7 @@ F ext/fts3/README.content fdc666a70d5257a64fee209f97cf89e0e6e32b51
|
||||
F ext/fts3/README.syntax a19711dc5458c20734b8e485e75fb1981ec2427a
|
||||
F ext/fts3/README.tokenizers e0a8b81383ea60d0334d274fadf305ea14a8c314
|
||||
F ext/fts3/README.txt 8c18f41574404623b76917b9da66fcb0ab38328d
|
||||
F ext/fts3/fts3.c f0d5de1bc2155ba7cd7c0c1a751779a3a8857fa34d5c12f3b233a23fa2e79ea2
|
||||
F ext/fts3/fts3.c 88ea5c444fdf262b4eb7b5872b9a3192b8b8d0df8cc9735c5aed159ec5dae02a
|
||||
F ext/fts3/fts3.h 3a10a0af180d502cecc50df77b1b22df142817fe
|
||||
F ext/fts3/fts3Int.h eb2502000148e80913b965db3e59f29251266d0a
|
||||
F ext/fts3/fts3_aux.c 9edc3655fcb287f0467d0a4b886a01c6185fe9f1
|
||||
@@ -99,26 +99,26 @@ F ext/fts3/unicode/mkunicode.tcl ab0543a3b2399092ea2dd75df1bef333405b0d7f6b8c495
|
||||
F ext/fts3/unicode/parseunicode.tcl da577d1384810fb4e2b209bf3313074353193e95
|
||||
F ext/fts5/extract_api_docs.tcl a36e54ec777172ddd3f9a88daf593b00848368e0
|
||||
F ext/fts5/fts5.h 62f3e33ceeb9a428db139f9c012186b371da1cc7
|
||||
F ext/fts5/fts5Int.h c629b24d2b92b99596f3b8e82289fddca06df6e1
|
||||
F ext/fts5/fts5Int.h 15e7514b46a845937d7c62e5c69e935091f0dbb72eb61aa4c8bcfbd39fdea158
|
||||
F ext/fts5/fts5_aux.c 67acf8d51723cf28ffc3828210ba662df4b8d267
|
||||
F ext/fts5/fts5_buffer.c 4c1502d4c956cd092c89ce4480867f9d8bf325cd
|
||||
F ext/fts5/fts5_config.c 5af9c360e99669d29f06492c370892394aba0857
|
||||
F ext/fts5/fts5_expr.c c6ecc2280162a3714d15dce2a8f2299f748b627c
|
||||
F ext/fts5/fts5_expr.c f2825f714d91bbe62ab5820aee9ad12e0c94205b2a01725eaa9072415ae9ff1c
|
||||
F ext/fts5/fts5_hash.c 880998e596b60f078348d48732ca4ad9a90caad2
|
||||
F ext/fts5/fts5_index.c f67032a9a529ba52a545e6e3ab970764199c05d4
|
||||
F ext/fts5/fts5_main.c f85281445dcf8be32d18841c93a6f90fe27dbfe2
|
||||
F ext/fts5/fts5_storage.c 8f0e65cb33bde8f449e1c9b4be4600d18b4da6e9
|
||||
F ext/fts5/fts5_index.c 9ce10106f42f8b84278a8ea859940224e2af5f0cc882f909364469f6f52769cb
|
||||
F ext/fts5/fts5_main.c 1ba0e7806886c1bc16e20d0dde1c2b535d1aeb98cbbb937c4c3e064af5ac6f03
|
||||
F ext/fts5/fts5_storage.c 7750986004f3f0c94619a85ecb5dd6cbef53e5e3853488e8a906c269d4d11db6
|
||||
F ext/fts5/fts5_tcl.c 4a901f00c8553740dba63511603f5527d741c26a
|
||||
F ext/fts5/fts5_test_mi.c 783b86697ebf773c18fc109992426c0173a055bc
|
||||
F ext/fts5/fts5_test_tok.c db08af63673c3a7d39f053b36fd6e065017706be
|
||||
F ext/fts5/fts5_test_tok.c f4c27f2e3200653a458f5316f6aaa863f7532d98fff7534ece3670fb7f2c196b
|
||||
F ext/fts5/fts5_tokenize.c 2ce7b44183538ec46b7907726262ee43ffdd39a8
|
||||
F ext/fts5/fts5_unicode2.c b450b209b157d598f7b9df9f837afb75a14c24bf
|
||||
F ext/fts5/fts5_varint.c a5aceacda04dafcbae725413d7a16818ecd65738
|
||||
F ext/fts5/fts5_vocab.c e44fefa7f0c1db252998af071daf06a7147e17e7
|
||||
F ext/fts5/fts5parse.y e51b375403421b8b37428a89b095d00597129aae
|
||||
F ext/fts5/fts5parse.y a070b538e08ae9e2177d15c337ed2a3464408f0f886e746307098f746efd94ca
|
||||
F ext/fts5/mkportersteps.tcl 5acf962d2e0074f701620bb5308155fa1e4a63ba
|
||||
F ext/fts5/test/fts5_common.tcl b01c584144b5064f30e6c648145a2dd6bc440841
|
||||
F ext/fts5/test/fts5aa.test bd2d88182b9f7f30d300044048ad14683306b745
|
||||
F ext/fts5/test/fts5aa.test 6dd1bfa4426a8d77e8c8d447aad02515c85118b082f24053ac89802300077ff1
|
||||
F ext/fts5/test/fts5ab.test 30325a89453280160106be411bba3acf138e6d1b
|
||||
F ext/fts5/test/fts5ac.test 55cad4275a1f5acabfe14d8442a8046b47e49e5f
|
||||
F ext/fts5/test/fts5ad.test 36995f0586f30f5602074e012b9224c71ec5171c
|
||||
@@ -136,7 +136,7 @@ F ext/fts5/test/fts5aux.test 5dd158a1e7869e27e9762a2a452b189c728d1be3
|
||||
F ext/fts5/test/fts5auxdata.test 141a7cbffcceb1bd2799b4b29c183ff8780d586e
|
||||
F ext/fts5/test/fts5bigpl.test 04ee0d7eebbebf17c31f5a0b5c5f9494eac3a0cb
|
||||
F ext/fts5/test/fts5bigtok.test 017a9397b14e7598883a6328ead4a6539b42d59a
|
||||
F ext/fts5/test/fts5colset.test 1cdf56e079316005aabda790059aee86f2222ee4
|
||||
F ext/fts5/test/fts5colset.test 97084e7fd3183a3c148ade1d4ad980b7e764cb2711ac77c3176680c3e75ea2b9
|
||||
F ext/fts5/test/fts5columnsize.test a8cfef21ffa1c264b9f670a7d94eeaccb5341c07
|
||||
F ext/fts5/test/fts5config.test 7788b9c058074d640dfcdd81d97b6a9480000368
|
||||
F ext/fts5/test/fts5conflict.test 26f4e46c4d31e16221794832a990dc4e30e18de5
|
||||
@@ -144,6 +144,7 @@ F ext/fts5/test/fts5content.test 9a952c95518a14182dc3b59e3c8fa71cda82a4e1
|
||||
F ext/fts5/test/fts5corrupt.test c2ad090192708150d50d961278df10ae7a4b8b62
|
||||
F ext/fts5/test/fts5corrupt2.test 128eb6e2d26b09f4da339e581f424b3321e0fdaa
|
||||
F ext/fts5/test/fts5corrupt3.test f77f65e386231daf62902466b40ff998b2c8ce4f
|
||||
F ext/fts5/test/fts5delete.test 0585395660889090a6a04b0cac0e70b16801da44ee321534d6169da49af8167f
|
||||
F ext/fts5/test/fts5detail.test ef5c690535a797413acaf5ad9b8ab5d49972df69
|
||||
F ext/fts5/test/fts5determin.test 10648edb75ef1e196b10978fd21a9be0c31e09c3
|
||||
F ext/fts5/test/fts5dlidx.test 007e9390c94638760797dbec2990c97c3fa08dfe
|
||||
@@ -160,7 +161,7 @@ F ext/fts5/test/fts5fault7.test cb14ea3c1f42394f06f2284abc58eecee6ff8080
|
||||
F ext/fts5/test/fts5fault8.test 6785af34bd1760de74e2824ea9c161965af78f85
|
||||
F ext/fts5/test/fts5fault9.test e10e395428a9ea0596ebe752ff7123d16ab78e08
|
||||
F ext/fts5/test/fts5faultA.test fa5d59c0ff62b7125cd14eee38ded1c46e15a7ea
|
||||
F ext/fts5/test/fts5faultB.test 7f3bba790fa172073ac314f9b8ed197390b61eca
|
||||
F ext/fts5/test/fts5faultB.test 8a7e4c89c663e599e88fa1b9f2b8dcf4b85a338bd250e1a94341773b1e9ebfcc
|
||||
F ext/fts5/test/fts5faultD.test cc5d1225556e356615e719c612e845d41bff7d5a
|
||||
F ext/fts5/test/fts5full.test 6f6143af0c6700501d9fd597189dfab1555bb741
|
||||
F ext/fts5/test/fts5fuzz1.test bece4695fc169b61ab236ada7931c6e4942cbef9
|
||||
@@ -175,7 +176,7 @@ F ext/fts5/test/fts5near.test b214cddb1c1f1bddf45c75af768f20145f7e71cc
|
||||
F ext/fts5/test/fts5onepass.test 7ed9608e258132cb8d55e7c479b08676ad68810c
|
||||
F ext/fts5/test/fts5optimize.test 9d3ac53bb9cae58cb070d795db86bcb2f9fec105
|
||||
F ext/fts5/test/fts5phrase.test f6d1d464da5beb25dc56277aa4f1d6102f0d9a2f
|
||||
F ext/fts5/test/fts5plan.test 6a55ecbac9890765b0e16f8c421c7e0888cfe436
|
||||
F ext/fts5/test/fts5plan.test fb0ee60c9a092b17bb958dd742f01e3731b520d50b5d61b288c49c7acdc286cb
|
||||
F ext/fts5/test/fts5porter.test 7cdc07bef301d70eebbfa75dcaf45c3680e1d0e1
|
||||
F ext/fts5/test/fts5porter2.test 2e65633d58a1c525d5af0f6c01e5a59155bb3487
|
||||
F ext/fts5/test/fts5prefix.test 6ef7e875738412907b17687d25db39a25cbdaba4
|
||||
@@ -209,16 +210,17 @@ F ext/icu/icu.c 84900472a088a3a172c6c079f58a1d3a1952c332
|
||||
F ext/icu/sqliteicu.h 728867a802baa5a96de7495e9689a8e01715ef37
|
||||
F ext/misc/README.md 8e008c8d2b02e09096b31dfba033253ac27c6c06a18aa5826e299fa7601d90b2
|
||||
F ext/misc/amatch.c 211108e201105e4bb0c076527b8cfd34330fc234
|
||||
F ext/misc/anycollseq.c 5ffdfde9829eeac52219136ad6aa7cd9a4edb3b15f4f2532de52f4a22525eddb
|
||||
F ext/misc/carray.c 40c27641010a4dc67e3690bdb7c9d36ca58b3c2d
|
||||
F ext/misc/closure.c 0d2a038df8fbae7f19de42e7c7d71f2e4dc88704
|
||||
F ext/misc/compress.c 122faa92d25033d6c3f07c39231de074ab3d2e83
|
||||
F ext/misc/csv.c 531a46cbad789fca0aa9db69a0e6c8ac9e68767d
|
||||
F ext/misc/dbdump.c 34174d537318027b159e3341105866c05a4149376ede59988c82280bed144e6d
|
||||
F ext/misc/dbdump.c 3509fa6b8932d04e932d6b6b827b6a82ca362781b8e8f3c77336f416793e215e
|
||||
F ext/misc/eval.c f971962e92ebb8b0a4e6b62949463ee454d88fa2
|
||||
F ext/misc/fileio.c d4171c815d6543a9edef8308aab2951413cd8d0f
|
||||
F ext/misc/fuzzer.c 7c64b8197bb77b7d64eff7cac7848870235d4c25
|
||||
F ext/misc/ieee754.c f190d0cc5182529acb15babd177781be1ac1718c
|
||||
F ext/misc/json1.c 92b9e404bd79cc76d3ef2b3a9e37bf775700f7d645466fd41d2e8742e3fa16fb
|
||||
F ext/misc/json1.c dbe086615b9546c156bf32b9378fc09383b58bd17513b866cfd24c1e15281984
|
||||
F ext/misc/memvfs.c e5225bc22e79dde6b28380f3a068ddf600683a33
|
||||
F ext/misc/nextchar.c 35c8b8baacb96d92abbb34a83a997b797075b342
|
||||
F ext/misc/percentile.c 92699c8cd7d517ff610e6037e56506f8904dae2e
|
||||
@@ -236,7 +238,7 @@ F ext/misc/vfslog.c fe40fab5c077a40477f7e5eba994309ecac6cc95
|
||||
F ext/misc/vfsstat.c bf10ef0bc51e1ad6756629e1edb142f7a8db1178
|
||||
F ext/misc/vtshim.c 1976e6dd68dd0d64508c91a6dfab8e75f8aaf6cd
|
||||
F ext/misc/wholenumber.c 784b12543d60702ebdd47da936e278aa03076212
|
||||
F ext/rbu/rbu.c b2c0b5e6ae1a89affc0edfc127ebfa5f637a0ce4
|
||||
F ext/rbu/rbu.c ea7d1b7eb44c123a2a619332e19fe5313500705c4a58aaa1887905c0d83ffc2e
|
||||
F ext/rbu/rbu1.test 43836fac8c7179a358eaf38a8a1ef3d6e6285842
|
||||
F ext/rbu/rbu10.test 046b0980041d30700464a800bbf6733ed2df515d
|
||||
F ext/rbu/rbu11.test 9bc68c2d3dbeb1720153626e3bd0466dcc017702
|
||||
@@ -271,9 +273,9 @@ F ext/rbu/sqlite3rbu.c 2a89efba9eeba8e6c89a498dc195e8efbdde2694
|
||||
F ext/rbu/sqlite3rbu.h 6fb6294c34a9ca93b5894a33bca530c6f08decba
|
||||
F ext/rbu/test_rbu.c 5aa22616afac6f71ebd3d9bc9bf1006cfabcca88
|
||||
F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761
|
||||
F ext/rtree/rtree.c 0acd285bfacc347579a5df9fe947212fb99e2775a40c43f027c3a16936c58e7e
|
||||
F ext/rtree/rtree.c 8205d6e4466f766e57ce1b8aa38224ac9e1cec2d2bf4684cd1cc5a6ddf9b7014
|
||||
F ext/rtree/rtree.h 834dbcb82dc85b2481cde6a07cdadfddc99e9b9e
|
||||
F ext/rtree/rtree1.test 42dadfc7b44a436cd74a1bebc0b9b689e4eaf7ec
|
||||
F ext/rtree/rtree1.test d5f0ba215b3bd1d05269ada86e74073b8445852aa0d33a63e10ec63a09c39473
|
||||
F ext/rtree/rtree2.test acbb3a4ce0f4fbc2c304d2b4b784cfa161856bba
|
||||
F ext/rtree/rtree3.test 2cafe8265d1ff28f206fce88d114f208349df482
|
||||
F ext/rtree/rtree4.test c8fe384f60ebd49540a5fecc990041bf452eb6e0
|
||||
@@ -340,25 +342,25 @@ F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a
|
||||
F src/alter.c 3b23977620ce9662ac54443f65b87ba996e36121
|
||||
F src/analyze.c 0d0ccf7520a201d8747ea2f02c92c26e26f801bc161f714f27b9f7630dde0421
|
||||
F src/attach.c 8c476f8bd5d2afe11d925f890d30e527e5b0ce43
|
||||
F src/auth.c 930b376a9c56998557367e6f7f8aaeac82a2a792
|
||||
F src/auth.c 79f96c6f33bf0e5da8d1c282cee5ebb1852bb8a6ccca3e485d7c459b035d9c3c
|
||||
F src/backup.c faf17e60b43233c214aae6a8179d24503a61e83b
|
||||
F src/bitvec.c 17ea48eff8ba979f1f5b04cc484c7bb2be632f33
|
||||
F src/btmutex.c 0e9ce2d56159b89b9bc8e197e023ee11e39ff8ca
|
||||
F src/btree.c ae0e0397e6ad58465bbf932239ee7539ca22f257c97b16c9d0960a1f5de743a3
|
||||
F src/btree.h bf64dfeeddeebdb775a5eba0098bbc00d073290d
|
||||
F src/btreeInt.h cd55d39d9916270837a88c12e701047cba0729b0
|
||||
F src/build.c 43f903c9082040ced2b421543cb0300c2973647d
|
||||
F src/btree.c 8c1fd4cfa2b0bf021386e0a1f4e30b64eea7a2c1bc2e0c3e5901a626b1ab6aa9
|
||||
F src/btree.h 80f518c0788be6cec8d9f8e13bd8e380df299d2b5e4ac340dc887b0642647cfc
|
||||
F src/btreeInt.h a392d353104b4add58b4a59cb185f5d5693dde832c565b77d8d4c343ed98f610
|
||||
F src/build.c 4026a9c554b233e50c5e9ad46963e676cf54dd2306d952aa1eaa07a1bc9ce14f
|
||||
F src/callback.c 2e76147783386374bf01b227f752c81ec872d730
|
||||
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
|
||||
F src/ctime.c 47d91a25ad8f199a71a5b1b7b169d6dd0d6e98c5719eca801568798743d1161c
|
||||
F src/date.c ee676e7694dfadbdd2fde1a258a71be8360ba5ae
|
||||
F src/date.c cc42a41c7422389860d40419a5e3bce5eaf6e7835c3ba2677751dc653550a5c7
|
||||
F src/dbstat.c 19ee7a4e89979d4df8e44cfac7a8f905ec89b77d
|
||||
F src/delete.c 0d9d5549d42e79ce4d82ff1db1e6c81e36d2f67c
|
||||
F src/expr.c f12a581f342a6fd85d14c31e4fb84f16b3dd107f54d7728dddb62cebc79d7ce1
|
||||
F src/delete.c bc2bfc227002ebe091e7cc321f09a48e52f86e1cd5ff9b028009db0671556749
|
||||
F src/expr.c c83f799f3e5e3f3863bd0716119383e4a062d00a1e34e7273a78555918840a7c
|
||||
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
|
||||
F src/fkey.c 2e9aabe1aee76273aff8a84ee92c464e095400ae
|
||||
F src/fkey.c db65492ae549c3b548c9ef1f279ce1684f1c473b116e1c56a90878cd5dcf968d
|
||||
F src/func.c 9d52522cc8ae7f5cdadfe14594262f1618bc1f86083c4cd6da861b4cf5af6174
|
||||
F src/global.c 4a34512d82fc5aa13c802db06bcfff5e1d3de955
|
||||
F src/global.c 8a6ab6b4d91effb96ffa81b39f0d70c862abca157f8aaa194600a4a8b7923344
|
||||
F src/hash.c 63d0ee752a3b92d4695b2b1f5259c4621b2cfebd
|
||||
F src/hash.h ab34c5c54a9e9de2e790b24349ba5aab3dbb4fd4
|
||||
F src/hwtime.h 747c1bbe9df21a92e9c50f3bbec1de841dc5e5da
|
||||
@@ -366,8 +368,8 @@ F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
|
||||
F src/insert.c d4bb3a135948553d18cf992f76f7ed7b18aa0327f250607b5a6671e55d9947d5
|
||||
F src/legacy.c e88ed13c2d531decde75d42c2e35623fb9ce3cb0
|
||||
F src/loadext.c a72909474dadce771d3669bf84bf689424f6f87d471fee898589c3ef9b2acfd9
|
||||
F src/main.c 158326243c5ddc8b98a1e983fa488650cf76d760
|
||||
F src/malloc.c 89c98e3619d362dcffa5c1c639b364b65b474751
|
||||
F src/main.c 1e448d204045c1dcd604853639d9d8fe253aa9ec302a2f1ffd2e22752fd6b708
|
||||
F src/malloc.c e20bb2b48abec52d3faf01cce12e8b4f95973755fafec98d45162dfdab111978
|
||||
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
|
||||
F src/mem1.c c12a42539b1ba105e3707d0e628ad70e611040d8f5e38cf942cee30c867083de
|
||||
F src/mem2.c f1940d9e91948dd6a908fbb9ce3835c36b5d83c3
|
||||
@@ -388,30 +390,30 @@ F src/os_setup.h 0dbaea40a7d36bf311613d31342e0b99e2536586
|
||||
F src/os_unix.c 30e2c43e4955db990e5b5a81e901f8aa74cc8820
|
||||
F src/os_win.c 2a6c73eef01c51a048cc4ddccd57f981afbec18a
|
||||
F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
|
||||
F src/pager.c ff1232b3088a39806035ecfac4fffeb22717d80b
|
||||
F src/pager.c 80893c0860199aebc6efa4f102ab11eebde338b7fdbb0c04d4b04647c2fd62d1
|
||||
F src/pager.h f2a99646c5533ffe11afa43e9e0bea74054e4efa
|
||||
F src/parse.y 48b03113704ee8bd78ee6996d81de7fbee22e105
|
||||
F src/parse.y 0513387ce02fea97897d8caef82d45f347818593f24f1bdc48e0c530a8af122d
|
||||
F src/pcache.c 62835bed959e2914edd26afadfecce29ece0e870
|
||||
F src/pcache.h 2cedcd8407eb23017d92790b112186886e179490
|
||||
F src/pcache1.c e3967219b2a92b9edcb9324a4ba75009090d3953
|
||||
F src/pragma.c 2b244434e76c7075edbcfd9e4d634899af0944ff01183b126d4671f7407c2368
|
||||
F src/pragma.h c9c763958fec92b04125571472c9500b351c5f7f
|
||||
F src/pcache1.c 1195a21fe28e223e024f900b2011e80df53793f0356a24caace4188b098540dc
|
||||
F src/pragma.c 2362670a9d28b71708aecb2b9b10b3f7be71f4c950961c07e81dc400e3ce6371
|
||||
F src/pragma.h 37a1311d0388db480388d7ec09054f7103045eff20d4971f8a433b77f40b9921
|
||||
F src/prepare.c b1140c3d0cf59bc85ace00ce363153041b424b7a
|
||||
F src/printf.c 8757834f1b54dae512fb25eb1acc8e94a0d15dd2290b58f2563f65973265adb2
|
||||
F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384
|
||||
F src/resolve.c 3e518b962d932a997fae373366880fc028c75706
|
||||
F src/rowset.c 7b7e7e479212e65b723bf40128c7b36dc5afdfac
|
||||
F src/select.c 2496d0cc6368dabe7ad2e4c7f5ed3ad9aa3b4d11cd90f33fa1d1ef72493f43aa
|
||||
F src/shell.c ceb2b2f1f958ea2c47a7f37972d0f715fbf9dcf6a34a5e98c886b85e3ce6a238
|
||||
F src/sqlite.h.in 723107d97f2345a7c103632169dc61366121c4ab65d75a7d83c6dc0e5bbe5ca4
|
||||
F src/select.c d74b1cde1d9ca6d08bec50b60a5be19440273646bc8ae16648d748c38161d5b7
|
||||
F src/shell.c a37d96b20b3644d0eb905df5aa7a0fcf9f6e73c15898337230c760a24a8df794
|
||||
F src/sqlite.h.in 8dd468837a4f6d76713e3a4cc65bea48095009038593d41040ab46c1b351197f
|
||||
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
|
||||
F src/sqlite3ext.h 58fd0676d3111d02e62e5a35992a7d3da5d3f88753acc174f2d37b774fbbdd28
|
||||
F src/sqliteInt.h a530e5baf5e559154d5c2e5cc57471bc780a7af4cd0a5d72750b1d850fef1e22
|
||||
F src/sqliteInt.h aea3aa1b81e0d07d5b1c39b8c5a54a1dc5e4f10136cb63da392aef9eb2a5108b
|
||||
F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b
|
||||
F src/status.c a9e66593dfb28a9e746cba7153f84d49c1ddc4b1
|
||||
F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34
|
||||
F src/tclsqlite.c 6c2151b6d8d98e183a04466d40df8889c0574d79
|
||||
F src/test1.c 8a98191a1da8e100f77cdb5cc716df67d405028d
|
||||
F src/tclsqlite.c c8cf60d0c5411d5e70e7c136470d29dbe760d250f55198b71682c67086524e4a
|
||||
F src/test1.c c99f0442918a7a5d5b68a95d6024c211989e6c782c15ced5a558994baaf76a5e
|
||||
F src/test2.c 3efb99ab7f1fc8d154933e02ae1378bac9637da5
|
||||
F src/test3.c d03f5b5da9a2410b7a91c64b0d3306ed28ab6fee
|
||||
F src/test4.c 18ec393bb4d0ad1de729f0b94da7267270f3d8e6
|
||||
@@ -427,7 +429,7 @@ F src/test_bestindex.c d23f80d334c59662af69191854c76b8d3d0c8c96
|
||||
F src/test_blob.c f65ac717da2618691cf9dad094e6da0219dcd208
|
||||
F src/test_btree.c 8b2dc8b8848cf3a4db93f11578f075e82252a274
|
||||
F src/test_config.c edcba290248dc18736dd814c9b95863c6762e0b35753048d8cbe5bf65f7abfbb
|
||||
F src/test_delete.c af7eab5702f853fb1c62a5f7665e2234cf1ae17b
|
||||
F src/test_delete.c e2fe07646dff6300b48d49b2fee2fe192ed389e834dd635e3b3bac0ce0bf9f8f
|
||||
F src/test_demovfs.c a0c3bdd45ed044115c2c9f7779e56eafff18741e
|
||||
F src/test_devsym.c 4e58dec2602d8e139ca08659f62a62450587cb58
|
||||
F src/test_fs.c e16cbe68d3b107e00a907c20a9a02629870eb69b
|
||||
@@ -461,31 +463,31 @@ F src/test_windirent.c 17f91f5f2aa1bb7328abb49414c363b5d2a9d3ff
|
||||
F src/test_windirent.h 5d67483a55442e31e1bde0f4a230e6e932ad5906
|
||||
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
|
||||
F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c
|
||||
F src/tokenize.c dc748c5afcb9e5beb3ef5651bc99a4622e30f6a1
|
||||
F src/treeview.c 84d0ac737e1231702679f0289180021e19c5cc186ec413e8dcb704a887c76ec8
|
||||
F src/tokenize.c 1003d6d90c6783206c711f0a9397656fa5b055209f4d092caa43bb3bf5215db5
|
||||
F src/treeview.c 6cf8d7fe9e63fae57dad1bb57f6615e14eac0c527e43d868e805042cae8ed1f7
|
||||
F src/trigger.c c9f0810043b265724fdb1bdd466894f984dfc182
|
||||
F src/update.c 456d4a4656f8a03c2abc88a51b19172197400e58
|
||||
F src/update.c c443935c652af9365e033f756550b5032d02e1b06eb2cb890ed7511ae0c051dc
|
||||
F src/utf.c 699001c79f28e48e9bcdf8a463da029ea660540c
|
||||
F src/util.c ca8440ede81e155d15cff7c101654f60b55a9ae6
|
||||
F src/util.c fc081ec6f63448dcd80d3dfad35baecfa104823254a815b081a4d9fe76e1db23
|
||||
F src/vacuum.c 1fe4555cd8c9b263afb85b5b4ee3a4a4181ad569
|
||||
F src/vdbe.c f1acf5744cef62cbfd0b503d84289f840b6cdc980ac47b0d9632dfdb89cc79eb
|
||||
F src/vdbe.h caa5346d52bae2a3c8c1dcfa60a7a4dc878a9e3865cb8239da55808b316c8158
|
||||
F src/vdbeInt.h 5db089ce18c4feff8820ec6e4cac2d2c82e03d4b1d96f10a6e43832147b8dffe
|
||||
F src/vdbeapi.c 5b08d82592bcff4470601fe78aaabebd50837860
|
||||
F src/vdbeaux.c ecd0468611925d218e1eb4b3f538907904b136f0e15e333291a232b521bfcef1
|
||||
F src/vdbe.c 9bac2bc2313ed682e6f48ccff6644d3263341885bfcbb3cdea7b720c722be2d5
|
||||
F src/vdbe.h f7d1456e28875c2dcb964056589b5b7149ab7edf39edeca801596a39bb3d3848
|
||||
F src/vdbeInt.h 1ecdacc1322fdd3241ec30c32a480e328a6f864e532dc53fae8e0ab68121aebf
|
||||
F src/vdbeapi.c dc904b3c5e459727993c2421e653e29d63223846d129fae98adc782b0a996481
|
||||
F src/vdbeaux.c 01dcf59b2a96bd3cc9db8c0d7f266518d113587459a2b3316279c4f9c90f28a9
|
||||
F src/vdbeblob.c 359891617358deefc85bef7bcf787fa6b77facb9
|
||||
F src/vdbemem.c 3b5a9a5b375458d3e12a50ae1aaa41eeec2175fd
|
||||
F src/vdbesort.c eda25cb2d1727efca6f7862fea32b8aa33c0face
|
||||
F src/vdbemem.c 2c70f8f5de6c71fb99a22c5b83be9fab5c47cdd8e279fa44a8c00cfed06d7e89
|
||||
F src/vdbesort.c e72fe02a2121386ba767ede8942e9450878b8fc873abf3d1b6824485f092570c
|
||||
F src/vdbetrace.c 41963d5376f0349842b5fc4aaaaacd7d9cdc0834
|
||||
F src/vtab.c 007513c2ef52472fcdea6a741683d50662e82790
|
||||
F src/vtab.c 35b9bdc2b41de32a417141d12097bcc4e29a77ed7cdb8f836d1d2305d946b61b
|
||||
F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
|
||||
F src/wal.c 40c543f0a2195d1b0dc88ef12142bea690009344
|
||||
F src/wal.h 06b2a0b599cc0f53ea97f497cf8c6b758c999f71
|
||||
F src/walker.c b71a992b413b3a022572eccf29ef4b4890223791
|
||||
F src/where.c e815093e5ee039b6b4eb19b646d22deb1a3a523f
|
||||
F src/whereInt.h 2d50c2b74a33be44cb68fdecee30b4d93552f1f4
|
||||
F src/wherecode.c 677e95413c472c0b413023b6b69a47f40fce1b04
|
||||
F src/whereexpr.c 130cdd1a43af71b19755270fb1224874cf55158c
|
||||
F src/where.c c6352f15be5031907c68bcbde96cad1a6da20e9f4051d10168a59235de9a8566
|
||||
F src/whereInt.h 2a4b634d63ce488b46d4b0da8f2eaa8f9aeab202bc25ef76f007de5e3fba1f20
|
||||
F src/wherecode.c 8ad48867660519e262a401720845dc76934f86f558ec9606335fafcd7a2554f8
|
||||
F src/whereexpr.c e913aaa7b73ffcce66abcea5f197e2c538d48b5df78d0b7bba8ff4d73cc2e745
|
||||
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
|
||||
F test/affinity2.test a6d901b436328bd67a79b41bb0ac2663918fe3bd
|
||||
F test/affinity3.test 6a101af2fc945ce2912f6fe54dd646018551710d
|
||||
@@ -525,9 +527,9 @@ F test/attach2.test 0ec5defa340363de6cd50fd595046465e9aaba2d
|
||||
F test/attach3.test c59d92791070c59272e00183b7353eeb94915976
|
||||
F test/attach4.test 53bf502f17647c6d6c5add46dda6bac8b6f4665c
|
||||
F test/attachmalloc.test 3a4bfca9545bfe906a8d2e622de10fbac5b711b0
|
||||
F test/auth.test c6ede04bee65637ff354b43fc1235aa560c0863e
|
||||
F test/auth.test 3d6cd8f3978ba55b1202574e6ecd79c6e00914ca44b9bfd6c1fe6fb873fcac88
|
||||
F test/auth2.test 9eb7fce9f34bf1f50d3f366fb3e606be5a2000a1
|
||||
F test/auth3.test 0d48b901cf111c14b4b1b5205c7d28f1a278190f
|
||||
F test/auth3.test db21405b95257c24d29273b6b31d0efc59e1d337e3d5804ba2d1fd4897b1ae49
|
||||
F test/autoanalyze1.test b9cc3f32a990fa56669b668d237c6d53e983554ae80c0604992e18869a0b2dec
|
||||
F test/autoinc.test 6ae8fb69c9f656962464ae4e6667045d0dfc3b46
|
||||
F test/autoindex1.test 14b63a9f1e405fe6d5bfc8c8d00249c2ebaf13ea
|
||||
@@ -575,6 +577,7 @@ F test/btreefault.test c2bcb542685eea44621275cfedbd8a13f65201e3
|
||||
F test/busy.test 76b4887f8b9160ba903c1ac22e8ff406ad6ae2f0
|
||||
F test/cache.test 13bc046b26210471ca6f2889aceb1ea52dc717de
|
||||
F test/cacheflush.test af25bb1509df04c1da10e38d8f322d66eceedf61
|
||||
F test/cachespill.test 895997f84a25b323b166aecb69baab2d6380ea98f9e0bcc688c4493c535cfab9
|
||||
F test/capi2.test 011c16da245fdc0106a2785035de6b242c05e738
|
||||
F test/capi3.test f0c66919e43d42e1572a69be039e4527a931b00f
|
||||
F test/capi3b.test efb2b9cfd127efa84433cd7a2d72ce0454ae0dc4
|
||||
@@ -602,7 +605,7 @@ F test/colmeta.test 2c765ea61ee37bc43bbe6d6047f89004e6508eb1
|
||||
F test/colname.test 08948a4809d22817e0e5de89c7c0a8bd90cb551b
|
||||
F test/conflict.test 029faa2d81a0d1cafb5f88614beb663d972c01db
|
||||
F test/conflict2.test bb0b94cf7196c64a3cbd815c66d3ee98c2fecd9c
|
||||
F test/conflict3.test dec0634c0f31dec9a4b01c63063e939f0cd21b6b
|
||||
F test/conflict3.test a83db76a6c3503b2fa057c7bfb08c318d8a422202d8bc5b86226e078e5b49ff9
|
||||
F test/contrib01.test 2a1cbc0f2f48955d7d073f725765da6fbceda6b4
|
||||
F test/corrupt.test 141c39ea650c1365e85a49e402fa05cb9617fb97
|
||||
F test/corrupt2.test e4964cee73dda57a90958e0087a6b388b1d9cb58
|
||||
@@ -658,6 +661,7 @@ F test/descidx2.test 9f1a0c83fd57f8667c82310ca21b30a350888b5d
|
||||
F test/descidx3.test 09ddbe3f5295f482d2f8b687cf6db8bad7acd9a2
|
||||
F test/diskfull.test 106391384780753ea6896b7b4f005d10e9866b6e
|
||||
F test/distinct.test a1783b960ad8c15a77cd9f207be072898db1026c
|
||||
F test/distinct2.test faef8a3f27424e2cfbe19b2a40752294de3b5d957e049e3336be53ec0476cb58
|
||||
F test/distinctagg.test 1a6ef9c87a58669438fc771450d7a72577417376
|
||||
F test/e_blobbytes.test 439a945953b35cb6948a552edaec4dc31fd70a05
|
||||
F test/e_blobclose.test 4b3c8c60c2171164d472059c73e9f3c1844bb66d
|
||||
@@ -706,7 +710,7 @@ F test/fkey1.test ba64806ff9a04eecab2679caad377ae99a5e94e4
|
||||
F test/fkey2.test 155809016fad6b2a1491facf2ac53a551bc57c2c
|
||||
F test/fkey3.test 76d475c80b84ee7a5d062e56ccb6ea68882e2b49
|
||||
F test/fkey4.test 86446017011273aad8f9a99c1a65019e7bd9ca9d
|
||||
F test/fkey5.test 5a373303f201ac03c22ba1ef17a733d3f56e611a
|
||||
F test/fkey5.test 24dd28eb3d9f1b5a174f47e9899ace5facb08373a4223593c8c631e6cf9f7d5a
|
||||
F test/fkey6.test d078a1e323a740062bed38df32b8a736fd320dc0
|
||||
F test/fkey7.test 72e915890ee4a005daaf3002cb208e8fe973ac13
|
||||
F test/fkey8.test e5372e32cdb4481f121ec3550703eeb7b4e0762c
|
||||
@@ -750,7 +754,7 @@ F test/fts2r.test b154c30b63061d8725e320fba1a39e2201cadd5e
|
||||
F test/fts2token.test d8070b241a15ff13592a9ae4a8b7c171af6f445a
|
||||
F test/fts3.test 672a040ea57036fb4b6fdc09027c18d7d24ab654
|
||||
F test/fts3_common.tcl 99cf6659b87c0f74f55963c2aea03b3a7d66ceb0
|
||||
F test/fts3aa.test 6c263a6f8845205ee02550981a94c2e8dc1e7058
|
||||
F test/fts3aa.test 39b65c11913d277c91d7426c62cfc1d147d1b4e9a48fecd9e38f60d0b5a5f505
|
||||
F test/fts3ab.test 7f6cf260ae80dda064023df8e8e503e9a412b91f
|
||||
F test/fts3ac.test 636ed7486043055d4f126a0e385f2d5a82ebbf63
|
||||
F test/fts3ad.test e40570cb6f74f059129ad48bcef3d7cbc20dda49
|
||||
@@ -775,6 +779,7 @@ F test/fts3comp1.test a0f5b16a2df44dd0b15751787130af2183167c0c
|
||||
F test/fts3conf.test 60317efd562080e198b5bdc9fcd222ce32cf01d7
|
||||
F test/fts3corrupt.test 2710b77983cc7789295ddbffea52c1d3b7506dbb
|
||||
F test/fts3corrupt2.test 6d96efae2f8a6af3eeaf283aba437e6d0e5447ba
|
||||
F test/fts3corrupt3.test 56e0ee83e90b57f5f3644cb7d1b36a067b7b8b19cdf0dedce45e5e13cf752f65
|
||||
F test/fts3cov.test e0fb00d8b715ddae4a94c305992dfc3ef70353d7
|
||||
F test/fts3d.test d3e9c8fb75135ada06bf3bab4f9666224965d708
|
||||
F test/fts3defer.test 0be4440b73a2e651fc1e472066686d6ada4b9963
|
||||
@@ -787,12 +792,13 @@ F test/fts3expr2.test 18da930352e5693eaa163a3eacf96233b7290d1a
|
||||
F test/fts3expr3.test c4d4a7d6327418428c96e0a3a1137c251b8dfbf8
|
||||
F test/fts3expr4.test c39a15d676b14fc439d9bf845aa7bddcf4a74dc3
|
||||
F test/fts3expr5.test f9abfffbf5e53d48a33e12a1e8f8ba2c551c9b49
|
||||
F test/fts3fault.test da49627b280b210ebc6657f76344c7851f10ce66
|
||||
F test/fts3fault2.test f953bb3cf903988172270a9a0aafd5a890b0f98f
|
||||
F test/fts3fault.test 3764ecffb3d341c5b05b3abe64153f385880035e67706ca2fc719e5d3352aedb
|
||||
F test/fts3fault2.test 536bbe01fe2946ec24b063a5eee813e8fd90354a6ca0b8f941d299c405edd17e
|
||||
F test/fts3first.test dbdedd20914c8d539aa3206c9b34a23775644641
|
||||
F test/fts3join.test 34750f3ce1e29b2749eaf0f1be2fa6301c5d50da
|
||||
F test/fts3malloc.test b0e4c133b8d61d4f6d112d8110f8320e9e453ef6
|
||||
F test/fts3matchinfo.test ce864e0bd92429df8008f31cf557269ba172482a
|
||||
F test/fts3misc.test 66e7b59576ce2c795f0baff6d47f7f6f57e6f41101cf85fad05989e43bb060dd
|
||||
F test/fts3near.test 7e3354d46f155a822b59c0e957fd2a70c1d7e905
|
||||
F test/fts3offsets.test b85fd382abdc78ebce721d8117bd552dfb75094c
|
||||
F test/fts3prefix.test fa794eaab0bdae466494947b0b153d7844478ab2
|
||||
@@ -812,7 +818,7 @@ F test/fts4docid.test e33c383cfbdff0284685604d256f347a18fdbf01
|
||||
F test/fts4growth.test e5390da74619cacc389711bac9349640b32c4f9a
|
||||
F test/fts4growth2.test 13ad4e76451af6e6906c95cdc725d01b00044269
|
||||
F test/fts4incr.test 4e353a0bd886ea984e56fce9e77724fc923b8d0d
|
||||
F test/fts4langid.test 65a7332c9bc257919e259a304aa8a38c41655b9d
|
||||
F test/fts4langid.test 89a107d36710dc3f44dab0861a784ffab967bd1f32c8d700b031748b9d2703c6
|
||||
F test/fts4lastrowid.test fa5e157955a3121615ef3e16ff5196e96c9e1e64
|
||||
F test/fts4merge.test d2b39f6b1bd4a9738a13540e2d044cba11c43d47
|
||||
F test/fts4merge2.test 5faa558d1b672f82b847d2a337465fa745e46891
|
||||
@@ -845,6 +851,7 @@ F test/fuzzer2.test a85ef814ce071293bce1ad8dffa217cbbaad4c14
|
||||
F test/fuzzerfault.test 8792cd77fd5bce765b05d0c8e01b9edcf8af8536
|
||||
F test/gcfault.test dd28c228a38976d6336a3fc42d7e5f1ad060cb8c
|
||||
F test/genesis.tcl 1e2e2e8e5cc4058549a154ff1892fe5c9de19f98
|
||||
F test/having.test 30a02b8a9a47cba7bdb5281999c5cbff407c2ac296511ee64dd0b418fe38eb0f
|
||||
F test/hexlit.test 4a6a5f46e3c65c4bf1fa06f5dd5a9507a5627751
|
||||
F test/hidden.test 23c1393a79e846d68fd902d72c85d5e5dcf98711
|
||||
F test/hook.test dbc0b87756e1e20e7497b56889c9e9cd2f8cc2b5
|
||||
@@ -856,7 +863,7 @@ F test/in.test 20c5529986998949908f889c8208b2cd894b2cc9
|
||||
F test/in2.test 5d4c61d17493c832f7d2d32bef785119e87bde75
|
||||
F test/in3.test 3cbf58c87f4052cee3a58b37b6389777505aa0c0
|
||||
F test/in4.test d2b38cba404bc4320f4fe1b595b3d163f212c068
|
||||
F test/in5.test 6c006e0bcd7351b69350ef566e65f244023489e9
|
||||
F test/in5.test 7ae37fcd4a5e198291c6ab5f31a5bb3d15397efe8b75a6736d7a95a7b8dd9e08
|
||||
F test/incrblob.test c9b96afc292aeff43d6687bcb09b0280aa599822
|
||||
F test/incrblob2.test a5ce5ed1d0b01e2ed347245a21170372528af0a5
|
||||
F test/incrblob3.test d8d036fde015d4a159cd3cbae9d29003b37227a4
|
||||
@@ -878,12 +885,13 @@ F test/index7.test 7feababe16f2091b229c22aff2bcc1d4d6b9d2bb
|
||||
F test/index8.test bc2e3db70e8e62459aaa1bd7e4a9b39664f8f9d7
|
||||
F test/indexedby.test 9c4cd331224e57f79fbf411ae245e6272d415985
|
||||
F test/indexexpr1.test 038b3befa74e5a75126b6e9dd2ae5df61c1c7cf7
|
||||
F test/indexexpr2.test 68ee9dbe83fcf85e50f4d0bd1f742a082496f2ee5153f4be2a1861db84462bf7
|
||||
F test/indexfault.test 31d4ab9a7d2f6e9616933eb079722362a883eb1d
|
||||
F test/init.test 15c823093fdabbf7b531fe22cf037134d09587a7
|
||||
F test/insert.test 38742b5e9601c8f8d76e9b7555f7270288c2d371
|
||||
F test/insert2.test 4d14b8f1b810a41995f6286b64a6943215d52208
|
||||
F test/insert3.test 1b7db95a03ad9c5013fdf7d6722b6cd66ee55e30
|
||||
F test/insert4.test a20432f1c0fbbcff8f11d0e6ab4acb8c9db58023
|
||||
F test/insert4.test 46bead5f39e181850ee56adcf49d3a3157c460c52249211714612ac89fe34835
|
||||
F test/insert5.test 394f96728d1258f406fe5f5aeb0aaf29487c39a6
|
||||
F test/instr.test 9a8802f28437d8ade53fedfc47b2ca599b4e48ba
|
||||
F test/instrfault.test 0f870b218ea17cd477bb19ed330eecdb460dd53a
|
||||
@@ -910,8 +918,8 @@ F test/journal3.test ff8af941f9e06161d3db1b46bb9f965ff0e7f307
|
||||
F test/jrnlmode.test 7864d59cf7f6e552b9b99ba0f38acd167edc10fa
|
||||
F test/jrnlmode2.test 81610545a4e6ed239ea8fa661891893385e23a1d
|
||||
F test/jrnlmode3.test 556b447a05be0e0963f4311e95ab1632b11c9eaa
|
||||
F test/json101.test c0897616f32d95431f37fd291cb78742181980ac
|
||||
F test/json102.test bf3fe7a706d30936a76a0f7a0375e1e8e73aff5a
|
||||
F test/json101.test 2bd3703a8566e39f8efee8b83bb60aac363fa312e69c94b4024114e0fe77e380
|
||||
F test/json102.test eeb54efa221e50b74a2d6fb9259963b48d7414dca3ce2fdfdeed45cb28487bc1
|
||||
F test/json103.test c5f6b85e69de05f6b3195f9f9d5ce9cd179099a0
|
||||
F test/json104.test 877d5845f6303899b7889ea5dd1bea99076e3100574d5c536082245c5805dcaa
|
||||
F test/keyword1.test 37ef6bba5d2ed5b07ecdd6810571de2956599dff
|
||||
@@ -939,7 +947,7 @@ F test/make-where7.tcl 05c16b5d4f5d6512881dfec560cb793915932ef9
|
||||
F test/malloc.test 21c213365f2cca95ab2d7dc078dc8525f96065f8
|
||||
F test/malloc3.test e3b32c724b5a124b57cb0ed177f675249ad0c66a
|
||||
F test/malloc4.test 957337613002b7058a85116493a262f679f3a261
|
||||
F test/malloc5.test 192d0b5ee1d023a07d5164c34cf47d010da73da1
|
||||
F test/malloc5.test a591be066ebc6ad34adaa4b38939a037a59ebd80ad681e79dedac7b4a9e7bc09
|
||||
F test/malloc6.test 2f039d9821927eacae43e1831f815e157659a151
|
||||
F test/malloc7.test 7c68a32942858bc715284856c5507446bba88c3a
|
||||
F test/malloc8.test 9b7a3f8cb9cf0b12fff566e80a980b1767bd961d
|
||||
@@ -1027,15 +1035,17 @@ F test/parser1.test 391b9bf9a229547a129c61ac345ed1a6f5eb1854
|
||||
F test/pcache.test c8acbedd3b6fd0f9a7ca887a83b11d24a007972b
|
||||
F test/pcache2.test af7f3deb1a819f77a6d0d81534e97d1cf62cd442
|
||||
F test/percentile.test 4243af26b8f3f4555abe166f723715a1f74c77ff
|
||||
F test/permutations.test af720e7d139e7e5417341d0f0eef2b911c0b067852138dc2f5b6a451b5725118
|
||||
F test/permutations.test 8aaa22a0f428a7e6b8446b97bc7691a273eaeff5dc290fb9129bf79fa9813a6e
|
||||
F test/pragma.test 1e94755164a3a3264cd39836de4bebcb7809e5f8
|
||||
F test/pragma2.test e5d5c176360c321344249354c0c16aec46214c9f
|
||||
F test/pragma3.test 14c12bc5352b1e100e0b6b44f371053a81ccf8ed
|
||||
F test/pragma4.test 6e85b6eab8e61ffc9c7db59d842276674e8e3264
|
||||
F test/pragmafault.test 275edaf3161771d37de60e5c2b412627ac94cef11739236bec12ed1258b240f8
|
||||
F test/printf.test b3ff34e73d59124140eaf89f7672e21bc2ca5fcc
|
||||
F test/printf2.test 9e6db85f81c63f2367c34a9d7db384088bd374ad
|
||||
F test/progress.test ebab27f670bd0d4eb9d20d49cef96e68141d92fb
|
||||
F test/ptrchng.test ef1aa72d6cf35a2bbd0869a649b744e9d84977fc
|
||||
F test/pushdown.test a5d2e5e66cc94cfb0989a5dd23e77427dd6c4313019155ba9051f52dfc5326aa
|
||||
F test/queryonly.test 5f653159e0f552f0552d43259890c1089391dcca
|
||||
F test/quick.test 1681febc928d686362d50057c642f77a02c62e57
|
||||
F test/quota-glob.test 32901e9eed6705d68ca3faee2a06b73b57cb3c26
|
||||
@@ -1119,7 +1129,7 @@ F test/shell2.test e242a9912f44f4c23c3d1d802a83e934e84c853b
|
||||
F test/shell3.test 9b95ba643eaa228376f06a898fb410ee9b6e57c1
|
||||
F test/shell4.test 89ad573879a745974ff2df20ff97c5d6ffffbd5d
|
||||
F test/shell5.test 50a732c1c2158b1cd62cf53975ce1ea7ce6b9dc9
|
||||
F test/shell6.test cff624fadf71bdb5e3a9b0f86eaf59a43c0622b1
|
||||
F test/shell6.test ab1592ebe881371f651f18ee6a0df21cbfb5310f88cb832ab642d4038f679772
|
||||
F test/shell7.test 07751911b294698e0c5df67bcbd29e7d2f0f2907
|
||||
F test/shortread1.test bb591ef20f0fd9ed26d0d12e80eee6d7ac8897a3
|
||||
F test/show_speedtest1_rtree.tcl 32e6c5f073d7426148a6936a0408f4b5b169aba5
|
||||
@@ -1159,6 +1169,7 @@ F test/sqllog.test 6af6cb0b09f4e44e1917e06ce85be7670302517a
|
||||
F test/stat.test f8f1279ffffabe6df825723af18cc6e0ae70a893
|
||||
F test/statfault.test f525a7bf633e50afd027700e9a486090684b1ac1
|
||||
F test/stmt.test 64844332db69cf1a735fcb3e11548557fc95392f
|
||||
F test/subjournal.test 2121a93ef3d3e83d52bf236c8a02aef4009fbf52884754104b2b6cad9a041095
|
||||
F test/subquery.test d7268d193dd33d5505df965399d3a594e76ae13f
|
||||
F test/subquery2.test 438f8a7da1457277b22e4176510f7659b286995f
|
||||
F test/subselect.test 0966aa8e720224dbd6a5e769a3ec2a723e332303
|
||||
@@ -1167,7 +1178,7 @@ F test/subtype1.test 7fe09496352f97053af1437150751be2d0a0cae8
|
||||
F test/superlock.test ec94f0556b6488d97f71c79f9061ae08d9ab8f12
|
||||
F test/symlink.test c9ebe7330d228249e447038276bfc8a7b22f4849
|
||||
F test/sync.test 2f84bdbc2b2df1fcb0220575b4b9f8cea94b7529
|
||||
F test/sync2.test 29af00fe9e468a1e20315d1edced8f8a32ac156df983ae9b53802e7d472675d5
|
||||
F test/sync2.test 6be8ed007fa063b147773c1982b5bdba97a32badc536bdc6077eff5cf8710ece
|
||||
F test/syscall.test f59ba4e25f7ba4a4c031026cc2ef8b6e4b4c639c
|
||||
F test/sysfault.test c9f2b0d8d677558f74de750c75e12a5454719d04
|
||||
F test/tabfunc01.test 699251cb99651415218a891384510a685c7ab012
|
||||
@@ -1481,7 +1492,7 @@ F test/zerodamage.test e59a56443d6298ecf7435f618f0b27654f0c849e
|
||||
F tool/GetFile.cs a15e08acb5dd7539b75ba23501581d7c2b462cb5
|
||||
F tool/GetTclKit.bat 6afa640edc7810725aec61c3076ac617c4aaf0b7
|
||||
F tool/Replace.cs 02c67258801c2fb5f63231e0ac0f220b4b36ba91
|
||||
F tool/addopcodes.tcl 10c889c4a65ec6c5604e4a47306fa77ff57ae189
|
||||
F tool/addopcodes.tcl edbd53806bf20e25af2373ad0c091be4385081c1aa1813b916bf093f94ed8380
|
||||
F tool/build-all-msvc.bat c12328d06c45fec8baada5949e3d5af54bf8c887 x
|
||||
F tool/build-shell.sh 950f47c6174f1eea171319438b93ba67ff5bf367
|
||||
F tool/cg_anno.tcl f95b0006c52cf7f0496b506343415b6ee3cdcdd3 x
|
||||
@@ -1490,12 +1501,12 @@ F tool/dbhash.c a06228aa21ebc4e6ea8daa486601d938499238a5
|
||||
F tool/extract.c 054069d81b095fbdc189a6f5d4466e40380505e2
|
||||
F tool/fast_vacuum.c 5ba0d6f5963a0a63bdc42840f678bad75b2ebce1
|
||||
F tool/fragck.tcl 5265a95126abcf6ab357f7efa544787e5963f439
|
||||
F tool/fuzzershell.c dbf6c26eef936ec78cb0707570de3a4308b2507e
|
||||
F tool/fuzzershell.c e1d90a03ca790d7c331c2aae08ca46ff435f1ae1faa6cb9cc48f4687c18fdc6e
|
||||
F tool/genfkey.README cf68fddd4643bbe3ff8e31b8b6d8b0a1b85e20f4
|
||||
F tool/genfkey.test 4196a8928b78f51d54ef58e99e99401ab2f0a7e5
|
||||
F tool/getlock.c f4c39b651370156cae979501a7b156bdba50e7ce
|
||||
F tool/kvtest-speed.sh 4761a9c4b3530907562314d7757995787f7aef8f
|
||||
F tool/lemon.c 5ccba178a8e8a4b21e1c9232944d23973da38ad7
|
||||
F tool/lemon.c f4f1045743e12f86b132253a3192ef92c94bfceb7f41ac41b8e3b373aa78474e
|
||||
F tool/lempar.c db1bdb4821f2d8fbd76e577cf3ab18642c8d08d1
|
||||
F tool/libvers.c caafc3b689638a1d88d44bc5f526c2278760d9b9
|
||||
F tool/loadfts.c c3c64e4d5e90e8ba41159232c2189dba4be7b862
|
||||
@@ -1503,19 +1514,19 @@ F tool/logest.c 11346aa019e2e77a00902aa7d0cabd27bd2e8cca
|
||||
F tool/max-limits.c cbb635fbb37ae4d05f240bfb5b5270bb63c54439
|
||||
F tool/mkautoconfamal.sh e855df211ecbcc7131dee817110ff386cfb112f7
|
||||
F tool/mkkeywordhash.c f7f3b342211ac6a14258b9726d5b97cf4f548f22
|
||||
F tool/mkmsvcmin.tcl 95b37e202cbed873aa8ffdbb493b9db45927be2b
|
||||
F tool/mkmsvcmin.tcl cbd93f1cfa3a0a9ae56fc958510aa3fc3ac65e29cb111716199e3d0e66eefaa4
|
||||
F tool/mkopcodec.tcl d1b6362bd3aa80d5520d4d6f3765badf01f6c43c
|
||||
F tool/mkopcodeh.tcl a01d2c1d8a6205b03fc635adf3735b4c523befd3
|
||||
F tool/mkopts.tcl 66ac10d240cc6e86abd37dc908d50382f84ff46e
|
||||
F tool/mkpragmatab.tcl 2ffe6d5fdc2d3381621d6c77978ba054466e757f
|
||||
F tool/mkpragmatab.tcl 32bb40741df11bddc8451de9ea4d130e7b4476d8064794b1cf402ac110840fba
|
||||
F tool/mkspeedsql.tcl a1a334d288f7adfe6e996f2e712becf076745c97
|
||||
F tool/mksqlite3c-noext.tcl fef88397668ae83166735c41af99d79f56afaabb
|
||||
F tool/mksqlite3c.tcl 06b2e6a0f21cc0a5d70fbbd136b3e0a96470645e
|
||||
F tool/mksqlite3h.tcl b9836752c3d08f9fab2dfc0017ca9fd5d90ac863
|
||||
F tool/mksqlite3h.tcl 51bd5e7e840a920388a5966c9f2ccc618f434c57bd68c1bab4085b2553e1e237
|
||||
F tool/mksqlite3internalh.tcl eb994013e833359137eb53a55acdad0b5ae1049b
|
||||
F tool/mkvsix.tcl b9e0777a213c23156b6542842c238479e496ebf5
|
||||
F tool/offsets.c fe4262fdfa378e8f5499a42136d17bf3b98f6091
|
||||
F tool/omittest.tcl 34d7ac01fe4fd18e3637f64abe12c40eca0f6b97
|
||||
F tool/omittest.tcl dfc8b18a23e9e5289104145b712cdb887c2d840c2d70dc09ce5dbeba8ed8d47c
|
||||
F tool/opcodesum.tcl 740ed206ba8c5040018988129abbf3089a0ccf4a
|
||||
F tool/pagesig.c ff0ca355fd3c2398e933da5e22439bbff89b803b
|
||||
F tool/replace.tcl 60f91e8dd06ab81f74d213ecbd9c9945f32ac048
|
||||
@@ -1526,7 +1537,7 @@ F tool/showdb.c e6bc9dba233bf1b57ca0a525a2bba762db4e223de84990739db3f09c46151b1e
|
||||
F tool/showjournal.c 5bad7ae8784a43d2b270d953060423b8bd480818
|
||||
F tool/showlocks.c 9920bcc64f58378ff1118caead34147201f48c68
|
||||
F tool/showstat4.c b14159aa062f661b394ba37b6b7b94bfb8012ab9
|
||||
F tool/showwal.c ec79959834f7b21f1e0a2aa52bb7c056d2203977
|
||||
F tool/showwal.c ad9d768f96ca6199ad3a8c9562d679680bd032dd01204ea3e5ea6fb931d81847
|
||||
F tool/soak1.tcl 8d407956e1a45b485a8e072470a3e629a27037fe
|
||||
F tool/spaceanal.tcl ab7d9bf68062907282a64b3e12ccbfad47193c5a
|
||||
F tool/speed-check.sh 9630ba0468b609c52f48309243d4eb6e9c34deda
|
||||
@@ -1546,7 +1557,7 @@ F tool/varint.c 5d94cb5003db9dbbcbcc5df08d66f16071aee003
|
||||
F tool/vdbe-compress.tcl 5926c71f9c12d2ab73ef35c29376e756eb68361c
|
||||
F tool/vdbe_profile.tcl 246d0da094856d72d2c12efec03250d71639d19f
|
||||
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
|
||||
F tool/warnings.sh d9ded5274b3cb947e98e70d587f71d6263f803b5
|
||||
F tool/warnings.sh 8a4acea31e0f9c562949a2d767329533c0930d699ea19c6704c0ca0aa9154068
|
||||
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
|
||||
F vsixtest/App.xaml b76d3b48860e7454775c47ea38ffea9c4abe3e85
|
||||
F vsixtest/App.xaml.cpp c465147f50871165c60ca16955219f6c5812d6d8
|
||||
@@ -1569,10 +1580,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 8469fc0d48d6af0accef9b8a84e08ad2ca32351907510d177b4ca4815c1ea7cb
|
||||
R e1b145e92e118b2bc2de7100fb7561b5
|
||||
T *branch * version-3.18
|
||||
T *sym-version-3.18 *
|
||||
P 7940bff32aa6ea868a53680822d148b7ec7a075c01ae9e0d5ad9859bcc339054
|
||||
R 7f4a731db0c6ec92ab37895dd85f915a
|
||||
T *branch * doc-type
|
||||
T *sym-doc-type *
|
||||
T -sym-trunk *
|
||||
U drh
|
||||
Z 2998f3cf8a15fbd1f3dc49f1b039f0d5
|
||||
Z 401c4b313e85ed363ad34cfb74831800
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
424a0d380332858ee55bdebc4af3789f74e70a2b3ba1cf29d84b9b4bcf3e2e37
|
||||
cfa4aa203646f44b303138c25672293bb87d97126fe2030d4709e8ad7814a807
|
||||
+12
@@ -216,6 +216,18 @@ int sqlite3AuthCheck(
|
||||
if( db->xAuth==0 ){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/* EVIDENCE-OF: R-43249-19882 The third through sixth parameters to the
|
||||
** callback are either NULL pointers or zero-terminated strings that
|
||||
** contain additional details about the action to be authorized.
|
||||
**
|
||||
** The following testcase() macros show that any of the 3rd through 6th
|
||||
** parameters can be either NULL or a string. */
|
||||
testcase( zArg1==0 );
|
||||
testcase( zArg2==0 );
|
||||
testcase( zArg3==0 );
|
||||
testcase( pParse->zAuthContext==0 );
|
||||
|
||||
rc = db->xAuth(db->pAuthArg, code, zArg1, zArg2, zArg3, pParse->zAuthContext
|
||||
#ifdef SQLITE_USER_AUTHENTICATION
|
||||
,db->auth.zAuthUser
|
||||
|
||||
+47
-46
@@ -499,6 +499,7 @@ static void invalidateAllOverflowCache(BtShared *pBt){
|
||||
*/
|
||||
static void invalidateIncrblobCursors(
|
||||
Btree *pBtree, /* The database file to check */
|
||||
Pgno pgnoRoot, /* The table that might be changing */
|
||||
i64 iRow, /* The rowid that might be changing */
|
||||
int isClearTable /* True if all rows are being deleted */
|
||||
){
|
||||
@@ -509,7 +510,7 @@ static void invalidateIncrblobCursors(
|
||||
for(p=pBtree->pBt->pCursor; p; p=p->pNext){
|
||||
if( (p->curFlags & BTCF_Incrblob)!=0 ){
|
||||
pBtree->hasIncrblobCur = 1;
|
||||
if( isClearTable || p->info.nKey==iRow ){
|
||||
if( p->pgnoRoot==pgnoRoot && (isClearTable || p->info.nKey==iRow) ){
|
||||
p->eState = CURSOR_INVALID;
|
||||
}
|
||||
}
|
||||
@@ -518,7 +519,7 @@ static void invalidateIncrblobCursors(
|
||||
|
||||
#else
|
||||
/* Stub function when INCRBLOB is omitted */
|
||||
#define invalidateIncrblobCursors(x,y,z)
|
||||
#define invalidateIncrblobCursors(w,x,y,z)
|
||||
#endif /* SQLITE_OMIT_INCRBLOB */
|
||||
|
||||
/*
|
||||
@@ -4316,7 +4317,7 @@ int sqlite3BtreeCloseCursor(BtCursor *pCur){
|
||||
CellInfo info;
|
||||
int iPage = pCur->iPage;
|
||||
memset(&info, 0, sizeof(info));
|
||||
btreeParseCell(pCur->apPage[iPage], pCur->aiIdx[iPage], &info);
|
||||
btreeParseCell(pCur->apPage[iPage], pCur->ix, &info);
|
||||
assert( CORRUPT_DB || memcmp(&info, &pCur->info, sizeof(info))==0 );
|
||||
}
|
||||
#else
|
||||
@@ -4326,7 +4327,7 @@ static SQLITE_NOINLINE void getCellInfo(BtCursor *pCur){
|
||||
if( pCur->info.nSize==0 ){
|
||||
int iPage = pCur->iPage;
|
||||
pCur->curFlags |= BTCF_ValidNKey;
|
||||
btreeParseCell(pCur->apPage[iPage],pCur->aiIdx[iPage],&pCur->info);
|
||||
btreeParseCell(pCur->apPage[iPage],pCur->ix,&pCur->info);
|
||||
}else{
|
||||
assertCellInfo(pCur);
|
||||
}
|
||||
@@ -4533,7 +4534,7 @@ static int accessPayload(
|
||||
assert( pPage );
|
||||
assert( eOp==0 || eOp==1 );
|
||||
assert( pCur->eState==CURSOR_VALID );
|
||||
assert( pCur->aiIdx[pCur->iPage]<pPage->nCell );
|
||||
assert( pCur->ix<pPage->nCell );
|
||||
assert( cursorHoldsMutex(pCur) );
|
||||
|
||||
getCellInfo(pCur);
|
||||
@@ -4720,7 +4721,7 @@ int sqlite3BtreePayload(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){
|
||||
assert( cursorHoldsMutex(pCur) );
|
||||
assert( pCur->eState==CURSOR_VALID );
|
||||
assert( pCur->iPage>=0 && pCur->apPage[pCur->iPage] );
|
||||
assert( pCur->aiIdx[pCur->iPage]<pCur->apPage[pCur->iPage]->nCell );
|
||||
assert( pCur->ix<pCur->apPage[pCur->iPage]->nCell );
|
||||
return accessPayload(pCur, offset, amt, (unsigned char*)pBuf, 0);
|
||||
}
|
||||
|
||||
@@ -4782,7 +4783,7 @@ static const void *fetchPayload(
|
||||
assert( pCur->eState==CURSOR_VALID );
|
||||
assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
|
||||
assert( cursorOwnsBtShared(pCur) );
|
||||
assert( pCur->aiIdx[pCur->iPage]<pCur->apPage[pCur->iPage]->nCell );
|
||||
assert( pCur->ix<pCur->apPage[pCur->iPage]->nCell );
|
||||
assert( pCur->info.nSize>0 );
|
||||
assert( pCur->info.pPayload>pCur->apPage[pCur->iPage]->aData || CORRUPT_DB );
|
||||
assert( pCur->info.pPayload<pCur->apPage[pCur->iPage]->aDataEnd ||CORRUPT_DB);
|
||||
@@ -4833,8 +4834,8 @@ static int moveToChild(BtCursor *pCur, u32 newPgno){
|
||||
}
|
||||
pCur->info.nSize = 0;
|
||||
pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
|
||||
pCur->iPage++;
|
||||
pCur->aiIdx[pCur->iPage] = 0;
|
||||
pCur->aiIdx[pCur->iPage++] = pCur->ix;
|
||||
pCur->ix = 0;
|
||||
return getAndInitPage(pBt, newPgno, &pCur->apPage[pCur->iPage],
|
||||
pCur, pCur->curPagerFlags);
|
||||
}
|
||||
@@ -4882,6 +4883,7 @@ static void moveToParent(BtCursor *pCur){
|
||||
testcase( pCur->aiIdx[pCur->iPage-1] > pCur->apPage[pCur->iPage-1]->nCell );
|
||||
pCur->info.nSize = 0;
|
||||
pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
|
||||
pCur->ix = pCur->aiIdx[pCur->iPage-1];
|
||||
releasePageNotNull(pCur->apPage[pCur->iPage--]);
|
||||
}
|
||||
|
||||
@@ -4963,7 +4965,7 @@ static int moveToRoot(BtCursor *pCur){
|
||||
}
|
||||
|
||||
skip_init:
|
||||
pCur->aiIdx[0] = 0;
|
||||
pCur->ix = 0;
|
||||
pCur->info.nSize = 0;
|
||||
pCur->curFlags &= ~(BTCF_AtLast|BTCF_ValidNKey|BTCF_ValidOvfl);
|
||||
|
||||
@@ -4997,8 +4999,8 @@ static int moveToLeftmost(BtCursor *pCur){
|
||||
assert( cursorOwnsBtShared(pCur) );
|
||||
assert( pCur->eState==CURSOR_VALID );
|
||||
while( rc==SQLITE_OK && !(pPage = pCur->apPage[pCur->iPage])->leaf ){
|
||||
assert( pCur->aiIdx[pCur->iPage]<pPage->nCell );
|
||||
pgno = get4byte(findCell(pPage, pCur->aiIdx[pCur->iPage]));
|
||||
assert( pCur->ix<pPage->nCell );
|
||||
pgno = get4byte(findCell(pPage, pCur->ix));
|
||||
rc = moveToChild(pCur, pgno);
|
||||
}
|
||||
return rc;
|
||||
@@ -5023,11 +5025,11 @@ static int moveToRightmost(BtCursor *pCur){
|
||||
assert( pCur->eState==CURSOR_VALID );
|
||||
while( !(pPage = pCur->apPage[pCur->iPage])->leaf ){
|
||||
pgno = get4byte(&pPage->aData[pPage->hdrOffset+8]);
|
||||
pCur->aiIdx[pCur->iPage] = pPage->nCell;
|
||||
pCur->ix = pPage->nCell;
|
||||
rc = moveToChild(pCur, pgno);
|
||||
if( rc ) return rc;
|
||||
}
|
||||
pCur->aiIdx[pCur->iPage] = pPage->nCell-1;
|
||||
pCur->ix = pPage->nCell-1;
|
||||
assert( pCur->info.nSize==0 );
|
||||
assert( (pCur->curFlags & BTCF_ValidNKey)==0 );
|
||||
return SQLITE_OK;
|
||||
@@ -5075,7 +5077,7 @@ int sqlite3BtreeLast(BtCursor *pCur, int *pRes){
|
||||
for(ii=0; ii<pCur->iPage; ii++){
|
||||
assert( pCur->aiIdx[ii]==pCur->apPage[ii]->nCell );
|
||||
}
|
||||
assert( pCur->aiIdx[pCur->iPage]==pCur->apPage[pCur->iPage]->nCell-1 );
|
||||
assert( pCur->ix==pCur->apPage[pCur->iPage]->nCell-1 );
|
||||
assert( pCur->apPage[pCur->iPage]->leaf );
|
||||
#endif
|
||||
return SQLITE_OK;
|
||||
@@ -5222,7 +5224,7 @@ int sqlite3BtreeMovetoUnpacked(
|
||||
upr = pPage->nCell-1;
|
||||
assert( biasRight==0 || biasRight==1 );
|
||||
idx = upr>>(1-biasRight); /* idx = biasRight ? upr : (lwr+upr)/2; */
|
||||
pCur->aiIdx[pCur->iPage] = (u16)idx;
|
||||
pCur->ix = (u16)idx;
|
||||
if( xRecordCompare==0 ){
|
||||
for(;;){
|
||||
i64 nCellKey;
|
||||
@@ -5241,7 +5243,7 @@ int sqlite3BtreeMovetoUnpacked(
|
||||
if( lwr>upr ){ c = +1; break; }
|
||||
}else{
|
||||
assert( nCellKey==intKey );
|
||||
pCur->aiIdx[pCur->iPage] = (u16)idx;
|
||||
pCur->ix = (u16)idx;
|
||||
if( !pPage->leaf ){
|
||||
lwr = idx;
|
||||
goto moveto_next_layer;
|
||||
@@ -5310,7 +5312,7 @@ int sqlite3BtreeMovetoUnpacked(
|
||||
rc = SQLITE_NOMEM_BKPT;
|
||||
goto moveto_finish;
|
||||
}
|
||||
pCur->aiIdx[pCur->iPage] = (u16)idx;
|
||||
pCur->ix = (u16)idx;
|
||||
rc = accessPayload(pCur, 0, nCell, (unsigned char*)pCellKey, 0);
|
||||
pCur->curFlags &= ~BTCF_ValidOvfl;
|
||||
if( rc ){
|
||||
@@ -5332,7 +5334,7 @@ int sqlite3BtreeMovetoUnpacked(
|
||||
assert( c==0 );
|
||||
*pRes = 0;
|
||||
rc = SQLITE_OK;
|
||||
pCur->aiIdx[pCur->iPage] = (u16)idx;
|
||||
pCur->ix = (u16)idx;
|
||||
if( pIdxKey->errCode ) rc = SQLITE_CORRUPT;
|
||||
goto moveto_finish;
|
||||
}
|
||||
@@ -5344,8 +5346,8 @@ int sqlite3BtreeMovetoUnpacked(
|
||||
assert( lwr==upr+1 || (pPage->intKey && !pPage->leaf) );
|
||||
assert( pPage->isInit );
|
||||
if( pPage->leaf ){
|
||||
assert( pCur->aiIdx[pCur->iPage]<pCur->apPage[pCur->iPage]->nCell );
|
||||
pCur->aiIdx[pCur->iPage] = (u16)idx;
|
||||
assert( pCur->ix<pCur->apPage[pCur->iPage]->nCell );
|
||||
pCur->ix = (u16)idx;
|
||||
*pRes = c;
|
||||
rc = SQLITE_OK;
|
||||
goto moveto_finish;
|
||||
@@ -5356,7 +5358,7 @@ moveto_next_layer:
|
||||
}else{
|
||||
chldPg = get4byte(findCell(pPage, lwr));
|
||||
}
|
||||
pCur->aiIdx[pCur->iPage] = (u16)lwr;
|
||||
pCur->ix = (u16)lwr;
|
||||
rc = moveToChild(pCur, chldPg);
|
||||
if( rc ) break;
|
||||
}
|
||||
@@ -5457,7 +5459,7 @@ static SQLITE_NOINLINE int btreeNext(BtCursor *pCur, int *pRes){
|
||||
}
|
||||
|
||||
pPage = pCur->apPage[pCur->iPage];
|
||||
idx = ++pCur->aiIdx[pCur->iPage];
|
||||
idx = ++pCur->ix;
|
||||
assert( pPage->isInit );
|
||||
|
||||
/* If the database file is corrupt, it is possible for the value of idx
|
||||
@@ -5481,7 +5483,7 @@ static SQLITE_NOINLINE int btreeNext(BtCursor *pCur, int *pRes){
|
||||
}
|
||||
moveToParent(pCur);
|
||||
pPage = pCur->apPage[pCur->iPage];
|
||||
}while( pCur->aiIdx[pCur->iPage]>=pPage->nCell );
|
||||
}while( pCur->ix>=pPage->nCell );
|
||||
if( pPage->intKey ){
|
||||
return sqlite3BtreeNext(pCur, pRes);
|
||||
}else{
|
||||
@@ -5505,8 +5507,8 @@ int sqlite3BtreeNext(BtCursor *pCur, int *pRes){
|
||||
*pRes = 0;
|
||||
if( pCur->eState!=CURSOR_VALID ) return btreeNext(pCur, pRes);
|
||||
pPage = pCur->apPage[pCur->iPage];
|
||||
if( (++pCur->aiIdx[pCur->iPage])>=pPage->nCell ){
|
||||
pCur->aiIdx[pCur->iPage]--;
|
||||
if( (++pCur->ix)>=pPage->nCell ){
|
||||
pCur->ix--;
|
||||
return btreeNext(pCur, pRes);
|
||||
}
|
||||
if( pPage->leaf ){
|
||||
@@ -5570,12 +5572,12 @@ static SQLITE_NOINLINE int btreePrevious(BtCursor *pCur, int *pRes){
|
||||
pPage = pCur->apPage[pCur->iPage];
|
||||
assert( pPage->isInit );
|
||||
if( !pPage->leaf ){
|
||||
int idx = pCur->aiIdx[pCur->iPage];
|
||||
int idx = pCur->ix;
|
||||
rc = moveToChild(pCur, get4byte(findCell(pPage, idx)));
|
||||
if( rc ) return rc;
|
||||
rc = moveToRightmost(pCur);
|
||||
}else{
|
||||
while( pCur->aiIdx[pCur->iPage]==0 ){
|
||||
while( pCur->ix==0 ){
|
||||
if( pCur->iPage==0 ){
|
||||
pCur->eState = CURSOR_INVALID;
|
||||
*pRes = 1;
|
||||
@@ -5586,7 +5588,7 @@ static SQLITE_NOINLINE int btreePrevious(BtCursor *pCur, int *pRes){
|
||||
assert( pCur->info.nSize==0 );
|
||||
assert( (pCur->curFlags & (BTCF_ValidOvfl))==0 );
|
||||
|
||||
pCur->aiIdx[pCur->iPage]--;
|
||||
pCur->ix--;
|
||||
pPage = pCur->apPage[pCur->iPage];
|
||||
if( pPage->intKey && !pPage->leaf ){
|
||||
rc = sqlite3BtreePrevious(pCur, pRes);
|
||||
@@ -5605,12 +5607,12 @@ int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){
|
||||
pCur->curFlags &= ~(BTCF_AtLast|BTCF_ValidOvfl|BTCF_ValidNKey);
|
||||
pCur->info.nSize = 0;
|
||||
if( pCur->eState!=CURSOR_VALID
|
||||
|| pCur->aiIdx[pCur->iPage]==0
|
||||
|| pCur->ix==0
|
||||
|| pCur->apPage[pCur->iPage]->leaf==0
|
||||
){
|
||||
return btreePrevious(pCur, pRes);
|
||||
}
|
||||
pCur->aiIdx[pCur->iPage]--;
|
||||
pCur->ix--;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
@@ -7932,8 +7934,8 @@ static int balance(BtCursor *pCur){
|
||||
rc = balance_deeper(pPage, &pCur->apPage[1]);
|
||||
if( rc==SQLITE_OK ){
|
||||
pCur->iPage = 1;
|
||||
pCur->ix = 0;
|
||||
pCur->aiIdx[0] = 0;
|
||||
pCur->aiIdx[1] = 0;
|
||||
assert( pCur->apPage[1]->nOverflow );
|
||||
}
|
||||
}else{
|
||||
@@ -8110,7 +8112,7 @@ int sqlite3BtreeInsert(
|
||||
assert( pX->pKey==0 );
|
||||
/* If this is an insert into a table b-tree, invalidate any incrblob
|
||||
** cursors open on the row being replaced */
|
||||
invalidateIncrblobCursors(p, pX->nKey, 0);
|
||||
invalidateIncrblobCursors(p, pCur->pgnoRoot, pX->nKey, 0);
|
||||
|
||||
/* If BTREE_SAVEPOSITION is set, the cursor must already be pointing
|
||||
** to a row with the same key as the new entry being inserted. */
|
||||
@@ -8122,9 +8124,6 @@ int sqlite3BtreeInsert(
|
||||
** btreeMoveto() call */
|
||||
if( (pCur->curFlags&BTCF_ValidNKey)!=0 && pX->nKey==pCur->info.nKey ){
|
||||
loc = 0;
|
||||
}else if( (pCur->curFlags&BTCF_ValidNKey)!=0 && pX->nKey>0
|
||||
&& pCur->info.nKey==pX->nKey-1 ){
|
||||
loc = -1;
|
||||
}else if( loc==0 ){
|
||||
rc = sqlite3BtreeMovetoUnpacked(pCur, 0, pX->nKey, flags!=0, &loc);
|
||||
if( rc ) return rc;
|
||||
@@ -8162,7 +8161,7 @@ int sqlite3BtreeInsert(
|
||||
if( rc ) goto end_insert;
|
||||
assert( szNew==pPage->xCellSize(pPage, newCell) );
|
||||
assert( szNew <= MX_CELL_SIZE(pBt) );
|
||||
idx = pCur->aiIdx[pCur->iPage];
|
||||
idx = pCur->ix;
|
||||
if( loc==0 ){
|
||||
CellInfo info;
|
||||
assert( idx<pPage->nCell );
|
||||
@@ -8190,7 +8189,8 @@ int sqlite3BtreeInsert(
|
||||
if( rc ) goto end_insert;
|
||||
}else if( loc<0 && pPage->nCell>0 ){
|
||||
assert( pPage->leaf );
|
||||
idx = ++pCur->aiIdx[pCur->iPage];
|
||||
idx = ++pCur->ix;
|
||||
pCur->curFlags &= ~BTCF_ValidNKey;
|
||||
}else{
|
||||
assert( pPage->leaf );
|
||||
}
|
||||
@@ -8286,12 +8286,12 @@ int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){
|
||||
assert( pCur->curFlags & BTCF_WriteFlag );
|
||||
assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) );
|
||||
assert( !hasReadConflicts(p, pCur->pgnoRoot) );
|
||||
assert( pCur->aiIdx[pCur->iPage]<pCur->apPage[pCur->iPage]->nCell );
|
||||
assert( pCur->ix<pCur->apPage[pCur->iPage]->nCell );
|
||||
assert( pCur->eState==CURSOR_VALID );
|
||||
assert( (flags & ~(BTREE_SAVEPOSITION | BTREE_AUXDELETE))==0 );
|
||||
|
||||
iCellDepth = pCur->iPage;
|
||||
iCellIdx = pCur->aiIdx[iCellDepth];
|
||||
iCellIdx = pCur->ix;
|
||||
pPage = pCur->apPage[iCellDepth];
|
||||
pCell = findCell(pPage, iCellIdx);
|
||||
|
||||
@@ -8340,7 +8340,7 @@ int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){
|
||||
/* If this is a delete operation to remove a row from a table b-tree,
|
||||
** invalidate any incrblob cursors open on the row being deleted. */
|
||||
if( pCur->pKeyInfo==0 ){
|
||||
invalidateIncrblobCursors(p, pCur->info.nKey, 0);
|
||||
invalidateIncrblobCursors(p, pCur->pgnoRoot, pCur->info.nKey, 0);
|
||||
}
|
||||
|
||||
/* Make the page containing the entry to be deleted writable. Then free any
|
||||
@@ -8408,7 +8408,7 @@ int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){
|
||||
pCur->eState = CURSOR_SKIPNEXT;
|
||||
if( iCellIdx>=pPage->nCell ){
|
||||
pCur->skipNext = -1;
|
||||
pCur->aiIdx[iCellDepth] = pPage->nCell-1;
|
||||
pCur->ix = pPage->nCell-1;
|
||||
}else{
|
||||
pCur->skipNext = 1;
|
||||
}
|
||||
@@ -8667,7 +8667,7 @@ int sqlite3BtreeClearTable(Btree *p, int iTable, int *pnChange){
|
||||
/* Invalidate all incrblob cursors open on table iTable (assuming iTable
|
||||
** is the root of a table b-tree - if it is not, the following call is
|
||||
** a no-op). */
|
||||
invalidateIncrblobCursors(p, 0, 1);
|
||||
invalidateIncrblobCursors(p, (Pgno)iTable, 0, 1);
|
||||
rc = clearDatabasePage(pBt, (Pgno)iTable, 0, pnChange);
|
||||
}
|
||||
sqlite3BtreeLeave(p);
|
||||
@@ -8921,16 +8921,16 @@ int sqlite3BtreeCount(BtCursor *pCur, i64 *pnEntry){
|
||||
return moveToRoot(pCur);
|
||||
}
|
||||
moveToParent(pCur);
|
||||
}while ( pCur->aiIdx[pCur->iPage]>=pCur->apPage[pCur->iPage]->nCell );
|
||||
}while ( pCur->ix>=pCur->apPage[pCur->iPage]->nCell );
|
||||
|
||||
pCur->aiIdx[pCur->iPage]++;
|
||||
pCur->ix++;
|
||||
pPage = pCur->apPage[pCur->iPage];
|
||||
}
|
||||
|
||||
/* Descend to the child node of the cell that the cursor currently
|
||||
** points at. This is the right-child if (iIdx==pPage->nCell).
|
||||
*/
|
||||
iIdx = pCur->aiIdx[pCur->iPage];
|
||||
iIdx = pCur->ix;
|
||||
if( iIdx==pPage->nCell ){
|
||||
rc = moveToChild(pCur, get4byte(&pPage->aData[pPage->hdrOffset+8]));
|
||||
}else{
|
||||
@@ -9315,6 +9315,7 @@ static int checkTreePage(
|
||||
checkAppendMsg(pCheck, "Rowid %lld out of order", info.nKey);
|
||||
}
|
||||
maxKey = info.nKey;
|
||||
keyCanBeEqual = 0; /* Only the first key on the page may ==maxKey */
|
||||
}
|
||||
|
||||
/* Check the content overflow list */
|
||||
|
||||
+1
-1
@@ -276,7 +276,7 @@ struct BtreePayload {
|
||||
const void *pKey; /* Key content for indexes. NULL for tables */
|
||||
sqlite3_int64 nKey; /* Size of pKey for indexes. PRIMARY KEY for tabs */
|
||||
const void *pData; /* Data for tables. NULL for indexes */
|
||||
struct Mem *aMem; /* First of nMem value in the unpacked pKey */
|
||||
sqlite3_value *aMem; /* First of nMem value in the unpacked pKey */
|
||||
u16 nMem; /* Number of aMem[] value. Might be zero */
|
||||
int nData; /* Size of pData. 0 if none. */
|
||||
int nZero; /* Extra zero data appended after pData,nData */
|
||||
|
||||
+4
-4
@@ -517,10 +517,10 @@ struct BtCursor {
|
||||
** initialized. */
|
||||
i8 iPage; /* Index of current page in apPage */
|
||||
u8 curIntKey; /* Value of apPage[0]->intKey */
|
||||
struct KeyInfo *pKeyInfo; /* Argument passed to comparison function */
|
||||
void *padding1; /* Make object size a multiple of 16 */
|
||||
u16 aiIdx[BTCURSOR_MAX_DEPTH]; /* Current index in apPage[i] */
|
||||
MemPage *apPage[BTCURSOR_MAX_DEPTH]; /* Pages from root to current page */
|
||||
u16 ix; /* Current index for apPage[iPage] */
|
||||
u16 aiIdx[BTCURSOR_MAX_DEPTH-1]; /* Current index in apPage[i] */
|
||||
struct KeyInfo *pKeyInfo; /* Arg passed to comparison function */
|
||||
MemPage *apPage[BTCURSOR_MAX_DEPTH]; /* Pages from root to current page */
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
+2
-2
@@ -3623,7 +3623,7 @@ void sqlite3IdListDelete(sqlite3 *db, IdList *pList){
|
||||
sqlite3DbFree(db, pList->a[i].zName);
|
||||
}
|
||||
sqlite3DbFree(db, pList->a);
|
||||
sqlite3DbFree(db, pList);
|
||||
sqlite3DbFreeNN(db, pList);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -3813,7 +3813,7 @@ void sqlite3SrcListDelete(sqlite3 *db, SrcList *pList){
|
||||
sqlite3ExprDelete(db, pItem->pOn);
|
||||
sqlite3IdListDelete(db, pItem->pUsing);
|
||||
}
|
||||
sqlite3DbFree(db, pList);
|
||||
sqlite3DbFreeNN(db, pList);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
+3
-1
@@ -423,8 +423,10 @@ static void computeYMD(DateTime *p){
|
||||
p->Y = 2000;
|
||||
p->M = 1;
|
||||
p->D = 1;
|
||||
}else if( !validJulianDay(p->iJD) ){
|
||||
datetimeError(p);
|
||||
return;
|
||||
}else{
|
||||
assert( validJulianDay(p->iJD) );
|
||||
Z = (int)((p->iJD + 43200000)/86400000);
|
||||
A = (int)((Z - 1867216.25)/36524.25);
|
||||
A = Z + 1 + A - (A/4);
|
||||
|
||||
+8
-1
@@ -350,7 +350,14 @@ void sqlite3DeleteFrom(
|
||||
/* Special case: A DELETE without a WHERE clause deletes everything.
|
||||
** It is easier just to erase the whole table. Prior to version 3.6.5,
|
||||
** this optimization caused the row change count (the value returned by
|
||||
** API function sqlite3_count_changes) to be set incorrectly. */
|
||||
** API function sqlite3_count_changes) to be set incorrectly.
|
||||
**
|
||||
** The "rcauth==SQLITE_OK" terms is the
|
||||
** IMPLEMENTATION-OF: R-17228-37124 If the action code is SQLITE_DELETE and
|
||||
** the callback returns SQLITE_IGNORE then the DELETE operation proceeds but
|
||||
** the truncate optimization is disabled and all rows are deleted
|
||||
** individually.
|
||||
*/
|
||||
if( rcauth==SQLITE_OK
|
||||
&& pWhere==0
|
||||
&& !bComplex
|
||||
|
||||
+116
-49
@@ -58,7 +58,7 @@ char sqlite3ExprAffinity(Expr *pExpr){
|
||||
return sqlite3AffinityType(pExpr->u.zToken, 0);
|
||||
}
|
||||
#endif
|
||||
if( op==TK_AGG_COLUMN || op==TK_COLUMN ){
|
||||
if( (op==TK_AGG_COLUMN || op==TK_COLUMN) && pExpr->pTab ){
|
||||
return sqlite3TableColumnAffinity(pExpr->pTab, pExpr->iColumn);
|
||||
}
|
||||
if( op==TK_SELECT_COLUMN ){
|
||||
@@ -352,7 +352,6 @@ int sqlite3ExprVectorSize(Expr *pExpr){
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_SUBQUERY
|
||||
/*
|
||||
** Return a pointer to a subexpression of pVector that is the i-th
|
||||
** column of the vector (numbered starting with 0). The caller must
|
||||
@@ -380,9 +379,7 @@ Expr *sqlite3VectorFieldSubexpr(Expr *pVector, int i){
|
||||
}
|
||||
return pVector;
|
||||
}
|
||||
#endif /* !defined(SQLITE_OMIT_SUBQUERY) */
|
||||
|
||||
#ifndef SQLITE_OMIT_SUBQUERY
|
||||
/*
|
||||
** Compute and return a new Expr object which when passed to
|
||||
** sqlite3ExprCode() will generate all necessary code to compute
|
||||
@@ -440,7 +437,6 @@ Expr *sqlite3ExprForVectorField(
|
||||
}
|
||||
return pRet;
|
||||
}
|
||||
#endif /* !define(SQLITE_OMIT_SUBQUERY) */
|
||||
|
||||
/*
|
||||
** If expression pExpr is of type TK_SELECT, generate code to evaluate
|
||||
@@ -956,7 +952,7 @@ void sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pExpr, u32 n){
|
||||
z = pExpr->u.zToken;
|
||||
assert( z!=0 );
|
||||
assert( z[0]!=0 );
|
||||
assert( n==sqlite3Strlen30(z) );
|
||||
assert( n==(u32)sqlite3Strlen30(z) );
|
||||
if( z[1]==0 ){
|
||||
/* Wildcard of the form "?". Assign the next variable number */
|
||||
assert( z[0]=='?' );
|
||||
@@ -1038,7 +1034,7 @@ static SQLITE_NOINLINE void sqlite3ExprDeleteNN(sqlite3 *db, Expr *p){
|
||||
}
|
||||
if( ExprHasProperty(p, EP_MemToken) ) sqlite3DbFree(db, p->u.zToken);
|
||||
if( !ExprHasProperty(p, EP_Static) ){
|
||||
sqlite3DbFree(db, p);
|
||||
sqlite3DbFreeNN(db, p);
|
||||
}
|
||||
}
|
||||
void sqlite3ExprDelete(sqlite3 *db, Expr *p){
|
||||
@@ -1305,15 +1301,11 @@ ExprList *sqlite3ExprListDup(sqlite3 *db, ExprList *p, int flags){
|
||||
Expr *pPriorSelectCol = 0;
|
||||
assert( db!=0 );
|
||||
if( p==0 ) return 0;
|
||||
pNew = sqlite3DbMallocRawNN(db, sizeof(*pNew) );
|
||||
pNew = sqlite3DbMallocRawNN(db,
|
||||
sizeof(*pNew)+sizeof(pNew->a[0])*(p->nExpr-1) );
|
||||
if( pNew==0 ) return 0;
|
||||
pNew->nExpr = i = p->nExpr;
|
||||
if( (flags & EXPRDUP_REDUCE)==0 ) for(i=1; i<p->nExpr; i+=i){}
|
||||
pNew->a = pItem = sqlite3DbMallocRawNN(db, i*sizeof(p->a[0]) );
|
||||
if( pItem==0 ){
|
||||
sqlite3DbFree(db, pNew);
|
||||
return 0;
|
||||
}
|
||||
pNew->nAlloc = pNew->nExpr = p->nExpr;
|
||||
pItem = pNew->a;
|
||||
pOldItem = p->a;
|
||||
for(i=0; i<p->nExpr; i++, pItem++, pOldItem++){
|
||||
Expr *pOldExpr = pOldItem->pExpr;
|
||||
@@ -1404,7 +1396,7 @@ IdList *sqlite3IdListDup(sqlite3 *db, IdList *p){
|
||||
pNew->nId = p->nId;
|
||||
pNew->a = sqlite3DbMallocRawNN(db, p->nId*sizeof(p->a[0]) );
|
||||
if( pNew->a==0 ){
|
||||
sqlite3DbFree(db, pNew);
|
||||
sqlite3DbFreeNN(db, pNew);
|
||||
return 0;
|
||||
}
|
||||
/* Note that because the size of the allocation for p->a[] is not
|
||||
@@ -1475,6 +1467,7 @@ ExprList *sqlite3ExprListAppend(
|
||||
ExprList *pList, /* List to which to append. Might be NULL */
|
||||
Expr *pExpr /* Expression to be appended. Might be NULL */
|
||||
){
|
||||
struct ExprList_item *pItem;
|
||||
sqlite3 *db = pParse->db;
|
||||
assert( db!=0 );
|
||||
if( pList==0 ){
|
||||
@@ -1483,23 +1476,20 @@ ExprList *sqlite3ExprListAppend(
|
||||
goto no_mem;
|
||||
}
|
||||
pList->nExpr = 0;
|
||||
pList->a = sqlite3DbMallocRawNN(db, sizeof(pList->a[0]));
|
||||
if( pList->a==0 ) goto no_mem;
|
||||
}else if( (pList->nExpr & (pList->nExpr-1))==0 ){
|
||||
struct ExprList_item *a;
|
||||
assert( pList->nExpr>0 );
|
||||
a = sqlite3DbRealloc(db, pList->a, pList->nExpr*2*sizeof(pList->a[0]));
|
||||
if( a==0 ){
|
||||
pList->nAlloc = 1;
|
||||
}else if( pList->nExpr==pList->nAlloc ){
|
||||
ExprList *pNew;
|
||||
pNew = sqlite3DbRealloc(db, pList,
|
||||
sizeof(*pList)+(2*pList->nAlloc - 1)*sizeof(pList->a[0]));
|
||||
if( pNew==0 ){
|
||||
goto no_mem;
|
||||
}
|
||||
pList->a = a;
|
||||
}
|
||||
assert( pList->a!=0 );
|
||||
if( 1 ){
|
||||
struct ExprList_item *pItem = &pList->a[pList->nExpr++];
|
||||
memset(pItem, 0, sizeof(*pItem));
|
||||
pItem->pExpr = pExpr;
|
||||
pList = pNew;
|
||||
pList->nAlloc *= 2;
|
||||
}
|
||||
pItem = &pList->a[pList->nExpr++];
|
||||
memset(pItem, 0, sizeof(*pItem));
|
||||
pItem->pExpr = pExpr;
|
||||
return pList;
|
||||
|
||||
no_mem:
|
||||
@@ -1556,20 +1546,19 @@ ExprList *sqlite3ExprListAppendVector(
|
||||
}
|
||||
}
|
||||
|
||||
if( pExpr->op==TK_SELECT ){
|
||||
if( pList && pList->a[iFirst].pExpr ){
|
||||
Expr *pFirst = pList->a[iFirst].pExpr;
|
||||
assert( pFirst->op==TK_SELECT_COLUMN );
|
||||
if( !db->mallocFailed && pExpr->op==TK_SELECT && ALWAYS(pList!=0) ){
|
||||
Expr *pFirst = pList->a[iFirst].pExpr;
|
||||
assert( pFirst!=0 );
|
||||
assert( pFirst->op==TK_SELECT_COLUMN );
|
||||
|
||||
/* Store the SELECT statement in pRight so it will be deleted when
|
||||
** sqlite3ExprListDelete() is called */
|
||||
pFirst->pRight = pExpr;
|
||||
pExpr = 0;
|
||||
/* Store the SELECT statement in pRight so it will be deleted when
|
||||
** sqlite3ExprListDelete() is called */
|
||||
pFirst->pRight = pExpr;
|
||||
pExpr = 0;
|
||||
|
||||
/* Remember the size of the LHS in iTable so that we can check that
|
||||
** the RHS and LHS sizes match during code generation. */
|
||||
pFirst->iTable = pColumns->nId;
|
||||
}
|
||||
/* Remember the size of the LHS in iTable so that we can check that
|
||||
** the RHS and LHS sizes match during code generation. */
|
||||
pFirst->iTable = pColumns->nId;
|
||||
}
|
||||
|
||||
vector_append_error:
|
||||
@@ -1663,16 +1652,16 @@ void sqlite3ExprListCheckLength(
|
||||
** Delete an entire expression list.
|
||||
*/
|
||||
static SQLITE_NOINLINE void exprListDeleteNN(sqlite3 *db, ExprList *pList){
|
||||
int i;
|
||||
struct ExprList_item *pItem;
|
||||
assert( pList->a!=0 || pList->nExpr==0 );
|
||||
for(pItem=pList->a, i=0; i<pList->nExpr; i++, pItem++){
|
||||
int i = pList->nExpr;
|
||||
struct ExprList_item *pItem = pList->a;
|
||||
assert( pList->nExpr>0 );
|
||||
do{
|
||||
sqlite3ExprDelete(db, pItem->pExpr);
|
||||
sqlite3DbFree(db, pItem->zName);
|
||||
sqlite3DbFree(db, pItem->zSpan);
|
||||
}
|
||||
sqlite3DbFree(db, pList->a);
|
||||
sqlite3DbFree(db, pList);
|
||||
pItem++;
|
||||
}while( --i>0 );
|
||||
sqlite3DbFreeNN(db, pList);
|
||||
}
|
||||
void sqlite3ExprListDelete(sqlite3 *db, ExprList *pList){
|
||||
if( pList ) exprListDeleteNN(db, pList);
|
||||
@@ -1822,6 +1811,65 @@ int sqlite3ExprIsTableConstant(Expr *p, int iCur){
|
||||
return exprIsConst(p, 3, iCur);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** sqlite3WalkExpr() callback used by sqlite3ExprIsConstantOrGroupBy().
|
||||
*/
|
||||
static int exprNodeIsConstantOrGroupBy(Walker *pWalker, Expr *pExpr){
|
||||
ExprList *pGroupBy = pWalker->u.pGroupBy;
|
||||
int i;
|
||||
|
||||
/* Check if pExpr is identical to any GROUP BY term. If so, consider
|
||||
** it constant. */
|
||||
for(i=0; i<pGroupBy->nExpr; i++){
|
||||
Expr *p = pGroupBy->a[i].pExpr;
|
||||
if( sqlite3ExprCompare(pExpr, p, -1)<2 ){
|
||||
CollSeq *pColl = sqlite3ExprCollSeq(pWalker->pParse, p);
|
||||
if( pColl==0 || sqlite3_stricmp("BINARY", pColl->zName)==0 ){
|
||||
return WRC_Prune;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if pExpr is a sub-select. If so, consider it variable. */
|
||||
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
|
||||
pWalker->eCode = 0;
|
||||
return WRC_Abort;
|
||||
}
|
||||
|
||||
return exprNodeIsConstant(pWalker, pExpr);
|
||||
}
|
||||
|
||||
/*
|
||||
** Walk the expression tree passed as the first argument. Return non-zero
|
||||
** if the expression consists entirely of constants or copies of terms
|
||||
** in pGroupBy that sort with the BINARY collation sequence.
|
||||
**
|
||||
** This routine is used to determine if a term of the HAVING clause can
|
||||
** be promoted into the WHERE clause. In order for such a promotion to work,
|
||||
** the value of the HAVING clause term must be the same for all members of
|
||||
** a "group". The requirement that the GROUP BY term must be BINARY
|
||||
** assumes that no other collating sequence will have a finer-grained
|
||||
** grouping than binary. In other words (A=B COLLATE binary) implies
|
||||
** A=B in every other collating sequence. The requirement that the
|
||||
** GROUP BY be BINARY is stricter than necessary. It would also work
|
||||
** to promote HAVING clauses that use the same alternative collating
|
||||
** sequence as the GROUP BY term, but that is much harder to check,
|
||||
** alternative collating sequences are uncommon, and this is only an
|
||||
** optimization, so we take the easy way out and simply require the
|
||||
** GROUP BY to use the BINARY collating sequence.
|
||||
*/
|
||||
int sqlite3ExprIsConstantOrGroupBy(Parse *pParse, Expr *p, ExprList *pGroupBy){
|
||||
Walker w;
|
||||
memset(&w, 0, sizeof(w));
|
||||
w.eCode = 1;
|
||||
w.xExprCallback = exprNodeIsConstantOrGroupBy;
|
||||
w.u.pGroupBy = pGroupBy;
|
||||
w.pParse = pParse;
|
||||
sqlite3WalkExpr(&w, p);
|
||||
return w.eCode;
|
||||
}
|
||||
|
||||
/*
|
||||
** Walk an expression tree. Return non-zero if the expression is constant
|
||||
** or a function call with constant arguments. Return and 0 if there
|
||||
@@ -3199,6 +3247,10 @@ void sqlite3ExprCodeGetColumnOfTable(
|
||||
int iCol, /* Index of the column to extract */
|
||||
int regOut /* Extract the value into this register */
|
||||
){
|
||||
if( pTab==0 ){
|
||||
sqlite3VdbeAddOp3(v, OP_Column, iTabCur, iCol, regOut);
|
||||
return;
|
||||
}
|
||||
if( iCol<0 || iCol==pTab->iPKey ){
|
||||
sqlite3VdbeAddOp2(v, OP_Rowid, iTabCur, regOut);
|
||||
}else{
|
||||
@@ -3355,7 +3407,11 @@ static int exprCodeVector(Parse *pParse, Expr *p, int *piFreeable){
|
||||
}else{
|
||||
*piFreeable = 0;
|
||||
if( p->op==TK_SELECT ){
|
||||
#if SQLITE_OMIT_SUBQUERY
|
||||
iResult = 0;
|
||||
#else
|
||||
iResult = sqlite3CodeSubselect(pParse, p, 0, 0);
|
||||
#endif
|
||||
}else{
|
||||
int i;
|
||||
iResult = pParse->nMem+1;
|
||||
@@ -3892,6 +3948,17 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
|
||||
break;
|
||||
}
|
||||
|
||||
case TK_IF_NULL_ROW: {
|
||||
int addrINR;
|
||||
addrINR = sqlite3VdbeAddOp1(v, OP_IfNullRow, pExpr->iTable);
|
||||
sqlite3ExprCachePush(pParse);
|
||||
inReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target);
|
||||
sqlite3ExprCachePop(pParse);
|
||||
sqlite3VdbeJumpHere(v, addrINR);
|
||||
sqlite3VdbeChangeP3(v, addrINR, inReg);
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
** Form A:
|
||||
** CASE x WHEN e1 THEN r1 WHEN e2 THEN r2 ... WHEN eN THEN rN ELSE y END
|
||||
|
||||
+21
-6
@@ -1087,8 +1087,16 @@ u32 sqlite3FkOldmask(
|
||||
** UPDATE statement modifies the rowid fields of the table.
|
||||
**
|
||||
** If any foreign key processing will be required, this function returns
|
||||
** true. If there is no foreign key related processing, this function
|
||||
** returns false.
|
||||
** non-zero. If there is no foreign key related processing, this function
|
||||
** returns zero.
|
||||
**
|
||||
** For an UPDATE, this function returns 2 if:
|
||||
**
|
||||
** * There are any FKs for which pTab is the child and the parent table, or
|
||||
** * the UPDATE modifies one or more parent keys for which the action is
|
||||
** not "NO ACTION" (i.e. is CASCADE, SET DEFAULT or SET NULL).
|
||||
**
|
||||
** Or, assuming some other foreign key processing is required, 1.
|
||||
*/
|
||||
int sqlite3FkRequired(
|
||||
Parse *pParse, /* Parse context */
|
||||
@@ -1096,12 +1104,13 @@ int sqlite3FkRequired(
|
||||
int *aChange, /* Non-NULL for UPDATE operations */
|
||||
int chngRowid /* True for UPDATE that affects rowid */
|
||||
){
|
||||
int eRet = 0;
|
||||
if( pParse->db->flags&SQLITE_ForeignKeys ){
|
||||
if( !aChange ){
|
||||
/* A DELETE operation. Foreign key processing is required if the
|
||||
** table in question is either the child or parent table for any
|
||||
** foreign key constraint. */
|
||||
return (sqlite3FkReferences(pTab) || pTab->pFKey);
|
||||
eRet = (sqlite3FkReferences(pTab) || pTab->pFKey);
|
||||
}else{
|
||||
/* This is an UPDATE. Foreign key processing is only required if the
|
||||
** operation modifies one or more child or parent key columns. */
|
||||
@@ -1109,16 +1118,22 @@ int sqlite3FkRequired(
|
||||
|
||||
/* Check if any child key columns are being modified. */
|
||||
for(p=pTab->pFKey; p; p=p->pNextFrom){
|
||||
if( fkChildIsModified(pTab, p, aChange, chngRowid) ) return 1;
|
||||
if( 0==sqlite3_stricmp(pTab->zName, p->zTo) ) return 2;
|
||||
if( fkChildIsModified(pTab, p, aChange, chngRowid) ){
|
||||
eRet = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if any parent key columns are being modified. */
|
||||
for(p=sqlite3FkReferences(pTab); p; p=p->pNextTo){
|
||||
if( fkParentIsModified(pTab, p, aChange, chngRowid) ) return 1;
|
||||
if( fkParentIsModified(pTab, p, aChange, chngRowid) ){
|
||||
if( p->aAction[1]!=OE_None ) return 2;
|
||||
eRet = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
return eRet;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
+8
-1
@@ -137,9 +137,16 @@ const unsigned char sqlite3CtypeMap[256] = {
|
||||
** EVIDENCE-OF: R-43642-56306 By default, URI handling is globally
|
||||
** disabled. The default value may be changed by compiling with the
|
||||
** SQLITE_USE_URI symbol defined.
|
||||
**
|
||||
** URI filenames are enabled by default if SQLITE_HAS_CODEC is
|
||||
** enabled.
|
||||
*/
|
||||
#ifndef SQLITE_USE_URI
|
||||
# define SQLITE_USE_URI 0
|
||||
# ifdef SQLITE_HAS_CODEC
|
||||
# define SQLITE_USE_URI 1
|
||||
# else
|
||||
# define SQLITE_USE_URI 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* EVIDENCE-OF: R-38720-18127 The default setting is determined by the
|
||||
|
||||
+9
-7
@@ -3095,16 +3095,18 @@ opendb_out:
|
||||
#endif
|
||||
#if defined(SQLITE_HAS_CODEC)
|
||||
if( rc==SQLITE_OK ){
|
||||
const char *zHexKey = sqlite3_uri_parameter(zOpen, "hexkey");
|
||||
if( zHexKey && zHexKey[0] ){
|
||||
const char *zKey;
|
||||
if( (zKey = sqlite3_uri_parameter(zOpen, "hexkey"))!=0 && zKey[0] ){;
|
||||
u8 iByte;
|
||||
int i;
|
||||
char zKey[40];
|
||||
for(i=0, iByte=0; i<sizeof(zKey)*2 && sqlite3Isxdigit(zHexKey[i]); i++){
|
||||
iByte = (iByte<<4) + sqlite3HexToInt(zHexKey[i]);
|
||||
if( (i&1)!=0 ) zKey[i/2] = iByte;
|
||||
char zDecoded[40];
|
||||
for(i=0, iByte=0; i<sizeof(zDecoded)*2 && sqlite3Isxdigit(zKey[i]); i++){
|
||||
iByte = (iByte<<4) + sqlite3HexToInt(zKey[i]);
|
||||
if( (i&1)!=0 ) zDecoded[i/2] = iByte;
|
||||
}
|
||||
sqlite3_key_v2(db, 0, zKey, i/2);
|
||||
sqlite3_key_v2(db, 0, zDecoded, i/2);
|
||||
}else if( (zKey = sqlite3_uri_parameter(zOpen, "key"))!=0 ){
|
||||
sqlite3_key_v2(db, 0, zKey, sqlite3Strlen30(zKey));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
+8
-3
@@ -474,11 +474,12 @@ static SQLITE_NOINLINE void measureAllocationSize(sqlite3 *db, void *p){
|
||||
|
||||
/*
|
||||
** Free memory that might be associated with a particular database
|
||||
** connection.
|
||||
** connection. Calling sqlite3DbFree(D,X) for X==0 is a harmless no-op.
|
||||
** The sqlite3DbFreeNN(D,X) version requires that X be non-NULL.
|
||||
*/
|
||||
void sqlite3DbFree(sqlite3 *db, void *p){
|
||||
void sqlite3DbFreeNN(sqlite3 *db, void *p){
|
||||
assert( db==0 || sqlite3_mutex_held(db->mutex) );
|
||||
if( p==0 ) return;
|
||||
assert( p!=0 );
|
||||
if( db ){
|
||||
if( db->pnBytesFreed ){
|
||||
measureAllocationSize(db, p);
|
||||
@@ -502,6 +503,10 @@ void sqlite3DbFree(sqlite3 *db, void *p){
|
||||
sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
|
||||
sqlite3_free(p);
|
||||
}
|
||||
void sqlite3DbFree(sqlite3 *db, void *p){
|
||||
assert( db==0 || sqlite3_mutex_held(db->mutex) );
|
||||
if( p ) sqlite3DbFreeNN(db, p);
|
||||
}
|
||||
|
||||
/*
|
||||
** Change the size of an existing memory allocation
|
||||
|
||||
+37
-5
@@ -2258,6 +2258,11 @@ static int pager_playback_one_page(
|
||||
char *aData; /* Temporary storage for the page */
|
||||
sqlite3_file *jfd; /* The file descriptor for the journal file */
|
||||
int isSynced; /* True if journal page is synced */
|
||||
#ifdef SQLITE_HAS_CODEC
|
||||
/* The jrnlEnc flag is true if Journal pages should be passed through
|
||||
** the codec. It is false for pure in-memory journals. */
|
||||
const int jrnlEnc = (isMainJrnl || pPager->subjInMemory==0);
|
||||
#endif
|
||||
|
||||
assert( (isMainJrnl&~1)==0 ); /* isMainJrnl is 0 or 1 */
|
||||
assert( (isSavepnt&~1)==0 ); /* isSavepnt is 0 or 1 */
|
||||
@@ -2381,14 +2386,34 @@ static int pager_playback_one_page(
|
||||
i64 ofst = (pgno-1)*(i64)pPager->pageSize;
|
||||
testcase( !isSavepnt && pPg!=0 && (pPg->flags&PGHDR_NEED_SYNC)!=0 );
|
||||
assert( !pagerUseWal(pPager) );
|
||||
|
||||
/* Write the data read from the journal back into the database file.
|
||||
** This is usually safe even for an encrypted database - as the data
|
||||
** was encrypted before it was written to the journal file. The exception
|
||||
** is if the data was just read from an in-memory sub-journal. In that
|
||||
** case it must be encrypted here before it is copied into the database
|
||||
** file. */
|
||||
#ifdef SQLITE_HAS_CODEC
|
||||
if( !jrnlEnc ){
|
||||
CODEC2(pPager, aData, pgno, 7, rc=SQLITE_NOMEM_BKPT, aData);
|
||||
rc = sqlite3OsWrite(pPager->fd, (u8 *)aData, pPager->pageSize, ofst);
|
||||
CODEC1(pPager, aData, pgno, 3, rc=SQLITE_NOMEM_BKPT);
|
||||
}else
|
||||
#endif
|
||||
rc = sqlite3OsWrite(pPager->fd, (u8 *)aData, pPager->pageSize, ofst);
|
||||
|
||||
if( pgno>pPager->dbFileSize ){
|
||||
pPager->dbFileSize = pgno;
|
||||
}
|
||||
if( pPager->pBackup ){
|
||||
CODEC1(pPager, aData, pgno, 3, rc=SQLITE_NOMEM_BKPT);
|
||||
#ifdef SQLITE_HAS_CODEC
|
||||
if( jrnlEnc ){
|
||||
CODEC1(pPager, aData, pgno, 3, rc=SQLITE_NOMEM_BKPT);
|
||||
sqlite3BackupUpdate(pPager->pBackup, pgno, (u8*)aData);
|
||||
CODEC2(pPager, aData, pgno, 7, rc=SQLITE_NOMEM_BKPT,aData);
|
||||
}else
|
||||
#endif
|
||||
sqlite3BackupUpdate(pPager->pBackup, pgno, (u8*)aData);
|
||||
CODEC2(pPager, aData, pgno, 7, rc=SQLITE_NOMEM_BKPT, aData);
|
||||
}
|
||||
}else if( !isMainJrnl && pPg==0 ){
|
||||
/* If this is a rollback of a savepoint and data was not written to
|
||||
@@ -2440,7 +2465,9 @@ static int pager_playback_one_page(
|
||||
}
|
||||
|
||||
/* Decode the page just read from disk */
|
||||
CODEC1(pPager, pData, pPg->pgno, 3, rc=SQLITE_NOMEM_BKPT);
|
||||
#if SQLITE_HAS_CODEC
|
||||
if( jrnlEnc ){ CODEC1(pPager, pData, pPg->pgno, 3, rc=SQLITE_NOMEM_BKPT); }
|
||||
#endif
|
||||
sqlite3PcacheRelease(pPg);
|
||||
}
|
||||
return rc;
|
||||
@@ -4452,8 +4479,13 @@ static int subjournalPage(PgHdr *pPg){
|
||||
void *pData = pPg->pData;
|
||||
i64 offset = (i64)pPager->nSubRec*(4+pPager->pageSize);
|
||||
char *pData2;
|
||||
|
||||
CODEC2(pPager, pData, pPg->pgno, 7, return SQLITE_NOMEM_BKPT, pData2);
|
||||
|
||||
#if SQLITE_HAS_CODEC
|
||||
if( !pPager->subjInMemory ){
|
||||
CODEC2(pPager, pData, pPg->pgno, 7, return SQLITE_NOMEM_BKPT, pData2);
|
||||
}else
|
||||
#endif
|
||||
pData2 = pData;
|
||||
PAGERTRACE(("STMT-JOURNAL %d page %d\n", PAGERID(pPager), pPg->pgno));
|
||||
rc = write32bits(pPager->sjfd, offset, pPg->pgno);
|
||||
if( rc==SQLITE_OK ){
|
||||
|
||||
+17
-17
@@ -193,6 +193,23 @@ columnlist ::= columnlist COMMA columnname carglist.
|
||||
columnlist ::= columnname carglist.
|
||||
columnname(A) ::= nm(A) typetoken(Y). {sqlite3AddColumn(pParse,&A,&Y);}
|
||||
|
||||
// The following directive causes tokens ABORT, AFTER, ASC, etc. to
|
||||
// fallback to ID if they will not parse as their original value.
|
||||
// This obviates the need for the "id" nonterminal.
|
||||
//
|
||||
%fallback ID
|
||||
ABORT ACTION AFTER ANALYZE ASC ATTACH BEFORE BEGIN BY CASCADE CAST COLUMNKW
|
||||
CONFLICT DATABASE DEFERRED DESC DETACH EACH END EXCLUSIVE EXPLAIN FAIL FOR
|
||||
IGNORE IMMEDIATE INITIALLY INSTEAD LIKE_KW MATCH NO PLAN
|
||||
QUERY KEY OF OFFSET PRAGMA RAISE RECURSIVE RELEASE REPLACE RESTRICT ROW
|
||||
ROLLBACK SAVEPOINT TEMP TRIGGER VACUUM VIEW VIRTUAL WITH WITHOUT
|
||||
%ifdef SQLITE_OMIT_COMPOUND_SELECT
|
||||
EXCEPT INTERSECT UNION
|
||||
%endif SQLITE_OMIT_COMPOUND_SELECT
|
||||
REINDEX RENAME CTIME_KW IF
|
||||
.
|
||||
%wildcard ANY.
|
||||
|
||||
// Define operator precedence early so that this is the first occurrence
|
||||
// of the operator tokens in the grammer. Keeping the operators together
|
||||
// causes them to be assigned integer values that are close together,
|
||||
@@ -222,23 +239,6 @@ columnname(A) ::= nm(A) typetoken(Y). {sqlite3AddColumn(pParse,&A,&Y);}
|
||||
//
|
||||
%token_class id ID|INDEXED.
|
||||
|
||||
// The following directive causes tokens ABORT, AFTER, ASC, etc. to
|
||||
// fallback to ID if they will not parse as their original value.
|
||||
// This obviates the need for the "id" nonterminal.
|
||||
//
|
||||
%fallback ID
|
||||
ABORT ACTION AFTER ANALYZE ASC ATTACH BEFORE BEGIN BY CASCADE CAST COLUMNKW
|
||||
CONFLICT DATABASE DEFERRED DESC DETACH EACH END EXCLUSIVE EXPLAIN FAIL FOR
|
||||
IGNORE IMMEDIATE INITIALLY INSTEAD LIKE_KW MATCH NO PLAN
|
||||
QUERY KEY OF OFFSET PRAGMA RAISE RECURSIVE RELEASE REPLACE RESTRICT ROW
|
||||
ROLLBACK SAVEPOINT TEMP TRIGGER VACUUM VIEW VIRTUAL WITH WITHOUT
|
||||
%ifdef SQLITE_OMIT_COMPOUND_SELECT
|
||||
EXCEPT INTERSECT UNION
|
||||
%endif SQLITE_OMIT_COMPOUND_SELECT
|
||||
REINDEX RENAME CTIME_KW IF
|
||||
.
|
||||
%wildcard ANY.
|
||||
|
||||
|
||||
// And "ids" is an identifer-or-string.
|
||||
//
|
||||
|
||||
+3
-4
@@ -285,8 +285,7 @@ static int pcache1InitBulk(PCache1 *pCache){
|
||||
sqlite3EndBenignMalloc();
|
||||
if( zBulk ){
|
||||
int nBulk = sqlite3MallocSize(zBulk)/pCache->szAlloc;
|
||||
int i;
|
||||
for(i=0; i<nBulk; i++){
|
||||
do{
|
||||
PgHdr1 *pX = (PgHdr1*)&zBulk[pCache->szPage];
|
||||
pX->page.pBuf = zBulk;
|
||||
pX->page.pExtra = &pX[1];
|
||||
@@ -295,7 +294,7 @@ static int pcache1InitBulk(PCache1 *pCache){
|
||||
pX->pNext = pCache->pFree;
|
||||
pCache->pFree = pX;
|
||||
zBulk += pCache->szAlloc;
|
||||
}
|
||||
}while( --nBulk );
|
||||
}
|
||||
return pCache->pFree!=0;
|
||||
}
|
||||
@@ -1211,7 +1210,7 @@ int sqlite3PcacheReleaseMemory(int nReq){
|
||||
int nFree = 0;
|
||||
assert( sqlite3_mutex_notheld(pcache1.grp.mutex) );
|
||||
assert( sqlite3_mutex_notheld(pcache1.mutex) );
|
||||
if( sqlite3GlobalConfig.nPage==0 ){
|
||||
if( sqlite3GlobalConfig.pPage==0 ){
|
||||
PgHdr1 *p;
|
||||
pcache1EnterMutex(&pcache1.grp);
|
||||
while( (nReq<0 || nFree<nReq)
|
||||
|
||||
+51
-44
@@ -1329,33 +1329,37 @@ void sqlite3Pragma(
|
||||
assert( x==0 );
|
||||
}
|
||||
addrOk = sqlite3VdbeMakeLabel(v);
|
||||
if( pParent && pIdx==0 ){
|
||||
int iKey = pFK->aCol[0].iFrom;
|
||||
assert( iKey>=0 && iKey<pTab->nCol );
|
||||
if( iKey!=pTab->iPKey ){
|
||||
sqlite3VdbeAddOp3(v, OP_Column, 0, iKey, regRow);
|
||||
sqlite3ColumnDefault(v, pTab, iKey, regRow);
|
||||
sqlite3VdbeAddOp2(v, OP_IsNull, regRow, addrOk); VdbeCoverage(v);
|
||||
}else{
|
||||
sqlite3VdbeAddOp2(v, OP_Rowid, 0, regRow);
|
||||
}
|
||||
sqlite3VdbeAddOp3(v, OP_SeekRowid, i, 0, regRow); VdbeCoverage(v);
|
||||
sqlite3VdbeGoto(v, addrOk);
|
||||
sqlite3VdbeJumpHere(v, sqlite3VdbeCurrentAddr(v)-2);
|
||||
}else{
|
||||
for(j=0; j<pFK->nCol; j++){
|
||||
sqlite3ExprCodeGetColumnOfTable(v, pTab, 0,
|
||||
aiCols ? aiCols[j] : pFK->aCol[j].iFrom, regRow+j);
|
||||
sqlite3VdbeAddOp2(v, OP_IsNull, regRow+j, addrOk); VdbeCoverage(v);
|
||||
}
|
||||
if( pParent ){
|
||||
sqlite3VdbeAddOp4(v, OP_MakeRecord, regRow, pFK->nCol, regKey,
|
||||
sqlite3IndexAffinityStr(db,pIdx), pFK->nCol);
|
||||
sqlite3VdbeAddOp4Int(v, OP_Found, i, addrOk, regKey, 0);
|
||||
VdbeCoverage(v);
|
||||
}
|
||||
|
||||
/* Generate code to read the child key values into registers
|
||||
** regRow..regRow+n. If any of the child key values are NULL, this
|
||||
** row cannot cause an FK violation. Jump directly to addrOk in
|
||||
** this case. */
|
||||
for(j=0; j<pFK->nCol; j++){
|
||||
int iCol = aiCols ? aiCols[j] : pFK->aCol[j].iFrom;
|
||||
sqlite3ExprCodeGetColumnOfTable(v, pTab, 0, iCol, regRow+j);
|
||||
sqlite3VdbeAddOp2(v, OP_IsNull, regRow+j, addrOk); VdbeCoverage(v);
|
||||
}
|
||||
|
||||
/* Generate code to query the parent index for a matching parent
|
||||
** key. If a match is found, jump to addrOk. */
|
||||
if( pIdx ){
|
||||
sqlite3VdbeAddOp4(v, OP_MakeRecord, regRow, pFK->nCol, regKey,
|
||||
sqlite3IndexAffinityStr(db,pIdx), pFK->nCol);
|
||||
sqlite3VdbeAddOp4Int(v, OP_Found, i, addrOk, regKey, 0);
|
||||
VdbeCoverage(v);
|
||||
}else if( pParent ){
|
||||
int jmp = sqlite3VdbeCurrentAddr(v)+2;
|
||||
sqlite3VdbeAddOp3(v, OP_SeekRowid, i, jmp, regRow); VdbeCoverage(v);
|
||||
sqlite3VdbeGoto(v, addrOk);
|
||||
assert( pFK->nCol==1 );
|
||||
}
|
||||
|
||||
/* Generate code to report an FK violation to the caller. */
|
||||
if( HasRowid(pTab) ){
|
||||
sqlite3VdbeAddOp2(v, OP_Rowid, 0, regResult+1);
|
||||
}else{
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, regResult+1);
|
||||
}
|
||||
sqlite3VdbeAddOp2(v, OP_Rowid, 0, regResult+1);
|
||||
sqlite3VdbeMultiLoad(v, regResult+2, "si", pFK->zTo, i-1);
|
||||
sqlite3VdbeAddOp2(v, OP_ResultRow, regResult, 4);
|
||||
sqlite3VdbeResolveLabel(v, addrOk);
|
||||
@@ -1541,25 +1545,28 @@ void sqlite3Pragma(
|
||||
}
|
||||
/* Verify CHECK constraints */
|
||||
if( pTab->pCheck && (db->flags & SQLITE_IgnoreChecks)==0 ){
|
||||
int addrCkFault = sqlite3VdbeMakeLabel(v);
|
||||
int addrCkOk = sqlite3VdbeMakeLabel(v);
|
||||
ExprList *pCheck = pTab->pCheck;
|
||||
char *zErr;
|
||||
int k;
|
||||
pParse->iSelfTab = iDataCur;
|
||||
sqlite3ExprCachePush(pParse);
|
||||
for(k=pCheck->nExpr-1; k>0; k--){
|
||||
sqlite3ExprIfFalse(pParse, pCheck->a[k].pExpr, addrCkFault, 0);
|
||||
ExprList *pCheck = sqlite3ExprListDup(db, pTab->pCheck, 0);
|
||||
if( db->mallocFailed==0 ){
|
||||
int addrCkFault = sqlite3VdbeMakeLabel(v);
|
||||
int addrCkOk = sqlite3VdbeMakeLabel(v);
|
||||
char *zErr;
|
||||
int k;
|
||||
pParse->iSelfTab = iDataCur;
|
||||
sqlite3ExprCachePush(pParse);
|
||||
for(k=pCheck->nExpr-1; k>0; k--){
|
||||
sqlite3ExprIfFalse(pParse, pCheck->a[k].pExpr, addrCkFault, 0);
|
||||
}
|
||||
sqlite3ExprIfTrue(pParse, pCheck->a[0].pExpr, addrCkOk,
|
||||
SQLITE_JUMPIFNULL);
|
||||
sqlite3VdbeResolveLabel(v, addrCkFault);
|
||||
zErr = sqlite3MPrintf(db, "CHECK constraint failed in %s",
|
||||
pTab->zName);
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC);
|
||||
integrityCheckResultRow(v, 3);
|
||||
sqlite3VdbeResolveLabel(v, addrCkOk);
|
||||
sqlite3ExprCachePop(pParse);
|
||||
}
|
||||
sqlite3ExprIfTrue(pParse, pCheck->a[0].pExpr, addrCkOk,
|
||||
SQLITE_JUMPIFNULL);
|
||||
sqlite3VdbeResolveLabel(v, addrCkFault);
|
||||
zErr = sqlite3MPrintf(db, "CHECK constraint failed in %s",
|
||||
pTab->zName);
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC);
|
||||
integrityCheckResultRow(v, 3);
|
||||
sqlite3VdbeResolveLabel(v, addrCkOk);
|
||||
sqlite3ExprCachePop(pParse);
|
||||
sqlite3ExprListDelete(db, pCheck);
|
||||
}
|
||||
/* Validate index entries for the current row */
|
||||
for(j=0, pIdx=pTab->pIndex; pIdx && !isQuick; pIdx=pIdx->pNext, j++){
|
||||
|
||||
+1
-1
@@ -417,7 +417,7 @@ static const PragmaName aPragmaName[] = {
|
||||
#endif
|
||||
{/* zName: */ "optimize",
|
||||
/* ePragTyp: */ PragTyp_OPTIMIZE,
|
||||
/* ePragFlg: */ PragFlg_Result1,
|
||||
/* ePragFlg: */ PragFlg_Result1|PragFlg_NeedSchema,
|
||||
/* ColNames: */ 0, 0,
|
||||
/* iArg: */ 0 },
|
||||
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
|
||||
|
||||
+260
-89
@@ -76,7 +76,7 @@ static void clearSelect(sqlite3 *db, Select *p, int bFree){
|
||||
sqlite3ExprDelete(db, p->pLimit);
|
||||
sqlite3ExprDelete(db, p->pOffset);
|
||||
if( p->pWith ) sqlite3WithDelete(db, p->pWith);
|
||||
if( bFree ) sqlite3DbFree(db, p);
|
||||
if( bFree ) sqlite3DbFreeNN(db, p);
|
||||
p = pPrior;
|
||||
bFree = 1;
|
||||
}
|
||||
@@ -112,14 +112,13 @@ Select *sqlite3SelectNew(
|
||||
){
|
||||
Select *pNew;
|
||||
Select standin;
|
||||
sqlite3 *db = pParse->db;
|
||||
pNew = sqlite3DbMallocRawNN(db, sizeof(*pNew) );
|
||||
pNew = sqlite3DbMallocRawNN(pParse->db, sizeof(*pNew) );
|
||||
if( pNew==0 ){
|
||||
assert( db->mallocFailed );
|
||||
assert( pParse->db->mallocFailed );
|
||||
pNew = &standin;
|
||||
}
|
||||
if( pEList==0 ){
|
||||
pEList = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(db,TK_ASTERISK,0));
|
||||
pEList = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(pParse->db,TK_ASTERISK,0));
|
||||
}
|
||||
pNew->pEList = pEList;
|
||||
pNew->op = TK_SELECT;
|
||||
@@ -132,7 +131,7 @@ Select *sqlite3SelectNew(
|
||||
pNew->addrOpenEphm[0] = -1;
|
||||
pNew->addrOpenEphm[1] = -1;
|
||||
pNew->nSelectRow = 0;
|
||||
if( pSrc==0 ) pSrc = sqlite3DbMallocZero(db, sizeof(*pSrc));
|
||||
if( pSrc==0 ) pSrc = sqlite3DbMallocZero(pParse->db, sizeof(*pSrc));
|
||||
pNew->pSrc = pSrc;
|
||||
pNew->pWhere = pWhere;
|
||||
pNew->pGroupBy = pGroupBy;
|
||||
@@ -143,9 +142,9 @@ Select *sqlite3SelectNew(
|
||||
pNew->pLimit = pLimit;
|
||||
pNew->pOffset = pOffset;
|
||||
pNew->pWith = 0;
|
||||
assert( pOffset==0 || pLimit!=0 || pParse->nErr>0 || db->mallocFailed!=0 );
|
||||
if( db->mallocFailed ) {
|
||||
clearSelect(db, pNew, pNew!=&standin);
|
||||
assert( pOffset==0 || pLimit!=0 || pParse->nErr>0 || pParse->db->mallocFailed!=0 );
|
||||
if( pParse->db->mallocFailed ) {
|
||||
clearSelect(pParse->db, pNew, pNew!=&standin);
|
||||
pNew = 0;
|
||||
}else{
|
||||
assert( pNew->pSrc!=0 || pParse->nErr>0 );
|
||||
@@ -1055,7 +1054,7 @@ void sqlite3KeyInfoUnref(KeyInfo *p){
|
||||
if( p ){
|
||||
assert( p->nRef>0 );
|
||||
p->nRef--;
|
||||
if( p->nRef==0 ) sqlite3DbFree(p->db, p);
|
||||
if( p->nRef==0 ) sqlite3DbFreeNN(p->db, p);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1530,6 +1529,7 @@ static void generateColumnTypes(
|
||||
NameContext sNC;
|
||||
sNC.pSrcList = pTabList;
|
||||
sNC.pParse = pParse;
|
||||
sNC.pNext = 0;
|
||||
for(i=0; i<pEList->nExpr; i++){
|
||||
Expr *p = pEList->a[i].pExpr;
|
||||
const char *zType;
|
||||
@@ -1554,6 +1554,19 @@ static void generateColumnTypes(
|
||||
#endif /* !defined(SQLITE_OMIT_DECLTYPE) */
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the Table objecct in the SrcList that has cursor iCursor.
|
||||
** Or return NULL if no such Table object exists in the SrcList.
|
||||
*/
|
||||
static Table *tableWithCursor(SrcList *pList, int iCursor){
|
||||
int j;
|
||||
for(j=0; j<pList->nSrc; j++){
|
||||
if( pList->a[j].iCursor==iCursor ) return pList->a[j].pTab;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Generate code that will tell the VDBE the names of columns
|
||||
** in the result set. This information is used to provide the
|
||||
@@ -1565,7 +1578,8 @@ static void generateColumnNames(
|
||||
ExprList *pEList /* Expressions defining the result set */
|
||||
){
|
||||
Vdbe *v = pParse->pVdbe;
|
||||
int i, j;
|
||||
int i;
|
||||
Table *pTab;
|
||||
sqlite3 *db = pParse->db;
|
||||
int fullNames, shortNames;
|
||||
|
||||
@@ -1590,15 +1604,11 @@ static void generateColumnNames(
|
||||
if( pEList->a[i].zName ){
|
||||
char *zName = pEList->a[i].zName;
|
||||
sqlite3VdbeSetColName(v, i, COLNAME_NAME, zName, SQLITE_TRANSIENT);
|
||||
}else if( p->op==TK_COLUMN || p->op==TK_AGG_COLUMN ){
|
||||
Table *pTab;
|
||||
}else if( (p->op==TK_COLUMN || p->op==TK_AGG_COLUMN)
|
||||
&& (pTab = tableWithCursor(pTabList, p->iTable))!=0
|
||||
){
|
||||
char *zCol;
|
||||
int iCol = p->iColumn;
|
||||
for(j=0; ALWAYS(j<pTabList->nSrc); j++){
|
||||
if( pTabList->a[j].iCursor==p->iTable ) break;
|
||||
}
|
||||
assert( j<pTabList->nSrc );
|
||||
pTab = pTabList->a[j].pTab;
|
||||
if( iCol<0 ) iCol = pTab->iPKey;
|
||||
assert( iCol==-1 || (iCol>=0 && iCol<pTab->nCol) );
|
||||
if( iCol<0 ){
|
||||
@@ -1680,7 +1690,7 @@ int sqlite3ColumnsFromExprList(
|
||||
pColExpr = pColExpr->pRight;
|
||||
assert( pColExpr!=0 );
|
||||
}
|
||||
if( pColExpr->op==TK_COLUMN && ALWAYS(pColExpr->pTab!=0) ){
|
||||
if( pColExpr->op==TK_COLUMN && pColExpr->pTab!=0 ){
|
||||
/* For columns use the column name name */
|
||||
int iCol = pColExpr->iColumn;
|
||||
pTab = pColExpr->pTab;
|
||||
@@ -2900,7 +2910,7 @@ static int multiSelectOrderBy(
|
||||
if( pNew==0 ) return SQLITE_NOMEM_BKPT;
|
||||
pNew->flags |= EP_IntValue;
|
||||
pNew->u.iValue = i;
|
||||
pOrderBy = sqlite3ExprListAppend(pParse, pOrderBy, pNew);
|
||||
p->pOrderBy = pOrderBy = sqlite3ExprListAppend(pParse, pOrderBy, pNew);
|
||||
if( pOrderBy ) pOrderBy->a[nOrderBy++].u.x.iOrderByCol = (u16)i;
|
||||
}
|
||||
}
|
||||
@@ -3134,9 +3144,24 @@ static int multiSelectOrderBy(
|
||||
#endif
|
||||
|
||||
#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
|
||||
|
||||
/* An instance of the SubstContext object describes an substitution edit
|
||||
** to be performed on a parse tree.
|
||||
**
|
||||
** All references to columns in table iTable are to be replaced by corresponding
|
||||
** expressions in pEList.
|
||||
*/
|
||||
typedef struct SubstContext {
|
||||
Parse *pParse; /* The parsing context */
|
||||
int iTable; /* Replace references to this table */
|
||||
int iNewTable; /* New table number */
|
||||
int isLeftJoin; /* Add TK_IF_NULL_ROW opcodes on each replacement */
|
||||
ExprList *pEList; /* Replacement expressions */
|
||||
} SubstContext;
|
||||
|
||||
/* Forward Declarations */
|
||||
static void substExprList(Parse*, ExprList*, int, ExprList*);
|
||||
static void substSelect(Parse*, Select *, int, ExprList*, int);
|
||||
static void substExprList(SubstContext*, ExprList*);
|
||||
static void substSelect(SubstContext*, Select*, int);
|
||||
|
||||
/*
|
||||
** Scan through the expression pExpr. Replace every reference to
|
||||
@@ -3147,29 +3172,38 @@ static void substSelect(Parse*, Select *, int, ExprList*, int);
|
||||
** This routine is part of the flattening procedure. A subquery
|
||||
** whose result set is defined by pEList appears as entry in the
|
||||
** FROM clause of a SELECT such that the VDBE cursor assigned to that
|
||||
** FORM clause entry is iTable. This routine make the necessary
|
||||
** FORM clause entry is iTable. This routine makes the necessary
|
||||
** changes to pExpr so that it refers directly to the source table
|
||||
** of the subquery rather the result set of the subquery.
|
||||
*/
|
||||
static Expr *substExpr(
|
||||
Parse *pParse, /* Report errors here */
|
||||
Expr *pExpr, /* Expr in which substitution occurs */
|
||||
int iTable, /* Table to be substituted */
|
||||
ExprList *pEList /* Substitute expressions */
|
||||
SubstContext *pSubst, /* Description of the substitution */
|
||||
Expr *pExpr /* Expr in which substitution occurs */
|
||||
){
|
||||
sqlite3 *db = pParse->db;
|
||||
if( pExpr==0 ) return 0;
|
||||
if( pExpr->op==TK_COLUMN && pExpr->iTable==iTable ){
|
||||
if( ExprHasProperty(pExpr, EP_FromJoin) && pExpr->iRightJoinTable==pSubst->iTable ){
|
||||
pExpr->iRightJoinTable = pSubst->iNewTable;
|
||||
}
|
||||
if( pExpr->op==TK_COLUMN && pExpr->iTable==pSubst->iTable ){
|
||||
if( pExpr->iColumn<0 ){
|
||||
pExpr->op = TK_NULL;
|
||||
}else{
|
||||
Expr *pNew;
|
||||
Expr *pCopy = pEList->a[pExpr->iColumn].pExpr;
|
||||
assert( pEList!=0 && pExpr->iColumn<pEList->nExpr );
|
||||
Expr *pCopy = pSubst->pEList->a[pExpr->iColumn].pExpr;
|
||||
Expr ifNullRow;
|
||||
assert( pSubst->pEList!=0 && pExpr->iColumn<pSubst->pEList->nExpr );
|
||||
assert( pExpr->pLeft==0 && pExpr->pRight==0 );
|
||||
if( sqlite3ExprIsVector(pCopy) ){
|
||||
sqlite3VectorErrorMsg(pParse, pCopy);
|
||||
sqlite3VectorErrorMsg(pSubst->pParse, pCopy);
|
||||
}else{
|
||||
sqlite3 *db = pSubst->pParse->db;
|
||||
if( pSubst->isLeftJoin && pCopy->op!=TK_COLUMN ){
|
||||
memset(&ifNullRow, 0, sizeof(ifNullRow));
|
||||
ifNullRow.op = TK_IF_NULL_ROW;
|
||||
ifNullRow.pLeft = pCopy;
|
||||
ifNullRow.iTable = pSubst->iNewTable;
|
||||
pCopy = &ifNullRow;
|
||||
}
|
||||
pNew = sqlite3ExprDup(db, pCopy, 0);
|
||||
if( pNew && (pExpr->flags & EP_FromJoin) ){
|
||||
pNew->iRightJoinTable = pExpr->iRightJoinTable;
|
||||
@@ -3180,51 +3214,47 @@ static Expr *substExpr(
|
||||
}
|
||||
}
|
||||
}else{
|
||||
pExpr->pLeft = substExpr(pParse, pExpr->pLeft, iTable, pEList);
|
||||
pExpr->pRight = substExpr(pParse, pExpr->pRight, iTable, pEList);
|
||||
pExpr->pLeft = substExpr(pSubst, pExpr->pLeft);
|
||||
pExpr->pRight = substExpr(pSubst, pExpr->pRight);
|
||||
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
|
||||
substSelect(pParse, pExpr->x.pSelect, iTable, pEList, 1);
|
||||
substSelect(pSubst, pExpr->x.pSelect, 1);
|
||||
}else{
|
||||
substExprList(pParse, pExpr->x.pList, iTable, pEList);
|
||||
substExprList(pSubst, pExpr->x.pList);
|
||||
}
|
||||
}
|
||||
return pExpr;
|
||||
}
|
||||
static void substExprList(
|
||||
Parse *pParse, /* Report errors here */
|
||||
ExprList *pList, /* List to scan and in which to make substitutes */
|
||||
int iTable, /* Table to be substituted */
|
||||
ExprList *pEList /* Substitute values */
|
||||
SubstContext *pSubst, /* Description of the substitution */
|
||||
ExprList *pList /* List to scan and in which to make substitutes */
|
||||
){
|
||||
int i;
|
||||
if( pList==0 ) return;
|
||||
for(i=0; i<pList->nExpr; i++){
|
||||
pList->a[i].pExpr = substExpr(pParse, pList->a[i].pExpr, iTable, pEList);
|
||||
pList->a[i].pExpr = substExpr(pSubst, pList->a[i].pExpr);
|
||||
}
|
||||
}
|
||||
static void substSelect(
|
||||
Parse *pParse, /* Report errors here */
|
||||
Select *p, /* SELECT statement in which to make substitutions */
|
||||
int iTable, /* Table to be replaced */
|
||||
ExprList *pEList, /* Substitute values */
|
||||
int doPrior /* Do substitutes on p->pPrior too */
|
||||
SubstContext *pSubst, /* Description of the substitution */
|
||||
Select *p, /* SELECT statement in which to make substitutions */
|
||||
int doPrior /* Do substitutes on p->pPrior too */
|
||||
){
|
||||
SrcList *pSrc;
|
||||
struct SrcList_item *pItem;
|
||||
int i;
|
||||
if( !p ) return;
|
||||
do{
|
||||
substExprList(pParse, p->pEList, iTable, pEList);
|
||||
substExprList(pParse, p->pGroupBy, iTable, pEList);
|
||||
substExprList(pParse, p->pOrderBy, iTable, pEList);
|
||||
p->pHaving = substExpr(pParse, p->pHaving, iTable, pEList);
|
||||
p->pWhere = substExpr(pParse, p->pWhere, iTable, pEList);
|
||||
substExprList(pSubst, p->pEList);
|
||||
substExprList(pSubst, p->pGroupBy);
|
||||
substExprList(pSubst, p->pOrderBy);
|
||||
p->pHaving = substExpr(pSubst, p->pHaving);
|
||||
p->pWhere = substExpr(pSubst, p->pWhere);
|
||||
pSrc = p->pSrc;
|
||||
assert( pSrc!=0 );
|
||||
for(i=pSrc->nSrc, pItem=pSrc->a; i>0; i--, pItem++){
|
||||
substSelect(pParse, pItem->pSelect, iTable, pEList, 1);
|
||||
substSelect(pSubst, pItem->pSelect, 1);
|
||||
if( pItem->fg.isTabFunc ){
|
||||
substExprList(pParse, pItem->u1.pFuncArg, iTable, pEList);
|
||||
substExprList(pSubst, pItem->u1.pFuncArg);
|
||||
}
|
||||
}
|
||||
}while( doPrior && (p = p->pPrior)!=0 );
|
||||
@@ -3267,8 +3297,8 @@ static void substSelect(
|
||||
** FROM-clause subquery that is a candidate for flattening. (2b is
|
||||
** due to ticket [2f7170d73bf9abf80] from 2015-02-09.)
|
||||
**
|
||||
** (3) The subquery is not the right operand of a left outer join
|
||||
** (Originally ticket #306. Strengthened by ticket #3300)
|
||||
** (3) The subquery is not the right operand of a LEFT JOIN
|
||||
** or the subquery is not itself a join.
|
||||
**
|
||||
** (4) The subquery is not DISTINCT.
|
||||
**
|
||||
@@ -3280,7 +3310,7 @@ static void substSelect(
|
||||
** DISTINCT.
|
||||
**
|
||||
** (7) The subquery has a FROM clause. TODO: For subqueries without
|
||||
** A FROM clause, consider adding a FROM close with the special
|
||||
** A FROM clause, consider adding a FROM clause with the special
|
||||
** table sqlite_once that consists of a single row containing a
|
||||
** single NULL.
|
||||
**
|
||||
@@ -3386,6 +3416,8 @@ static int flattenSubquery(
|
||||
SrcList *pSubSrc; /* The FROM clause of the subquery */
|
||||
ExprList *pList; /* The result set of the outer query */
|
||||
int iParent; /* VDBE cursor number of the pSub result set temp table */
|
||||
int iNewParent = -1;/* Replacement table for iParent */
|
||||
int isLeftJoin = 0; /* True if pSub is the right side of a LEFT JOIN */
|
||||
int i; /* Loop counter */
|
||||
Expr *pWhere; /* The WHERE clause */
|
||||
struct SrcList_item *pSubitem; /* The subquery */
|
||||
@@ -3412,7 +3444,7 @@ static int flattenSubquery(
|
||||
return 0; /* Restriction (2b) */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pSubSrc = pSub->pSrc;
|
||||
assert( pSubSrc );
|
||||
/* Prior to version 3.1.2, when LIMIT and OFFSET had to be simple constants,
|
||||
@@ -3450,10 +3482,9 @@ static int flattenSubquery(
|
||||
return 0; /* Restriction (23) */
|
||||
}
|
||||
|
||||
/* OBSOLETE COMMENT 1:
|
||||
** Restriction 3: If the subquery is a join, make sure the subquery is
|
||||
** not used as the right operand of an outer join. Examples of why this
|
||||
** is not allowed:
|
||||
/*
|
||||
** If the subquery is the right operand of a LEFT JOIN, then the
|
||||
** subquery may not be a join itself. Example of why this is not allowed:
|
||||
**
|
||||
** t1 LEFT OUTER JOIN (t2 JOIN t3)
|
||||
**
|
||||
@@ -3463,27 +3494,13 @@ static int flattenSubquery(
|
||||
**
|
||||
** which is not at all the same thing.
|
||||
**
|
||||
** OBSOLETE COMMENT 2:
|
||||
** Restriction 12: If the subquery is the right operand of a left outer
|
||||
** join, make sure the subquery has no WHERE clause.
|
||||
** An examples of why this is not allowed:
|
||||
**
|
||||
** t1 LEFT OUTER JOIN (SELECT * FROM t2 WHERE t2.x>0)
|
||||
**
|
||||
** If we flatten the above, we would get
|
||||
**
|
||||
** (t1 LEFT OUTER JOIN t2) WHERE t2.x>0
|
||||
**
|
||||
** But the t2.x>0 test will always fail on a NULL row of t2, which
|
||||
** effectively converts the OUTER JOIN into an INNER JOIN.
|
||||
**
|
||||
** THIS OVERRIDES OBSOLETE COMMENTS 1 AND 2 ABOVE:
|
||||
** Ticket #3300 shows that flattening the right term of a LEFT JOIN
|
||||
** is fraught with danger. Best to avoid the whole thing. If the
|
||||
** subquery is the right term of a LEFT JOIN, then do not flatten.
|
||||
** See also tickets #306, #350, and #3300.
|
||||
*/
|
||||
if( (pSubitem->fg.jointype & JT_OUTER)!=0 ){
|
||||
return 0;
|
||||
isLeftJoin = 1;
|
||||
if( pSubSrc->nSrc>1 ){
|
||||
return 0; /* Restriction (3) */
|
||||
}
|
||||
}
|
||||
|
||||
/* Restriction 17: If the sub-query is a compound SELECT, then it must
|
||||
@@ -3692,6 +3709,7 @@ static int flattenSubquery(
|
||||
sqlite3IdListDelete(db, pSrc->a[i+iFrom].pUsing);
|
||||
assert( pSrc->a[i+iFrom].fg.isTabFunc==0 );
|
||||
pSrc->a[i+iFrom] = pSubSrc->a[i];
|
||||
iNewParent = pSubSrc->a[i].iCursor;
|
||||
memset(&pSubSrc->a[i], 0, sizeof(pSubSrc->a[i]));
|
||||
}
|
||||
pSrc->a[iFrom].fg.jointype = jointype;
|
||||
@@ -3737,6 +3755,9 @@ static int flattenSubquery(
|
||||
pSub->pOrderBy = 0;
|
||||
}
|
||||
pWhere = sqlite3ExprDup(db, pSub->pWhere, 0);
|
||||
if( isLeftJoin ){
|
||||
setJoinExpr(pWhere, iNewParent);
|
||||
}
|
||||
if( subqueryIsAgg ){
|
||||
assert( pParent->pHaving==0 );
|
||||
pParent->pHaving = pParent->pWhere;
|
||||
@@ -3750,7 +3771,13 @@ static int flattenSubquery(
|
||||
pParent->pWhere = sqlite3ExprAnd(db, pWhere, pParent->pWhere);
|
||||
}
|
||||
if( db->mallocFailed==0 ){
|
||||
substSelect(pParse, pParent, iParent, pSub->pEList, 0);
|
||||
SubstContext x;
|
||||
x.pParse = pParse;
|
||||
x.iTable = iParent;
|
||||
x.iNewTable = iNewParent;
|
||||
x.isLeftJoin = isLeftJoin;
|
||||
x.pEList = pSub->pEList;
|
||||
substSelect(&x, pParent, 0);
|
||||
}
|
||||
|
||||
/* The flattened query is distinct if either the inner or the
|
||||
@@ -3853,8 +3880,14 @@ static int pushDownWhereTerms(
|
||||
if( sqlite3ExprIsTableConstant(pWhere, iCursor) ){
|
||||
nChng++;
|
||||
while( pSubq ){
|
||||
SubstContext x;
|
||||
pNew = sqlite3ExprDup(pParse->db, pWhere, 0);
|
||||
pNew = substExpr(pParse, pNew, iCursor, pSubq->pEList);
|
||||
x.pParse = pParse;
|
||||
x.iTable = iCursor;
|
||||
x.iNewTable = iCursor;
|
||||
x.isLeftJoin = 0;
|
||||
x.pEList = pSubq->pEList;
|
||||
pNew = substExpr(&x, pNew);
|
||||
pSubq->pWhere = sqlite3ExprAnd(pParse->db, pSubq->pWhere, pNew);
|
||||
pSubq = pSubq->pPrior;
|
||||
}
|
||||
@@ -4846,6 +4879,103 @@ static void explainSimpleCount(
|
||||
# define explainSimpleCount(a,b,c)
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Context object for havingToWhereExprCb().
|
||||
*/
|
||||
struct HavingToWhereCtx {
|
||||
Expr **ppWhere;
|
||||
ExprList *pGroupBy;
|
||||
};
|
||||
|
||||
/*
|
||||
** sqlite3WalkExpr() callback used by havingToWhere().
|
||||
**
|
||||
** If the node passed to the callback is a TK_AND node, return
|
||||
** WRC_Continue to tell sqlite3WalkExpr() to iterate through child nodes.
|
||||
**
|
||||
** Otherwise, return WRC_Prune. In this case, also check if the
|
||||
** sub-expression matches the criteria for being moved to the WHERE
|
||||
** clause. If so, add it to the WHERE clause and replace the sub-expression
|
||||
** within the HAVING expression with a constant "1".
|
||||
*/
|
||||
static int havingToWhereExprCb(Walker *pWalker, Expr *pExpr){
|
||||
if( pExpr->op!=TK_AND ){
|
||||
struct HavingToWhereCtx *p = pWalker->u.pHavingCtx;
|
||||
if( sqlite3ExprIsConstantOrGroupBy(pWalker->pParse, pExpr, p->pGroupBy) ){
|
||||
sqlite3 *db = pWalker->pParse->db;
|
||||
Expr *pNew = sqlite3ExprAlloc(db, TK_INTEGER, &sqlite3IntTokens[1], 0);
|
||||
if( pNew ){
|
||||
Expr *pWhere = *(p->ppWhere);
|
||||
SWAP(Expr, *pNew, *pExpr);
|
||||
pNew = sqlite3ExprAnd(db, pWhere, pNew);
|
||||
*(p->ppWhere) = pNew;
|
||||
}
|
||||
}
|
||||
return WRC_Prune;
|
||||
}
|
||||
return WRC_Continue;
|
||||
}
|
||||
|
||||
/*
|
||||
** Transfer eligible terms from the HAVING clause of a query, which is
|
||||
** processed after grouping, to the WHERE clause, which is processed before
|
||||
** grouping. For example, the query:
|
||||
**
|
||||
** SELECT * FROM <tables> WHERE a=? GROUP BY b HAVING b=? AND c=?
|
||||
**
|
||||
** can be rewritten as:
|
||||
**
|
||||
** SELECT * FROM <tables> WHERE a=? AND b=? GROUP BY b HAVING c=?
|
||||
**
|
||||
** A term of the HAVING expression is eligible for transfer if it consists
|
||||
** entirely of constants and expressions that are also GROUP BY terms that
|
||||
** use the "BINARY" collation sequence.
|
||||
*/
|
||||
static void havingToWhere(
|
||||
Parse *pParse,
|
||||
ExprList *pGroupBy,
|
||||
Expr *pHaving,
|
||||
Expr **ppWhere
|
||||
){
|
||||
struct HavingToWhereCtx sCtx;
|
||||
Walker sWalker;
|
||||
|
||||
sCtx.ppWhere = ppWhere;
|
||||
sCtx.pGroupBy = pGroupBy;
|
||||
|
||||
memset(&sWalker, 0, sizeof(sWalker));
|
||||
sWalker.pParse = pParse;
|
||||
sWalker.xExprCallback = havingToWhereExprCb;
|
||||
sWalker.u.pHavingCtx = &sCtx;
|
||||
sqlite3WalkExpr(&sWalker, pHaving);
|
||||
}
|
||||
|
||||
/*
|
||||
** Check to see if the pThis entry of pTabList is a self-join of a prior view.
|
||||
** If it is, then return the SrcList_item for the prior view. If it is not,
|
||||
** then return 0.
|
||||
*/
|
||||
static struct SrcList_item *isSelfJoinView(
|
||||
SrcList *pTabList, /* Search for self-joins in this FROM clause */
|
||||
struct SrcList_item *pThis /* Search for prior reference to this subquery */
|
||||
){
|
||||
struct SrcList_item *pItem;
|
||||
for(pItem = pTabList->a; pItem<pThis; pItem++){
|
||||
if( pItem->pSelect==0 ) continue;
|
||||
if( pItem->fg.viaCoroutine ) continue;
|
||||
if( pItem->zName==0 ) continue;
|
||||
if( sqlite3_stricmp(pItem->zDatabase, pThis->zDatabase)!=0 ) continue;
|
||||
if( sqlite3_stricmp(pItem->zName, pThis->zName)!=0 ) continue;
|
||||
if( sqlite3ExprCompare(pThis->pSelect->pWhere, pItem->pSelect->pWhere, -1) ){
|
||||
/* The view was modified by some other optimization such as
|
||||
** pushDownWhereTerms() */
|
||||
continue;
|
||||
}
|
||||
return pItem;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate code for the SELECT statement given in the p argument.
|
||||
**
|
||||
@@ -4985,13 +5115,38 @@ int sqlite3Select(
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Generate code for all sub-queries in the FROM clause
|
||||
/* For each term in the FROM clause, do two things:
|
||||
** (1) Authorized unreferenced tables
|
||||
** (2) Generate code for all sub-queries
|
||||
*/
|
||||
#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
|
||||
for(i=0; i<pTabList->nSrc; i++){
|
||||
struct SrcList_item *pItem = &pTabList->a[i];
|
||||
SelectDest dest;
|
||||
Select *pSub = pItem->pSelect;
|
||||
Select *pSub;
|
||||
|
||||
/* Issue SQLITE_READ authorizations with a fake column name for any tables that
|
||||
** are referenced but from which no values are extracted. Examples of where these
|
||||
** kinds of null SQLITE_READ authorizations would occur:
|
||||
**
|
||||
** SELECT count(*) FROM t1; -- SQLITE_READ t1.""
|
||||
** SELECT t1.* FROM t1, t2; -- SQLITE_READ t2.""
|
||||
**
|
||||
** The fake column name is an empty string. It is possible for a table to
|
||||
** have a column named by the empty string, in which case there is no way to
|
||||
** distinguish between an unreferenced table and an actual reference to the
|
||||
** "" column. The original design was for the fake column name to be a NULL,
|
||||
** which would be unambiguous. But legacy authorization callbacks might
|
||||
** assume the column name is non-NULL and segfault. The use of an empty string
|
||||
** for the fake column name seems safer.
|
||||
*/
|
||||
if( pItem->colUsed==0 ){
|
||||
sqlite3AuthCheck(pParse, SQLITE_READ, pItem->zName, "", pItem->zDatabase);
|
||||
}
|
||||
|
||||
#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
|
||||
/* Generate code for all sub-queries in the FROM clause
|
||||
*/
|
||||
pSub = pItem->pSelect;
|
||||
if( pSub==0 ) continue;
|
||||
|
||||
/* Sometimes the code for a subquery will be generated more than
|
||||
@@ -5002,6 +5157,10 @@ int sqlite3Select(
|
||||
** to be invoked again. */
|
||||
if( pItem->addrFillSub ){
|
||||
if( pItem->fg.viaCoroutine==0 ){
|
||||
/* The subroutine that manifests the view might be a one-time routine,
|
||||
** or it might need to be rerun on each iteration because it
|
||||
** encodes a correlated subquery. */
|
||||
testcase( sqlite3VdbeGetOp(v, pItem->addrFillSub)->opcode==OP_Once );
|
||||
sqlite3VdbeAddOp2(v, OP_Gosub, pItem->regReturn, pItem->addrFillSub);
|
||||
}
|
||||
continue;
|
||||
@@ -5076,6 +5235,8 @@ int sqlite3Select(
|
||||
int topAddr;
|
||||
int onceAddr = 0;
|
||||
int retAddr;
|
||||
struct SrcList_item *pPrior;
|
||||
|
||||
assert( pItem->addrFillSub==0 );
|
||||
pItem->regReturn = ++pParse->nMem;
|
||||
topAddr = sqlite3VdbeAddOp2(v, OP_Integer, 0, pItem->regReturn);
|
||||
@@ -5089,9 +5250,14 @@ int sqlite3Select(
|
||||
}else{
|
||||
VdbeNoopComment((v, "materialize \"%s\"", pItem->pTab->zName));
|
||||
}
|
||||
sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor);
|
||||
explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId);
|
||||
sqlite3Select(pParse, pSub, &dest);
|
||||
pPrior = isSelfJoinView(pTabList, pItem);
|
||||
if( pPrior ){
|
||||
sqlite3VdbeAddOp2(v, OP_OpenDup, pItem->iCursor, pPrior->iCursor);
|
||||
}else{
|
||||
sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor);
|
||||
explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId);
|
||||
sqlite3Select(pParse, pSub, &dest);
|
||||
}
|
||||
pItem->pTab->nRowLogEst = pSub->nSelectRow;
|
||||
if( onceAddr ) sqlite3VdbeJumpHere(v, onceAddr);
|
||||
retAddr = sqlite3VdbeAddOp1(v, OP_Return, pItem->regReturn);
|
||||
@@ -5101,8 +5267,8 @@ int sqlite3Select(
|
||||
}
|
||||
if( db->mallocFailed ) goto select_end;
|
||||
pParse->nHeight -= sqlite3SelectExprHeight(p);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Various elements of the SELECT copied into local variables for
|
||||
** convenience */
|
||||
@@ -5310,6 +5476,11 @@ int sqlite3Select(
|
||||
sqlite3ExprAnalyzeAggList(&sNC, pEList);
|
||||
sqlite3ExprAnalyzeAggList(&sNC, sSort.pOrderBy);
|
||||
if( pHaving ){
|
||||
if( pGroupBy ){
|
||||
assert( pWhere==p->pWhere );
|
||||
havingToWhere(pParse, pGroupBy, pHaving, &p->pWhere);
|
||||
pWhere = p->pWhere;
|
||||
}
|
||||
sqlite3ExprAnalyzeAggregates(&sNC, pHaving);
|
||||
}
|
||||
sAggInfo.nAccumulator = sAggInfo.nColumn;
|
||||
|
||||
+192
-63
@@ -427,6 +427,36 @@ static void SQLITE_CDECL iotracePrintf(const char *zFormat, ...){
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Output string zUtf to stream pOut as w characters. If w is negative,
|
||||
** then right-justify the text. W is the width in UTF-8 characters, not
|
||||
** in bytes. This is different from the %*.*s specification in printf
|
||||
** since with %*.*s the width is measured in bytes, not characters.
|
||||
*/
|
||||
static void utf8_width_print(FILE *pOut, int w, const char *zUtf){
|
||||
int i;
|
||||
int n;
|
||||
int aw = w<0 ? -w : w;
|
||||
char zBuf[1000];
|
||||
if( aw>(int)sizeof(zBuf)/3 ) aw = (int)sizeof(zBuf)/3;
|
||||
for(i=n=0; zUtf[i]; i++){
|
||||
if( (zUtf[i]&0xc0)!=0x80 ){
|
||||
n++;
|
||||
if( n==aw ){
|
||||
do{ i++; }while( (zUtf[i]&0xc0)==0x80 );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if( n>=aw ){
|
||||
utf8_printf(pOut, "%.*s", i, zUtf);
|
||||
}else if( w<0 ){
|
||||
utf8_printf(pOut, "%*s%s", aw-n, "", zUtf);
|
||||
}else{
|
||||
utf8_printf(pOut, "%s%*s", zUtf, aw-n, "");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Determines if a string is a number of not.
|
||||
@@ -714,6 +744,10 @@ struct SHA3Context {
|
||||
unsigned ixMask; /* Insert next input into u.x[nLoaded^ixMask]. */
|
||||
};
|
||||
|
||||
/* Allow the following routine to use the B0 variable, which is also
|
||||
** a macro in the termios.h header file */
|
||||
#undef B0
|
||||
|
||||
/*
|
||||
** A single step of the Keccak mixing function for a 1600-bit state
|
||||
*/
|
||||
@@ -1488,13 +1522,72 @@ static void output_hex_blob(FILE *out, const void *pBlob, int nBlob){
|
||||
raw_printf(out,"'");
|
||||
}
|
||||
|
||||
/*
|
||||
** Find a string that is not found anywhere in z[]. Return a pointer
|
||||
** to that string.
|
||||
**
|
||||
** Try to use zA and zB first. If both of those are already found in z[]
|
||||
** then make up some string and store it in the buffer zBuf.
|
||||
*/
|
||||
static const char *unused_string(
|
||||
const char *z, /* Result must not appear anywhere in z */
|
||||
const char *zA, const char *zB, /* Try these first */
|
||||
char *zBuf /* Space to store a generated string */
|
||||
){
|
||||
unsigned i = 0;
|
||||
if( strstr(z, zA)==0 ) return zA;
|
||||
if( strstr(z, zB)==0 ) return zB;
|
||||
do{
|
||||
sqlite3_snprintf(20,zBuf,"(%s%u)", zA, i++);
|
||||
}while( strstr(z,zBuf)!=0 );
|
||||
return zBuf;
|
||||
}
|
||||
|
||||
/*
|
||||
** Output the given string as a quoted string using SQL quoting conventions.
|
||||
**
|
||||
** The "\n" and "\r" characters are converted to char(10) and char(13)
|
||||
** to prevent them from being transformed by end-of-line translators.
|
||||
** See also: output_quoted_escaped_string()
|
||||
*/
|
||||
static void output_quoted_string(FILE *out, const char *z){
|
||||
int i;
|
||||
char c;
|
||||
setBinaryMode(out, 1);
|
||||
for(i=0; (c = z[i])!=0 && c!='\''; i++){}
|
||||
if( c==0 ){
|
||||
utf8_printf(out,"'%s'",z);
|
||||
}else{
|
||||
raw_printf(out, "'");
|
||||
while( *z ){
|
||||
for(i=0; (c = z[i])!=0 && c!='\''; i++){}
|
||||
if( c=='\'' ) i++;
|
||||
if( i ){
|
||||
utf8_printf(out, "%.*s", i, z);
|
||||
z += i;
|
||||
}
|
||||
if( c=='\'' ){
|
||||
raw_printf(out, "'");
|
||||
continue;
|
||||
}
|
||||
if( c==0 ){
|
||||
break;
|
||||
}
|
||||
z++;
|
||||
}
|
||||
raw_printf(out, "'");
|
||||
}
|
||||
setTextMode(out, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
** Output the given string as a quoted string using SQL quoting conventions.
|
||||
** Additionallly , escape the "\n" and "\r" characters so that they do not
|
||||
** get corrupted by end-of-line translation facilities in some operating
|
||||
** systems.
|
||||
**
|
||||
** This is like output_quoted_string() but with the addition of the \r\n
|
||||
** escape mechanism.
|
||||
*/
|
||||
static void output_quoted_escaped_string(FILE *out, const char *z){
|
||||
int i;
|
||||
char c;
|
||||
setBinaryMode(out, 1);
|
||||
@@ -1502,40 +1595,52 @@ static void output_quoted_string(FILE *out, const char *z){
|
||||
if( c==0 ){
|
||||
utf8_printf(out,"'%s'",z);
|
||||
}else{
|
||||
int inQuote = 0;
|
||||
int bStarted = 0;
|
||||
const char *zNL = 0;
|
||||
const char *zCR = 0;
|
||||
int nNL = 0;
|
||||
int nCR = 0;
|
||||
char zBuf1[20], zBuf2[20];
|
||||
for(i=0; z[i]; i++){
|
||||
if( z[i]=='\n' ) nNL++;
|
||||
if( z[i]=='\r' ) nCR++;
|
||||
}
|
||||
if( nNL ){
|
||||
raw_printf(out, "replace(");
|
||||
zNL = unused_string(z, "\\n", "\\012", zBuf1);
|
||||
}
|
||||
if( nCR ){
|
||||
raw_printf(out, "replace(");
|
||||
zCR = unused_string(z, "\\r", "\\015", zBuf2);
|
||||
}
|
||||
raw_printf(out, "'");
|
||||
while( *z ){
|
||||
for(i=0; (c = z[i])!=0 && c!='\n' && c!='\r' && c!='\''; i++){}
|
||||
if( c=='\'' ) i++;
|
||||
if( i ){
|
||||
if( !inQuote ){
|
||||
if( bStarted ) raw_printf(out, "||");
|
||||
raw_printf(out, "'");
|
||||
inQuote = 1;
|
||||
}
|
||||
utf8_printf(out, "%.*s", i, z);
|
||||
z += i;
|
||||
bStarted = 1;
|
||||
}
|
||||
if( c=='\'' ){
|
||||
raw_printf(out, "'");
|
||||
continue;
|
||||
}
|
||||
if( inQuote ){
|
||||
raw_printf(out, "'");
|
||||
inQuote = 0;
|
||||
}
|
||||
if( c==0 ){
|
||||
break;
|
||||
}
|
||||
for(i=0; (c = z[i])=='\r' || c=='\n'; i++){
|
||||
if( bStarted ) raw_printf(out, "||");
|
||||
raw_printf(out, "char(%d)", c);
|
||||
bStarted = 1;
|
||||
z++;
|
||||
if( c=='\n' ){
|
||||
raw_printf(out, "%s", zNL);
|
||||
continue;
|
||||
}
|
||||
z += i;
|
||||
raw_printf(out, "%s", zCR);
|
||||
}
|
||||
raw_printf(out, "'");
|
||||
if( nCR ){
|
||||
raw_printf(out, ",'%s',char(13))", zCR);
|
||||
}
|
||||
if( nNL ){
|
||||
raw_printf(out, ",'%s',char(10))", zNL);
|
||||
}
|
||||
if( inQuote ) raw_printf(out, "'");
|
||||
}
|
||||
setTextMode(out, 1);
|
||||
}
|
||||
@@ -1807,13 +1912,8 @@ static int shell_callback(
|
||||
p->actualWidth[i] = w;
|
||||
}
|
||||
if( showHdr ){
|
||||
if( w<0 ){
|
||||
utf8_printf(p->out,"%*.*s%s",-w,-w,azCol[i],
|
||||
i==nArg-1 ? rowSep : " ");
|
||||
}else{
|
||||
utf8_printf(p->out,"%-*.*s%s",w,w,azCol[i],
|
||||
i==nArg-1 ? rowSep : " ");
|
||||
}
|
||||
utf8_width_print(p->out, w, azCol[i]);
|
||||
utf8_printf(p->out, "%s", i==nArg-1 ? rowSep : " ");
|
||||
}
|
||||
}
|
||||
if( showHdr ){
|
||||
@@ -1849,15 +1949,8 @@ static int shell_callback(
|
||||
}
|
||||
p->iIndent++;
|
||||
}
|
||||
if( w<0 ){
|
||||
utf8_printf(p->out,"%*.*s%s",-w,-w,
|
||||
azArg[i] ? azArg[i] : p->nullValue,
|
||||
i==nArg-1 ? rowSep : " ");
|
||||
}else{
|
||||
utf8_printf(p->out,"%-*.*s%s",w,w,
|
||||
azArg[i] ? azArg[i] : p->nullValue,
|
||||
i==nArg-1 ? rowSep : " ");
|
||||
}
|
||||
utf8_width_print(p->out, w, azArg[i] ? azArg[i] : p->nullValue);
|
||||
utf8_printf(p->out, "%s", i==nArg-1 ? rowSep : " ");
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -1998,21 +2091,53 @@ static int shell_callback(
|
||||
setTextMode(p->out, 1);
|
||||
break;
|
||||
}
|
||||
case MODE_Quote:
|
||||
case MODE_Insert: {
|
||||
if( azArg==0 ) break;
|
||||
if( p->cMode==MODE_Insert ){
|
||||
utf8_printf(p->out,"INSERT INTO %s",p->zDestTable);
|
||||
if( p->showHeader ){
|
||||
raw_printf(p->out,"(");
|
||||
for(i=0; i<nArg; i++){
|
||||
char *zSep = i>0 ? ",": "";
|
||||
utf8_printf(p->out, "%s%s", zSep, azCol[i]);
|
||||
utf8_printf(p->out,"INSERT INTO %s",p->zDestTable);
|
||||
if( p->showHeader ){
|
||||
raw_printf(p->out,"(");
|
||||
for(i=0; i<nArg; i++){
|
||||
if( i>0 ) raw_printf(p->out, ",");
|
||||
if( quoteChar(azCol[i]) ){
|
||||
char *z = sqlite3_mprintf("\"%w\"", azCol[i]);
|
||||
utf8_printf(p->out, "%s", z);
|
||||
sqlite3_free(z);
|
||||
}else{
|
||||
raw_printf(p->out, "%s", azCol[i]);
|
||||
}
|
||||
raw_printf(p->out,")");
|
||||
}
|
||||
raw_printf(p->out," VALUES(");
|
||||
}else if( p->cnt==0 && p->showHeader ){
|
||||
raw_printf(p->out,")");
|
||||
}
|
||||
p->cnt++;
|
||||
for(i=0; i<nArg; i++){
|
||||
raw_printf(p->out, i>0 ? "," : " VALUES(");
|
||||
if( (azArg[i]==0) || (aiType && aiType[i]==SQLITE_NULL) ){
|
||||
utf8_printf(p->out,"NULL");
|
||||
}else if( aiType && aiType[i]==SQLITE_TEXT ){
|
||||
output_quoted_escaped_string(p->out, azArg[i]);
|
||||
}else if( aiType && aiType[i]==SQLITE_INTEGER ){
|
||||
utf8_printf(p->out,"%s", azArg[i]);
|
||||
}else if( aiType && aiType[i]==SQLITE_FLOAT ){
|
||||
char z[50];
|
||||
double r = sqlite3_column_double(p->pStmt, i);
|
||||
sqlite3_snprintf(50,z,"%!.20g", r);
|
||||
raw_printf(p->out, "%s", z);
|
||||
}else if( aiType && aiType[i]==SQLITE_BLOB && p->pStmt ){
|
||||
const void *pBlob = sqlite3_column_blob(p->pStmt, i);
|
||||
int nBlob = sqlite3_column_bytes(p->pStmt, i);
|
||||
output_hex_blob(p->out, pBlob, nBlob);
|
||||
}else if( isNumber(azArg[i], 0) ){
|
||||
utf8_printf(p->out,"%s", azArg[i]);
|
||||
}else{
|
||||
output_quoted_escaped_string(p->out, azArg[i]);
|
||||
}
|
||||
}
|
||||
raw_printf(p->out,");\n");
|
||||
break;
|
||||
}
|
||||
case MODE_Quote: {
|
||||
if( azArg==0 ) break;
|
||||
if( p->cnt==0 && p->showHeader ){
|
||||
for(i=0; i<nArg; i++){
|
||||
if( i>0 ) raw_printf(p->out, ",");
|
||||
output_quoted_string(p->out, azCol[i]);
|
||||
@@ -2021,32 +2146,29 @@ static int shell_callback(
|
||||
}
|
||||
p->cnt++;
|
||||
for(i=0; i<nArg; i++){
|
||||
char *zSep = i>0 ? ",": "";
|
||||
if( i>0 ) raw_printf(p->out, ",");
|
||||
if( (azArg[i]==0) || (aiType && aiType[i]==SQLITE_NULL) ){
|
||||
utf8_printf(p->out,"%sNULL",zSep);
|
||||
utf8_printf(p->out,"NULL");
|
||||
}else if( aiType && aiType[i]==SQLITE_TEXT ){
|
||||
if( zSep[0] ) utf8_printf(p->out,"%s",zSep);
|
||||
output_quoted_string(p->out, azArg[i]);
|
||||
}else if( aiType && aiType[i]==SQLITE_INTEGER ){
|
||||
utf8_printf(p->out,"%s%s",zSep, azArg[i]);
|
||||
utf8_printf(p->out,"%s", azArg[i]);
|
||||
}else if( aiType && aiType[i]==SQLITE_FLOAT ){
|
||||
char z[50];
|
||||
double r = sqlite3_column_double(p->pStmt, i);
|
||||
sqlite3_snprintf(50,z,"%!.20g", r);
|
||||
raw_printf(p->out, "%s%s", zSep, z);
|
||||
raw_printf(p->out, "%s", z);
|
||||
}else if( aiType && aiType[i]==SQLITE_BLOB && p->pStmt ){
|
||||
const void *pBlob = sqlite3_column_blob(p->pStmt, i);
|
||||
int nBlob = sqlite3_column_bytes(p->pStmt, i);
|
||||
if( zSep[0] ) utf8_printf(p->out,"%s",zSep);
|
||||
output_hex_blob(p->out, pBlob, nBlob);
|
||||
}else if( isNumber(azArg[i], 0) ){
|
||||
utf8_printf(p->out,"%s%s",zSep, azArg[i]);
|
||||
utf8_printf(p->out,"%s", azArg[i]);
|
||||
}else{
|
||||
if( zSep[0] ) utf8_printf(p->out,"%s",zSep);
|
||||
output_quoted_string(p->out, azArg[i]);
|
||||
}
|
||||
}
|
||||
raw_printf(p->out,p->cMode==MODE_Quote?"\n":");\n");
|
||||
raw_printf(p->out,"\n");
|
||||
break;
|
||||
}
|
||||
case MODE_Ascii: {
|
||||
@@ -4331,29 +4453,30 @@ static int lintFkeyIndexes(
|
||||
"SELECT "
|
||||
" 'EXPLAIN QUERY PLAN SELECT rowid FROM ' || quote(s.name) || ' WHERE '"
|
||||
" || group_concat(quote(s.name) || '.' || quote(f.[from]) || '=?' "
|
||||
" || fkey_collate_clause(f.[table], f.[to], s.name, f.[from]),' AND ')"
|
||||
" || fkey_collate_clause("
|
||||
" f.[table], COALESCE(f.[to], p.[name]), s.name, f.[from]),' AND ')"
|
||||
", "
|
||||
" 'SEARCH TABLE ' || s.name || ' USING COVERING INDEX*('"
|
||||
" || group_concat('*=?', ' AND ') || ')'"
|
||||
", "
|
||||
" s.name || '(' || group_concat(f.[from], ', ') || ')'"
|
||||
", "
|
||||
" f.[table] || '(' || group_concat(COALESCE(f.[to], "
|
||||
" (SELECT name FROM pragma_table_info(f.[table]) WHERE pk=seq+1)"
|
||||
" )) || ')'"
|
||||
" f.[table] || '(' || group_concat(COALESCE(f.[to], p.[name])) || ')'"
|
||||
", "
|
||||
" 'CREATE INDEX ' || quote(s.name ||'_'|| group_concat(f.[from], '_'))"
|
||||
" || ' ON ' || quote(s.name) || '('"
|
||||
" || group_concat(quote(f.[from]) ||"
|
||||
" fkey_collate_clause(f.[table], f.[to], s.name, f.[from]), ', ')"
|
||||
" fkey_collate_clause("
|
||||
" f.[table], COALESCE(f.[to], p.[name]), s.name, f.[from]), ', ')"
|
||||
" || ');'"
|
||||
", "
|
||||
" f.[table] "
|
||||
|
||||
"FROM sqlite_master AS s, pragma_foreign_key_list(s.name) AS f "
|
||||
"LEFT JOIN pragma_table_info AS p ON (pk-1=seq AND p.arg=f.[table]) "
|
||||
"GROUP BY s.name, f.id "
|
||||
"ORDER BY (CASE WHEN ? THEN f.[table] ELSE s.name END)"
|
||||
;
|
||||
const char *zGlobIPK = "SEARCH TABLE * USING INTEGER PRIMARY KEY (rowid=?)";
|
||||
|
||||
for(i=2; i<nArg; i++){
|
||||
int n = (int)strlen(azArg[i]);
|
||||
@@ -4402,7 +4525,10 @@ static int lintFkeyIndexes(
|
||||
if( rc!=SQLITE_OK ) break;
|
||||
if( SQLITE_ROW==sqlite3_step(pExplain) ){
|
||||
const char *zPlan = (const char*)sqlite3_column_text(pExplain, 3);
|
||||
res = (0==sqlite3_strglob(zGlob, zPlan));
|
||||
res = (
|
||||
0==sqlite3_strglob(zGlob, zPlan)
|
||||
|| 0==sqlite3_strglob(zGlobIPK, zPlan)
|
||||
);
|
||||
}
|
||||
rc = sqlite3_finalize(pExplain);
|
||||
if( rc!=SQLITE_OK ) break;
|
||||
@@ -4680,6 +4806,7 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
if( c=='d' && strncmp(azArg[0], "dump", n)==0 ){
|
||||
const char *zLike = 0;
|
||||
int i;
|
||||
int savedShowHeader = p->showHeader;
|
||||
ShellClearFlag(p, SHFLG_PreserveRowid);
|
||||
for(i=1; i<nArg; i++){
|
||||
if( azArg[i][0]=='-' ){
|
||||
@@ -4715,6 +4842,7 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
raw_printf(p->out, "PRAGMA foreign_keys=OFF;\n");
|
||||
raw_printf(p->out, "BEGIN TRANSACTION;\n");
|
||||
p->writableSchema = 0;
|
||||
p->showHeader = 0;
|
||||
/* Set writable_schema=ON since doing so forces SQLite to initialize
|
||||
** as much of the schema as it can even if the sqlite_master table is
|
||||
** corrupt. */
|
||||
@@ -4756,6 +4884,7 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
sqlite3_exec(p->db, "PRAGMA writable_schema=OFF;", 0, 0, 0);
|
||||
sqlite3_exec(p->db, "RELEASE dump;", 0, 0, 0);
|
||||
raw_printf(p->out, p->nErr ? "ROLLBACK; -- due to errors\n" : "COMMIT;\n");
|
||||
p->showHeader = savedShowHeader;
|
||||
}else
|
||||
|
||||
if( c=='e' && strncmp(azArg[0], "echo", n)==0 ){
|
||||
|
||||
+20
-11
@@ -857,7 +857,7 @@ struct sqlite3_io_methods {
|
||||
** opcode allows these two values (10 retries and 25 milliseconds of delay)
|
||||
** to be adjusted. The values are changed for all database connections
|
||||
** within the same process. The argument is a pointer to an array of two
|
||||
** integers where the first integer i the new retry count and the second
|
||||
** integers where the first integer is the new retry count and the second
|
||||
** integer is the delay. If either integer is negative, then the setting
|
||||
** is not changed but instead the prior value of that setting is written
|
||||
** into the array entry, allowing the current retry settings to be
|
||||
@@ -2211,9 +2211,6 @@ int sqlite3_total_changes(sqlite3*);
|
||||
** ^A call to sqlite3_interrupt(D) that occurs when there are no running
|
||||
** SQL statements is a no-op and has no effect on SQL statements
|
||||
** that are started after the sqlite3_interrupt() call returns.
|
||||
**
|
||||
** If the database connection closes while [sqlite3_interrupt()]
|
||||
** is running then bad things will likely happen.
|
||||
*/
|
||||
void sqlite3_interrupt(sqlite3*);
|
||||
|
||||
@@ -2676,6 +2673,7 @@ void sqlite3_randomness(int N, void *P);
|
||||
/*
|
||||
** CAPI3REF: Compile-Time Authorization Callbacks
|
||||
** METHOD: sqlite3
|
||||
** KEYWORDS: {authorizer callback}
|
||||
**
|
||||
** ^This routine registers an authorizer callback with a particular
|
||||
** [database connection], supplied in the first argument.
|
||||
@@ -2703,8 +2701,10 @@ void sqlite3_randomness(int N, void *P);
|
||||
** parameter to the sqlite3_set_authorizer() interface. ^The second parameter
|
||||
** to the callback is an integer [SQLITE_COPY | action code] that specifies
|
||||
** the particular action to be authorized. ^The third through sixth parameters
|
||||
** to the callback are zero-terminated strings that contain additional
|
||||
** details about the action to be authorized.
|
||||
** to the callback are either NULL pointers or zero-terminated strings
|
||||
** that contain additional details about the action to be authorized.
|
||||
** Applications must always be prepared to encounter a NULL pointer in any
|
||||
** of the third through the sixth parameters of the authorization callback.
|
||||
**
|
||||
** ^If the action code is [SQLITE_READ]
|
||||
** and the callback returns [SQLITE_IGNORE] then the
|
||||
@@ -2713,6 +2713,10 @@ void sqlite3_randomness(int N, void *P);
|
||||
** been read if [SQLITE_OK] had been returned. The [SQLITE_IGNORE]
|
||||
** return can be used to deny an untrusted user access to individual
|
||||
** columns of a table.
|
||||
** ^When a table is referenced by a [SELECT] but no column values are
|
||||
** extracted from that table (for example in a query like
|
||||
** "SELECT count(*) FROM tab") then the [SQLITE_READ] authorizer callback
|
||||
** is invoked once for that table with a column name that is an empty string.
|
||||
** ^If the action code is [SQLITE_DELETE] and the callback returns
|
||||
** [SQLITE_IGNORE] then the [DELETE] operation proceeds but the
|
||||
** [truncate optimization] is disabled and all rows are deleted individually.
|
||||
@@ -3705,7 +3709,7 @@ int sqlite3_stmt_busy(sqlite3_stmt*);
|
||||
** The [sqlite3_value_blob | sqlite3_value_type()] family of
|
||||
** interfaces require protected sqlite3_value objects.
|
||||
*/
|
||||
typedef struct Mem sqlite3_value;
|
||||
typedef struct sqlite3_value sqlite3_value;
|
||||
|
||||
/*
|
||||
** CAPI3REF: SQL Function Context Object
|
||||
@@ -4759,10 +4763,11 @@ sqlite3 *sqlite3_context_db_handle(sqlite3_context*);
|
||||
** the compiled regular expression can be reused on multiple
|
||||
** invocations of the same function.
|
||||
**
|
||||
** ^The sqlite3_get_auxdata() interface returns a pointer to the metadata
|
||||
** associated by the sqlite3_set_auxdata() function with the Nth argument
|
||||
** value to the application-defined function. ^If there is no metadata
|
||||
** associated with the function argument, this sqlite3_get_auxdata() interface
|
||||
** ^The sqlite3_get_auxdata(C,N) interface returns a pointer to the metadata
|
||||
** associated by the sqlite3_set_auxdata(C,N,P,X) function with the Nth argument
|
||||
** value to the application-defined function. ^N is zero for the left-most
|
||||
** function argument. ^If there is no metadata
|
||||
** associated with the function argument, the sqlite3_get_auxdata(C,N) interface
|
||||
** returns a NULL pointer.
|
||||
**
|
||||
** ^The sqlite3_set_auxdata(C,N,P,X) interface saves P as metadata for the N-th
|
||||
@@ -4793,6 +4798,10 @@ sqlite3 *sqlite3_context_db_handle(sqlite3_context*);
|
||||
** function parameters that are compile-time constants, including literal
|
||||
** values and [parameters] and expressions composed from the same.)^
|
||||
**
|
||||
** The value of the N parameter to these interfaces should be non-negative.
|
||||
** Future enhancements may make use of negative N values to define new
|
||||
** kinds of function caching behavior.
|
||||
**
|
||||
** These routines must be called from the same thread in which
|
||||
** the SQL function is running.
|
||||
*/
|
||||
|
||||
+15
-9
@@ -2443,6 +2443,7 @@ struct Expr {
|
||||
*/
|
||||
struct ExprList {
|
||||
int nExpr; /* Number of expressions on the list */
|
||||
int nAlloc; /* Number of a[] slots allocated */
|
||||
struct ExprList_item { /* For each expression in the list */
|
||||
Expr *pExpr; /* The parse tree for this expression */
|
||||
char *zName; /* Token associated with this expression */
|
||||
@@ -2458,7 +2459,7 @@ struct ExprList {
|
||||
} x;
|
||||
int iConstExprReg; /* Register in which Expr value is cached */
|
||||
} u;
|
||||
} *a; /* Alloc a power of two greater or equal to nExpr */
|
||||
} a[1]; /* One slot for each expression in the list */
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -3315,14 +3316,17 @@ struct Walker {
|
||||
int walkerDepth; /* Number of subqueries */
|
||||
u8 eCode; /* A small processing code */
|
||||
union { /* Extra data for callback */
|
||||
NameContext *pNC; /* Naming context */
|
||||
int n; /* A counter */
|
||||
int iCur; /* A cursor number */
|
||||
SrcList *pSrcList; /* FROM clause */
|
||||
struct SrcCount *pSrcCount; /* Counting column references */
|
||||
struct CCurHint *pCCurHint; /* Used by codeCursorHint() */
|
||||
int *aiCol; /* array of column indexes */
|
||||
struct IdxCover *pIdxCover; /* Check for index coverage */
|
||||
NameContext *pNC; /* Naming context */
|
||||
int n; /* A counter */
|
||||
int iCur; /* A cursor number */
|
||||
SrcList *pSrcList; /* FROM clause */
|
||||
struct SrcCount *pSrcCount; /* Counting column references */
|
||||
struct CCurHint *pCCurHint; /* Used by codeCursorHint() */
|
||||
int *aiCol; /* array of column indexes */
|
||||
struct IdxCover *pIdxCover; /* Check for index coverage */
|
||||
struct IdxExprTrans *pIdxTrans; /* Convert indexed expr to column */
|
||||
ExprList *pGroupBy; /* GROUP BY clause */
|
||||
struct HavingToWhereCtx *pHavingCtx; /* HAVING to WHERE clause ctx */
|
||||
} u;
|
||||
};
|
||||
|
||||
@@ -3476,6 +3480,7 @@ void *sqlite3Realloc(void*, u64);
|
||||
void *sqlite3DbReallocOrFree(sqlite3 *, void *, u64);
|
||||
void *sqlite3DbRealloc(sqlite3 *, void *, u64);
|
||||
void sqlite3DbFree(sqlite3*, void*);
|
||||
void sqlite3DbFreeNN(sqlite3*, void*);
|
||||
int sqlite3MallocSize(void*);
|
||||
int sqlite3DbMallocSize(sqlite3*, void*);
|
||||
void *sqlite3ScratchMalloc(int);
|
||||
@@ -3791,6 +3796,7 @@ void sqlite3LeaveMutexAndCloseZombie(sqlite3*);
|
||||
int sqlite3ExprIsConstant(Expr*);
|
||||
int sqlite3ExprIsConstantNotJoin(Expr*);
|
||||
int sqlite3ExprIsConstantOrFunction(Expr*, u8);
|
||||
int sqlite3ExprIsConstantOrGroupBy(Parse*, Expr*, ExprList*);
|
||||
int sqlite3ExprIsTableConstant(Expr*,int);
|
||||
#ifdef SQLITE_ENABLE_CURSOR_HINTS
|
||||
int sqlite3ExprContainsSubquery(Expr*);
|
||||
|
||||
@@ -1033,9 +1033,16 @@ static int auth_callback(
|
||||
Tcl_DString str;
|
||||
int rc;
|
||||
const char *zReply;
|
||||
/* EVIDENCE-OF: R-38590-62769 The first parameter to the authorizer
|
||||
** callback is a copy of the third parameter to the
|
||||
** sqlite3_set_authorizer() interface.
|
||||
*/
|
||||
SqliteDb *pDb = (SqliteDb*)pArg;
|
||||
if( pDb->disableAuth ) return SQLITE_OK;
|
||||
|
||||
/* EVIDENCE-OF: R-56518-44310 The second parameter to the callback is an
|
||||
** integer action code that specifies the particular action to be
|
||||
** authorized. */
|
||||
switch( code ){
|
||||
case SQLITE_COPY : zCode="SQLITE_COPY"; break;
|
||||
case SQLITE_CREATE_INDEX : zCode="SQLITE_CREATE_INDEX"; break;
|
||||
|
||||
-47
@@ -4949,52 +4949,6 @@ static int SQLITE_TCLAPI test_interrupt(
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
static u8 *sqlite3_stack_baseline = 0;
|
||||
|
||||
/*
|
||||
** Fill the stack with a known bitpattern.
|
||||
*/
|
||||
static void prepStack(void){
|
||||
int i;
|
||||
u32 bigBuf[65536];
|
||||
for(i=0; i<sizeof(bigBuf)/sizeof(bigBuf[0]); i++) bigBuf[i] = 0xdeadbeef;
|
||||
sqlite3_stack_baseline = (u8*)&bigBuf[65536];
|
||||
}
|
||||
|
||||
/*
|
||||
** Get the current stack depth. Used for debugging only.
|
||||
*/
|
||||
u64 sqlite3StackDepth(void){
|
||||
u8 x;
|
||||
return (u64)(sqlite3_stack_baseline - &x);
|
||||
}
|
||||
|
||||
/*
|
||||
** Usage: sqlite3_stack_used DB SQL
|
||||
**
|
||||
** Try to measure the amount of stack space used by a call to sqlite3_exec
|
||||
*/
|
||||
static int SQLITE_TCLAPI test_stack_used(
|
||||
void * clientData,
|
||||
Tcl_Interp *interp,
|
||||
int argc,
|
||||
char **argv
|
||||
){
|
||||
sqlite3 *db;
|
||||
int i;
|
||||
if( argc!=3 ){
|
||||
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
|
||||
" DB SQL", 0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
|
||||
prepStack();
|
||||
(void)sqlite3_exec(db, argv[2], 0, 0, 0);
|
||||
for(i=65535; i>=0 && ((u32*)sqlite3_stack_baseline)[-i]==0xdeadbeef; i--){}
|
||||
Tcl_SetObjResult(interp, Tcl_NewIntObj(i*4));
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Usage: sqlite_delete_function DB function-name
|
||||
**
|
||||
@@ -7473,7 +7427,6 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
||||
{ "sqlite_delete_function", (Tcl_CmdProc*)delete_function },
|
||||
{ "sqlite_delete_collation", (Tcl_CmdProc*)delete_collation },
|
||||
{ "sqlite3_get_autocommit", (Tcl_CmdProc*)get_autocommit },
|
||||
{ "sqlite3_stack_used", (Tcl_CmdProc*)test_stack_used },
|
||||
{ "sqlite3_busy_timeout", (Tcl_CmdProc*)test_busy_timeout },
|
||||
{ "printf", (Tcl_CmdProc*)test_printf },
|
||||
{ "sqlite3IoTrace", (Tcl_CmdProc*)test_io_trace },
|
||||
|
||||
+36
-18
@@ -19,14 +19,12 @@
|
||||
** above.
|
||||
*/
|
||||
|
||||
#if SQLITE_OS_WIN
|
||||
# include <io.h>
|
||||
# define F_OK 0
|
||||
#else
|
||||
#ifndef SQLITE_OS_WIN
|
||||
# include <unistd.h>
|
||||
# include <errno.h>
|
||||
#endif
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include "sqlite3.h"
|
||||
|
||||
/* The following #defines are copied from test_multiplex.c */
|
||||
@@ -57,23 +55,37 @@ static void sqlite3Delete83Name(char *z){
|
||||
** set *pbExists to true and unlink it. Or, if the file does not exist,
|
||||
** set *pbExists to false before returning.
|
||||
**
|
||||
** If an error occurs, the value of errno is returned. Or, if no error
|
||||
** occurs, zero is returned.
|
||||
** If an error occurs, non-zero is returned. Or, if no error occurs, zero.
|
||||
*/
|
||||
static int sqlite3DeleteUnlinkIfExists(const char *zFile, int *pbExists){
|
||||
int rc;
|
||||
static int sqlite3DeleteUnlinkIfExists(
|
||||
sqlite3_vfs *pVfs,
|
||||
const char *zFile,
|
||||
int *pbExists
|
||||
){
|
||||
int rc = SQLITE_ERROR;
|
||||
#if SQLITE_OS_WIN
|
||||
if( pVfs ){
|
||||
if( pbExists ) *pbExists = 1;
|
||||
rc = pVfs->xDelete(pVfs, zFile, 0);
|
||||
if( rc==SQLITE_IOERR_DELETE_NOENT ){
|
||||
if( pbExists ) *pbExists = 0;
|
||||
rc = SQLITE_OK;
|
||||
}
|
||||
}
|
||||
#else
|
||||
assert( pVfs==0 );
|
||||
rc = access(zFile, F_OK);
|
||||
if( rc ){
|
||||
if( errno==ENOENT ){
|
||||
if( pbExists ) *pbExists = 0;
|
||||
return 0;
|
||||
rc = SQLITE_OK;
|
||||
}
|
||||
return errno;
|
||||
}else{
|
||||
if( pbExists ) *pbExists = 1;
|
||||
rc = unlink(zFile);
|
||||
}
|
||||
if( pbExists ) *pbExists = 1;
|
||||
rc = unlink(zFile);
|
||||
if( rc ) return errno;
|
||||
return 0;
|
||||
#endif
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -103,6 +115,12 @@ SQLITE_API int sqlite3_delete_database(
|
||||
{ "%s-wal%03d", SQLITE_MULTIPLEX_WAL_8_3_OFFSET, 1 },
|
||||
};
|
||||
|
||||
#ifdef SQLITE_OS_WIN
|
||||
sqlite3_vfs *pVfs = sqlite3_vfs_find("win32");
|
||||
#else
|
||||
sqlite3_vfs *pVfs = 0;
|
||||
#endif
|
||||
|
||||
/* Allocate a buffer large enough for any of the files that need to be
|
||||
** deleted. */
|
||||
nBuf = (int)strlen(zFile) + 100;
|
||||
@@ -113,10 +131,10 @@ SQLITE_API int sqlite3_delete_database(
|
||||
** journal, wal and shm files. */
|
||||
for(i=0; rc==0 && i<sizeof(azFmt)/sizeof(azFmt[0]); i++){
|
||||
sqlite3_snprintf(nBuf, zBuf, azFmt[i], zFile);
|
||||
rc = sqlite3DeleteUnlinkIfExists(zBuf, 0);
|
||||
rc = sqlite3DeleteUnlinkIfExists(pVfs, zBuf, 0);
|
||||
if( rc==0 && i!=0 ){
|
||||
sqlite3Delete83Name(zBuf);
|
||||
rc = sqlite3DeleteUnlinkIfExists(zBuf, 0);
|
||||
rc = sqlite3DeleteUnlinkIfExists(pVfs, zBuf, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -128,7 +146,7 @@ SQLITE_API int sqlite3_delete_database(
|
||||
int bExists;
|
||||
sqlite3_snprintf(nBuf, zBuf, p->zFmt, zFile, iChunk+p->iOffset);
|
||||
if( p->b83 ) sqlite3Delete83Name(zBuf);
|
||||
rc = sqlite3DeleteUnlinkIfExists(zBuf, &bExists);
|
||||
rc = sqlite3DeleteUnlinkIfExists(pVfs, zBuf, &bExists);
|
||||
if( bExists==0 || rc!=0 ) break;
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -482,7 +482,7 @@ int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
|
||||
sqlite3 *db = pParse->db; /* The database connection */
|
||||
int mxSqlLen; /* Max length of an SQL string */
|
||||
#ifdef sqlite3Parser_ENGINEALWAYSONSTACK
|
||||
unsigned char zSpace[sizeof(yyParser)]; /* Space for parser engine object */
|
||||
yyParser sEngine; /* Space to hold the Lemon-generated Parser object */
|
||||
#endif
|
||||
|
||||
assert( zSql!=0 );
|
||||
@@ -495,7 +495,7 @@ int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
|
||||
assert( pzErrMsg!=0 );
|
||||
/* sqlite3ParserTrace(stdout, "parser: "); */
|
||||
#ifdef sqlite3Parser_ENGINEALWAYSONSTACK
|
||||
pEngine = zSpace;
|
||||
pEngine = &sEngine;
|
||||
sqlite3ParserInit(pEngine);
|
||||
#else
|
||||
pEngine = sqlite3ParserAlloc(sqlite3Malloc);
|
||||
@@ -604,7 +604,7 @@ int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
|
||||
while( pParse->pAinc ){
|
||||
AutoincInfo *p = pParse->pAinc;
|
||||
pParse->pAinc = p->pNext;
|
||||
sqlite3DbFree(db, p);
|
||||
sqlite3DbFreeNN(db, p);
|
||||
}
|
||||
while( pParse->pZombieTab ){
|
||||
Table *p = pParse->pZombieTab;
|
||||
|
||||
+12
-2
@@ -238,7 +238,7 @@ void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 moreToFollow){
|
||||
void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){
|
||||
const char *zBinOp = 0; /* Binary operator */
|
||||
const char *zUniOp = 0; /* Unary operator */
|
||||
char zFlgs[30];
|
||||
char zFlgs[60];
|
||||
pView = sqlite3TreeViewPush(pView, moreToFollow);
|
||||
if( pExpr==0 ){
|
||||
sqlite3TreeViewLine(pView, "nil");
|
||||
@@ -246,7 +246,12 @@ void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){
|
||||
return;
|
||||
}
|
||||
if( pExpr->flags ){
|
||||
sqlite3_snprintf(sizeof(zFlgs),zFlgs," flags=0x%x",pExpr->flags);
|
||||
if( ExprHasProperty(pExpr, EP_FromJoin) ){
|
||||
sqlite3_snprintf(sizeof(zFlgs),zFlgs," flags=0x%x iRJT=%d",
|
||||
pExpr->flags, pExpr->iRightJoinTable);
|
||||
}else{
|
||||
sqlite3_snprintf(sizeof(zFlgs),zFlgs," flags=0x%x",pExpr->flags);
|
||||
}
|
||||
}else{
|
||||
zFlgs[0] = 0;
|
||||
}
|
||||
@@ -465,6 +470,11 @@ void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){
|
||||
sqlite3TreeViewSelect(pView, pExpr->pLeft->x.pSelect, 0);
|
||||
break;
|
||||
}
|
||||
case TK_IF_NULL_ROW: {
|
||||
sqlite3TreeViewLine(pView, "IF-NULL-ROW %d", pExpr->iTable);
|
||||
sqlite3TreeViewExpr(pView, pExpr->pLeft, 0);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
sqlite3TreeViewLine(pView, "op=%d", pExpr->op);
|
||||
break;
|
||||
|
||||
+3
-3
@@ -285,7 +285,7 @@ void sqlite3Update(
|
||||
*/
|
||||
for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
|
||||
int reg;
|
||||
if( chngKey || hasFK || pIdx->pPartIdxWhere || pIdx==pPk ){
|
||||
if( chngKey || hasFK>1 || pIdx->pPartIdxWhere || pIdx==pPk ){
|
||||
reg = ++pParse->nMem;
|
||||
pParse->nMem += pIdx->nColumn;
|
||||
}else{
|
||||
@@ -640,7 +640,7 @@ void sqlite3Update(
|
||||
assert( regNew==regNewRowid+1 );
|
||||
#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
|
||||
sqlite3VdbeAddOp3(v, OP_Delete, iDataCur,
|
||||
OPFLAG_ISUPDATE | ((hasFK || chngKey) ? 0 : OPFLAG_ISNOOP),
|
||||
OPFLAG_ISUPDATE | ((hasFK>1 || chngKey) ? 0 : OPFLAG_ISNOOP),
|
||||
regNewRowid
|
||||
);
|
||||
if( eOnePass==ONEPASS_MULTI ){
|
||||
@@ -651,7 +651,7 @@ void sqlite3Update(
|
||||
sqlite3VdbeAppendP4(v, pTab, P4_TABLE);
|
||||
}
|
||||
#else
|
||||
if( hasFK || chngKey ){
|
||||
if( hasFK>1 || chngKey ){
|
||||
sqlite3VdbeAddOp2(v, OP_Delete, iDataCur, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -713,6 +713,7 @@ int sqlite3GetInt32(const char *zNum, int *pValue){
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if( !sqlite3Isdigit(zNum[0]) ) return 0;
|
||||
while( zNum[0]=='0' ) zNum++;
|
||||
for(i=0; i<11 && (c = zNum[i] - '0')>=0 && c<=9; i++){
|
||||
v = v*10 + c;
|
||||
|
||||
+92
-36
@@ -486,6 +486,7 @@ static void registerTrace(int iReg, Mem *p){
|
||||
printf("REG[%d] = ", iReg);
|
||||
memTracePrint(p);
|
||||
printf("\n");
|
||||
sqlite3VdbeCheckMemInvariants(p);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -763,7 +764,7 @@ jump_to_p2_and_check_for_interrupt:
|
||||
pOp = &aOp[pOp->p2 - 1];
|
||||
|
||||
/* Opcodes that are used as the bottom of a loop (OP_Next, OP_Prev,
|
||||
** OP_VNext, OP_RowSetNext, or OP_SorterNext) all jump here upon
|
||||
** OP_VNext, or OP_SorterNext) all jump here upon
|
||||
** completion. Check to see if sqlite3_interrupt() has been called
|
||||
** or if the progress callback needs to be invoked.
|
||||
**
|
||||
@@ -1151,7 +1152,7 @@ case OP_Null: { /* out2 */
|
||||
case OP_SoftNull: {
|
||||
assert( pOp->p1>0 && pOp->p1<=(p->nMem+1 - p->nCursor) );
|
||||
pOut = &aMem[pOp->p1];
|
||||
pOut->flags = (pOut->flags|MEM_Null)&~MEM_Undefined;
|
||||
pOut->flags = (pOut->flags&~(MEM_Undefined|MEM_AffMask))|MEM_Null;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1494,7 +1495,6 @@ case OP_Remainder: { /* same as TK_REM, in1, in2, out3 */
|
||||
type2 = numericType(pIn2);
|
||||
pOut = &aMem[pOp->p3];
|
||||
flags = pIn1->flags | pIn2->flags;
|
||||
if( (flags & MEM_Null)!=0 ) goto arithmetic_result_is_null;
|
||||
if( (type1 & type2 & MEM_Int)!=0 ){
|
||||
iA = pIn1->u.i;
|
||||
iB = pIn2->u.i;
|
||||
@@ -1518,6 +1518,8 @@ case OP_Remainder: { /* same as TK_REM, in1, in2, out3 */
|
||||
}
|
||||
pOut->u.i = iB;
|
||||
MemSetTypeFlag(pOut, MEM_Int);
|
||||
}else if( (flags & MEM_Null)!=0 ){
|
||||
goto arithmetic_result_is_null;
|
||||
}else{
|
||||
bIntint = 0;
|
||||
fp_math:
|
||||
@@ -1565,7 +1567,7 @@ arithmetic_result_is_null:
|
||||
|
||||
/* Opcode: CollSeq P1 * * P4
|
||||
**
|
||||
** P4 is a pointer to a CollSeq struct. If the next call to a user function
|
||||
** P4 is a pointer to a CollSeq object. If the next call to a user function
|
||||
** or aggregate calls sqlite3GetFuncCollSeq(), this collation sequence will
|
||||
** be returned. This is used by the built-in min(), max() and nullif()
|
||||
** functions.
|
||||
@@ -1846,11 +1848,11 @@ case OP_RealAffinity: { /* in1 */
|
||||
** Force the value in register P1 to be the type defined by P2.
|
||||
**
|
||||
** <ul>
|
||||
** <li value="97"> TEXT
|
||||
** <li value="98"> BLOB
|
||||
** <li value="99"> NUMERIC
|
||||
** <li value="100"> INTEGER
|
||||
** <li value="101"> REAL
|
||||
** <li> P2=='A' → BLOB
|
||||
** <li> P2=='B' → TEXT
|
||||
** <li> P2=='C' → NUMERIC
|
||||
** <li> P2=='D' → INTEGER
|
||||
** <li> P2=='E' → REAL
|
||||
** </ul>
|
||||
**
|
||||
** A NULL value is not changed by this routine. It remains NULL.
|
||||
@@ -2429,6 +2431,23 @@ case OP_NotNull: { /* same as TK_NOTNULL, jump, in1 */
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: IfNullRow P1 P2 P3 * *
|
||||
** Synopsis: if P1.nullRow then r[P3]=NULL, goto P2
|
||||
**
|
||||
** Check the cursor P1 to see if it is currently pointing at a NULL row.
|
||||
** If it is, then set register P3 to NULL and jump immediately to P2.
|
||||
** If P1 is not on a NULL row, then fall through without making any
|
||||
** changes.
|
||||
*/
|
||||
case OP_IfNullRow: { /* jump */
|
||||
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
|
||||
if( p->apCsr[pOp->p1]->nullRow ){
|
||||
sqlite3VdbeMemSetNull(aMem + pOp->p3);
|
||||
goto jump_to_p2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: Column P1 P2 P3 P4 P5
|
||||
** Synopsis: r[P3]=PX
|
||||
**
|
||||
@@ -2440,7 +2459,7 @@ case OP_NotNull: { /* same as TK_NOTNULL, jump, in1 */
|
||||
**
|
||||
** The value extracted is stored in register P3.
|
||||
**
|
||||
** If the column contains fewer than P2 fields, then extract a NULL. Or,
|
||||
** If the record contains fewer than P2 fields, then extract a NULL. Or,
|
||||
** if the P4 argument is a P4_MEM use the value of the P4 argument as
|
||||
** the result.
|
||||
**
|
||||
@@ -2449,7 +2468,7 @@ case OP_NotNull: { /* same as TK_NOTNULL, jump, in1 */
|
||||
** The first OP_Column against a pseudo-table after the value of the content
|
||||
** register has changed should have this bit set.
|
||||
**
|
||||
** If the OPFLAG_LENGTHARG and OPFLAG_TYPEOFARG bits are set on P5 when
|
||||
** If the OPFLAG_LENGTHARG and OPFLAG_TYPEOFARG bits are set on P5 then
|
||||
** the result is guaranteed to only be used as the argument of a length()
|
||||
** or typeof() function, respectively. The loading of large blobs can be
|
||||
** skipped for length() and all content loading can be skipped for typeof().
|
||||
@@ -2704,24 +2723,24 @@ op_column_out:
|
||||
**
|
||||
** Apply affinities to a range of P2 registers starting with P1.
|
||||
**
|
||||
** P4 is a string that is P2 characters long. The nth character of the
|
||||
** string indicates the column affinity that should be used for the nth
|
||||
** P4 is a string that is P2 characters long. The N-th character of the
|
||||
** string indicates the column affinity that should be used for the N-th
|
||||
** memory cell in the range.
|
||||
*/
|
||||
case OP_Affinity: {
|
||||
const char *zAffinity; /* The affinity to be applied */
|
||||
char cAff; /* A single character of affinity */
|
||||
|
||||
zAffinity = pOp->p4.z;
|
||||
assert( zAffinity!=0 );
|
||||
assert( pOp->p2>0 );
|
||||
assert( zAffinity[pOp->p2]==0 );
|
||||
pIn1 = &aMem[pOp->p1];
|
||||
while( (cAff = *(zAffinity++))!=0 ){
|
||||
do{
|
||||
assert( pIn1 <= &p->aMem[(p->nMem+1 - p->nCursor)] );
|
||||
assert( memIsValid(pIn1) );
|
||||
applyAffinity(pIn1, cAff, encoding);
|
||||
applyAffinity(pIn1, *(zAffinity++), encoding);
|
||||
pIn1++;
|
||||
}
|
||||
}while( zAffinity[0] );
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2732,8 +2751,8 @@ case OP_Affinity: {
|
||||
** use as a data record in a database table or as a key
|
||||
** in an index. The OP_Column opcode can decode the record later.
|
||||
**
|
||||
** P4 may be a string that is P2 characters long. The nth character of the
|
||||
** string indicates the column affinity that should be used for the nth
|
||||
** P4 may be a string that is P2 characters long. The N-th character of the
|
||||
** string indicates the column affinity that should be used for the N-th
|
||||
** field of the index key.
|
||||
**
|
||||
** The mapping from character to affinity is given by the SQLITE_AFF_
|
||||
@@ -2892,7 +2911,6 @@ case OP_MakeRecord: {
|
||||
pOut->u.nZero = nZero;
|
||||
pOut->flags |= MEM_Zero;
|
||||
}
|
||||
pOut->enc = SQLITE_UTF8; /* In case the blob is ever converted to text */
|
||||
REGISTER_TRACE(pOp->p3, pOut);
|
||||
UPDATE_MAX_BLOBSIZE(pOut);
|
||||
break;
|
||||
@@ -3522,6 +3540,37 @@ open_cursor_set_hints:
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: OpenDup P1 P2 * * *
|
||||
**
|
||||
** Open a new cursor P1 that points to the same ephemeral table as
|
||||
** cursor P2. The P2 cursor must have been opened by a prior OP_OpenEphemeral
|
||||
** opcode. Only ephemeral cursors may be duplicated.
|
||||
**
|
||||
** Duplicate ephemeral cursors are used for self-joins of materialized views.
|
||||
*/
|
||||
case OP_OpenDup: {
|
||||
VdbeCursor *pOrig; /* The original cursor to be duplicated */
|
||||
VdbeCursor *pCx; /* The new cursor */
|
||||
|
||||
pOrig = p->apCsr[pOp->p2];
|
||||
assert( pOrig->pBtx!=0 ); /* Only ephemeral cursors can be duplicated */
|
||||
|
||||
pCx = allocateCursor(p, pOp->p1, pOrig->nField, -1, CURTYPE_BTREE);
|
||||
if( pCx==0 ) goto no_mem;
|
||||
pCx->nullRow = 1;
|
||||
pCx->isEphemeral = 1;
|
||||
pCx->pKeyInfo = pOrig->pKeyInfo;
|
||||
pCx->isTable = pOrig->isTable;
|
||||
rc = sqlite3BtreeCursor(pOrig->pBtx, MASTER_ROOT, BTREE_WRCSR,
|
||||
pCx->pKeyInfo, pCx->uc.pCursor);
|
||||
/* The sqlite3BtreeCursor() routine can only fail for the first cursor
|
||||
** opened for a database. Since there is already an open cursor when this
|
||||
** opcode is run, the sqlite3BtreeCursor() cannot fail */
|
||||
assert( rc==SQLITE_OK );
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
/* Opcode: OpenEphemeral P1 P2 * P4 P5
|
||||
** Synopsis: nColumn=P2
|
||||
**
|
||||
@@ -4077,7 +4126,7 @@ case OP_Found: { /* jump, in3 */
|
||||
}
|
||||
}
|
||||
rc = sqlite3BtreeMovetoUnpacked(pC->uc.pCursor, pIdxKey, 0, 0, &res);
|
||||
if( pFree ) sqlite3DbFree(db, pFree);
|
||||
if( pFree ) sqlite3DbFreeNN(db, pFree);
|
||||
if( rc!=SQLITE_OK ){
|
||||
goto abort_due_to_error;
|
||||
}
|
||||
@@ -5387,10 +5436,17 @@ case OP_IdxGE: { /* jump */
|
||||
** might be moved into the newly deleted root page in order to keep all
|
||||
** root pages contiguous at the beginning of the database. The former
|
||||
** value of the root page that moved - its value before the move occurred -
|
||||
** is stored in register P2. If no page
|
||||
** movement was required (because the table being dropped was already
|
||||
** the last one in the database) then a zero is stored in register P2.
|
||||
** If AUTOVACUUM is disabled then a zero is stored in register P2.
|
||||
** is stored in register P2. If no page movement was required (because the
|
||||
** table being dropped was already the last one in the database) then a
|
||||
** zero is stored in register P2. If AUTOVACUUM is disabled then a zero
|
||||
** is stored in register P2.
|
||||
**
|
||||
** This opcode throws an error if there are any active reader VMs when
|
||||
** it is invoked. This is done to avoid the difficulty associated with
|
||||
** updating existing cursors when a root page is moved in an AUTOVACUUM
|
||||
** database. This error is thrown even if the database is not an AUTOVACUUM
|
||||
** db in order to avoid introducing an incompatibility between autovacuum
|
||||
** and non-autovacuum modes.
|
||||
**
|
||||
** See also: Clear
|
||||
*/
|
||||
@@ -5595,7 +5651,7 @@ case OP_ParseSchema: {
|
||||
assert( !db->mallocFailed );
|
||||
rc = sqlite3_exec(db, zSql, sqlite3InitCallback, &initData, 0);
|
||||
if( rc==SQLITE_OK ) rc = initData.rc;
|
||||
sqlite3DbFree(db, zSql);
|
||||
sqlite3DbFreeNN(db, zSql);
|
||||
db->init.busy = 0;
|
||||
}
|
||||
}
|
||||
@@ -5723,7 +5779,7 @@ case OP_IntegrityCk: {
|
||||
/* Opcode: RowSetAdd P1 P2 * * *
|
||||
** Synopsis: rowset(P1)=r[P2]
|
||||
**
|
||||
** Insert the integer value held by register P2 into a boolean index
|
||||
** Insert the integer value held by register P2 into a RowSet object
|
||||
** held in register P1.
|
||||
**
|
||||
** An assertion fails if P2 is not an integer.
|
||||
@@ -5743,8 +5799,9 @@ case OP_RowSetAdd: { /* in1, in2 */
|
||||
/* Opcode: RowSetRead P1 P2 P3 * *
|
||||
** Synopsis: r[P3]=rowset(P1)
|
||||
**
|
||||
** Extract the smallest value from boolean index P1 and put that value into
|
||||
** register P3. Or, if boolean index P1 is initially empty, leave P3
|
||||
** Extract the smallest value from the RowSet object in P1
|
||||
** and put that value into register P3.
|
||||
** Or, if RowSet object P1 is initially empty, leave P3
|
||||
** unchanged and jump to instruction P2.
|
||||
*/
|
||||
case OP_RowSetRead: { /* jump, in1, out3 */
|
||||
@@ -5775,15 +5832,14 @@ case OP_RowSetRead: { /* jump, in1, out3 */
|
||||
** integer in P3 into the RowSet and continue on to the
|
||||
** next opcode.
|
||||
**
|
||||
** The RowSet object is optimized for the case where successive sets
|
||||
** of integers, where each set contains no duplicates. Each set
|
||||
** of values is identified by a unique P4 value. The first set
|
||||
** must have P4==0, the final set P4=-1. P4 must be either -1 or
|
||||
** non-negative. For non-negative values of P4 only the lower 4
|
||||
** bits are significant.
|
||||
** The RowSet object is optimized for the case where sets of integers
|
||||
** are inserted in distinct phases, which each set contains no duplicates.
|
||||
** Each set is identified by a unique P4 value. The first set
|
||||
** must have P4==0, the final set must have P4==-1, and for all other sets
|
||||
** must have P4>0.
|
||||
**
|
||||
** This allows optimizations: (a) when P4==0 there is no need to test
|
||||
** the rowset object for P3, as it is guaranteed not to contain it,
|
||||
** the RowSet object for P3, as it is guaranteed not to contain it,
|
||||
** (b) when P4==-1 there is no need to insert the value, as it will
|
||||
** never be tested for, and (c) when a value that is part of set X is
|
||||
** inserted, there is no need to search to see if the same value was
|
||||
|
||||
+1
-1
@@ -30,7 +30,7 @@ typedef struct Vdbe Vdbe;
|
||||
** The names of the following types declared in vdbeInt.h are required
|
||||
** for the VdbeOp definition.
|
||||
*/
|
||||
typedef struct Mem Mem;
|
||||
typedef struct sqlite3_value Mem;
|
||||
typedef struct SubProgram SubProgram;
|
||||
|
||||
/*
|
||||
|
||||
+5
-5
@@ -185,7 +185,7 @@ struct VdbeFrame {
|
||||
** structures. Each Mem struct may cache multiple representations (string,
|
||||
** integer etc.) of the same value.
|
||||
*/
|
||||
struct Mem {
|
||||
struct sqlite3_value {
|
||||
union MemValue {
|
||||
double r; /* Real value used when MEM_Real is set in flags */
|
||||
i64 i; /* Integer value used when MEM_Int is set in flags */
|
||||
@@ -287,11 +287,11 @@ struct Mem {
|
||||
** when the VM is halted (if not before).
|
||||
*/
|
||||
struct AuxData {
|
||||
int iOp; /* Instruction number of OP_Function opcode */
|
||||
int iArg; /* Index of function argument. */
|
||||
int iAuxOp; /* Instruction number of OP_Function opcode */
|
||||
int iAuxArg; /* Index of function argument. */
|
||||
void *pAux; /* Aux data pointer */
|
||||
void (*xDelete)(void *); /* Destructor for the aux data */
|
||||
AuxData *pNext; /* Next element in list */
|
||||
void (*xDeleteAux)(void*); /* Destructor for the aux data */
|
||||
AuxData *pNextAux; /* Next element in list */
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
+27
-13
@@ -804,6 +804,12 @@ void *sqlite3_aggregate_context(sqlite3_context *p, int nByte){
|
||||
/*
|
||||
** Return the auxiliary data pointer, if any, for the iArg'th argument to
|
||||
** the user-function defined by pCtx.
|
||||
**
|
||||
** The left-most argument is 0.
|
||||
**
|
||||
** Undocumented behavior: If iArg is negative then access a cache of
|
||||
** auxiliary data pointers that is available to all functions within a
|
||||
** single prepared statement. The iArg values must match.
|
||||
*/
|
||||
void *sqlite3_get_auxdata(sqlite3_context *pCtx, int iArg){
|
||||
AuxData *pAuxData;
|
||||
@@ -814,17 +820,24 @@ void *sqlite3_get_auxdata(sqlite3_context *pCtx, int iArg){
|
||||
#else
|
||||
assert( pCtx->pVdbe!=0 );
|
||||
#endif
|
||||
for(pAuxData=pCtx->pVdbe->pAuxData; pAuxData; pAuxData=pAuxData->pNext){
|
||||
if( pAuxData->iOp==pCtx->iOp && pAuxData->iArg==iArg ) break;
|
||||
for(pAuxData=pCtx->pVdbe->pAuxData; pAuxData; pAuxData=pAuxData->pNextAux){
|
||||
if( pAuxData->iAuxArg==iArg && (pAuxData->iAuxOp==pCtx->iOp || iArg<0) ){
|
||||
return pAuxData->pAux;
|
||||
}
|
||||
}
|
||||
|
||||
return (pAuxData ? pAuxData->pAux : 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Set the auxiliary data pointer and delete function, for the iArg'th
|
||||
** argument to the user-function defined by pCtx. Any previous value is
|
||||
** deleted by calling the delete function specified when it was set.
|
||||
**
|
||||
** The left-most argument is 0.
|
||||
**
|
||||
** Undocumented behavior: If iArg is negative then make the data available
|
||||
** to all functions within the current prepared statement using iArg as an
|
||||
** access code.
|
||||
*/
|
||||
void sqlite3_set_auxdata(
|
||||
sqlite3_context *pCtx,
|
||||
@@ -836,33 +849,34 @@ void sqlite3_set_auxdata(
|
||||
Vdbe *pVdbe = pCtx->pVdbe;
|
||||
|
||||
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
|
||||
if( iArg<0 ) goto failed;
|
||||
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
if( pVdbe==0 ) goto failed;
|
||||
#else
|
||||
assert( pVdbe!=0 );
|
||||
#endif
|
||||
|
||||
for(pAuxData=pVdbe->pAuxData; pAuxData; pAuxData=pAuxData->pNext){
|
||||
if( pAuxData->iOp==pCtx->iOp && pAuxData->iArg==iArg ) break;
|
||||
for(pAuxData=pVdbe->pAuxData; pAuxData; pAuxData=pAuxData->pNextAux){
|
||||
if( pAuxData->iAuxArg==iArg && (pAuxData->iAuxOp==pCtx->iOp || iArg<0) ){
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( pAuxData==0 ){
|
||||
pAuxData = sqlite3DbMallocZero(pVdbe->db, sizeof(AuxData));
|
||||
if( !pAuxData ) goto failed;
|
||||
pAuxData->iOp = pCtx->iOp;
|
||||
pAuxData->iArg = iArg;
|
||||
pAuxData->pNext = pVdbe->pAuxData;
|
||||
pAuxData->iAuxOp = pCtx->iOp;
|
||||
pAuxData->iAuxArg = iArg;
|
||||
pAuxData->pNextAux = pVdbe->pAuxData;
|
||||
pVdbe->pAuxData = pAuxData;
|
||||
if( pCtx->fErrorOrAux==0 ){
|
||||
pCtx->isError = 0;
|
||||
pCtx->fErrorOrAux = 1;
|
||||
}
|
||||
}else if( pAuxData->xDelete ){
|
||||
pAuxData->xDelete(pAuxData->pAux);
|
||||
}else if( pAuxData->xDeleteAux ){
|
||||
pAuxData->xDeleteAux(pAuxData->pAux);
|
||||
}
|
||||
|
||||
pAuxData->pAux = pAux;
|
||||
pAuxData->xDelete = xDelete;
|
||||
pAuxData->xDeleteAux = xDelete;
|
||||
return;
|
||||
|
||||
failed:
|
||||
|
||||
+19
-18
@@ -811,7 +811,7 @@ void sqlite3VdbeJumpHere(Vdbe *p, int addr){
|
||||
*/
|
||||
static void freeEphemeralFunction(sqlite3 *db, FuncDef *pDef){
|
||||
if( (pDef->funcFlags & SQLITE_FUNC_EPHEM)!=0 ){
|
||||
sqlite3DbFree(db, pDef);
|
||||
sqlite3DbFreeNN(db, pDef);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -822,11 +822,11 @@ static void vdbeFreeOpArray(sqlite3 *, Op *, int);
|
||||
*/
|
||||
static SQLITE_NOINLINE void freeP4Mem(sqlite3 *db, Mem *p){
|
||||
if( p->szMalloc ) sqlite3DbFree(db, p->zMalloc);
|
||||
sqlite3DbFree(db, p);
|
||||
sqlite3DbFreeNN(db, p);
|
||||
}
|
||||
static SQLITE_NOINLINE void freeP4FuncCtx(sqlite3 *db, sqlite3_context *p){
|
||||
freeEphemeralFunction(db, p->pFunc);
|
||||
sqlite3DbFree(db, p);
|
||||
sqlite3DbFreeNN(db, p);
|
||||
}
|
||||
static void freeP4(sqlite3 *db, int p4type, void *p4){
|
||||
assert( db );
|
||||
@@ -879,14 +879,14 @@ static void freeP4(sqlite3 *db, int p4type, void *p4){
|
||||
static void vdbeFreeOpArray(sqlite3 *db, Op *aOp, int nOp){
|
||||
if( aOp ){
|
||||
Op *pOp;
|
||||
for(pOp=aOp; pOp<&aOp[nOp]; pOp++){
|
||||
for(pOp=&aOp[nOp-1]; pOp>=aOp; pOp--){
|
||||
if( pOp->p4type ) freeP4(db, pOp->p4type, pOp->p4.p);
|
||||
#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
|
||||
sqlite3DbFree(db, pOp->zComment);
|
||||
#endif
|
||||
}
|
||||
sqlite3DbFreeNN(db, aOp);
|
||||
}
|
||||
sqlite3DbFree(db, aOp);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1559,7 +1559,7 @@ static void releaseMemArray(Mem *p, int N){
|
||||
if( p->flags&(MEM_Agg|MEM_Dyn|MEM_Frame|MEM_RowSet) ){
|
||||
sqlite3VdbeMemRelease(p);
|
||||
}else if( p->szMalloc ){
|
||||
sqlite3DbFree(db, p->zMalloc);
|
||||
sqlite3DbFreeNN(db, p->zMalloc);
|
||||
p->szMalloc = 0;
|
||||
}
|
||||
|
||||
@@ -2035,8 +2035,8 @@ void sqlite3VdbeFreeCursor(Vdbe *p, VdbeCursor *pCx){
|
||||
break;
|
||||
}
|
||||
case CURTYPE_BTREE: {
|
||||
if( pCx->pBtx ){
|
||||
sqlite3BtreeClose(pCx->pBtx);
|
||||
if( pCx->isEphemeral ){
|
||||
if( pCx->pBtx ) sqlite3BtreeClose(pCx->pBtx);
|
||||
/* The pCx->pCursor will be close automatically, if it exists, by
|
||||
** the call above. */
|
||||
}else{
|
||||
@@ -2930,7 +2930,6 @@ int sqlite3VdbeReset(Vdbe *p){
|
||||
}
|
||||
}
|
||||
#endif
|
||||
p->iCurrentTime = 0;
|
||||
p->magic = VDBE_MAGIC_RESET;
|
||||
return p->rc & db->errMask;
|
||||
}
|
||||
@@ -2969,16 +2968,18 @@ void sqlite3VdbeDeleteAuxData(sqlite3 *db, AuxData **pp, int iOp, int mask){
|
||||
while( *pp ){
|
||||
AuxData *pAux = *pp;
|
||||
if( (iOp<0)
|
||||
|| (pAux->iOp==iOp && (pAux->iArg>31 || !(mask & MASKBIT32(pAux->iArg))))
|
||||
|| (pAux->iAuxOp==iOp
|
||||
&& pAux->iAuxArg>=0
|
||||
&& (pAux->iAuxArg>31 || !(mask & MASKBIT32(pAux->iAuxArg))))
|
||||
){
|
||||
testcase( pAux->iArg==31 );
|
||||
if( pAux->xDelete ){
|
||||
pAux->xDelete(pAux->pAux);
|
||||
testcase( pAux->iAuxArg==31 );
|
||||
if( pAux->xDeleteAux ){
|
||||
pAux->xDeleteAux(pAux->pAux);
|
||||
}
|
||||
*pp = pAux->pNext;
|
||||
*pp = pAux->pNextAux;
|
||||
sqlite3DbFree(db, pAux);
|
||||
}else{
|
||||
pp= &pAux->pNext;
|
||||
pp= &pAux->pNextAux;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3040,7 +3041,7 @@ void sqlite3VdbeDelete(Vdbe *p){
|
||||
}
|
||||
p->magic = VDBE_MAGIC_DEAD;
|
||||
p->db = 0;
|
||||
sqlite3DbFree(db, p);
|
||||
sqlite3DbFreeNN(db, p);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -4599,7 +4600,7 @@ static void vdbeFreeUnpacked(sqlite3 *db, int nField, UnpackedRecord *p){
|
||||
Mem *pMem = &p->aMem[i];
|
||||
if( pMem->zMalloc ) sqlite3VdbeMemRelease(pMem);
|
||||
}
|
||||
sqlite3DbFree(db, p);
|
||||
sqlite3DbFreeNN(db, p);
|
||||
}
|
||||
}
|
||||
#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
|
||||
@@ -4666,7 +4667,7 @@ void sqlite3VdbePreUpdateHook(
|
||||
for(i=0; i<pCsr->nField; i++){
|
||||
sqlite3VdbeMemRelease(&preupdate.aNew[i]);
|
||||
}
|
||||
sqlite3DbFree(db, preupdate.aNew);
|
||||
sqlite3DbFreeNN(db, preupdate.aNew);
|
||||
}
|
||||
}
|
||||
#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
|
||||
|
||||
+41
-33
@@ -40,6 +40,10 @@ int sqlite3VdbeCheckMemInvariants(Mem *p){
|
||||
/* Cannot be both MEM_Int and MEM_Real at the same time */
|
||||
assert( (p->flags & (MEM_Int|MEM_Real))!=(MEM_Int|MEM_Real) );
|
||||
|
||||
/* Cannot be both MEM_Null and some other type */
|
||||
assert( (p->flags & MEM_Null)==0 ||
|
||||
(p->flags & (MEM_Int|MEM_Real|MEM_Str|MEM_Blob))==0 );
|
||||
|
||||
/* The szMalloc field holds the correct memory allocation size */
|
||||
assert( p->szMalloc==0
|
||||
|| p->szMalloc==sqlite3DbMallocSize(p->db,p->zMalloc) );
|
||||
@@ -125,26 +129,24 @@ SQLITE_NOINLINE int sqlite3VdbeMemGrow(Mem *pMem, int n, int bPreserve){
|
||||
|
||||
assert( pMem->szMalloc==0
|
||||
|| pMem->szMalloc==sqlite3DbMallocSize(pMem->db, pMem->zMalloc) );
|
||||
if( pMem->szMalloc<n ){
|
||||
if( n<32 ) n = 32;
|
||||
if( bPreserve && pMem->szMalloc>0 && pMem->z==pMem->zMalloc ){
|
||||
pMem->z = pMem->zMalloc = sqlite3DbReallocOrFree(pMem->db, pMem->z, n);
|
||||
bPreserve = 0;
|
||||
}else{
|
||||
if( pMem->szMalloc>0 ) sqlite3DbFree(pMem->db, pMem->zMalloc);
|
||||
pMem->zMalloc = sqlite3DbMallocRaw(pMem->db, n);
|
||||
}
|
||||
if( pMem->zMalloc==0 ){
|
||||
sqlite3VdbeMemSetNull(pMem);
|
||||
pMem->z = 0;
|
||||
pMem->szMalloc = 0;
|
||||
return SQLITE_NOMEM_BKPT;
|
||||
}else{
|
||||
pMem->szMalloc = sqlite3DbMallocSize(pMem->db, pMem->zMalloc);
|
||||
}
|
||||
if( n<32 ) n = 32;
|
||||
if( bPreserve && pMem->szMalloc>0 && pMem->z==pMem->zMalloc ){
|
||||
pMem->z = pMem->zMalloc = sqlite3DbReallocOrFree(pMem->db, pMem->z, n);
|
||||
bPreserve = 0;
|
||||
}else{
|
||||
if( pMem->szMalloc>0 ) sqlite3DbFreeNN(pMem->db, pMem->zMalloc);
|
||||
pMem->zMalloc = sqlite3DbMallocRaw(pMem->db, n);
|
||||
}
|
||||
if( pMem->zMalloc==0 ){
|
||||
sqlite3VdbeMemSetNull(pMem);
|
||||
pMem->z = 0;
|
||||
pMem->szMalloc = 0;
|
||||
return SQLITE_NOMEM_BKPT;
|
||||
}else{
|
||||
pMem->szMalloc = sqlite3DbMallocSize(pMem->db, pMem->zMalloc);
|
||||
}
|
||||
|
||||
if( bPreserve && pMem->z && pMem->z!=pMem->zMalloc ){
|
||||
if( bPreserve && pMem->z && ALWAYS(pMem->z!=pMem->zMalloc) ){
|
||||
memcpy(pMem->zMalloc, pMem->z, pMem->n);
|
||||
}
|
||||
if( (pMem->flags&MEM_Dyn)!=0 ){
|
||||
@@ -341,7 +343,7 @@ int sqlite3VdbeMemFinalize(Mem *pMem, FuncDef *pFunc){
|
||||
ctx.pFunc = pFunc;
|
||||
pFunc->xFinalize(&ctx); /* IMP: R-24505-23230 */
|
||||
assert( (pMem->flags & MEM_Dyn)==0 );
|
||||
if( pMem->szMalloc>0 ) sqlite3DbFree(pMem->db, pMem->zMalloc);
|
||||
if( pMem->szMalloc>0 ) sqlite3DbFreeNN(pMem->db, pMem->zMalloc);
|
||||
memcpy(pMem, &t, sizeof(t));
|
||||
rc = ctx.isError;
|
||||
}
|
||||
@@ -392,7 +394,7 @@ static SQLITE_NOINLINE void vdbeMemClear(Mem *p){
|
||||
vdbeMemClearExternAndSetNull(p);
|
||||
}
|
||||
if( p->szMalloc ){
|
||||
sqlite3DbFree(p->db, p->zMalloc);
|
||||
sqlite3DbFreeNN(p->db, p->zMalloc);
|
||||
p->szMalloc = 0;
|
||||
}
|
||||
p->z = 0;
|
||||
@@ -420,7 +422,7 @@ void sqlite3VdbeMemRelease(Mem *p){
|
||||
** If the double is out of range of a 64-bit signed integer then
|
||||
** return the closest available 64-bit signed integer.
|
||||
*/
|
||||
static i64 doubleToInt64(double r){
|
||||
static SQLITE_NOINLINE i64 doubleToInt64(double r){
|
||||
#ifdef SQLITE_OMIT_FLOATING_POINT
|
||||
/* When floating-point is omitted, double and int64 are the same thing */
|
||||
return r;
|
||||
@@ -456,6 +458,11 @@ static i64 doubleToInt64(double r){
|
||||
**
|
||||
** If pMem represents a string value, its encoding might be changed.
|
||||
*/
|
||||
static SQLITE_NOINLINE i64 memIntValue(Mem *pMem){
|
||||
i64 value = 0;
|
||||
sqlite3Atoi64(pMem->z, &value, pMem->n, pMem->enc);
|
||||
return value;
|
||||
}
|
||||
i64 sqlite3VdbeIntValue(Mem *pMem){
|
||||
int flags;
|
||||
assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
|
||||
@@ -466,10 +473,8 @@ i64 sqlite3VdbeIntValue(Mem *pMem){
|
||||
}else if( flags & MEM_Real ){
|
||||
return doubleToInt64(pMem->u.r);
|
||||
}else if( flags & (MEM_Str|MEM_Blob) ){
|
||||
i64 value = 0;
|
||||
assert( pMem->z || pMem->n==0 );
|
||||
sqlite3Atoi64(pMem->z, &value, pMem->n, pMem->enc);
|
||||
return value;
|
||||
return memIntValue(pMem);
|
||||
}else{
|
||||
return 0;
|
||||
}
|
||||
@@ -481,6 +486,12 @@ i64 sqlite3VdbeIntValue(Mem *pMem){
|
||||
** value. If it is a string or blob, try to convert it to a double.
|
||||
** If it is a NULL, return 0.0.
|
||||
*/
|
||||
static SQLITE_NOINLINE double memRealValue(Mem *pMem){
|
||||
/* (double)0 In case of SQLITE_OMIT_FLOATING_POINT... */
|
||||
double val = (double)0;
|
||||
sqlite3AtoF(pMem->z, &val, pMem->n, pMem->enc);
|
||||
return val;
|
||||
}
|
||||
double sqlite3VdbeRealValue(Mem *pMem){
|
||||
assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
|
||||
assert( EIGHT_BYTE_ALIGNMENT(pMem) );
|
||||
@@ -489,10 +500,7 @@ double sqlite3VdbeRealValue(Mem *pMem){
|
||||
}else if( pMem->flags & MEM_Int ){
|
||||
return (double)pMem->u.i;
|
||||
}else if( pMem->flags & (MEM_Str|MEM_Blob) ){
|
||||
/* (double)0 In case of SQLITE_OMIT_FLOATING_POINT... */
|
||||
double val = (double)0;
|
||||
sqlite3AtoF(pMem->z, &val, pMem->n, pMem->enc);
|
||||
return val;
|
||||
return memRealValue(pMem);
|
||||
}else{
|
||||
/* (double)0 In case of SQLITE_OMIT_FLOATING_POINT... */
|
||||
return (double)0;
|
||||
@@ -1117,7 +1125,7 @@ static sqlite3_value *valueNew(sqlite3 *db, struct ValueNewStat4Ctx *p){
|
||||
pRec->aMem[i].db = db;
|
||||
}
|
||||
}else{
|
||||
sqlite3DbFree(db, pRec);
|
||||
sqlite3DbFreeNN(db, pRec);
|
||||
pRec = 0;
|
||||
}
|
||||
}
|
||||
@@ -1229,7 +1237,7 @@ static int valueFromFunction(
|
||||
for(i=0; i<nVal; i++){
|
||||
sqlite3ValueFree(apVal[i]);
|
||||
}
|
||||
sqlite3DbFree(db, apVal);
|
||||
sqlite3DbFreeNN(db, apVal);
|
||||
}
|
||||
|
||||
*ppVal = pVal;
|
||||
@@ -1428,7 +1436,7 @@ static void recordFunc(
|
||||
putVarint32(&aRet[1], iSerial);
|
||||
sqlite3VdbeSerialPut(&aRet[1+nSerial], argv[0], iSerial);
|
||||
sqlite3_result_blob(context, aRet, nRet, SQLITE_TRANSIENT);
|
||||
sqlite3DbFree(db, aRet);
|
||||
sqlite3DbFreeNN(db, aRet);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1655,7 +1663,7 @@ void sqlite3Stat4ProbeFree(UnpackedRecord *pRec){
|
||||
sqlite3VdbeMemRelease(&aMem[i]);
|
||||
}
|
||||
sqlite3KeyInfoUnref(pRec->pKeyInfo);
|
||||
sqlite3DbFree(db, pRec);
|
||||
sqlite3DbFreeNN(db, pRec);
|
||||
}
|
||||
}
|
||||
#endif /* ifdef SQLITE_ENABLE_STAT4 */
|
||||
@@ -1679,7 +1687,7 @@ void sqlite3ValueSetStr(
|
||||
void sqlite3ValueFree(sqlite3_value *v){
|
||||
if( !v ) return;
|
||||
sqlite3VdbeMemRelease((Mem *)v);
|
||||
sqlite3DbFree(((Mem*)v)->db, v);
|
||||
sqlite3DbFreeNN(((Mem*)v)->db, v);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
+26
-27
@@ -858,37 +858,36 @@ static int vdbeSorterCompareInt(
|
||||
assert( (s1>0 && s1<7) || s1==8 || s1==9 );
|
||||
assert( (s2>0 && s2<7) || s2==8 || s2==9 );
|
||||
|
||||
if( s1>7 && s2>7 ){
|
||||
if( s1==s2 ){
|
||||
/* The two values have the same sign. Compare using memcmp(). */
|
||||
static const u8 aLen[] = {0, 1, 2, 3, 4, 6, 8, 0, 0, 0 };
|
||||
const u8 n = aLen[s1];
|
||||
int i;
|
||||
res = 0;
|
||||
for(i=0; i<n; i++){
|
||||
if( (res = v1[i] - v2[i])!=0 ){
|
||||
if( ((v1[0] ^ v2[0]) & 0x80)!=0 ){
|
||||
res = v1[0] & 0x80 ? -1 : +1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}else if( s1>7 && s2>7 ){
|
||||
res = s1 - s2;
|
||||
}else{
|
||||
if( s1==s2 ){
|
||||
if( (*v1 ^ *v2) & 0x80 ){
|
||||
/* The two values have different signs */
|
||||
res = (*v1 & 0x80) ? -1 : +1;
|
||||
}else{
|
||||
/* The two values have the same sign. Compare using memcmp(). */
|
||||
static const u8 aLen[] = {0, 1, 2, 3, 4, 6, 8 };
|
||||
int i;
|
||||
res = 0;
|
||||
for(i=0; i<aLen[s1]; i++){
|
||||
if( (res = v1[i] - v2[i]) ) break;
|
||||
}
|
||||
}
|
||||
if( s2>7 ){
|
||||
res = +1;
|
||||
}else if( s1>7 ){
|
||||
res = -1;
|
||||
}else{
|
||||
if( s2>7 ){
|
||||
res = +1;
|
||||
}else if( s1>7 ){
|
||||
res = -1;
|
||||
}else{
|
||||
res = s1 - s2;
|
||||
}
|
||||
assert( res!=0 );
|
||||
res = s1 - s2;
|
||||
}
|
||||
assert( res!=0 );
|
||||
|
||||
if( res>0 ){
|
||||
if( *v1 & 0x80 ) res = -1;
|
||||
}else{
|
||||
if( *v2 & 0x80 ) res = +1;
|
||||
}
|
||||
if( res>0 ){
|
||||
if( *v1 & 0x80 ) res = -1;
|
||||
}else{
|
||||
if( *v2 & 0x80 ) res = +1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -1053,7 +1053,7 @@ FuncDef *sqlite3VtabOverloadFunction(
|
||||
if( NEVER(pExpr==0) ) return pDef;
|
||||
if( pExpr->op!=TK_COLUMN ) return pDef;
|
||||
pTab = pExpr->pTab;
|
||||
if( NEVER(pTab==0) ) return pDef;
|
||||
if( pTab==0 ) return pDef;
|
||||
if( !IsVirtual(pTab) ) return pDef;
|
||||
pVtab = sqlite3GetVTable(db, pTab)->pVtab;
|
||||
assert( pVtab!=0 );
|
||||
|
||||
+48
-11
@@ -1786,7 +1786,7 @@ static void whereLoopClearUnion(sqlite3 *db, WhereLoop *p){
|
||||
p->u.vtab.idxStr = 0;
|
||||
}else if( (p->wsFlags & WHERE_AUTO_INDEX)!=0 && p->u.btree.pIndex!=0 ){
|
||||
sqlite3DbFree(db, p->u.btree.pIndex->zColAff);
|
||||
sqlite3DbFree(db, p->u.btree.pIndex);
|
||||
sqlite3DbFreeNN(db, p->u.btree.pIndex);
|
||||
p->u.btree.pIndex = 0;
|
||||
}
|
||||
}
|
||||
@@ -1796,7 +1796,7 @@ static void whereLoopClearUnion(sqlite3 *db, WhereLoop *p){
|
||||
** Deallocate internal memory used by a WhereLoop object
|
||||
*/
|
||||
static void whereLoopClear(sqlite3 *db, WhereLoop *p){
|
||||
if( p->aLTerm!=p->aLTermSpace ) sqlite3DbFree(db, p->aLTerm);
|
||||
if( p->aLTerm!=p->aLTermSpace ) sqlite3DbFreeNN(db, p->aLTerm);
|
||||
whereLoopClearUnion(db, p);
|
||||
whereLoopInit(p);
|
||||
}
|
||||
@@ -1811,7 +1811,7 @@ static int whereLoopResize(sqlite3 *db, WhereLoop *p, int n){
|
||||
paNew = sqlite3DbMallocRawNN(db, sizeof(p->aLTerm[0])*n);
|
||||
if( paNew==0 ) return SQLITE_NOMEM_BKPT;
|
||||
memcpy(paNew, p->aLTerm, sizeof(p->aLTerm[0])*p->nLSlot);
|
||||
if( p->aLTerm!=p->aLTermSpace ) sqlite3DbFree(db, p->aLTerm);
|
||||
if( p->aLTerm!=p->aLTermSpace ) sqlite3DbFreeNN(db, p->aLTerm);
|
||||
p->aLTerm = paNew;
|
||||
p->nLSlot = n;
|
||||
return SQLITE_OK;
|
||||
@@ -1841,7 +1841,7 @@ static int whereLoopXfer(sqlite3 *db, WhereLoop *pTo, WhereLoop *pFrom){
|
||||
*/
|
||||
static void whereLoopDelete(sqlite3 *db, WhereLoop *p){
|
||||
whereLoopClear(db, p);
|
||||
sqlite3DbFree(db, p);
|
||||
sqlite3DbFreeNN(db, p);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1862,7 +1862,7 @@ static void whereInfoFree(sqlite3 *db, WhereInfo *pWInfo){
|
||||
pWInfo->pLoops = p->pNextLoop;
|
||||
whereLoopDelete(db, p);
|
||||
}
|
||||
sqlite3DbFree(db, pWInfo);
|
||||
sqlite3DbFreeNN(db, pWInfo);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3253,7 +3253,7 @@ static int whereLoopAddVirtual(
|
||||
}
|
||||
|
||||
if( p->needToFreeIdxStr ) sqlite3_free(p->idxStr);
|
||||
sqlite3DbFree(pParse->db, p);
|
||||
sqlite3DbFreeNN(pParse->db, p);
|
||||
return rc;
|
||||
}
|
||||
#endif /* SQLITE_OMIT_VIRTUALTABLE */
|
||||
@@ -3437,7 +3437,7 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){
|
||||
}
|
||||
|
||||
/*
|
||||
** Examine a WherePath (with the addition of the extra WhereLoop of the 5th
|
||||
** Examine a WherePath (with the addition of the extra WhereLoop of the 6th
|
||||
** parameters) to see if it outputs rows in the requested ORDER BY
|
||||
** (or GROUP BY) without requiring a separate sort operation. Return N:
|
||||
**
|
||||
@@ -3532,6 +3532,8 @@ static i8 wherePathSatisfiesOrderBy(
|
||||
if( pLoop->wsFlags & WHERE_VIRTUALTABLE ){
|
||||
if( pLoop->u.vtab.isOrdered ) obSat = obDone;
|
||||
break;
|
||||
}else{
|
||||
pLoop->u.btree.nIdxCol = 0;
|
||||
}
|
||||
iCur = pWInfo->pTabList->a[pLoop->iTab].iCursor;
|
||||
|
||||
@@ -3677,6 +3679,7 @@ static i8 wherePathSatisfiesOrderBy(
|
||||
if( !pColl ) pColl = db->pDfltColl;
|
||||
if( sqlite3StrICmp(pColl->zName, pIndex->azColl[j])!=0 ) continue;
|
||||
}
|
||||
pLoop->u.btree.nIdxCol = j+1;
|
||||
isMatch = 1;
|
||||
break;
|
||||
}
|
||||
@@ -4108,7 +4111,7 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
|
||||
|
||||
if( nFrom==0 ){
|
||||
sqlite3ErrorMsg(pParse, "no query solution");
|
||||
sqlite3DbFree(db, pSpace);
|
||||
sqlite3DbFreeNN(db, pSpace);
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
|
||||
@@ -4184,7 +4187,7 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
|
||||
pWInfo->nRowOut = pFrom->nRow;
|
||||
|
||||
/* Free temporary memory and return success */
|
||||
sqlite3DbFree(db, pSpace);
|
||||
sqlite3DbFreeNN(db, pSpace);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
@@ -4262,7 +4265,8 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){
|
||||
if( pLoop->wsFlags ){
|
||||
pLoop->nOut = (LogEst)1;
|
||||
pWInfo->a[0].pWLoop = pLoop;
|
||||
pLoop->maskSelf = sqlite3WhereGetMask(&pWInfo->sMaskSet, iCur);
|
||||
assert( pWInfo->sMaskSet.n==1 && iCur==pWInfo->sMaskSet.ix[0] );
|
||||
pLoop->maskSelf = 1; /* sqlite3WhereGetMask(&pWInfo->sMaskSet, iCur); */
|
||||
pWInfo->a[0].iTabCur = iCur;
|
||||
pWInfo->nRowOut = 1;
|
||||
if( pWInfo->pOrderBy ) pWInfo->nOBSat = pWInfo->pOrderBy->nExpr;
|
||||
@@ -4446,6 +4450,7 @@ WhereInfo *sqlite3WhereBegin(
|
||||
pWInfo->pParse = pParse;
|
||||
pWInfo->pTabList = pTabList;
|
||||
pWInfo->pOrderBy = pOrderBy;
|
||||
pWInfo->pWhere = pWhere;
|
||||
pWInfo->pResultSet = pResultSet;
|
||||
pWInfo->aiCurOnePass[0] = pWInfo->aiCurOnePass[1] = -1;
|
||||
pWInfo->nLevel = nTabList;
|
||||
@@ -4756,6 +4761,7 @@ WhereInfo *sqlite3WhereBegin(
|
||||
if( (pLoop->wsFlags & WHERE_CONSTRAINT)!=0
|
||||
&& (pLoop->wsFlags & (WHERE_COLUMN_RANGE|WHERE_SKIPSCAN))==0
|
||||
&& (pWInfo->wctrlFlags&WHERE_ORDERBY_MIN)==0
|
||||
&& pWInfo->eDistinct!=WHERE_DISTINCT_ORDERED
|
||||
){
|
||||
sqlite3VdbeChangeP5(v, OPFLAG_SEEKEQ); /* Hint to COMDB2 */
|
||||
}
|
||||
@@ -4844,14 +4850,43 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
|
||||
int addr;
|
||||
pLevel = &pWInfo->a[i];
|
||||
pLoop = pLevel->pWLoop;
|
||||
sqlite3VdbeResolveLabel(v, pLevel->addrCont);
|
||||
if( pLevel->op!=OP_Noop ){
|
||||
#ifndef SQLITE_DISABLE_SKIPAHEAD_DISTINCT
|
||||
int addrSeek = 0;
|
||||
Index *pIdx;
|
||||
int n;
|
||||
if( pWInfo->eDistinct==WHERE_DISTINCT_ORDERED
|
||||
&& (pLoop->wsFlags & WHERE_INDEXED)!=0
|
||||
&& (pIdx = pLoop->u.btree.pIndex)->hasStat1
|
||||
&& (n = pLoop->u.btree.nIdxCol)>0
|
||||
&& pIdx->aiRowLogEst[n]>=36
|
||||
){
|
||||
int r1 = pParse->nMem+1;
|
||||
int j, op;
|
||||
for(j=0; j<n; j++){
|
||||
sqlite3VdbeAddOp3(v, OP_Column, pLevel->iIdxCur, j, r1+j);
|
||||
}
|
||||
pParse->nMem += n+1;
|
||||
op = pLevel->op==OP_Prev ? OP_SeekLT : OP_SeekGT;
|
||||
addrSeek = sqlite3VdbeAddOp4Int(v, op, pLevel->iIdxCur, 0, r1, n);
|
||||
VdbeCoverageIf(v, op==OP_SeekLT);
|
||||
VdbeCoverageIf(v, op==OP_SeekGT);
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 1, pLevel->p2);
|
||||
}
|
||||
#endif /* SQLITE_DISABLE_SKIPAHEAD_DISTINCT */
|
||||
/* The common case: Advance to the next row */
|
||||
sqlite3VdbeResolveLabel(v, pLevel->addrCont);
|
||||
sqlite3VdbeAddOp3(v, pLevel->op, pLevel->p1, pLevel->p2, pLevel->p3);
|
||||
sqlite3VdbeChangeP5(v, pLevel->p5);
|
||||
VdbeCoverage(v);
|
||||
VdbeCoverageIf(v, pLevel->op==OP_Next);
|
||||
VdbeCoverageIf(v, pLevel->op==OP_Prev);
|
||||
VdbeCoverageIf(v, pLevel->op==OP_VNext);
|
||||
#ifndef SQLITE_DISABLE_SKIPAHEAD_DISTINCT
|
||||
if( addrSeek ) sqlite3VdbeJumpHere(v, addrSeek);
|
||||
#endif
|
||||
}else{
|
||||
sqlite3VdbeResolveLabel(v, pLevel->addrCont);
|
||||
}
|
||||
if( pLoop->wsFlags & WHERE_IN_ABLE && pLevel->u.in.nIn>0 ){
|
||||
struct InLoop *pIn;
|
||||
@@ -4974,6 +5009,8 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
|
||||
}else if( pOp->opcode==OP_Rowid ){
|
||||
pOp->p1 = pLevel->iIdxCur;
|
||||
pOp->opcode = OP_IdxRowid;
|
||||
}else if( pOp->opcode==OP_IfNullRow ){
|
||||
pOp->p1 = pLevel->iIdxCur;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,6 +124,7 @@ struct WhereLoop {
|
||||
u16 nEq; /* Number of equality constraints */
|
||||
u16 nBtm; /* Size of BTM vector */
|
||||
u16 nTop; /* Size of TOP vector */
|
||||
u16 nIdxCol; /* Index column used for ORDER BY */
|
||||
Index *pIndex; /* Index used, or NULL */
|
||||
} btree;
|
||||
struct { /* Information for virtual tables */
|
||||
@@ -417,6 +418,7 @@ struct WhereInfo {
|
||||
SrcList *pTabList; /* List of tables in the join */
|
||||
ExprList *pOrderBy; /* The ORDER BY clause or NULL */
|
||||
ExprList *pResultSet; /* Result set of the query */
|
||||
Expr *pWhere; /* The complete WHERE clause */
|
||||
LogEst iLimit; /* LIMIT if wctrlFlags has WHERE_USE_LIMIT */
|
||||
int aiCurOnePass[2]; /* OP_OpenWrite cursors for the ONEPASS opt */
|
||||
int iContinue; /* Jump here to continue with next record */
|
||||
|
||||
+118
-33
@@ -1039,6 +1039,69 @@ static void codeExprOrVector(Parse *pParse, Expr *p, int iReg, int nReg){
|
||||
}
|
||||
}
|
||||
|
||||
/* An instance of the IdxExprTrans object carries information about a
|
||||
** mapping from an expression on table columns into a column in an index
|
||||
** down through the Walker.
|
||||
*/
|
||||
typedef struct IdxExprTrans {
|
||||
Expr *pIdxExpr; /* The index expression */
|
||||
int iTabCur; /* The cursor of the corresponding table */
|
||||
int iIdxCur; /* The cursor for the index */
|
||||
int iIdxCol; /* The column for the index */
|
||||
} IdxExprTrans;
|
||||
|
||||
/* The walker node callback used to transform matching expressions into
|
||||
** a reference to an index column for an index on an expression.
|
||||
**
|
||||
** If pExpr matches, then transform it into a reference to the index column
|
||||
** that contains the value of pExpr.
|
||||
*/
|
||||
static int whereIndexExprTransNode(Walker *p, Expr *pExpr){
|
||||
IdxExprTrans *pX = p->u.pIdxTrans;
|
||||
if( sqlite3ExprCompare(pExpr, pX->pIdxExpr, pX->iTabCur)==0 ){
|
||||
pExpr->op = TK_COLUMN;
|
||||
pExpr->iTable = pX->iIdxCur;
|
||||
pExpr->iColumn = pX->iIdxCol;
|
||||
pExpr->pTab = 0;
|
||||
return WRC_Prune;
|
||||
}else{
|
||||
return WRC_Continue;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** For an indexes on expression X, locate every instance of expression X in pExpr
|
||||
** and change that subexpression into a reference to the appropriate column of
|
||||
** the index.
|
||||
*/
|
||||
static void whereIndexExprTrans(
|
||||
Index *pIdx, /* The Index */
|
||||
int iTabCur, /* Cursor of the table that is being indexed */
|
||||
int iIdxCur, /* Cursor of the index itself */
|
||||
WhereInfo *pWInfo /* Transform expressions in this WHERE clause */
|
||||
){
|
||||
int iIdxCol; /* Column number of the index */
|
||||
ExprList *aColExpr; /* Expressions that are indexed */
|
||||
Walker w;
|
||||
IdxExprTrans x;
|
||||
aColExpr = pIdx->aColExpr;
|
||||
if( aColExpr==0 ) return; /* Not an index on expressions */
|
||||
memset(&w, 0, sizeof(w));
|
||||
w.xExprCallback = whereIndexExprTransNode;
|
||||
w.u.pIdxTrans = &x;
|
||||
x.iTabCur = iTabCur;
|
||||
x.iIdxCur = iIdxCur;
|
||||
for(iIdxCol=0; iIdxCol<aColExpr->nExpr; iIdxCol++){
|
||||
if( pIdx->aiColumn[iIdxCol]!=XN_EXPR ) continue;
|
||||
assert( aColExpr->a[iIdxCol].pExpr!=0 );
|
||||
x.iIdxCol = iIdxCol;
|
||||
x.pIdxExpr = aColExpr->a[iIdxCol].pExpr;
|
||||
sqlite3WalkExpr(&w, pWInfo->pWhere);
|
||||
sqlite3WalkExprList(&w, pWInfo->pOrderBy);
|
||||
sqlite3WalkExprList(&w, pWInfo->pResultSet);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate code for the start of the iLevel-th loop in the WHERE clause
|
||||
** implementation described by pWInfo.
|
||||
@@ -1066,6 +1129,8 @@ Bitmask sqlite3WhereCodeOneLoopStart(
|
||||
int addrCont; /* Jump here to continue with next cycle */
|
||||
int iRowidReg = 0; /* Rowid is stored in this register, if not zero */
|
||||
int iReleaseReg = 0; /* Temp register to free before returning */
|
||||
Index *pIdx = 0; /* Index used by loop (if any) */
|
||||
int loopAgain; /* True if constraint generator loop should repeat */
|
||||
|
||||
pParse = pWInfo->pParse;
|
||||
v = pParse->pVdbe;
|
||||
@@ -1391,7 +1456,6 @@ Bitmask sqlite3WhereCodeOneLoopStart(
|
||||
int endEq; /* True if range end uses ==, >= or <= */
|
||||
int start_constraints; /* Start of range is constrained */
|
||||
int nConstraint; /* Number of constraint terms */
|
||||
Index *pIdx; /* The index we will be using */
|
||||
int iIdxCur; /* The VDBE cursor for the index */
|
||||
int nExtraReg = 0; /* Number of extra registers needed */
|
||||
int op; /* Instruction opcode */
|
||||
@@ -1620,6 +1684,13 @@ Bitmask sqlite3WhereCodeOneLoopStart(
|
||||
iRowidReg, pPk->nKeyCol); VdbeCoverage(v);
|
||||
}
|
||||
|
||||
/* If pIdx is an index on one or more expressions, then look through
|
||||
** all the expressions in pWInfo and try to transform matching expressions
|
||||
** into reference to index columns.
|
||||
*/
|
||||
whereIndexExprTrans(pIdx, iCur, iIdxCur, pWInfo);
|
||||
|
||||
|
||||
/* Record the instruction used to terminate the loop. */
|
||||
if( pLoop->wsFlags & WHERE_ONEROW ){
|
||||
pLevel->op = OP_Noop;
|
||||
@@ -1635,6 +1706,7 @@ Bitmask sqlite3WhereCodeOneLoopStart(
|
||||
}else{
|
||||
assert( pLevel->p5==0 );
|
||||
}
|
||||
if( omitTable ) pIdx = 0;
|
||||
}else
|
||||
|
||||
#ifndef SQLITE_OMIT_OR_OPTIMIZATION
|
||||
@@ -1952,43 +2024,56 @@ Bitmask sqlite3WhereCodeOneLoopStart(
|
||||
|
||||
/* Insert code to test every subexpression that can be completely
|
||||
** computed using the current set of tables.
|
||||
**
|
||||
** This loop may run either once (pIdx==0) or twice (pIdx!=0). If
|
||||
** it is run twice, then the first iteration codes those sub-expressions
|
||||
** that can be computed using columns from pIdx only (without seeking
|
||||
** the main table cursor).
|
||||
*/
|
||||
for(pTerm=pWC->a, j=pWC->nTerm; j>0; j--, pTerm++){
|
||||
Expr *pE;
|
||||
int skipLikeAddr = 0;
|
||||
testcase( pTerm->wtFlags & TERM_VIRTUAL );
|
||||
testcase( pTerm->wtFlags & TERM_CODED );
|
||||
if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue;
|
||||
if( (pTerm->prereqAll & pLevel->notReady)!=0 ){
|
||||
testcase( pWInfo->untestedTerms==0
|
||||
&& (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)!=0 );
|
||||
pWInfo->untestedTerms = 1;
|
||||
continue;
|
||||
}
|
||||
pE = pTerm->pExpr;
|
||||
assert( pE!=0 );
|
||||
if( pLevel->iLeftJoin && !ExprHasProperty(pE, EP_FromJoin) ){
|
||||
continue;
|
||||
}
|
||||
if( pTerm->wtFlags & TERM_LIKECOND ){
|
||||
/* If the TERM_LIKECOND flag is set, that means that the range search
|
||||
** is sufficient to guarantee that the LIKE operator is true, so we
|
||||
** can skip the call to the like(A,B) function. But this only works
|
||||
** for strings. So do not skip the call to the function on the pass
|
||||
** that compares BLOBs. */
|
||||
do{
|
||||
loopAgain = 0;
|
||||
for(pTerm=pWC->a, j=pWC->nTerm; j>0; j--, pTerm++){
|
||||
Expr *pE;
|
||||
int skipLikeAddr = 0;
|
||||
testcase( pTerm->wtFlags & TERM_VIRTUAL );
|
||||
testcase( pTerm->wtFlags & TERM_CODED );
|
||||
if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue;
|
||||
if( (pTerm->prereqAll & pLevel->notReady)!=0 ){
|
||||
testcase( pWInfo->untestedTerms==0
|
||||
&& (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)!=0 );
|
||||
pWInfo->untestedTerms = 1;
|
||||
continue;
|
||||
}
|
||||
pE = pTerm->pExpr;
|
||||
assert( pE!=0 );
|
||||
if( pLevel->iLeftJoin && !ExprHasProperty(pE, EP_FromJoin) ){
|
||||
continue;
|
||||
}
|
||||
if( pIdx && !sqlite3ExprCoveredByIndex(pE, pLevel->iTabCur, pIdx) ){
|
||||
loopAgain = 1;
|
||||
continue;
|
||||
}
|
||||
if( pTerm->wtFlags & TERM_LIKECOND ){
|
||||
/* If the TERM_LIKECOND flag is set, that means that the range search
|
||||
** is sufficient to guarantee that the LIKE operator is true, so we
|
||||
** can skip the call to the like(A,B) function. But this only works
|
||||
** for strings. So do not skip the call to the function on the pass
|
||||
** that compares BLOBs. */
|
||||
#ifdef SQLITE_LIKE_DOESNT_MATCH_BLOBS
|
||||
continue;
|
||||
continue;
|
||||
#else
|
||||
u32 x = pLevel->iLikeRepCntr;
|
||||
assert( x>0 );
|
||||
skipLikeAddr = sqlite3VdbeAddOp1(v, (x&1)? OP_IfNot : OP_If, (int)(x>>1));
|
||||
VdbeCoverage(v);
|
||||
u32 x = pLevel->iLikeRepCntr;
|
||||
assert( x>0 );
|
||||
skipLikeAddr = sqlite3VdbeAddOp1(v, (x&1)?OP_IfNot:OP_If, (int)(x>>1));
|
||||
VdbeCoverage(v);
|
||||
#endif
|
||||
}
|
||||
sqlite3ExprIfFalse(pParse, pE, addrCont, SQLITE_JUMPIFNULL);
|
||||
if( skipLikeAddr ) sqlite3VdbeJumpHere(v, skipLikeAddr);
|
||||
pTerm->wtFlags |= TERM_CODED;
|
||||
}
|
||||
sqlite3ExprIfFalse(pParse, pE, addrCont, SQLITE_JUMPIFNULL);
|
||||
if( skipLikeAddr ) sqlite3VdbeJumpHere(v, skipLikeAddr);
|
||||
pTerm->wtFlags |= TERM_CODED;
|
||||
}
|
||||
pIdx = 0;
|
||||
}while( loopAgain );
|
||||
|
||||
/* Insert code to test for implied constraints based on transitivity
|
||||
** of the "==" operator.
|
||||
|
||||
+37
-31
@@ -830,8 +830,8 @@ static Bitmask exprSelectUsage(WhereMaskSet *pMaskSet, Select *pS){
|
||||
** Expression pExpr is one operand of a comparison operator that might
|
||||
** be useful for indexing. This routine checks to see if pExpr appears
|
||||
** in any index. Return TRUE (1) if pExpr is an indexed term and return
|
||||
** FALSE (0) if not. If TRUE is returned, also set *piCur to the cursor
|
||||
** number of the table that is indexed and *piColumn to the column number
|
||||
** FALSE (0) if not. If TRUE is returned, also set aiCurCol[0] to the cursor
|
||||
** number of the table that is indexed and aiCurCol[1] to the column number
|
||||
** of the column that is indexed, or XN_EXPR (-2) if an expression is being
|
||||
** indexed.
|
||||
**
|
||||
@@ -839,18 +839,37 @@ static Bitmask exprSelectUsage(WhereMaskSet *pMaskSet, Select *pS){
|
||||
** true even if that particular column is not indexed, because the column
|
||||
** might be added to an automatic index later.
|
||||
*/
|
||||
static int exprMightBeIndexed(
|
||||
static SQLITE_NOINLINE int exprMightBeIndexed2(
|
||||
SrcList *pFrom, /* The FROM clause */
|
||||
int op, /* The specific comparison operator */
|
||||
Bitmask mPrereq, /* Bitmask of FROM clause terms referenced by pExpr */
|
||||
Expr *pExpr, /* An operand of a comparison operator */
|
||||
int *piCur, /* Write the referenced table cursor number here */
|
||||
int *piColumn /* Write the referenced table column number here */
|
||||
int *aiCurCol, /* Write the referenced table cursor and column here */
|
||||
Expr *pExpr /* An operand of a comparison operator */
|
||||
){
|
||||
Index *pIdx;
|
||||
int i;
|
||||
int iCur;
|
||||
|
||||
for(i=0; mPrereq>1; i++, mPrereq>>=1){}
|
||||
iCur = pFrom->a[i].iCursor;
|
||||
for(pIdx=pFrom->a[i].pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
||||
if( pIdx->aColExpr==0 ) continue;
|
||||
for(i=0; i<pIdx->nKeyCol; i++){
|
||||
if( pIdx->aiColumn[i]!=XN_EXPR ) continue;
|
||||
if( sqlite3ExprCompareSkip(pExpr, pIdx->aColExpr->a[i].pExpr, iCur)==0 ){
|
||||
aiCurCol[0] = iCur;
|
||||
aiCurCol[1] = XN_EXPR;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
static int exprMightBeIndexed(
|
||||
SrcList *pFrom, /* The FROM clause */
|
||||
Bitmask mPrereq, /* Bitmask of FROM clause terms referenced by pExpr */
|
||||
int *aiCurCol, /* Write the referenced table cursor & column here */
|
||||
Expr *pExpr, /* An operand of a comparison operator */
|
||||
int op /* The specific comparison operator */
|
||||
){
|
||||
/* If this expression is a vector to the left or right of a
|
||||
** inequality constraint (>, <, >= or <=), perform the processing
|
||||
** on the first element of the vector. */
|
||||
@@ -862,26 +881,13 @@ static int exprMightBeIndexed(
|
||||
}
|
||||
|
||||
if( pExpr->op==TK_COLUMN ){
|
||||
*piCur = pExpr->iTable;
|
||||
*piColumn = pExpr->iColumn;
|
||||
aiCurCol[0] = pExpr->iTable;
|
||||
aiCurCol[1] = pExpr->iColumn;
|
||||
return 1;
|
||||
}
|
||||
if( mPrereq==0 ) return 0; /* No table references */
|
||||
if( (mPrereq&(mPrereq-1))!=0 ) return 0; /* Refs more than one table */
|
||||
for(i=0; mPrereq>1; i++, mPrereq>>=1){}
|
||||
iCur = pFrom->a[i].iCursor;
|
||||
for(pIdx=pFrom->a[i].pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
||||
if( pIdx->aColExpr==0 ) continue;
|
||||
for(i=0; i<pIdx->nKeyCol; i++){
|
||||
if( pIdx->aiColumn[i]!=XN_EXPR ) continue;
|
||||
if( sqlite3ExprCompareSkip(pExpr, pIdx->aColExpr->a[i].pExpr, iCur)==0 ){
|
||||
*piCur = iCur;
|
||||
*piColumn = XN_EXPR;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
return exprMightBeIndexed2(pFrom,mPrereq,aiCurCol,pExpr);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -961,7 +967,7 @@ static void exprAnalyze(
|
||||
pTerm->iParent = -1;
|
||||
pTerm->eOperator = 0;
|
||||
if( allowedOp(op) ){
|
||||
int iCur, iColumn;
|
||||
int aiCurCol[2];
|
||||
Expr *pLeft = sqlite3ExprSkipCollate(pExpr->pLeft);
|
||||
Expr *pRight = sqlite3ExprSkipCollate(pExpr->pRight);
|
||||
u16 opMask = (pTerm->prereqRight & prereqLeft)==0 ? WO_ALL : WO_EQUIV;
|
||||
@@ -972,14 +978,14 @@ static void exprAnalyze(
|
||||
pLeft = pLeft->x.pList->a[pTerm->iField-1].pExpr;
|
||||
}
|
||||
|
||||
if( exprMightBeIndexed(pSrc, op, prereqLeft, pLeft, &iCur, &iColumn) ){
|
||||
pTerm->leftCursor = iCur;
|
||||
pTerm->u.leftColumn = iColumn;
|
||||
if( exprMightBeIndexed(pSrc, prereqLeft, aiCurCol, pLeft, op) ){
|
||||
pTerm->leftCursor = aiCurCol[0];
|
||||
pTerm->u.leftColumn = aiCurCol[1];
|
||||
pTerm->eOperator = operatorMask(op) & opMask;
|
||||
}
|
||||
if( op==TK_IS ) pTerm->wtFlags |= TERM_IS;
|
||||
if( pRight
|
||||
&& exprMightBeIndexed(pSrc, op, pTerm->prereqRight, pRight, &iCur,&iColumn)
|
||||
&& exprMightBeIndexed(pSrc, pTerm->prereqRight, aiCurCol, pRight, op)
|
||||
){
|
||||
WhereTerm *pNew;
|
||||
Expr *pDup;
|
||||
@@ -1009,8 +1015,8 @@ static void exprAnalyze(
|
||||
pNew = pTerm;
|
||||
}
|
||||
exprCommute(pParse, pDup);
|
||||
pNew->leftCursor = iCur;
|
||||
pNew->u.leftColumn = iColumn;
|
||||
pNew->leftCursor = aiCurCol[0];
|
||||
pNew->u.leftColumn = aiCurCol[1];
|
||||
testcase( (prereqLeft | extraRight) != prereqLeft );
|
||||
pNew->prereqRight = prereqLeft | extraRight;
|
||||
pNew->prereqAll = prereqAll;
|
||||
|
||||
@@ -36,12 +36,20 @@ proc_real proc {name arguments script} {
|
||||
do_test auth-1.1.1 {
|
||||
db close
|
||||
set ::DB [sqlite3 db test.db]
|
||||
proc authx {code arg1 arg2 arg3 arg4 args} {return SQLITE_DENY}
|
||||
proc auth {code arg1 arg2 arg3 arg4 args} {
|
||||
if {$code=="SQLITE_INSERT" && $arg1=="sqlite_master"} {
|
||||
return SQLITE_DENY
|
||||
}
|
||||
return SQLITE_OK
|
||||
}
|
||||
db authorizer ::authx
|
||||
# EVIDENCE-OF: R-03993-24285 Only a single authorizer can be in place on
|
||||
# a database connection at a time. Each call to sqlite3_set_authorizer
|
||||
# overrides the previous call.
|
||||
#
|
||||
# The authx authorizer above is overridden by the auth authorizer below
|
||||
# authx is never invoked.
|
||||
db authorizer ::auth
|
||||
catchsql {CREATE TABLE t1(a,b,c)}
|
||||
} {1 {not authorized}}
|
||||
@@ -60,6 +68,9 @@ do_test auth-1.1.4 {
|
||||
do_test auth-1.2 {
|
||||
execsql {SELECT name FROM sqlite_master}
|
||||
} {}
|
||||
# EVIDENCE-OF: R-04452-49349 When the callback returns SQLITE_DENY, the
|
||||
# sqlite3_prepare_v2() or equivalent call that triggered the authorizer
|
||||
# will fail with an error message explaining that access is denied.
|
||||
do_test auth-1.3.1 {
|
||||
proc auth {code arg1 arg2 arg3 arg4 args} {
|
||||
if {$code=="SQLITE_CREATE_TABLE"} {
|
||||
@@ -312,6 +323,10 @@ ifcapable attach {
|
||||
} {1 {access to two.t2.b is prohibited}}
|
||||
execsql {DETACH DATABASE two}
|
||||
}
|
||||
# EVIDENCE-OF: R-38392-49970 If the action code is SQLITE_READ and the
|
||||
# callback returns SQLITE_IGNORE then the prepared statement statement
|
||||
# is constructed to substitute a NULL value in place of the table column
|
||||
# that would have been read if SQLITE_OK had been returned.
|
||||
do_test auth-1.36 {
|
||||
proc auth {code arg1 arg2 arg3 arg4 args} {
|
||||
if {$code=="SQLITE_READ" && $arg1=="t2" && $arg2=="b"} {
|
||||
@@ -1606,6 +1621,8 @@ do_test auth-1.248 {
|
||||
set ::authargs
|
||||
} {COMMIT {} {} {}}
|
||||
do_test auth-1.249 {
|
||||
# EVIDENCE-OF: R-52112-44167 Disable the authorizer by installing a NULL
|
||||
# callback.
|
||||
db authorizer {}
|
||||
catchsql {ROLLBACK}
|
||||
} {0 {}}
|
||||
@@ -2478,6 +2495,57 @@ do_test auth-7.4 {
|
||||
SQLITE_READ t7 c main {} \
|
||||
]
|
||||
|
||||
# If a table is referenced but no columns are read from the table,
|
||||
# that causes a single SQLITE_READ authorization with a NULL column
|
||||
# name.
|
||||
#
|
||||
# EVIDENCE-OF: R-31520-16302 When a table is referenced by a SELECT but
|
||||
# no column values are extracted from that table (for example in a query
|
||||
# like "SELECT count(*) FROM tab") then the SQLITE_READ authorizer
|
||||
# callback is invoked once for that table with a column name that is an
|
||||
# empty string.
|
||||
#
|
||||
set ::authargs [list]
|
||||
do_test auth-8.1 {
|
||||
execsql {SELECT count(*) FROM t7}
|
||||
set ::authargs
|
||||
} [list \
|
||||
SQLITE_SELECT {} {} {} {} \
|
||||
SQLITE_FUNCTION {} count {} {} \
|
||||
SQLITE_READ t7 {} {} {} \
|
||||
]
|
||||
set ::authargs [list]
|
||||
|
||||
do_test auth-8.2 {
|
||||
execsql {SELECT t6.a FROM t6, t7}
|
||||
set ::authargs
|
||||
} [list \
|
||||
SQLITE_SELECT {} {} {} {} \
|
||||
SQLITE_READ t6 a main {} \
|
||||
SQLITE_READ t7 {} {} {} \
|
||||
]
|
||||
|
||||
# Test also that if SQLITE_DENY is returned from an SQLITE_READ authorizer
|
||||
# invocation with no column name specified, compilation fails.
|
||||
#
|
||||
set ::authargs [list]
|
||||
proc auth {op a b c d} {
|
||||
lappend ::authargs $op $a $b $c $d
|
||||
if {$op == "SQLITE_READ"} { return "SQLITE_DENY" }
|
||||
return "SQLITE_OK"
|
||||
}
|
||||
set ::authargs [list]
|
||||
do_catchsql_test auth-8.3 {
|
||||
SELECT count(*) FROM t7
|
||||
} {1 {not authorized}}
|
||||
do_test auth-8.4 {
|
||||
set ::authargs
|
||||
} [list \
|
||||
SQLITE_SELECT {} {} {} {} \
|
||||
SQLITE_FUNCTION {} count {} {} \
|
||||
SQLITE_READ t7 {} {} {} \
|
||||
]
|
||||
|
||||
|
||||
rename proc {}
|
||||
rename proc_real proc
|
||||
|
||||
@@ -53,6 +53,10 @@ do_test auth3.1.2 {
|
||||
set ::authcode SQLITE_DENY
|
||||
catchsql { DELETE FROM t1 }
|
||||
} {1 {not authorized}}
|
||||
# EVIDENCE-OF: R-64962-58611 If the authorizer callback returns any
|
||||
# value other than SQLITE_IGNORE, SQLITE_OK, or SQLITE_DENY then the
|
||||
# sqlite3_prepare_v2() or equivalent call that triggered the authorizer
|
||||
# will fail with an error message.
|
||||
do_test auth3.1.3 {
|
||||
set ::authcode SQLITE_INVALID
|
||||
catchsql { DELETE FROM t1 }
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
# 2017 April 26
|
||||
#
|
||||
# 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 cachespill
|
||||
|
||||
ifcapable !pager_pragmas {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test that "PRAGMA cache_spill = 0" completely disables cache spilling.
|
||||
#
|
||||
do_execsql_test 1.1 {
|
||||
PRAGMA auto_vacuum = 0;
|
||||
PRAGMA page_size = 1024;
|
||||
PRAGMA cache_size = 100;
|
||||
CREATE TABLE t1(a);
|
||||
}
|
||||
|
||||
do_test 1.2 {
|
||||
file size test.db
|
||||
} {2048}
|
||||
|
||||
do_test 1.3 {
|
||||
execsql {
|
||||
BEGIN;
|
||||
WITH s(i) AS (
|
||||
SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<200
|
||||
) INSERT INTO t1 SELECT randomblob(900) FROM s;
|
||||
}
|
||||
expr {[file size test.db] > 50000}
|
||||
} {1}
|
||||
|
||||
do_test 1.4 {
|
||||
execsql ROLLBACK
|
||||
file size test.db
|
||||
} {2048}
|
||||
|
||||
do_test 1.5 {
|
||||
execsql {
|
||||
PRAGMA cache_spill = 0;
|
||||
BEGIN;
|
||||
WITH s(i) AS (
|
||||
SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<200
|
||||
) INSERT INTO t1 SELECT randomblob(900) FROM s;
|
||||
}
|
||||
file size test.db
|
||||
} {2048}
|
||||
|
||||
do_test 1.5 {
|
||||
execsql {
|
||||
ROLLBACK;
|
||||
PRAGMA cache_spill = 1;
|
||||
BEGIN;
|
||||
WITH s(i) AS (
|
||||
SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<200
|
||||
) INSERT INTO t1 SELECT randomblob(900) FROM s;
|
||||
}
|
||||
expr {[file size test.db] > 50000}
|
||||
} {1}
|
||||
|
||||
do_execsql_test 1.6 { ROLLBACK }
|
||||
|
||||
|
||||
finish_test
|
||||
+58
-44
@@ -19,13 +19,14 @@
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix conflict3
|
||||
|
||||
ifcapable !conflict {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
do_execsql_test conflict-1.1 {
|
||||
do_execsql_test 1.1 {
|
||||
CREATE TABLE t1(
|
||||
a INTEGER PRIMARY KEY ON CONFLICT REPLACE,
|
||||
b UNIQUE ON CONFLICT IGNORE,
|
||||
@@ -37,7 +38,7 @@ do_execsql_test conflict-1.1 {
|
||||
|
||||
# Insert a row that conflicts on column B. The insert should be ignored.
|
||||
#
|
||||
do_execsql_test conflict-1.2 {
|
||||
do_execsql_test 1.2 {
|
||||
INSERT INTO t1(a,b,c) VALUES(3,2,5);
|
||||
SELECT a,b,c FROM t1 ORDER BY a;
|
||||
} {1 2 3 2 3 4}
|
||||
@@ -45,16 +46,16 @@ do_execsql_test conflict-1.2 {
|
||||
# Insert two rows where the second conflicts on C. The first row show go
|
||||
# and and then there should be a constraint error.
|
||||
#
|
||||
do_test conflict-1.3 {
|
||||
do_test 1.3 {
|
||||
catchsql {INSERT INTO t1(a,b,c) VALUES(4,5,6), (5,6,4);}
|
||||
} {1 {UNIQUE constraint failed: t1.c}}
|
||||
do_execsql_test conflict-1.4 {
|
||||
do_execsql_test 1.4 {
|
||||
SELECT a,b,c FROM t1 ORDER BY a;
|
||||
} {1 2 3 2 3 4 4 5 6}
|
||||
|
||||
# Replete the tests above, but this time on a table non-INTEGER primary key.
|
||||
#
|
||||
do_execsql_test conflict-2.1 {
|
||||
do_execsql_test 2.1 {
|
||||
DROP TABLE t1;
|
||||
CREATE TABLE t1(
|
||||
a INT PRIMARY KEY ON CONFLICT REPLACE,
|
||||
@@ -67,7 +68,7 @@ do_execsql_test conflict-2.1 {
|
||||
|
||||
# Insert a row that conflicts on column B. The insert should be ignored.
|
||||
#
|
||||
do_execsql_test conflict-2.2 {
|
||||
do_execsql_test 2.2 {
|
||||
INSERT INTO t1(a,b,c) VALUES(3,2,5);
|
||||
SELECT a,b,c FROM t1 ORDER BY a;
|
||||
} {1 2 3 2 3 4}
|
||||
@@ -75,16 +76,16 @@ do_execsql_test conflict-2.2 {
|
||||
# Insert two rows where the second conflicts on C. The first row show go
|
||||
# and and then there should be a constraint error.
|
||||
#
|
||||
do_test conflict-2.3 {
|
||||
do_test 2.3 {
|
||||
catchsql {INSERT INTO t1(a,b,c) VALUES(4,5,6), (5,6,4);}
|
||||
} {1 {UNIQUE constraint failed: t1.c}}
|
||||
do_execsql_test conflict-2.4 {
|
||||
do_execsql_test 2.4 {
|
||||
SELECT a,b,c FROM t1 ORDER BY a;
|
||||
} {1 2 3 2 3 4 4 5 6}
|
||||
|
||||
# Replete again on a WITHOUT ROWID table.
|
||||
#
|
||||
do_execsql_test conflict-3.1 {
|
||||
do_execsql_test 3.1 {
|
||||
DROP TABLE t1;
|
||||
CREATE TABLE t1(
|
||||
a INT PRIMARY KEY ON CONFLICT REPLACE,
|
||||
@@ -97,7 +98,7 @@ do_execsql_test conflict-3.1 {
|
||||
|
||||
# Insert a row that conflicts on column B. The insert should be ignored.
|
||||
#
|
||||
do_execsql_test conflict-3.2 {
|
||||
do_execsql_test 3.2 {
|
||||
INSERT INTO t1(a,b,c) VALUES(3,2,5);
|
||||
SELECT a,b,c FROM t1 ORDER BY a;
|
||||
} {1 2 3 2 3 4}
|
||||
@@ -105,16 +106,16 @@ do_execsql_test conflict-3.2 {
|
||||
# Insert two rows where the second conflicts on C. The first row show go
|
||||
# and and then there should be a constraint error.
|
||||
#
|
||||
do_test conflict-3.3 {
|
||||
do_test 3.3 {
|
||||
catchsql {INSERT INTO t1(a,b,c) VALUES(4,5,6), (5,6,4);}
|
||||
} {1 {UNIQUE constraint failed: t1.c}}
|
||||
do_execsql_test conflict-3.4 {
|
||||
do_execsql_test 3.4 {
|
||||
SELECT a,b,c FROM t1 ORDER BY a;
|
||||
} {1 2 3 2 3 4 4 5 6}
|
||||
|
||||
# Arrange the table rows in a different order and repeat.
|
||||
#
|
||||
do_execsql_test conflict-4.1 {
|
||||
do_execsql_test 4.1 {
|
||||
DROP TABLE t1;
|
||||
CREATE TABLE t1(
|
||||
b UNIQUE ON CONFLICT IGNORE,
|
||||
@@ -127,7 +128,7 @@ do_execsql_test conflict-4.1 {
|
||||
|
||||
# Insert a row that conflicts on column B. The insert should be ignored.
|
||||
#
|
||||
do_execsql_test conflict-4.2 {
|
||||
do_execsql_test 4.2 {
|
||||
INSERT INTO t1(a,b,c) VALUES(3,2,5);
|
||||
SELECT a,b,c FROM t1 ORDER BY a;
|
||||
} {1 2 3 2 3 4}
|
||||
@@ -135,16 +136,16 @@ do_execsql_test conflict-4.2 {
|
||||
# Insert two rows where the second conflicts on C. The first row show go
|
||||
# and and then there should be a constraint error.
|
||||
#
|
||||
do_test conflict-4.3 {
|
||||
do_test 4.3 {
|
||||
catchsql {INSERT INTO t1(a,b,c) VALUES(4,5,6), (5,6,4);}
|
||||
} {1 {UNIQUE constraint failed: t1.c}}
|
||||
do_execsql_test conflict-4.4 {
|
||||
do_execsql_test 4.4 {
|
||||
SELECT a,b,c FROM t1 ORDER BY a;
|
||||
} {1 2 3 2 3 4 4 5 6}
|
||||
|
||||
# Arrange the table rows in a different order and repeat.
|
||||
#
|
||||
do_execsql_test conflict-5.1 {
|
||||
do_execsql_test 5.1 {
|
||||
DROP TABLE t1;
|
||||
CREATE TABLE t1(
|
||||
b UNIQUE ON CONFLICT IGNORE,
|
||||
@@ -157,7 +158,7 @@ do_execsql_test conflict-5.1 {
|
||||
|
||||
# Insert a row that conflicts on column B. The insert should be ignored.
|
||||
#
|
||||
do_execsql_test conflict-5.2 {
|
||||
do_execsql_test 5.2 {
|
||||
INSERT INTO t1(a,b,c) VALUES(3,2,5);
|
||||
SELECT a,b,c FROM t1 ORDER BY a;
|
||||
} {1 2 3 2 3 4}
|
||||
@@ -165,16 +166,16 @@ do_execsql_test conflict-5.2 {
|
||||
# Insert two rows where the second conflicts on C. The first row show go
|
||||
# and and then there should be a constraint error.
|
||||
#
|
||||
do_test conflict-5.3 {
|
||||
do_test 5.3 {
|
||||
catchsql {INSERT INTO t1(a,b,c) VALUES(4,5,6), (5,6,4);}
|
||||
} {1 {UNIQUE constraint failed: t1.c}}
|
||||
do_execsql_test conflict-5.4 {
|
||||
do_execsql_test 5.4 {
|
||||
SELECT a,b,c FROM t1 ORDER BY a;
|
||||
} {1 2 3 2 3 4 4 5 6}
|
||||
|
||||
# Arrange the table rows in a different order and repeat.
|
||||
#
|
||||
do_execsql_test conflict-6.1 {
|
||||
do_execsql_test 6.1 {
|
||||
DROP TABLE t1;
|
||||
CREATE TABLE t1(
|
||||
c UNIQUE ON CONFLICT FAIL,
|
||||
@@ -187,7 +188,7 @@ do_execsql_test conflict-6.1 {
|
||||
|
||||
# Insert a row that conflicts on column B. The insert should be ignored.
|
||||
#
|
||||
do_execsql_test conflict-6.2 {
|
||||
do_execsql_test 6.2 {
|
||||
INSERT INTO t1(a,b,c) VALUES(3,2,5);
|
||||
SELECT a,b,c FROM t1 ORDER BY a;
|
||||
} {1 2 3 2 3 4}
|
||||
@@ -195,16 +196,16 @@ do_execsql_test conflict-6.2 {
|
||||
# Insert two rows where the second conflicts on C. The first row show go
|
||||
# and and then there should be a constraint error.
|
||||
#
|
||||
do_test conflict-6.3 {
|
||||
do_test 6.3 {
|
||||
catchsql {INSERT INTO t1(a,b,c) VALUES(4,5,6), (5,6,4);}
|
||||
} {1 {UNIQUE constraint failed: t1.c}}
|
||||
do_execsql_test conflict-6.4 {
|
||||
do_execsql_test 6.4 {
|
||||
SELECT a,b,c FROM t1 ORDER BY a;
|
||||
} {1 2 3 2 3 4 4 5 6}
|
||||
|
||||
# Change which column is the PRIMARY KEY
|
||||
#
|
||||
do_execsql_test conflict-7.1 {
|
||||
do_execsql_test 7.1 {
|
||||
DROP TABLE t1;
|
||||
CREATE TABLE t1(
|
||||
a UNIQUE ON CONFLICT REPLACE,
|
||||
@@ -217,7 +218,7 @@ do_execsql_test conflict-7.1 {
|
||||
|
||||
# Insert a row that conflicts on column B. The insert should be ignored.
|
||||
#
|
||||
do_execsql_test conflict-7.2 {
|
||||
do_execsql_test 7.2 {
|
||||
INSERT INTO t1(a,b,c) VALUES(3,2,5);
|
||||
SELECT a,b,c FROM t1 ORDER BY a;
|
||||
} {1 2 3 2 3 4}
|
||||
@@ -225,16 +226,16 @@ do_execsql_test conflict-7.2 {
|
||||
# Insert two rows where the second conflicts on C. The first row show go
|
||||
# and and then there should be a constraint error.
|
||||
#
|
||||
do_test conflict-7.3 {
|
||||
do_test 7.3 {
|
||||
catchsql {INSERT INTO t1(a,b,c) VALUES(4,5,6), (5,6,4);}
|
||||
} {1 {UNIQUE constraint failed: t1.c}}
|
||||
do_execsql_test conflict-7.4 {
|
||||
do_execsql_test 7.4 {
|
||||
SELECT a,b,c FROM t1 ORDER BY a;
|
||||
} {1 2 3 2 3 4 4 5 6}
|
||||
|
||||
# Change which column is the PRIMARY KEY
|
||||
#
|
||||
do_execsql_test conflict-8.1 {
|
||||
do_execsql_test 8.1 {
|
||||
DROP TABLE t1;
|
||||
CREATE TABLE t1(
|
||||
a UNIQUE ON CONFLICT REPLACE,
|
||||
@@ -247,7 +248,7 @@ do_execsql_test conflict-8.1 {
|
||||
|
||||
# Insert a row that conflicts on column B. The insert should be ignored.
|
||||
#
|
||||
do_execsql_test conflict-8.2 {
|
||||
do_execsql_test 8.2 {
|
||||
INSERT INTO t1(a,b,c) VALUES(3,2,5);
|
||||
SELECT a,b,c FROM t1 ORDER BY a;
|
||||
} {1 2 3 2 3 4}
|
||||
@@ -255,16 +256,16 @@ do_execsql_test conflict-8.2 {
|
||||
# Insert two rows where the second conflicts on C. The first row show go
|
||||
# and and then there should be a constraint error.
|
||||
#
|
||||
do_test conflict-8.3 {
|
||||
do_test 8.3 {
|
||||
catchsql {INSERT INTO t1(a,b,c) VALUES(4,5,6), (5,6,4);}
|
||||
} {1 {UNIQUE constraint failed: t1.c}}
|
||||
do_execsql_test conflict-8.4 {
|
||||
do_execsql_test 8.4 {
|
||||
SELECT a,b,c FROM t1 ORDER BY a;
|
||||
} {1 2 3 2 3 4 4 5 6}
|
||||
|
||||
# Change which column is the PRIMARY KEY
|
||||
#
|
||||
do_execsql_test conflict-9.1 {
|
||||
do_execsql_test 9.1 {
|
||||
DROP TABLE t1;
|
||||
CREATE TABLE t1(
|
||||
a UNIQUE ON CONFLICT REPLACE,
|
||||
@@ -277,7 +278,7 @@ do_execsql_test conflict-9.1 {
|
||||
|
||||
# Insert a row that conflicts on column B. The insert should be ignored.
|
||||
#
|
||||
do_execsql_test conflict-9.2 {
|
||||
do_execsql_test 9.2 {
|
||||
INSERT INTO t1(a,b,c) VALUES(3,2,5);
|
||||
SELECT a,b,c FROM t1 ORDER BY a;
|
||||
} {1 2 3 2 3 4}
|
||||
@@ -285,16 +286,16 @@ do_execsql_test conflict-9.2 {
|
||||
# Insert two rows where the second conflicts on C. The first row show go
|
||||
# and and then there should be a constraint error.
|
||||
#
|
||||
do_test conflict-9.3 {
|
||||
do_test 9.3 {
|
||||
catchsql {INSERT INTO t1(a,b,c) VALUES(4,5,6), (5,6,4);}
|
||||
} {1 {UNIQUE constraint failed: t1.c}}
|
||||
do_execsql_test conflict-9.4 {
|
||||
do_execsql_test 9.4 {
|
||||
SELECT a,b,c FROM t1 ORDER BY a;
|
||||
} {1 2 3 2 3 4 4 5 6}
|
||||
|
||||
# Change which column is the PRIMARY KEY
|
||||
#
|
||||
do_execsql_test conflict-10.1 {
|
||||
do_execsql_test 10.1 {
|
||||
DROP TABLE t1;
|
||||
CREATE TABLE t1(
|
||||
a UNIQUE ON CONFLICT REPLACE,
|
||||
@@ -307,7 +308,7 @@ do_execsql_test conflict-10.1 {
|
||||
|
||||
# Insert a row that conflicts on column B. The insert should be ignored.
|
||||
#
|
||||
do_execsql_test conflict-10.2 {
|
||||
do_execsql_test 10.2 {
|
||||
INSERT INTO t1(a,b,c) VALUES(3,2,5);
|
||||
SELECT a,b,c FROM t1 ORDER BY a;
|
||||
} {1 2 3 2 3 4}
|
||||
@@ -315,16 +316,16 @@ do_execsql_test conflict-10.2 {
|
||||
# Insert two rows where the second conflicts on C. The first row show go
|
||||
# and and then there should be a constraint error.
|
||||
#
|
||||
do_test conflict-10.3 {
|
||||
do_test 10.3 {
|
||||
catchsql {INSERT INTO t1(a,b,c) VALUES(4,5,6), (5,6,4);}
|
||||
} {1 {UNIQUE constraint failed: t1.c}}
|
||||
do_execsql_test conflict-10.4 {
|
||||
do_execsql_test 10.4 {
|
||||
SELECT a,b,c FROM t1 ORDER BY a;
|
||||
} {1 2 3 2 3 4 4 5 6}
|
||||
|
||||
# Change which column is the PRIMARY KEY
|
||||
#
|
||||
do_execsql_test conflict-11.1 {
|
||||
do_execsql_test 11.1 {
|
||||
DROP TABLE t1;
|
||||
CREATE TABLE t1(
|
||||
a UNIQUE ON CONFLICT REPLACE,
|
||||
@@ -337,7 +338,7 @@ do_execsql_test conflict-11.1 {
|
||||
|
||||
# Insert a row that conflicts on column B. The insert should be ignored.
|
||||
#
|
||||
do_execsql_test conflict-11.2 {
|
||||
do_execsql_test 11.2 {
|
||||
INSERT INTO t1(a,b,c) VALUES(3,2,5);
|
||||
SELECT a,b,c FROM t1 ORDER BY a;
|
||||
} {1 2 3 2 3 4}
|
||||
@@ -345,12 +346,25 @@ do_execsql_test conflict-11.2 {
|
||||
# Insert two rows where the second conflicts on C. The first row show go
|
||||
# and and then there should be a constraint error.
|
||||
#
|
||||
do_test conflict-11.3 {
|
||||
do_test 11.3 {
|
||||
catchsql {INSERT INTO t1(a,b,c) VALUES(4,5,6), (5,6,4);}
|
||||
} {1 {UNIQUE constraint failed: t1.c}}
|
||||
do_execsql_test conflict-11.4 {
|
||||
do_execsql_test 11.4 {
|
||||
SELECT a,b,c FROM t1 ORDER BY a;
|
||||
} {1 2 3 2 3 4 4 5 6}
|
||||
|
||||
# Check that ticket [f68dc596c4] has been fixed.
|
||||
#
|
||||
do_execsql_test 12.1 {
|
||||
CREATE TABLE t2(a INTEGER PRIMARY KEY, b TEXT);
|
||||
INSERT INTO t2 VALUES(111, '111');
|
||||
}
|
||||
do_execsql_test 12.2 {
|
||||
REPLACE INTO t2 VALUES(NULL, '112'), (111, '111B');
|
||||
}
|
||||
do_execsql_test 12.3 {
|
||||
SELECT * FROM t2;
|
||||
} {111 111B 112 112}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -0,0 +1,183 @@
|
||||
# 2016-04-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 script is DISTINCT queries using the skip-ahead
|
||||
# optimization.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
set testprefix distinct2
|
||||
|
||||
do_execsql_test 100 {
|
||||
CREATE TABLE t1(x INTEGER PRIMARY KEY);
|
||||
INSERT INTO t1 VALUES(0),(1),(2);
|
||||
CREATE TABLE t2 AS
|
||||
SELECT DISTINCT a.x AS aa, b.x AS bb
|
||||
FROM t1 a, t1 b;
|
||||
SELECT *, '|' FROM t2 ORDER BY aa, bb;
|
||||
} {0 0 | 0 1 | 0 2 | 1 0 | 1 1 | 1 2 | 2 0 | 2 1 | 2 2 |}
|
||||
do_execsql_test 110 {
|
||||
DROP TABLE t2;
|
||||
CREATE TABLE t2 AS
|
||||
SELECT DISTINCT a.x AS aa, b.x AS bb
|
||||
FROM t1 a, t1 b
|
||||
WHERE a.x IN t1 AND b.x IN t1;
|
||||
SELECT *, '|' FROM t2 ORDER BY aa, bb;
|
||||
} {0 0 | 0 1 | 0 2 | 1 0 | 1 1 | 1 2 | 2 0 | 2 1 | 2 2 |}
|
||||
do_execsql_test 120 {
|
||||
CREATE TABLE t102 (i0 TEXT UNIQUE NOT NULL);
|
||||
INSERT INTO t102 VALUES ('0'),('1'),('2');
|
||||
DROP TABLE t2;
|
||||
CREATE TABLE t2 AS
|
||||
SELECT DISTINCT *
|
||||
FROM t102 AS t0
|
||||
JOIN t102 AS t4 ON (t2.i0 IN t102)
|
||||
NATURAL JOIN t102 AS t3
|
||||
JOIN t102 AS t1 ON (t0.i0 IN t102)
|
||||
JOIN t102 AS t2 ON (t2.i0=+t0.i0 OR (t0.i0<>500 AND t2.i0=t1.i0));
|
||||
SELECT *, '|' FROM t2 ORDER BY 1, 2, 3, 4, 5;
|
||||
} {0 0 0 0 | 0 0 1 0 | 0 0 1 1 | 0 0 2 0 | 0 0 2 2 | 0 1 0 0 | 0 1 1 0 | 0 1 1 1 | 0 1 2 0 | 0 1 2 2 | 0 2 0 0 | 0 2 1 0 | 0 2 1 1 | 0 2 2 0 | 0 2 2 2 | 1 0 0 0 | 1 0 0 1 | 1 0 1 1 | 1 0 2 1 | 1 0 2 2 | 1 1 0 0 | 1 1 0 1 | 1 1 1 1 | 1 1 2 1 | 1 1 2 2 | 1 2 0 0 | 1 2 0 1 | 1 2 1 1 | 1 2 2 1 | 1 2 2 2 | 2 0 0 0 | 2 0 0 2 | 2 0 1 1 | 2 0 1 2 | 2 0 2 2 | 2 1 0 0 | 2 1 0 2 | 2 1 1 1 | 2 1 1 2 | 2 1 2 2 | 2 2 0 0 | 2 2 0 2 | 2 2 1 1 | 2 2 1 2 | 2 2 2 2 |}
|
||||
|
||||
do_execsql_test 400 {
|
||||
CREATE TABLE t4(a,b,c,d,e,f,g,h,i,j);
|
||||
INSERT INTO t4 VALUES(0,1,2,3,4,5,6,7,8,9);
|
||||
INSERT INTO t4 SELECT * FROM t4;
|
||||
INSERT INTO t4 SELECT * FROM t4;
|
||||
CREATE INDEX t4x ON t4(c,d,e);
|
||||
SELECT DISTINCT a,b,c FROM t4 WHERE a=0 AND b=1;
|
||||
} {0 1 2}
|
||||
do_execsql_test 410 {
|
||||
SELECT DISTINCT a,b,c,d FROM t4 WHERE a=0 AND b=1;
|
||||
} {0 1 2 3}
|
||||
do_execsql_test 411 {
|
||||
SELECT DISTINCT d,a,b,c FROM t4 WHERE a=0 AND b=1;
|
||||
} {3 0 1 2}
|
||||
do_execsql_test 420 {
|
||||
SELECT DISTINCT a,b,c,d,e FROM t4 WHERE a=0 AND b=1;
|
||||
} {0 1 2 3 4}
|
||||
do_execsql_test 430 {
|
||||
SELECT DISTINCT a,b,c,d,e,f FROM t4 WHERE a=0 AND b=1;
|
||||
} {0 1 2 3 4 5}
|
||||
|
||||
do_execsql_test 500 {
|
||||
CREATE TABLE t5(a INT, b INT);
|
||||
CREATE UNIQUE INDEX t5x ON t5(a+b);
|
||||
INSERT INTO t5(a,b) VALUES(0,0),(1,0),(1,1),(0,3);
|
||||
CREATE TEMP TABLE out AS SELECT DISTINCT a+b FROM t5;
|
||||
SELECT * FROM out ORDER BY 1;
|
||||
} {0 1 2 3}
|
||||
|
||||
do_execsql_test 600 {
|
||||
CREATE TABLE t6a(x INTEGER PRIMARY KEY);
|
||||
INSERT INTO t6a VALUES(1);
|
||||
CREATE TABLE t6b(y INTEGER PRIMARY KEY);
|
||||
INSERT INTO t6b VALUES(2),(3);
|
||||
SELECT DISTINCT x, x FROM t6a, t6b;
|
||||
} {1 1}
|
||||
|
||||
do_execsql_test 700 {
|
||||
CREATE TABLE t7(a, b, c);
|
||||
WITH s(i) AS (
|
||||
SELECT 1 UNION ALL SELECT i+1 FROM s WHERE (i+1)<200
|
||||
)
|
||||
INSERT INTO t7 SELECT i/100, i/50, i FROM s;
|
||||
}
|
||||
do_execsql_test 710 {
|
||||
SELECT DISTINCT a, b FROM t7;
|
||||
} {
|
||||
0 0 0 1
|
||||
1 2 1 3
|
||||
}
|
||||
do_execsql_test 720 {
|
||||
SELECT DISTINCT a, b+1 FROM t7;
|
||||
} {
|
||||
0 1 0 2
|
||||
1 3 1 4
|
||||
}
|
||||
do_execsql_test 730 {
|
||||
CREATE INDEX i7 ON t7(a, b+1);
|
||||
ANALYZE;
|
||||
SELECT DISTINCT a, b+1 FROM t7;
|
||||
} {
|
||||
0 1 0 2
|
||||
1 3 1 4
|
||||
}
|
||||
|
||||
do_execsql_test 800 {
|
||||
CREATE TABLE t8(a, b, c);
|
||||
WITH s(i) AS (
|
||||
SELECT 1 UNION ALL SELECT i+1 FROM s WHERE (i+1)<100
|
||||
)
|
||||
INSERT INTO t8 SELECT i/40, i/20, i/40 FROM s;
|
||||
}
|
||||
|
||||
do_execsql_test 820 {
|
||||
SELECT DISTINCT a, b, c FROM t8;
|
||||
} {
|
||||
0 0 0 0 1 0
|
||||
1 2 1 1 3 1
|
||||
2 4 2
|
||||
}
|
||||
|
||||
do_execsql_test 820 {
|
||||
SELECT DISTINCT a, b, c FROM t8 WHERE b=3;
|
||||
} {1 3 1}
|
||||
|
||||
do_execsql_test 830 {
|
||||
CREATE INDEX i8 ON t8(a, c);
|
||||
ANALYZE;
|
||||
SELECT DISTINCT a, b, c FROM t8 WHERE b=3;
|
||||
} {1 3 1}
|
||||
|
||||
do_execsql_test 900 {
|
||||
CREATE TABLE t9(v);
|
||||
INSERT INTO t9 VALUES
|
||||
('abcd'), ('Abcd'), ('aBcd'), ('ABcd'), ('abCd'), ('AbCd'), ('aBCd'),
|
||||
('ABCd'), ('abcD'), ('AbcD'), ('aBcD'), ('ABcD'), ('abCD'), ('AbCD'),
|
||||
('aBCD'), ('ABCD'),
|
||||
('wxyz'), ('Wxyz'), ('wXyz'), ('WXyz'), ('wxYz'), ('WxYz'), ('wXYz'),
|
||||
('WXYz'), ('wxyZ'), ('WxyZ'), ('wXyZ'), ('WXyZ'), ('wxYZ'), ('WxYZ'),
|
||||
('wXYZ'), ('WXYZ');
|
||||
}
|
||||
|
||||
do_execsql_test 910 {
|
||||
SELECT DISTINCT v COLLATE NOCASE, v FROM t9 ORDER BY +v;
|
||||
} {
|
||||
ABCD ABCD ABCd ABCd ABcD ABcD ABcd ABcd AbCD
|
||||
AbCD AbCd AbCd AbcD AbcD Abcd Abcd
|
||||
WXYZ WXYZ WXYz WXYz WXyZ WXyZ WXyz WXyz WxYZ
|
||||
WxYZ WxYz WxYz WxyZ WxyZ Wxyz Wxyz
|
||||
aBCD aBCD aBCd aBCd aBcD aBcD aBcd aBcd abCD
|
||||
abCD abCd abCd abcD abcD abcd abcd
|
||||
wXYZ wXYZ wXYz wXYz wXyZ wXyZ wXyz wXyz wxYZ
|
||||
wxYZ wxYz wxYz wxyZ wxyZ wxyz wxyz
|
||||
}
|
||||
|
||||
do_execsql_test 920 {
|
||||
CREATE INDEX i9 ON t9(v COLLATE NOCASE, v);
|
||||
ANALYZE;
|
||||
|
||||
SELECT DISTINCT v COLLATE NOCASE, v FROM t9 ORDER BY +v;
|
||||
} {
|
||||
ABCD ABCD ABCd ABCd ABcD ABcD ABcd ABcd AbCD
|
||||
AbCD AbCd AbCd AbcD AbcD Abcd Abcd
|
||||
WXYZ WXYZ WXYz WXYz WXyZ WXyZ WXyz WXyz WxYZ
|
||||
WxYZ WxYz WxYz WxyZ WxyZ Wxyz Wxyz
|
||||
aBCD aBCD aBCd aBCd aBcD aBcD aBcd aBcd abCD
|
||||
abCD abCd abCd abcD abcD abcd abcd
|
||||
wXYZ wXYZ wXYz wXYz wXyZ wXyZ wXyz wXyz wxYZ
|
||||
wxYZ wxYz wxYz wxyZ wxyZ wxyz wxyz
|
||||
}
|
||||
|
||||
|
||||
finish_test
|
||||
+43
-2
@@ -115,8 +115,11 @@ do_test fkey5-1.6 {
|
||||
# EVIDENCE-OF: R-55672-01620 The first column is the name of the table
|
||||
# that contains the REFERENCES clause.
|
||||
#
|
||||
# EVIDENCE-OF: R-25219-25618 The second column is the rowid of the row
|
||||
# that contains the invalid REFERENCES clause.
|
||||
# EVIDENCE-OF: R-00471-55166 The second column is the rowid of the row
|
||||
# that contains the invalid REFERENCES clause, or NULL if the child
|
||||
# table is a WITHOUT ROWID table.
|
||||
#
|
||||
# The second clause in the previous is tested by fkey5-10.3.
|
||||
#
|
||||
# EVIDENCE-OF: R-40482-20265 The third column is the name of the table
|
||||
# that is referred to.
|
||||
@@ -388,5 +391,43 @@ do_execsql_test 9.4 {
|
||||
PRAGMA foreign_key_check(k2);
|
||||
} {k2 3 s1 0}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test using a WITHOUT ROWID table as the child table with an INTEGER
|
||||
# PRIMARY KEY as the parent key.
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 10.1 {
|
||||
CREATE TABLE p30 (id INTEGER PRIMARY KEY);
|
||||
CREATE TABLE IF NOT EXISTS c30 (
|
||||
line INTEGER,
|
||||
master REFERENCES p30(id),
|
||||
PRIMARY KEY(master)
|
||||
) WITHOUT ROWID;
|
||||
|
||||
INSERT INTO p30 (id) VALUES (1);
|
||||
INSERT INTO c30 (master, line) VALUES (1, 999);
|
||||
}
|
||||
do_execsql_test 10.2 {
|
||||
PRAGMA foreign_key_check;
|
||||
}
|
||||
# EVIDENCE-OF: R-00471-55166 The second column is the rowid of the row
|
||||
# that contains the invalid REFERENCES clause, or NULL if the child
|
||||
# table is a WITHOUT ROWID table.
|
||||
do_execsql_test 10.3 {
|
||||
INSERT INTO c30 VALUES(45, 45);
|
||||
PRAGMA foreign_key_check;
|
||||
} {c30 {} p30 0}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test "foreign key mismatch" errors.
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 11.0 {
|
||||
CREATE TABLE tt(y);
|
||||
CREATE TABLE c11(x REFERENCES tt(y));
|
||||
}
|
||||
do_catchsql_test 11.1 {
|
||||
PRAGMA foreign_key_check;
|
||||
} {1 {foreign key mismatch - "c11" referencing "tt"}}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -243,5 +243,11 @@ do_execsql_test 8.5 {
|
||||
SELECT docid FROM t0 WHERE t0 MATCH '"abc abc"';
|
||||
} {}
|
||||
|
||||
do_execsql_test 9.1 {
|
||||
CREATE VIRTUAL TABLE t9 USING fts4(a, "", '---');
|
||||
}
|
||||
do_execsql_test 9.2 {
|
||||
CREATE VIRTUAL TABLE t10 USING fts3(<, b, c);
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
# 2010 October 27
|
||||
#
|
||||
# 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 that the FTS3 extension does not crash when it encounters a
|
||||
# corrupt data structure on disk.
|
||||
#
|
||||
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
# If SQLITE_ENABLE_FTS3 is not defined, omit this file.
|
||||
ifcapable !fts3 { finish_test ; return }
|
||||
|
||||
set ::testprefix fts3corrupt3
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test that fts3 does not choke on an oversized varint.
|
||||
#
|
||||
do_execsql_test 1.0 {
|
||||
PRAGMA page_size = 512;
|
||||
CREATE VIRTUAL TABLE t1 USING fts3;
|
||||
BEGIN;
|
||||
INSERT INTO t1 VALUES('one');
|
||||
INSERT INTO t1 VALUES('one');
|
||||
INSERT INTO t1 VALUES('one');
|
||||
COMMIT;
|
||||
}
|
||||
do_execsql_test 1.1 {
|
||||
SELECT quote(root) from t1_segdir;
|
||||
} {X'00036F6E6509010200010200010200'}
|
||||
do_execsql_test 1.2 {
|
||||
UPDATE t1_segdir SET root = X'00036F6E650EFFFFFFFFFFFFFFFFFFFFFFFF0200';
|
||||
}
|
||||
do_catchsql_test 1.3 {
|
||||
SELECT rowid FROM t1 WHERE t1 MATCH 'one'
|
||||
} {0 -1}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Interior node with the prefix or suffix count of an entry set to a
|
||||
# negative value.
|
||||
#
|
||||
set doc1 [string repeat "x " 600]
|
||||
set doc2 [string repeat "y " 600]
|
||||
set doc3 [string repeat "z " 600]
|
||||
|
||||
do_execsql_test 2.0 {
|
||||
CREATE VIRTUAL TABLE t2 USING fts3;
|
||||
BEGIN;
|
||||
INSERT INTO t2 VALUES($doc1);
|
||||
INSERT INTO t2 VALUES($doc2);
|
||||
INSERT INTO t2 VALUES($doc3);
|
||||
COMMIT;
|
||||
}
|
||||
do_execsql_test 2.1 {
|
||||
SELECT quote(root) from t2_segdir;
|
||||
} {X'0101017900017A'}
|
||||
|
||||
|
||||
|
||||
finish_test
|
||||
+17
-11
@@ -18,8 +18,6 @@ set ::testprefix fts3fault
|
||||
# If SQLITE_ENABLE_FTS3 is not defined, omit this file.
|
||||
ifcapable !fts3 { finish_test ; return }
|
||||
|
||||
if 0 {
|
||||
|
||||
# Test error handling in the sqlite3Fts3Init() function. This is the
|
||||
# function that registers the FTS3 module and various support functions
|
||||
# with SQLite.
|
||||
@@ -160,8 +158,6 @@ do_faultsim_test 7.3 -prep {
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
proc mit {blob} {
|
||||
set scan(littleEndian) i*
|
||||
set scan(bigEndian) I*
|
||||
@@ -181,13 +177,15 @@ do_test 8.0 {
|
||||
faultsim_save_and_close
|
||||
} {}
|
||||
|
||||
do_faultsim_test 8.1 -faults oom-t* -prep {
|
||||
faultsim_restore_and_reopen
|
||||
db func mit mit
|
||||
} -body {
|
||||
execsql { SELECT mit(matchinfo(t8, 'x')) FROM t8 WHERE t8 MATCH 'a b c' }
|
||||
} -test {
|
||||
faultsim_test_result {0 {{1 1 1 1 4 2 1 5 5}}}
|
||||
ifcapable fts4_deferred {
|
||||
do_faultsim_test 8.1 -faults oom-t* -prep {
|
||||
faultsim_restore_and_reopen
|
||||
db func mit mit
|
||||
} -body {
|
||||
execsql { SELECT mit(matchinfo(t8, 'x')) FROM t8 WHERE t8 MATCH 'a b c' }
|
||||
} -test {
|
||||
faultsim_test_result {0 {{1 1 1 1 4 2 1 5 5}}}
|
||||
}
|
||||
}
|
||||
|
||||
do_faultsim_test 8.2 -faults oom-t* -prep {
|
||||
@@ -234,4 +232,12 @@ do_faultsim_test 9.1 -prep {
|
||||
faultsim_test_result {0 {{0 0 20 39 0 0 64 2}}}
|
||||
}
|
||||
|
||||
do_faultsim_test 10.1 -prep {
|
||||
faultsim_delete_and_reopen
|
||||
} -body {
|
||||
execsql { CREATE VIRTUAL TABLE t1 USING fts4(a, b, languageid=d) }
|
||||
} -test {
|
||||
faultsim_test_result {0 {}}
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -174,4 +174,76 @@ do_faultsim_test 6.1 -faults oom* -prep {
|
||||
faultsim_test_result {0 -1}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Inject faults into a query for an N-byte prefix that uses a prefix=N+1
|
||||
# index.
|
||||
reset_db
|
||||
do_execsql_test 7.0 {
|
||||
CREATE VIRTUAL TABLE t7 USING fts4(x,prefix=2);
|
||||
INSERT INTO t7 VALUES('the quick brown fox');
|
||||
INSERT INTO t7 VALUES('jumped over the');
|
||||
INSERT INTO t7 VALUES('lazy dog');
|
||||
}
|
||||
do_faultsim_test 7.1 -faults oom* -body {
|
||||
execsql { SELECT docid FROM t7 WHERE t7 MATCH 't*' }
|
||||
} -test {
|
||||
faultsim_test_result {0 {1 2}}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Inject faults into a opening an existing fts3 table that has been
|
||||
# upgraded to add an %_stat table.
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 8.0 {
|
||||
CREATE VIRTUAL TABLE t8 USING fts3;
|
||||
INSERT INTO t8 VALUES('the quick brown fox');
|
||||
INSERT INTO t8 VALUES('jumped over the');
|
||||
INSERT INTO t8 VALUES('lazy dog');
|
||||
INSERT INTO t8(t8) VALUES('automerge=8');
|
||||
SELECT name FROM sqlite_master WHERE name LIKE 't8%';
|
||||
} {
|
||||
t8 t8_content t8_segments t8_segdir t8_stat
|
||||
}
|
||||
faultsim_save_and_close
|
||||
|
||||
do_faultsim_test 8.1 -faults oom* -prep {
|
||||
faultsim_restore_and_reopen
|
||||
} -body {
|
||||
execsql { INSERT INTO t8 VALUES('one two three') }
|
||||
} -test {
|
||||
faultsim_test_result {0 {}}
|
||||
}
|
||||
|
||||
do_faultsim_test 8.2 -faults oom* -prep {
|
||||
faultsim_restore_and_reopen
|
||||
} -body {
|
||||
execsql { ALTER TABLE t8 RENAME TO t8ii }
|
||||
} -test {
|
||||
faultsim_test_result {0 {}}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
set chunkconfig [fts3_configure_incr_load 1 1]
|
||||
do_execsql_test 9.0 {
|
||||
PRAGMA page_size = 512;
|
||||
CREATE VIRTUAL TABLE t9 USING fts3;
|
||||
WITH s(i) AS (
|
||||
SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<50
|
||||
)
|
||||
INSERT INTO t9 SELECT 'one two three' FROM s;
|
||||
}
|
||||
|
||||
do_faultsim_test 8.2 -faults io* -body {
|
||||
execsql { SELECT count(*) FROM t9 WHERE t9 MATCH '"one two three"' }
|
||||
} -test {
|
||||
faultsim_test_result {0 50}
|
||||
}
|
||||
|
||||
eval fts3_configure_incr_load $chunkconfig
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,230 @@
|
||||
# 2017 March 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 script is testing the FTS3 module.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix fts3misc
|
||||
|
||||
# If SQLITE_ENABLE_FTS3 is defined, omit this file.
|
||||
ifcapable !fts3 {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# A self-join.
|
||||
#
|
||||
do_execsql_test 1.0 {
|
||||
CREATE VIRTUAL TABLE t1 USING fts3(a, b);
|
||||
INSERT INTO t1 VALUES('one', 'i');
|
||||
INSERT INTO t1 VALUES('one', 'ii');
|
||||
INSERT INTO t1 VALUES('two', 'i');
|
||||
INSERT INTO t1 VALUES('two', 'ii');
|
||||
}
|
||||
|
||||
do_execsql_test 1.1 {
|
||||
SELECT a.a, b.b FROM t1 a, t1 b WHERE a.t1 MATCH 'two' AND b.t1 MATCH 'i'
|
||||
} {two i two i two i two i}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# FTS tables with 128 or more columns.
|
||||
#
|
||||
proc v1 {v} {
|
||||
set vector [list a b c d e f g h]
|
||||
set res [list]
|
||||
for {set i 0} {$i<8} {incr i} {
|
||||
if {$v & (1 << $i)} { lappend res [lindex $vector $i] }
|
||||
}
|
||||
set res
|
||||
}
|
||||
proc v2 {v} {
|
||||
set vector [list d e f g h i j k]
|
||||
set res [list]
|
||||
for {set i 0} {$i<8} {incr i} {
|
||||
if {$v & (1 << $i)} { lappend res [lindex $vector $i] }
|
||||
}
|
||||
set res
|
||||
}
|
||||
db func v1 v1
|
||||
db func v2 v2
|
||||
|
||||
do_test 2.0 {
|
||||
set cols [list]
|
||||
for {set i 0} {$i<200} {incr i} {
|
||||
lappend cols "c$i"
|
||||
}
|
||||
execsql "CREATE VIRTUAL TABLE t2 USING fts3([join $cols ,])"
|
||||
execsql {
|
||||
WITH data(i) AS (
|
||||
SELECT 1 UNION ALL SELECT i+1 FROM data WHERE i<200
|
||||
)
|
||||
INSERT INTO t2(c198, c199) SELECT v1(i), v2(i) FROM data;
|
||||
}
|
||||
} {}
|
||||
do_execsql_test 2.1 {
|
||||
SELECT rowid FROM t2 WHERE t2 MATCH '"a b c"'
|
||||
} {
|
||||
7 15 23 31 39 47 55 63 71 79 87 95 103 111
|
||||
119 127 135 143 151 159 167 175 183 191 199
|
||||
}
|
||||
do_execsql_test 2.2 {
|
||||
SELECT rowid FROM t2 WHERE t2 MATCH '"g h i"'
|
||||
} {
|
||||
56 57 58 59 60 61 62 63 120 121 122 123 124
|
||||
125 126 127 184 185 186 187 188 189 190 191
|
||||
}
|
||||
do_execsql_test 2.3 {
|
||||
SELECT rowid FROM t2 WHERE t2 MATCH '"i h"'
|
||||
} {
|
||||
}
|
||||
do_execsql_test 2.4 {
|
||||
SELECT rowid FROM t2 WHERE t2 MATCH '"f e"'
|
||||
} {
|
||||
}
|
||||
do_execsql_test 2.5 {
|
||||
SELECT rowid FROM t2 WHERE t2 MATCH '"e f"'
|
||||
} {
|
||||
6 7 14 15 22 23 30 31 38 39 46 47 48 49 50 51 52 53 54 55 56
|
||||
57 58 59 60 61 62 63 70 71 78 79 86 87 94 95 102 103 110
|
||||
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
|
||||
134 135 142 143 150 151 158 159 166 167 174 175 176 177 178 179 180
|
||||
181 182 183 184 185 186 187 188 189 190 191 198 199
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Range constraints on the docid using non-integer values.
|
||||
#
|
||||
do_execsql_test 2.6 {
|
||||
SELECT rowid FROM t2 WHERE t2 MATCH 'e' AND rowid BETWEEN NULL AND 45;
|
||||
} {}
|
||||
do_execsql_test 2.7 {
|
||||
SELECT rowid FROM t2 WHERE t2 MATCH 'e' AND rowid BETWEEN 11.5 AND 48.2;
|
||||
} {
|
||||
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
|
||||
29 30 31 34 35 38 39 42 43 46 47 48
|
||||
}
|
||||
do_execsql_test 2.8 {
|
||||
SELECT rowid FROM t2 WHERE t2 MATCH 'e' AND rowid BETWEEN '11.5' AND '48.2';
|
||||
} {
|
||||
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
|
||||
29 30 31 34 35 38 39 42 43 46 47 48
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Phrase query tests.
|
||||
#
|
||||
do_execsql_test 3.1.1 {
|
||||
CREATE VIRTUAL TABLE t3 USING fts3;
|
||||
INSERT INTO t3 VALUES('a b c');
|
||||
INSERT INTO t3 VALUES('d e f');
|
||||
INSERT INTO t3 VALUES('a b d');
|
||||
INSERT INTO t3 VALUES('1 2 3 4 5 6 7 8 9 10 11');
|
||||
}
|
||||
do_execsql_test 3.1.2 {
|
||||
SELECT * FROM t3 WHERE t3 MATCH '"a b x y"' ORDER BY docid DESC
|
||||
}
|
||||
do_execsql_test 3.1.3 {
|
||||
SELECT * FROM t3 WHERE t3 MATCH '"a b c" OR "a b x y"' ORDER BY docid DESC
|
||||
} {{a b c}}
|
||||
do_execsql_test 3.1.4 {
|
||||
SELECT * FROM t3 WHERE t3 MATCH '"a* b* x* a*"'
|
||||
}
|
||||
do_execsql_test 3.1.5 {
|
||||
SELECT rowid FROM t3 WHERE t3 MATCH '"2 3 4 5 6 7 8 9"'
|
||||
} {4}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
reset_db
|
||||
ifcapable fts4_deferred {
|
||||
do_execsql_test 4.0 {
|
||||
PRAGMA page_size = 512;
|
||||
CREATE VIRTUAL TABLE t4 USING fts4;
|
||||
WITH s(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<8000 )
|
||||
INSERT INTO t4 SELECT 'a b c a b c a b c' FROM s;
|
||||
}
|
||||
do_execsql_test 4.1 {
|
||||
SELECT count(*) FROM t4 WHERE t4 MATCH '"a b c" OR "c a b"'
|
||||
} {8000}
|
||||
do_execsql_test 4.2 {
|
||||
SELECT quote(value) from t4_stat where id=0
|
||||
} {X'C03EC0B204C0A608'}
|
||||
do_execsql_test 4.3 {
|
||||
UPDATE t4_stat SET value = X'C03EC0B204C0A60800' WHERE id=0;
|
||||
}
|
||||
do_catchsql_test 4.4 {
|
||||
SELECT count(*) FROM t4 WHERE t4 MATCH '"a b c" OR "c a b"'
|
||||
} {1 {database disk image is malformed}}
|
||||
do_execsql_test 4.5 {
|
||||
UPDATE t4_stat SET value = X'00C03EC0B204C0A608' WHERE id=0;
|
||||
}
|
||||
do_catchsql_test 4.6 {
|
||||
SELECT count(*) FROM t4 WHERE t4 MATCH '"a b c" OR "c a b"'
|
||||
} {1 {database disk image is malformed}}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 5.0 {
|
||||
CREATE VIRTUAL TABLE t5 USING fts4;
|
||||
INSERT INTO t5 VALUES('a x x x x b x x x x c');
|
||||
INSERT INTO t5 VALUES('a x x x x b x x x x c');
|
||||
INSERT INTO t5 VALUES('a x x x x b x x x x c');
|
||||
}
|
||||
do_execsql_test 5.1 {
|
||||
SELECT rowid FROM t5 WHERE t5 MATCH 'a NEAR/4 b NEAR/4 c'
|
||||
} {1 2 3}
|
||||
do_execsql_test 5.2 {
|
||||
SELECT rowid FROM t5 WHERE t5 MATCH 'a NEAR/3 b NEAR/4 c'
|
||||
} {}
|
||||
do_execsql_test 5.3 {
|
||||
SELECT rowid FROM t5 WHERE t5 MATCH 'a NEAR/4 b NEAR/3 c'
|
||||
} {}
|
||||
do_execsql_test 5.4 {
|
||||
SELECT rowid FROM t5 WHERE t5 MATCH 'y NEAR/4 b NEAR/4 c'
|
||||
} {}
|
||||
do_execsql_test 5.5 {
|
||||
SELECT rowid FROM t5 WHERE t5 MATCH 'x OR a NEAR/3 b NEAR/3 c'
|
||||
} {1 2 3}
|
||||
do_execsql_test 5.5 {
|
||||
SELECT rowid FROM t5 WHERE t5 MATCH 'x OR y NEAR/3 b NEAR/3 c'
|
||||
} {1 2 3}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 6.0 {
|
||||
CREATE VIRTUAL TABLE t6 USING fts4;
|
||||
|
||||
BEGIN;
|
||||
WITH s(i) AS (SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<50000)
|
||||
INSERT INTO t6 SELECT 'x x x x x x x x x x x' FROM s;
|
||||
|
||||
INSERT INTO t6 VALUES('x x x x x x x x x x x A');
|
||||
INSERT INTO t6 VALUES('x x x x x x x x x x x B');
|
||||
INSERT INTO t6 VALUES('x x x x x x x x x x x A');
|
||||
INSERT INTO t6 VALUES('x x x x x x x x x x x B');
|
||||
|
||||
WITH s(i) AS (SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<50000)
|
||||
INSERT INTO t6 SELECT 'x x x x x x x x x x x' FROM s;
|
||||
COMMIT;
|
||||
}
|
||||
breakpoint
|
||||
do_execsql_test 6.1 {
|
||||
SELECT rowid FROM t6 WHERE t6 MATCH 'b OR "x a"'
|
||||
} {50001 50002 50003 50004}
|
||||
|
||||
|
||||
finish_test
|
||||
@@ -14,7 +14,6 @@
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set ::testprefix fts4content
|
||||
|
||||
# If SQLITE_ENABLE_FTS3 is defined, omit this file.
|
||||
ifcapable !fts3 {
|
||||
@@ -341,6 +340,13 @@ do_test_query1 3.3.4 {"zero one" OR "one two"} {
|
||||
or_merge_lists [rowid_list "zero one"] [rowid_list "one two"]
|
||||
}
|
||||
|
||||
do_execsql_test 3.4 {
|
||||
CREATE TABLE t8c(a, b);
|
||||
CREATE VIRTUAL TABLE t8 USING fts4(content=t8c, languageid=langid);
|
||||
INSERT INTO t8(docid, a, b) VALUES(-1, 'one two three', 'x y z');
|
||||
SELECT docid FROM t8 WHERE t8 MATCH 'one x' AND langid=0
|
||||
} {-1}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test cases 4.*
|
||||
#
|
||||
|
||||
@@ -0,0 +1,154 @@
|
||||
# 2017 April 30
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
# Test the HAVING->WHERE optimization.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix having
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE TABLE t2(c, d);
|
||||
|
||||
CREATE TABLE t1(a, b);
|
||||
INSERT INTO t1 VALUES(1, 1);
|
||||
INSERT INTO t1 VALUES(2, 2);
|
||||
INSERT INTO t1 VALUES(1, 3);
|
||||
INSERT INTO t1 VALUES(2, 4);
|
||||
INSERT INTO t1 VALUES(1, 5);
|
||||
INSERT INTO t1 VALUES(2, 6);
|
||||
} {}
|
||||
|
||||
foreach {tn sql res} {
|
||||
1 "SELECT a, sum(b) FROM t1 GROUP BY a HAVING a=2" {2 12}
|
||||
2 "SELECT a, sum(b) FROM t1 GROUP BY a HAVING a=2 AND sum(b)>10" {2 12}
|
||||
3 "SELECT a, sum(b) FROM t1 GROUP BY a HAVING sum(b)>12" {}
|
||||
} {
|
||||
do_execsql_test 1.$tn $sql $res
|
||||
}
|
||||
|
||||
# Run an EXPLAIN command for both SQL statements. Return true if
|
||||
# the outputs are identical, or false otherwise.
|
||||
#
|
||||
proc compare_vdbe {sql1 sql2} {
|
||||
set r1 [list]
|
||||
set r2 [list]
|
||||
db eval "explain $sql1" { lappend r1 $opcode $p1 $p2 $p3 $p4 $p5}
|
||||
db eval "explain $sql2" { lappend r2 $opcode $p1 $p2 $p3 $p4 $p5}
|
||||
return [expr {$r1==$r2}]
|
||||
}
|
||||
|
||||
proc do_compare_vdbe_test {tn sql1 sql2 res} {
|
||||
uplevel [list do_test $tn [list compare_vdbe $sql1 $sql2] $res]
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test that various statements that are eligible for the optimization
|
||||
# produce the same VDBE code as optimizing by hand does.
|
||||
#
|
||||
foreach {tn sql1 sql2} {
|
||||
1 "SELECT a, sum(b) FROM t1 GROUP BY a HAVING a=2"
|
||||
"SELECT a, sum(b) FROM t1 WHERE a=2 GROUP BY a"
|
||||
|
||||
2 "SELECT a, sum(b) FROM t1 GROUP BY a HAVING sum(b)>5 AND a=2"
|
||||
"SELECT a, sum(b) FROM t1 WHERE a=2 GROUP BY a HAVING sum(b)>5"
|
||||
|
||||
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"
|
||||
|
||||
4 {
|
||||
SELECT x,y FROM (
|
||||
SELECT a AS x, sum(b) AS y FROM t1
|
||||
GROUP BY a
|
||||
) WHERE x BETWEEN 8888 AND 9999
|
||||
} {
|
||||
SELECT x,y FROM (
|
||||
SELECT a AS x, sum(b) AS y FROM t1
|
||||
WHERE x BETWEEN 8888 AND 9999
|
||||
GROUP BY a
|
||||
)
|
||||
}
|
||||
|
||||
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"
|
||||
|
||||
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"
|
||||
|
||||
7 {
|
||||
SELECT count(*) FROM t1,t2 WHERE a=c GROUP BY b, d
|
||||
HAVING b=d COLLATE nocase
|
||||
} {
|
||||
SELECT count(*) FROM t1,t2 WHERE a=c AND b=d COLLATE nocase
|
||||
GROUP BY b, d
|
||||
}
|
||||
|
||||
8 "SELECT a, sum(b) FROM t1 GROUP BY a||b HAVING substr(a||b, 1, 1)='a'"
|
||||
"SELECT a, sum(b) FROM t1 WHERE substr(a||b, 1, 1)='a' GROUP BY a||b"
|
||||
} {
|
||||
do_compare_vdbe_test 2.$tn $sql1 $sql2 1
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# 1: Test that the optimization is only applied if the GROUP BY term
|
||||
# uses BINARY collation.
|
||||
#
|
||||
# 2: Not applied if there is a non-deterministic function in the HAVING
|
||||
# term.
|
||||
#
|
||||
foreach {tn sql1 sql2} {
|
||||
1 "SELECT a, sum(b) FROM t1 GROUP BY a COLLATE nocase HAVING a=2"
|
||||
"SELECT a, sum(b) FROM t1 WHERE a=2 GROUP BY a COLLATE nocase"
|
||||
|
||||
2 "SELECT a, sum(b) FROM t1 GROUP BY a HAVING randomblob(a)<X'88'"
|
||||
"SELECT a, sum(b) FROM t1 WHERE randomblob(a)<X'88' GROUP BY a"
|
||||
} {
|
||||
do_compare_vdbe_test 3.$tn $sql1 $sql2 0
|
||||
}
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test that non-deterministic functions disqualify a term from being
|
||||
# moved from the HAVING to WHERE clause.
|
||||
#
|
||||
do_execsql_test 4.1 {
|
||||
CREATE TABLE t3(a, b);
|
||||
INSERT INTO t3 VALUES(1, 1);
|
||||
INSERT INTO t3 VALUES(1, 2);
|
||||
INSERT INTO t3 VALUES(1, 3);
|
||||
INSERT INTO t3 VALUES(2, 1);
|
||||
INSERT INTO t3 VALUES(2, 2);
|
||||
INSERT INTO t3 VALUES(2, 3);
|
||||
}
|
||||
|
||||
proc nondeter {args} {
|
||||
incr ::nondeter_ret
|
||||
expr {$::nondeter_ret % 2}
|
||||
}
|
||||
db func nondeter nondeter
|
||||
|
||||
set ::nondeter_ret 0
|
||||
do_execsql_test 4.2 {
|
||||
SELECT a, sum(b) FROM t3 GROUP BY a HAVING nondeter(a)
|
||||
} {1 6}
|
||||
|
||||
# If the term where moved, the query above would return the same
|
||||
# result as the following. But it does not.
|
||||
#
|
||||
set ::nondeter_ret 0
|
||||
do_execsql_test 4.3 {
|
||||
SELECT a, sum(b) FROM t3 WHERE nondeter(a) GROUP BY a
|
||||
} {1 4 2 2}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -237,4 +237,16 @@ do_execsql_test 8.4 {
|
||||
SELECT count(*) FROM n1 WHERE a IN (SELECT +a FROM n1)
|
||||
} 3
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test that ticket 61fe97454c is fixed.
|
||||
#
|
||||
do_execsql_test 9.0 {
|
||||
CREATE TABLE t9(a INTEGER PRIMARY KEY);
|
||||
INSERT INTO t9 VALUES (44), (45);
|
||||
}
|
||||
do_execsql_test 9.1 {
|
||||
SELECT * FROM t9 WHERE a IN (44, 45, 44, 45)
|
||||
} {44 45}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
# 2017 April 11
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
# This file implements regression tests for SQLite library.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix indexexpr2
|
||||
|
||||
do_execsql_test 1 {
|
||||
CREATE TABLE t1(a, b);
|
||||
INSERT INTO t1 VALUES(1, 'one');
|
||||
INSERT INTO t1 VALUES(2, 'two');
|
||||
INSERT INTO t1 VALUES(3, 'three');
|
||||
|
||||
CREATE INDEX i1 ON t1(b || 'x');
|
||||
}
|
||||
|
||||
do_execsql_test 1.1 {
|
||||
SELECT 'TWOX' == (b || 'x') FROM t1 WHERE (b || 'x')>'onex'
|
||||
} {0 0}
|
||||
|
||||
do_execsql_test 1.2 {
|
||||
SELECT 'TWOX' == (b || 'x') COLLATE nocase FROM t1 WHERE (b || 'x')>'onex'
|
||||
} {0 1}
|
||||
|
||||
do_execsql_test 2.0 {
|
||||
CREATE INDEX i2 ON t1(a+1);
|
||||
}
|
||||
|
||||
do_execsql_test 2.1 {
|
||||
SELECT a+1, quote(a+1) FROM t1 ORDER BY 1;
|
||||
} {2 2 3 3 4 4}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix insert4
|
||||
|
||||
ifcapable !view||!subquery {
|
||||
finish_test
|
||||
@@ -566,4 +567,36 @@ do_catchsql_test insert4-9.1 {
|
||||
INSERT INTO t1(x) VALUES(5 COLLATE xyzzy) UNION SELECT 0;
|
||||
} {1 {no such collation sequence: xyzzy}}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Check that running an integrity-check does not disable the xfer
|
||||
# optimization for tables with CHECK constraints.
|
||||
#
|
||||
do_execsql_test 10.1 {
|
||||
CREATE TABLE t8(
|
||||
rid INTEGER,
|
||||
pid INTEGER,
|
||||
mid INTEGER,
|
||||
px INTEGER DEFAULT(0) CHECK(px IN(0, 1))
|
||||
);
|
||||
CREATE TEMP TABLE x(
|
||||
rid INTEGER,
|
||||
pid INTEGER,
|
||||
mid INTEGER,
|
||||
px INTEGER DEFAULT(0) CHECK(px IN(0, 1))
|
||||
);
|
||||
}
|
||||
do_test 10.2 {
|
||||
set sqlite3_xferopt_count 0
|
||||
execsql { INSERT INTO x SELECT * FROM t8 }
|
||||
set sqlite3_xferopt_count
|
||||
} {1}
|
||||
|
||||
do_test 10.3 {
|
||||
execsql { PRAGMA integrity_check }
|
||||
set sqlite3_xferopt_count 0
|
||||
execsql { INSERT INTO x SELECT * FROM t8 }
|
||||
set sqlite3_xferopt_count
|
||||
} {1}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -356,6 +356,15 @@ do_execsql_test json-8.2 {
|
||||
SELECT a=json_extract(b,'$[0]') FROM t8;
|
||||
} {1}
|
||||
|
||||
# 2017-04-12. Regression reported on the mailing list by Rolf Ade
|
||||
#
|
||||
do_execsql_test json-8.3 {
|
||||
SELECT json_valid(char(0x22,0xe4,0x22));
|
||||
} {1}
|
||||
do_execsql_test json-8.4 {
|
||||
SELECT unicode(json_extract(char(0x22,228,0x22),'$'));
|
||||
} {228}
|
||||
|
||||
# The json_quote() function transforms an SQL value into a JSON value.
|
||||
# String values are quoted and interior quotes are escaped. NULL values
|
||||
# are rendered as the unquoted string "null".
|
||||
@@ -688,5 +697,29 @@ do_execsql_test json-10.95 {
|
||||
SELECT json_valid('" \~ "');
|
||||
} {0}
|
||||
|
||||
#--------------------------------------------------------------------------
|
||||
# 2017-04-11. https://www.sqlite.org/src/info/981329adeef51011
|
||||
# Stack overflow on deeply nested JSON.
|
||||
#
|
||||
# The following tests confirm that deeply nested JSON is considered invalid.
|
||||
#
|
||||
do_execsql_test json-11.0 {
|
||||
/* Shallow enough to be parsed */
|
||||
SELECT json_valid(printf('%.2000c0%.2000c','[',']'));
|
||||
} {1}
|
||||
do_execsql_test json-11.1 {
|
||||
/* Too deep by one */
|
||||
SELECT json_valid(printf('%.2001c0%.2001c','[',']'));
|
||||
} {0}
|
||||
do_execsql_test json-11.2 {
|
||||
/* Shallow enough to be parsed { */
|
||||
SELECT json_valid(replace(printf('%.2000c0%.2000c','[','}'),'[','{"a":'));
|
||||
/* } */
|
||||
} {1}
|
||||
do_execsql_test json-11.3 {
|
||||
/* Too deep by one { */
|
||||
SELECT json_valid(replace(printf('%.2001c0%.2001c','[','}'),'[','{"a":'));
|
||||
/* } */
|
||||
} {0}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -298,4 +298,43 @@ for {set i 0} {$i<100} {incr i} {
|
||||
} {1}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# 2017-04-08 ticket b93be8729a895a528e2849fca99f7
|
||||
# JSON extension accepts invalid numeric values
|
||||
#
|
||||
# JSON does not allow leading zeros. But the JSON extension was
|
||||
# allowing them. The following tests verify that the problem is now
|
||||
# fixed.
|
||||
#
|
||||
do_execsql_test json102-1401 { SELECT json_valid('{"x":01}') } 0
|
||||
do_execsql_test json102-1402 { SELECT json_valid('{"x":-01}') } 0
|
||||
do_execsql_test json102-1403 { SELECT json_valid('{"x":0}') } 1
|
||||
do_execsql_test json102-1404 { SELECT json_valid('{"x":-0}') } 1
|
||||
do_execsql_test json102-1405 { SELECT json_valid('{"x":0.1}') } 1
|
||||
do_execsql_test json102-1406 { SELECT json_valid('{"x":-0.1}') } 1
|
||||
do_execsql_test json102-1407 { SELECT json_valid('{"x":0.0000}') } 1
|
||||
do_execsql_test json102-1408 { SELECT json_valid('{"x":-0.0000}') } 1
|
||||
do_execsql_test json102-1409 { SELECT json_valid('{"x":01.5}') } 0
|
||||
do_execsql_test json102-1410 { SELECT json_valid('{"x":-01.5}') } 0
|
||||
do_execsql_test json102-1411 { SELECT json_valid('{"x":00}') } 0
|
||||
do_execsql_test json102-1412 { SELECT json_valid('{"x":-00}') } 0
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
# 2017-04-10 ticket 6c9b5514077fed34551f98e64c09a10dc2fc8e16
|
||||
# JSON extension accepts strings containing control characters.
|
||||
#
|
||||
# The JSON spec requires that all control characters be escaped.
|
||||
#
|
||||
do_execsql_test json102-1500 {
|
||||
WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<0x20)
|
||||
SELECT x FROM c WHERE json_valid(printf('{"a":"x%sz"}', char(x))) ORDER BY x;
|
||||
} {32}
|
||||
|
||||
# All control characters are escaped
|
||||
#
|
||||
do_execsql_test json102-1501 {
|
||||
WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<0x1f)
|
||||
SELECT sum(json_valid(json_quote('a'||char(x)||'z'))) FROM c ORDER BY x;
|
||||
} {31}
|
||||
|
||||
finish_test
|
||||
|
||||
+30
-28
@@ -39,11 +39,27 @@ ifcapable !memorymanage {
|
||||
return
|
||||
}
|
||||
|
||||
# The sizes of memory allocations from system malloc() might vary,
|
||||
# depending on the memory allocator algorithms used. The following
|
||||
# routine is designed to support answers that fall within a range
|
||||
# of values while also supplying easy-to-understand "expected" values
|
||||
# when errors occur.
|
||||
#
|
||||
proc value_in_range {target x args} {
|
||||
set v [lindex $args 0]
|
||||
if {$v!=""} {
|
||||
if {$v<$target*$x} {return $v}
|
||||
if {$v>$target/$x} {return $v}
|
||||
}
|
||||
return "number between [expr {int($target*$x)}] and [expr {int($target/$x)}]"
|
||||
}
|
||||
set mrange 0.98 ;# plus or minus 2%
|
||||
|
||||
test_set_config_pagecache 0 100
|
||||
|
||||
sqlite3_soft_heap_limit 0
|
||||
sqlite3 db test.db
|
||||
db eval {PRAGMA cache_size=1}
|
||||
# db eval {PRAGMA cache_size=1}
|
||||
|
||||
do_test malloc5-1.1 {
|
||||
# Simplest possible test. Call sqlite3_release_memory when there is exactly
|
||||
@@ -71,24 +87,8 @@ do_test malloc5-1.3 {
|
||||
# in the cache belonging to db2.
|
||||
#
|
||||
set ::pgalloc [sqlite3_release_memory]
|
||||
} {0}
|
||||
|
||||
# The sizes of memory allocations from system malloc() might vary,
|
||||
# depending on the memory allocator algorithms used. The following
|
||||
# routine is designed to support answers that fall within a range
|
||||
# of values while also supplying easy-to-understand "expected" values
|
||||
# when errors occur.
|
||||
#
|
||||
proc value_in_range {target x args} {
|
||||
set v [lindex $args 0]
|
||||
if {$v!=""} {
|
||||
if {$v<$target*$x} {return $v}
|
||||
if {$v>$target/$x} {return $v}
|
||||
}
|
||||
return "number between [expr {int($target*$x)}] and [expr {int($target/$x)}]"
|
||||
}
|
||||
set mrange 0.98 ;# plus or minus 2%
|
||||
|
||||
value_in_range 1288 0.75
|
||||
} [value_in_range 1288 0.75]
|
||||
|
||||
do_test malloc5-1.4 {
|
||||
# Commit the transaction and open a new one. Read 1 page into the cache.
|
||||
@@ -117,12 +117,12 @@ do_test malloc5-1.6 {
|
||||
db2 close
|
||||
execsql {
|
||||
BEGIN;
|
||||
SELECT * FROM abc;
|
||||
CREATE TABLE def(d, e, f);
|
||||
SELECT * FROM abc;
|
||||
}
|
||||
breakpoint
|
||||
value_in_range $::pgalloc $::mrange [sqlite3_release_memory 500]
|
||||
} [value_in_range $::pgalloc $::mrange]
|
||||
|
||||
do_test malloc5-1.7 {
|
||||
# Database should not be locked this time.
|
||||
sqlite3 db2 test.db
|
||||
@@ -346,7 +346,7 @@ do_test malloc5-6.2.2 {
|
||||
# If we now try to reclaim some memory, it should come from the db2 cache.
|
||||
sqlite3_release_memory 3000
|
||||
expr [nPage db] + [nPage db2]
|
||||
} {4}
|
||||
} {1}
|
||||
do_test malloc5-6.2.3 {
|
||||
# Access the db2 cache again, so that all the db2 pages have been used
|
||||
# more recently than all the db pages. Then try to reclaim 3000 bytes.
|
||||
@@ -354,7 +354,7 @@ do_test malloc5-6.2.3 {
|
||||
execsql { SELECT * FROM abc } db2
|
||||
sqlite3_release_memory 3000
|
||||
expr [nPage db] + [nPage db2]
|
||||
} {4}
|
||||
} {0}
|
||||
|
||||
do_test malloc5-6.3.1 {
|
||||
# Now open a transaction and update 2 pages in the db2 cache. Then
|
||||
@@ -364,6 +364,8 @@ do_test malloc5-6.3.1 {
|
||||
# sync() to free up the dirty db2 pages. The only page that cannot be
|
||||
# freed is page1 of db2. Because there is an open transaction, the
|
||||
# btree layer holds a reference to page 1 in the db2 cache.
|
||||
#
|
||||
# UPDATE: No longer. As release_memory() does not cause a sync()
|
||||
execsql {
|
||||
BEGIN;
|
||||
UPDATE abc SET c = randstr(100,100)
|
||||
@@ -377,13 +379,13 @@ do_test malloc5-6.3.2 {
|
||||
# non-dirty pages held by db2.
|
||||
sqlite3_release_memory [expr 7*1132]
|
||||
list [nPage db] [nPage db2]
|
||||
} {1 3}
|
||||
} {0 3}
|
||||
do_test malloc5-6.3.3 {
|
||||
# Try to release another 1000 bytes. This should come fromt the db
|
||||
# cache, since all three pages held by db2 are either in-use or diry.
|
||||
sqlite3_release_memory 1000
|
||||
list [nPage db] [nPage db2]
|
||||
} {1 3}
|
||||
} {0 3}
|
||||
do_test malloc5-6.3.4 {
|
||||
# Now release 9900 more (about 9 pages worth). This should expunge
|
||||
# the rest of the db cache. But the db2 cache remains intact, because
|
||||
@@ -394,20 +396,20 @@ do_test malloc5-6.3.4 {
|
||||
sqlite3_release_memory 9900
|
||||
}
|
||||
list [nPage db] [nPage db2]
|
||||
} {1 3}
|
||||
} {0 3}
|
||||
do_test malloc5-6.3.5 {
|
||||
# But if we are really insistent, SQLite will consent to call sync()
|
||||
# if there is no other option. UPDATE: As of 3.6.2, SQLite will not
|
||||
# call sync() in this scenario. So no further memory can be reclaimed.
|
||||
sqlite3_release_memory 1000
|
||||
list [nPage db] [nPage db2]
|
||||
} {1 3}
|
||||
} {0 3}
|
||||
do_test malloc5-6.3.6 {
|
||||
# The referenced page (page 1 of the db2 cache) will not be freed no
|
||||
# matter how much memory we ask for:
|
||||
sqlite3_release_memory 31459
|
||||
list [nPage db] [nPage db2]
|
||||
} {1 3}
|
||||
} {0 3}
|
||||
|
||||
db2 close
|
||||
|
||||
|
||||
@@ -265,6 +265,8 @@ test_suite "fts3" -prefix "" -description {
|
||||
fts4incr.test fts4langid.test fts4lastrowid.test fts4merge2.test
|
||||
fts4merge4.test fts4merge.test fts4noti.test fts4onepass.test
|
||||
fts4opt.test fts4unicode.test
|
||||
fts3corrupt3.test
|
||||
fts3misc.test
|
||||
}
|
||||
|
||||
test_suite "fts5" -prefix "" -description {
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
# 2010 June 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.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
source $testdir/lock_common.tcl
|
||||
source $testdir/malloc_common.tcl
|
||||
set testprefix pragmafault
|
||||
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
sqlite3_db_config_lookaside db 0 0 0
|
||||
do_execsql_test 1.0 {
|
||||
CREATE TABLE t1(a, b, CHECK(a!=b));
|
||||
INSERT INTO t1 VALUES(1, 2);
|
||||
INSERT INTO t1 VALUES(3, 4);
|
||||
}
|
||||
faultsim_save_and_close
|
||||
|
||||
do_faultsim_test 1 -prep {
|
||||
faultsim_restore_and_reopen
|
||||
} -body {
|
||||
catchsql { PRAGMA integrity_check }
|
||||
set {} 0
|
||||
} -test {
|
||||
faultsim_test_result {0 0}
|
||||
}
|
||||
|
||||
|
||||
finish_test
|
||||
@@ -0,0 +1,59 @@
|
||||
# 2017 April 29
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix pushdown
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE TABLE t1(a, b, c);
|
||||
INSERT INTO t1 VALUES(1, 'b1', 'c1');
|
||||
INSERT INTO t1 VALUES(2, 'b2', 'c2');
|
||||
INSERT INTO t1 VALUES(3, 'b3', 'c3');
|
||||
INSERT INTO t1 VALUES(4, 'b4', 'c4');
|
||||
CREATE INDEX i1 ON t1(a, c);
|
||||
}
|
||||
|
||||
proc f {val} {
|
||||
lappend ::L $val
|
||||
return 0
|
||||
}
|
||||
db func f f
|
||||
|
||||
do_test 1.1 {
|
||||
set L [list]
|
||||
execsql { SELECT * FROM t1 WHERE a=2 AND f(b) AND f(c) }
|
||||
set L
|
||||
} {c2}
|
||||
|
||||
do_test 1.2 {
|
||||
set L [list]
|
||||
execsql { SELECT * FROM t1 WHERE a=3 AND f(c) AND f(b) }
|
||||
set L
|
||||
} {c3}
|
||||
|
||||
do_execsql_test 1.3 {
|
||||
DROP INDEX i1;
|
||||
CREATE INDEX i1 ON t1(a, b);
|
||||
}
|
||||
do_test 1.4 {
|
||||
set L [list]
|
||||
execsql { SELECT * FROM t1 WHERE a=2 AND f(b) AND f(c) }
|
||||
set L
|
||||
} {b2}
|
||||
|
||||
do_test 1.5 {
|
||||
set L [list]
|
||||
execsql { SELECT * FROM t1 WHERE a=3 AND f(c) AND f(b) }
|
||||
set L
|
||||
} {b3}
|
||||
|
||||
finish_test
|
||||
@@ -73,6 +73,26 @@ foreach {tn schema output} {
|
||||
CREATE INDEX 'y1_a' ON 'y1'('a' COLLATE nocase); --> x1(a)
|
||||
}
|
||||
|
||||
7 {
|
||||
CREATE TABLE x1(a PRIMARY KEY COLLATE nocase, b);
|
||||
CREATE TABLE y1(a REFERENCES x1);
|
||||
} {
|
||||
CREATE INDEX 'y1_a' ON 'y1'('a' COLLATE nocase); --> x1(a)
|
||||
}
|
||||
|
||||
8 {
|
||||
CREATE TABLE x1(a, b COLLATE nocase, c COLLATE rtrim, PRIMARY KEY(c, b, a));
|
||||
CREATE TABLE y1(d, e, f, FOREIGN KEY(d, e, f) REFERENCES x1);
|
||||
} {
|
||||
CREATE INDEX 'y1_d_e_f' ON 'y1'('d' COLLATE rtrim, 'e' COLLATE nocase, 'f'); --> x1(c,b,a)
|
||||
}
|
||||
|
||||
9 {
|
||||
CREATE TABLE p1(a, b UNIQUE);
|
||||
CREATE TABLE c1(x INTEGER PRIMARY KEY REFERENCES p1(b));
|
||||
} {
|
||||
}
|
||||
|
||||
} {
|
||||
forcedelete test.db
|
||||
sqlite3 db test.db
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
# 2017 May 9
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix subjournal
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
PRAGMA temp_store = memory;
|
||||
CREATE TABLE t1(a,b,c);
|
||||
INSERT INTO t1 VALUES(1, 2, 3);
|
||||
} {}
|
||||
do_execsql_test 1.1 {
|
||||
BEGIN;
|
||||
INSERT INTO t1 VALUES(4, 5, 6);
|
||||
SAVEPOINT one;
|
||||
INSERT INTO t1 VALUES(7, 8, 9);
|
||||
ROLLBACK TO one;
|
||||
SELECT * FROM t1;
|
||||
} {1 2 3 4 5 6}
|
||||
do_execsql_test 1.2 {
|
||||
COMMIT;
|
||||
}
|
||||
|
||||
do_execsql_test 2.0 {
|
||||
PRAGMA cache_size = 5;
|
||||
CREATE TABLE t2(a BLOB);
|
||||
CREATE INDEX i2 ON t2(a);
|
||||
WITH s(i) AS (
|
||||
SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<100
|
||||
) INSERT INTO t2 SELECT randomblob(500) FROM s;
|
||||
}
|
||||
|
||||
do_test 2.1 {
|
||||
forcedelete test.db2
|
||||
sqlite3 db2 test2.db
|
||||
sqlite3_backup B db2 main db main
|
||||
set nPage [db one {PRAGMA page_count}]
|
||||
B step [expr $nPage-10]
|
||||
} {SQLITE_OK}
|
||||
|
||||
do_execsql_test 2.2 {
|
||||
BEGIN;
|
||||
UPDATE t2 SET a=randomblob(499);
|
||||
SAVEPOINT two;
|
||||
UPDATE t2 SET a=randomblob(498);
|
||||
ROLLBACK TO two;
|
||||
COMMIT;
|
||||
PRAGMA integrity_check;
|
||||
} {ok}
|
||||
|
||||
do_test 2.3 {
|
||||
B step 1000
|
||||
} {SQLITE_DONE}
|
||||
do_test 2.4 {
|
||||
B finish
|
||||
execsql { PRAGMA integrity_check } db2
|
||||
} {ok}
|
||||
|
||||
finish_test
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@ set testprefix sync2
|
||||
# enabled. Also, since every test uses an ATTACHed database, they
|
||||
# are only run when ATTACH is enabled.
|
||||
#
|
||||
ifcapable !pager_pragmas||!attach {
|
||||
ifcapable !pager_pragmas||!attach||!dirsync {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
@@ -39,6 +39,7 @@ set extras {
|
||||
REGISTER
|
||||
VECTOR
|
||||
SELECT_COLUMN
|
||||
IF_NULL_ROW
|
||||
ASTERISK
|
||||
SPAN
|
||||
SPACE
|
||||
|
||||
+7
-7
@@ -250,7 +250,7 @@ static void StrAppend(Str *p, const char *z){
|
||||
sqlite3_uint64 nNew;
|
||||
if( p->oomErr ) return;
|
||||
nNew = p->nAlloc*2 + 100 + n;
|
||||
zNew = sqlite3_realloc(p->z, nNew);
|
||||
zNew = sqlite3_realloc(p->z, (int)nNew);
|
||||
if( zNew==0 ){
|
||||
sqlite3_free(p->z);
|
||||
memset(p, 0, sizeof(*p));
|
||||
@@ -260,7 +260,7 @@ static void StrAppend(Str *p, const char *z){
|
||||
p->z = zNew;
|
||||
p->nAlloc = nNew;
|
||||
}
|
||||
memcpy(p->z + p->n, z, n);
|
||||
memcpy(p->z + p->n, z, (size_t)n);
|
||||
p->n += n;
|
||||
p->z[p->n] = 0;
|
||||
}
|
||||
@@ -1116,15 +1116,15 @@ int main(int argc, char **argv){
|
||||
** if the database file is the input being fuzzed, the SQL text is
|
||||
** fuzzed at the same time. */
|
||||
if( sqlite3_table_column_metadata(db,0,"autoexec","sql",0,0,0,0,0)==0 ){
|
||||
sqlite3_stmt *pStmt;
|
||||
rc = sqlite3_prepare_v2(db, "SELECT sql FROM autoexec", -1, &pStmt, 0);
|
||||
sqlite3_stmt *pStmt2;
|
||||
rc = sqlite3_prepare_v2(db,"SELECT sql FROM autoexec",-1,&pStmt2,0);
|
||||
if( rc==SQLITE_OK ){
|
||||
while( sqlite3_step(pStmt)==SQLITE_ROW ){
|
||||
StrAppend(&sql, (const char*)sqlite3_column_text(pStmt, 0));
|
||||
while( sqlite3_step(pStmt2)==SQLITE_ROW ){
|
||||
StrAppend(&sql, (const char*)sqlite3_column_text(pStmt2, 0));
|
||||
StrAppend(&sql, "\n");
|
||||
}
|
||||
}
|
||||
sqlite3_finalize(pStmt);
|
||||
sqlite3_finalize(pStmt2);
|
||||
zSql = StrStr(&sql);
|
||||
}
|
||||
|
||||
|
||||
+49
-49
@@ -168,12 +168,12 @@ static struct action *Action_new(void);
|
||||
static struct action *Action_sort(struct action *);
|
||||
|
||||
/********** From the file "build.h" ************************************/
|
||||
void FindRulePrecedences();
|
||||
void FindFirstSets();
|
||||
void FindStates();
|
||||
void FindLinks();
|
||||
void FindFollowSets();
|
||||
void FindActions();
|
||||
void FindRulePrecedences(struct lemon*);
|
||||
void FindFirstSets(struct lemon*);
|
||||
void FindStates(struct lemon*);
|
||||
void FindLinks(struct lemon*);
|
||||
void FindFollowSets(struct lemon*);
|
||||
void FindActions(struct lemon*);
|
||||
|
||||
/********* From the file "configlist.h" *********************************/
|
||||
void Configlist_init(void);
|
||||
@@ -457,7 +457,7 @@ struct state *State_new(void);
|
||||
void State_init(void);
|
||||
int State_insert(struct state *, struct config *);
|
||||
struct state *State_find(struct config *);
|
||||
struct state **State_arrayof(/* */);
|
||||
struct state **State_arrayof(void);
|
||||
|
||||
/* Routines used for efficiency in Configlist_add */
|
||||
|
||||
@@ -561,8 +561,8 @@ void Action_add(
|
||||
** default action for the state_number is returned.
|
||||
**
|
||||
** All actions associated with a single state_number are first entered
|
||||
** into aLookahead[] using multiple calls to acttab_action(). Then the
|
||||
** actions for that single state_number are placed into the aAction[]
|
||||
** into aLookahead[] using multiple calls to acttab_action(). Then the
|
||||
** actions for that single state_number are placed into the aAction[]
|
||||
** array with a single call to acttab_insert(). The acttab_insert() call
|
||||
** also resets the aLookahead[] array in preparation for the next
|
||||
** state number.
|
||||
@@ -612,7 +612,7 @@ acttab *acttab_alloc(void){
|
||||
return p;
|
||||
}
|
||||
|
||||
/* Add a new action to the current transaction set.
|
||||
/* Add a new action to the current transaction set.
|
||||
**
|
||||
** This routine is called once for each lookahead for a particular
|
||||
** state.
|
||||
@@ -674,7 +674,7 @@ int acttab_insert(acttab *p){
|
||||
}
|
||||
}
|
||||
|
||||
/* Scan the existing action table looking for an offset that is a
|
||||
/* Scan the existing action table looking for an offset that is a
|
||||
** duplicate of the current transaction set. Fall out of the loop
|
||||
** if and when the duplicate is found.
|
||||
**
|
||||
@@ -752,7 +752,7 @@ int acttab_insert(acttab *p){
|
||||
*/
|
||||
|
||||
/* Find a precedence symbol of every rule in the grammar.
|
||||
**
|
||||
**
|
||||
** Those rules which have a precedence symbol coded in the input
|
||||
** grammar using the "[symbol]" construct will already have the
|
||||
** rp->precsym field filled. Other rules take as their precedence
|
||||
@@ -1072,7 +1072,7 @@ void FindFollowSets(struct lemon *lemp)
|
||||
cfp->status = INCOMPLETE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
do{
|
||||
progress = 0;
|
||||
for(i=0; i<lemp->nstate; i++){
|
||||
@@ -1103,7 +1103,7 @@ void FindActions(struct lemon *lemp)
|
||||
struct symbol *sp;
|
||||
struct rule *rp;
|
||||
|
||||
/* Add all of the reduce actions
|
||||
/* Add all of the reduce actions
|
||||
** A reduce action is added for each element of the followset of
|
||||
** a configuration which has its dot at the extreme right.
|
||||
*/
|
||||
@@ -1220,7 +1220,7 @@ static int resolve_conflict(
|
||||
apx->type = RD_RESOLVED;
|
||||
}
|
||||
}else{
|
||||
assert(
|
||||
assert(
|
||||
apx->type==SH_RESOLVED ||
|
||||
apx->type==RD_RESOLVED ||
|
||||
apx->type==SSCONFLICT ||
|
||||
@@ -1251,7 +1251,7 @@ static struct config *basis = 0; /* Top of list of basis configs */
|
||||
static struct config **basisend = 0; /* End of list of basis configs */
|
||||
|
||||
/* Return a pointer to a new configuration */
|
||||
PRIVATE struct config *newconfig(){
|
||||
PRIVATE struct config *newconfig(void){
|
||||
struct config *newcfg;
|
||||
if( freelist==0 ){
|
||||
int i;
|
||||
@@ -1277,7 +1277,7 @@ PRIVATE void deleteconfig(struct config *old)
|
||||
}
|
||||
|
||||
/* Initialized the configuration list builder */
|
||||
void Configlist_init(){
|
||||
void Configlist_init(void){
|
||||
current = 0;
|
||||
currentend = ¤t;
|
||||
basis = 0;
|
||||
@@ -1287,7 +1287,7 @@ void Configlist_init(){
|
||||
}
|
||||
|
||||
/* Initialized the configuration list builder */
|
||||
void Configlist_reset(){
|
||||
void Configlist_reset(void){
|
||||
current = 0;
|
||||
currentend = ¤t;
|
||||
basis = 0;
|
||||
@@ -1397,7 +1397,7 @@ void Configlist_closure(struct lemon *lemp)
|
||||
}
|
||||
|
||||
/* Sort the configuration list */
|
||||
void Configlist_sort(){
|
||||
void Configlist_sort(void){
|
||||
current = (struct config*)msort((char*)current,(char**)&(current->next),
|
||||
Configcmp);
|
||||
currentend = 0;
|
||||
@@ -1405,7 +1405,7 @@ void Configlist_sort(){
|
||||
}
|
||||
|
||||
/* Sort the basis configuration list */
|
||||
void Configlist_sortbasis(){
|
||||
void Configlist_sortbasis(void){
|
||||
basis = (struct config*)msort((char*)current,(char**)&(current->bp),
|
||||
Configcmp);
|
||||
basisend = 0;
|
||||
@@ -1414,7 +1414,7 @@ void Configlist_sortbasis(){
|
||||
|
||||
/* Return a pointer to the head of the configuration list and
|
||||
** reset the list */
|
||||
struct config *Configlist_return(){
|
||||
struct config *Configlist_return(void){
|
||||
struct config *old;
|
||||
old = current;
|
||||
current = 0;
|
||||
@@ -1424,7 +1424,7 @@ struct config *Configlist_return(){
|
||||
|
||||
/* Return a pointer to the head of the configuration list and
|
||||
** reset the list */
|
||||
struct config *Configlist_basis(){
|
||||
struct config *Configlist_basis(void){
|
||||
struct config *old;
|
||||
old = basis;
|
||||
basis = 0;
|
||||
@@ -1466,7 +1466,7 @@ void ErrorMsg(const char *filename, int lineno, const char *format, ...){
|
||||
/* Report an out-of-memory condition and abort. This function
|
||||
** is used mostly by the "MemoryCheck" macro in struct.h
|
||||
*/
|
||||
void memory_error(){
|
||||
void memory_error(void){
|
||||
fprintf(stderr,"Out of memory. Aborting...\n");
|
||||
exit(1);
|
||||
}
|
||||
@@ -1606,7 +1606,7 @@ int main(int argc, char **argv)
|
||||
OptInit(argv,options,stderr);
|
||||
if( version ){
|
||||
printf("Lemon version 1.0\n");
|
||||
exit(0);
|
||||
exit(0);
|
||||
}
|
||||
if( OptNArgs()!=1 ){
|
||||
fprintf(stderr,"Exactly one filename argument is required.\n");
|
||||
@@ -2051,7 +2051,7 @@ int OptInit(char **a, struct s_options *o, FILE *err)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int OptNArgs(){
|
||||
int OptNArgs(void){
|
||||
int cnt = 0;
|
||||
int dashdash = 0;
|
||||
int i;
|
||||
@@ -2078,7 +2078,7 @@ void OptErr(int n)
|
||||
if( i>=0 ) errline(i,0,errstream);
|
||||
}
|
||||
|
||||
void OptPrint(){
|
||||
void OptPrint(void){
|
||||
int i;
|
||||
int max, len;
|
||||
max = 0;
|
||||
@@ -2307,7 +2307,7 @@ to follow the previous rule.");
|
||||
case IN_RHS:
|
||||
if( x[0]=='.' ){
|
||||
struct rule *rp;
|
||||
rp = (struct rule *)calloc( sizeof(struct rule) +
|
||||
rp = (struct rule *)calloc( sizeof(struct rule) +
|
||||
sizeof(struct symbol*)*psp->nrhs + sizeof(char*)*psp->nrhs, 1);
|
||||
if( rp==0 ){
|
||||
ErrorMsg(psp->filename,psp->tokenlineno,
|
||||
@@ -2896,7 +2896,7 @@ void Parse(struct lemon *gp)
|
||||
static struct plink *plink_freelist = 0;
|
||||
|
||||
/* Allocate a new plink */
|
||||
struct plink *Plink_new(){
|
||||
struct plink *Plink_new(void){
|
||||
struct plink *newlink;
|
||||
|
||||
if( plink_freelist==0 ){
|
||||
@@ -2997,7 +2997,7 @@ PRIVATE FILE *file_open(
|
||||
return fp;
|
||||
}
|
||||
|
||||
/* Duplicate the input file without comments and without actions
|
||||
/* Duplicate the input file without comments and without actions
|
||||
** on rules */
|
||||
void Reprint(struct lemon *lemp)
|
||||
{
|
||||
@@ -3148,7 +3148,7 @@ int PrintAction(
|
||||
indent,ap->sp->name,ap->x.rp->iRule);
|
||||
break;
|
||||
case SSCONFLICT:
|
||||
fprintf(fp,"%*s shift %-7d ** Parsing conflict **",
|
||||
fprintf(fp,"%*s shift %-7d ** Parsing conflict **",
|
||||
indent,ap->sp->name,ap->x.stp->statenum);
|
||||
break;
|
||||
case SH_RESOLVED:
|
||||
@@ -3421,7 +3421,7 @@ PRIVATE void tplt_print(FILE *out, struct lemon *lemp, char *str, int *lineno)
|
||||
(*lineno)++;
|
||||
}
|
||||
if (!lemp->nolinenosflag) {
|
||||
(*lineno)++; tplt_linedir(out,*lineno,lemp->outname);
|
||||
(*lineno)++; tplt_linedir(out,*lineno,lemp->outname);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -3466,8 +3466,8 @@ void emit_destructor_code(
|
||||
fputc(*cp,out);
|
||||
}
|
||||
fprintf(out,"\n"); (*lineno)++;
|
||||
if (!lemp->nolinenosflag) {
|
||||
(*lineno)++; tplt_linedir(out,*lineno,lemp->outname);
|
||||
if (!lemp->nolinenosflag) {
|
||||
(*lineno)++; tplt_linedir(out,*lineno,lemp->outname);
|
||||
}
|
||||
fprintf(out,"}\n"); (*lineno)++;
|
||||
return;
|
||||
@@ -3590,7 +3590,7 @@ PRIVATE int translate_code(struct lemon *lemp, struct rule *rp){
|
||||
/* There is no LHS value symbol. */
|
||||
lhsdirect = 1;
|
||||
}else if( strcmp(rp->lhsalias,rp->rhsalias[0])==0 ){
|
||||
/* The LHS symbol and the left-most RHS symbol are the same, so
|
||||
/* The LHS symbol and the left-most RHS symbol are the same, so
|
||||
** direct writing is allowed */
|
||||
lhsdirect = 1;
|
||||
lhsused = 1;
|
||||
@@ -3601,7 +3601,7 @@ PRIVATE int translate_code(struct lemon *lemp, struct rule *rp){
|
||||
"different datatypes.",
|
||||
rp->lhs->name, rp->lhsalias, rp->rhs[0]->name, rp->rhsalias[0]);
|
||||
lemp->errorcnt++;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
lemon_sprintf(zOvwrt, "/*%s-overwrites-%s*/",
|
||||
rp->lhsalias, rp->rhsalias[0]);
|
||||
@@ -3740,7 +3740,7 @@ PRIVATE int translate_code(struct lemon *lemp, struct rule *rp){
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
** Generate code which executes when the rule "rp" is reduced. Write
|
||||
** the code to "out". Make sure lineno stays up-to-date.
|
||||
*/
|
||||
@@ -4161,7 +4161,7 @@ void ReportTable(
|
||||
for(i=0; i<lemp->nxstate; i++){
|
||||
for(ap=lemp->sorted[i]->ap; ap; ap=ap->next){
|
||||
if( ap->type==REDUCE || ap->type==SHIFTREDUCE ){
|
||||
ap->x.rp->doesReduce = i;
|
||||
ap->x.rp->doesReduce = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4237,7 +4237,7 @@ void ReportTable(
|
||||
fprintf(out, "#define YY_SHIFT_COUNT (%d)\n", n-1); lineno++;
|
||||
fprintf(out, "#define YY_SHIFT_MIN (%d)\n", mnTknOfst); lineno++;
|
||||
fprintf(out, "#define YY_SHIFT_MAX (%d)\n", mxTknOfst); lineno++;
|
||||
fprintf(out, "static const %s yy_shift_ofst[] = {\n",
|
||||
fprintf(out, "static const %s yy_shift_ofst[] = {\n",
|
||||
minimum_size_type(mnTknOfst, lemp->nterminal+lemp->nactiontab, &sz));
|
||||
lineno++;
|
||||
lemp->tablesize += n*sz;
|
||||
@@ -4264,7 +4264,7 @@ void ReportTable(
|
||||
fprintf(out, "#define YY_REDUCE_COUNT (%d)\n", n-1); lineno++;
|
||||
fprintf(out, "#define YY_REDUCE_MIN (%d)\n", mnNtOfst); lineno++;
|
||||
fprintf(out, "#define YY_REDUCE_MAX (%d)\n", mxNtOfst); lineno++;
|
||||
fprintf(out, "static const %s yy_reduce_ofst[] = {\n",
|
||||
fprintf(out, "static const %s yy_reduce_ofst[] = {\n",
|
||||
minimum_size_type(mnNtOfst-1, mxNtOfst, &sz)); lineno++;
|
||||
lemp->tablesize += n*sz;
|
||||
for(i=j=0; i<n; i++){
|
||||
@@ -4343,7 +4343,7 @@ void ReportTable(
|
||||
tplt_xfer(lemp->name,in,out,&lineno);
|
||||
|
||||
/* Generate code which executes every time a symbol is popped from
|
||||
** the stack while processing errors or while destroying the parser.
|
||||
** the stack while processing errors or while destroying the parser.
|
||||
** (In other words, generate the %destructor actions)
|
||||
*/
|
||||
if( lemp->tokendest ){
|
||||
@@ -4409,7 +4409,7 @@ void ReportTable(
|
||||
tplt_print(out,lemp,lemp->overflow,&lineno);
|
||||
tplt_xfer(lemp->name,in,out,&lineno);
|
||||
|
||||
/* Generate the table of rule information
|
||||
/* Generate the table of rule information
|
||||
**
|
||||
** Note: This code depends on the fact that rules are number
|
||||
** sequentually beginning with 0.
|
||||
@@ -4520,7 +4520,7 @@ void ReportHeader(struct lemon *lemp)
|
||||
for(i=1; i<lemp->nterminal; i++){
|
||||
fprintf(out,"#define %s%-30s %3d\n",prefix,lemp->symbols[i]->name,i);
|
||||
}
|
||||
fclose(out);
|
||||
fclose(out);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -4567,7 +4567,7 @@ void CompressTables(struct lemon *lemp)
|
||||
rbest = rp;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Do not make a default if the number of rules to default
|
||||
** is not at least 1 or if the wildcard token is a possible
|
||||
** lookahead.
|
||||
@@ -4724,7 +4724,7 @@ void SetSize(int n)
|
||||
}
|
||||
|
||||
/* Allocate a new set */
|
||||
char *SetNew(){
|
||||
char *SetNew(void){
|
||||
char *s;
|
||||
s = (char*)calloc( size, 1);
|
||||
if( s==0 ){
|
||||
@@ -4830,7 +4830,7 @@ typedef struct s_x1node {
|
||||
static struct s_x1 *x1a;
|
||||
|
||||
/* Allocate a new associative array */
|
||||
void Strsafe_init(){
|
||||
void Strsafe_init(void){
|
||||
if( x1a ) return;
|
||||
x1a = (struct s_x1*)malloc( sizeof(struct s_x1) );
|
||||
if( x1a ){
|
||||
@@ -4997,7 +4997,7 @@ typedef struct s_x2node {
|
||||
static struct s_x2 *x2a;
|
||||
|
||||
/* Allocate a new associative array */
|
||||
void Symbol_init(){
|
||||
void Symbol_init(void){
|
||||
if( x2a ) return;
|
||||
x2a = (struct s_x2*)malloc( sizeof(struct s_x2) );
|
||||
if( x2a ){
|
||||
@@ -5194,7 +5194,7 @@ typedef struct s_x3node {
|
||||
static struct s_x3 *x3a;
|
||||
|
||||
/* Allocate a new associative array */
|
||||
void State_init(){
|
||||
void State_init(void){
|
||||
if( x3a ) return;
|
||||
x3a = (struct s_x3*)malloc( sizeof(struct s_x3) );
|
||||
if( x3a ){
|
||||
@@ -5288,7 +5288,7 @@ struct state *State_find(struct config *key)
|
||||
/* Return an array of pointers to all data in the table.
|
||||
** The array is obtained from malloc. Return NULL if memory allocation
|
||||
** problems, or if the array is empty. */
|
||||
struct state **State_arrayof()
|
||||
struct state **State_arrayof(void)
|
||||
{
|
||||
struct state **array;
|
||||
int i,arrSize;
|
||||
@@ -5334,7 +5334,7 @@ typedef struct s_x4node {
|
||||
static struct s_x4 *x4a;
|
||||
|
||||
/* Allocate a new associative array */
|
||||
void Configtable_init(){
|
||||
void Configtable_init(void){
|
||||
if( x4a ) return;
|
||||
x4a = (struct s_x4*)malloc( sizeof(struct s_x4) );
|
||||
if( x4a ){
|
||||
|
||||
+1
-1
@@ -83,7 +83,7 @@ Replace.exe:
|
||||
sqlite3.def: Replace.exe $(LIBOBJ)
|
||||
echo EXPORTS > sqlite3.def
|
||||
dumpbin /all $(LIBOBJ) \\
|
||||
| .\Replace.exe "^\s+/EXPORT:_?(sqlite3(?:session|changeset)?_[^@,]*)(?:@\d+|,DATA)?$$" $$1 true \\
|
||||
| .\Replace.exe "^\s+/EXPORT:_?(sqlite3(?:session|changeset|changegroup)?_[^@,]*)(?:@\d+|,DATA)?$$" $$1 true \\
|
||||
| sort >> sqlite3.def
|
||||
}]]
|
||||
|
||||
|
||||
@@ -363,7 +363,7 @@ set pragma_def {
|
||||
FLAG: Result0
|
||||
|
||||
NAME: optimize
|
||||
FLAG: Result1
|
||||
FLAG: Result1 NeedSchema
|
||||
}
|
||||
|
||||
# Open the output file
|
||||
|
||||
+5
-1
@@ -81,6 +81,9 @@ set declpattern2 \
|
||||
set declpattern3 \
|
||||
{^ *([a-zA-Z][a-zA-Z_0-9 ]+ \**)(sqlite3changeset_[_a-zA-Z0-9]+)(\(.*)$}
|
||||
|
||||
set declpattern4 \
|
||||
{^ *([a-zA-Z][a-zA-Z_0-9 ]+ \**)(sqlite3changegroup_[_a-zA-Z0-9]+)(\(.*)$}
|
||||
|
||||
# Force the output to use unix line endings, even on Windows.
|
||||
fconfigure stdout -translation lf
|
||||
|
||||
@@ -129,7 +132,8 @@ foreach file $filelist {
|
||||
} else {
|
||||
if {[regexp $declpattern1 $line all rettype funcname rest] || \
|
||||
[regexp $declpattern2 $line all rettype funcname rest] || \
|
||||
[regexp $declpattern3 $line all rettype funcname rest]} {
|
||||
[regexp $declpattern3 $line all rettype funcname rest] || \
|
||||
[regexp $declpattern4 $line all rettype funcname rest]} {
|
||||
set line SQLITE_API
|
||||
append line " " [string trim $rettype]
|
||||
if {[string index $rettype end] ne "*"} {
|
||||
|
||||
+16
-8
@@ -1,6 +1,3 @@
|
||||
|
||||
set rcsid {$Id: omittest.tcl,v 1.8 2008/10/13 15:35:09 drh Exp $}
|
||||
|
||||
# Documentation for this script. This may be output to stderr
|
||||
# if the script is invoked incorrectly.
|
||||
set ::USAGE_MESSAGE {
|
||||
@@ -134,26 +131,37 @@ proc process_options {argv} {
|
||||
set ::TARGET testfixture ;# Default thing to build
|
||||
|
||||
for {set i 0} {$i < [llength $argv]} {incr i} {
|
||||
switch -- [lindex $argv $i] {
|
||||
-makefile {
|
||||
switch -regexp -- [lindex $argv $i] {
|
||||
-{1,2}makefile {
|
||||
incr i
|
||||
set ::MAKEFILE [lindex $argv $i]
|
||||
}
|
||||
|
||||
-nmake {
|
||||
-{1,2}nmake {
|
||||
set ::MAKEBIN nmake
|
||||
set ::MAKEFILE ./Makefile.msc
|
||||
}
|
||||
|
||||
-target {
|
||||
-{1,2}target {
|
||||
incr i
|
||||
set ::TARGET [lindex $argv $i]
|
||||
}
|
||||
|
||||
-skip_run {
|
||||
-{1,2}skip_run {
|
||||
set ::SKIP_RUN 1
|
||||
}
|
||||
|
||||
-{1,2}help {
|
||||
puts $::USAGE_MESSAGE
|
||||
exit
|
||||
}
|
||||
|
||||
-.* {
|
||||
puts stderr "Unknown option: [lindex $argv i]"
|
||||
puts stderr $::USAGE_MESSAGE
|
||||
exit 1
|
||||
}
|
||||
|
||||
default {
|
||||
if {[info exists ::SYMBOL]} {
|
||||
puts stderr [string trim $::USAGE_MESSAGE]
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
#if !defined(_MSC_VER)
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#else
|
||||
#include <io.h>
|
||||
#endif
|
||||
@@ -579,6 +580,14 @@ int main(int argc, char **argv){
|
||||
decode_btree_page(a, iStart, hdrSize, zLeft+1);
|
||||
free(a);
|
||||
continue;
|
||||
#if !defined(_MSC_VER)
|
||||
}else if( zLeft && strcmp(zLeft,"truncate")==0 ){
|
||||
/* Frame number followed by "truncate" truncates the WAL file
|
||||
** after that frame */
|
||||
off_t newSize = 32 + iStart*(pagesize+24);
|
||||
truncate(argv[1], newSize);
|
||||
continue;
|
||||
#endif
|
||||
}else{
|
||||
iEnd = iStart;
|
||||
}
|
||||
|
||||
+9
-7
@@ -4,13 +4,15 @@
|
||||
# compiler warnings in SQLite.
|
||||
#
|
||||
|
||||
# Use these for testing on Linux and Mac OSX:
|
||||
WARNING_OPTS="-Wshadow -Wall -Wextra -pedantic-errors -Wno-long-long"
|
||||
WARNING_ANDROID_OPTS="-Wshadow -Wall -Wextra"
|
||||
|
||||
# Use these for testing on OpenBSD:
|
||||
# WARNING_OPTS=-Wall
|
||||
# WARNING_ANDROID_OPTS=-Wall
|
||||
if uname | grep -i openbsd ; then
|
||||
# Use these for testing on OpenBSD:
|
||||
WARNING_OPTS=-Wall
|
||||
WARNING_ANDROID_OPTS=-Wall
|
||||
else
|
||||
# Use these for testing on Linux and Mac OSX:
|
||||
WARNING_OPTS="-Wshadow -Wall -Wextra -pedantic-errors -Wno-long-long"
|
||||
WARNING_ANDROID_OPTS="-Wshadow -Wall -Wextra"
|
||||
fi
|
||||
|
||||
rm -f sqlite3.c
|
||||
make sqlite3.c
|
||||
|
||||
Reference in New Issue
Block a user