Compare commits
40 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a0651b3707 | |||
| bb36d55e63 | |||
| 0766cbf511 | |||
| 692c160360 | |||
| ff176231da | |||
| 27c680cc69 | |||
| ff4ad29d05 | |||
| 1521ca4c20 | |||
| b204b6aa7b | |||
| 8797bd695f | |||
| 21363ac78d | |||
| f87a54ab41 | |||
| 52d0310256 | |||
| 65a46af7ae | |||
| b8123415b2 | |||
| 2ed4f5016a | |||
| 42f997d768 | |||
| 743188642d | |||
| 235b5d0ac5 | |||
| 7c5a829025 | |||
| 3f138e1d8f | |||
| ff7200e75b | |||
| 78f9ba9774 | |||
| 8ff952773d | |||
| 797fcb8433 | |||
| 8c411f7fce | |||
| 195ef6baca | |||
| 5af9fd53f4 | |||
| 4a9a5cbbe9 | |||
| 6010980914 | |||
| fe4ed96006 | |||
| 4098aa5d19 | |||
| 555aaa432c | |||
| c5900bfd59 | |||
| c60c928717 | |||
| 8f924f0530 | |||
| 610a5bafe2 | |||
| 8bc2647e0c | |||
| 1107b4b9cf | |||
| caa7a62591 |
+9
-5
@@ -796,6 +796,10 @@ has_tclsh85:
|
||||
sh $(TOP)/tool/cktclsh.sh 8.5 $(TCLSH_CMD)
|
||||
touch has_tclsh85
|
||||
|
||||
has_tclconfig:
|
||||
@ if test x"$(HAVE_TCL)" != "x1"; then echo 'ERROR: Requires access to "tclConfig.sh" which "configure" was not able to locate'; exit 1; fi
|
||||
touch has_tclconfig
|
||||
|
||||
|
||||
# This target creates a directory named "tsrc" and fills it with
|
||||
# copies of all of the C source code and header files needed to
|
||||
@@ -1118,7 +1122,7 @@ tclsqlite-shell.lo: $(TOP)/src/tclsqlite.c $(HDR)
|
||||
tclsqlite-stubs.lo: $(TOP)/src/tclsqlite.c $(HDR)
|
||||
$(LTCOMPILE) -DUSE_TCL_STUBS=1 -o $@ -c $(TOP)/src/tclsqlite.c
|
||||
|
||||
tclsqlite3$(TEXE): tclsqlite-shell.lo libsqlite3.la
|
||||
tclsqlite3$(TEXE): has_tclconfig tclsqlite-shell.lo libsqlite3.la
|
||||
$(LTLINK) -o $@ tclsqlite-shell.lo \
|
||||
libsqlite3.la $(LIBTCL)
|
||||
|
||||
@@ -1305,7 +1309,7 @@ TESTFIXTURE_SRC1 = sqlite3.c
|
||||
TESTFIXTURE_SRC = $(TESTSRC) $(TOP)/src/tclsqlite.c
|
||||
TESTFIXTURE_SRC += $(TESTFIXTURE_SRC$(USE_AMALGAMATION))
|
||||
|
||||
testfixture$(TEXE): has_tclsh85 $(TESTFIXTURE_SRC)
|
||||
testfixture$(TEXE): has_tclconfig has_tclsh85 $(TESTFIXTURE_SRC)
|
||||
$(LTLINK) -DSQLITE_NO_SYNC=1 $(TEMP_STORE) $(TESTFIXTURE_FLAGS) \
|
||||
-o $@ $(TESTFIXTURE_SRC) $(LIBTCL) $(TLIBS)
|
||||
|
||||
@@ -1404,13 +1408,13 @@ shelltest: $(TESTPROGS)
|
||||
sqlite3_analyzer.c: sqlite3.c $(TOP)/src/tclsqlite.c $(TOP)/tool/spaceanal.tcl $(TOP)/tool/mkccode.tcl $(TOP)/tool/sqlite3_analyzer.c.in has_tclsh85
|
||||
$(TCLSH_CMD) $(TOP)/tool/mkccode.tcl $(TOP)/tool/sqlite3_analyzer.c.in >sqlite3_analyzer.c
|
||||
|
||||
sqlite3_analyzer$(TEXE): sqlite3_analyzer.c
|
||||
sqlite3_analyzer$(TEXE): has_tclconfig sqlite3_analyzer.c
|
||||
$(LTLINK) sqlite3_analyzer.c -o $@ $(LIBTCL) $(TLIBS)
|
||||
|
||||
sqltclsh.c: sqlite3.c $(TOP)/src/tclsqlite.c $(TOP)/tool/sqltclsh.tcl $(TOP)/ext/misc/appendvfs.c $(TOP)/tool/mkccode.tcl $(TOP)/tool/sqltclsh.c.in has_tclsh85
|
||||
$(TCLSH_CMD) $(TOP)/tool/mkccode.tcl $(TOP)/tool/sqltclsh.c.in >sqltclsh.c
|
||||
|
||||
sqltclsh$(TEXE): sqltclsh.c
|
||||
sqltclsh$(TEXE): has_tclconfig sqltclsh.c
|
||||
$(LTLINK) sqltclsh.c -o $@ $(LIBTCL) $(TLIBS)
|
||||
|
||||
sqlite3_expert$(TEXE): $(TOP)/ext/expert/sqlite3expert.h $(TOP)/ext/expert/sqlite3expert.c $(TOP)/ext/expert/expert.c sqlite3.c
|
||||
@@ -1429,7 +1433,7 @@ CHECKER_DEPS =\
|
||||
sqlite3_checker.c: $(CHECKER_DEPS) has_tclsh85
|
||||
$(TCLSH_CMD) $(TOP)/tool/mkccode.tcl $(TOP)/ext/repair/sqlite3_checker.c.in >$@
|
||||
|
||||
sqlite3_checker$(TEXE): sqlite3_checker.c
|
||||
sqlite3_checker$(TEXE): has_tclconfig sqlite3_checker.c
|
||||
$(LTLINK) sqlite3_checker.c -o $@ $(LIBTCL) $(TLIBS)
|
||||
|
||||
dbdump$(TEXE): $(TOP)/ext/misc/dbdump.c sqlite3.lo
|
||||
|
||||
@@ -888,6 +888,7 @@ enable_libtool_lock
|
||||
enable_largefile
|
||||
with_tclsh
|
||||
with_tcl
|
||||
enable_tcl
|
||||
with_wasi_sdk
|
||||
enable_threadsafe
|
||||
enable_releasemode
|
||||
@@ -1543,6 +1544,8 @@ Optional Features:
|
||||
optimize for fast installation [default=yes]
|
||||
--disable-libtool-lock avoid locking (might break parallel builds)
|
||||
--disable-largefile omit support for large files
|
||||
--disable-tcl omit building accessory programs that require
|
||||
TCL-dev
|
||||
--disable-threadsafe Disable mutexing
|
||||
--enable-releasemode Support libtool link to release mode
|
||||
--enable-tempstore Use an in-ram database for temporary tables
|
||||
@@ -3936,13 +3939,13 @@ if ${lt_cv_nm_interface+:} false; then :
|
||||
else
|
||||
lt_cv_nm_interface="BSD nm"
|
||||
echo "int some_variable = 0;" > conftest.$ac_ext
|
||||
(eval echo "\"\$as_me:3939: $ac_compile\"" >&5)
|
||||
(eval echo "\"\$as_me:3942: $ac_compile\"" >&5)
|
||||
(eval "$ac_compile" 2>conftest.err)
|
||||
cat conftest.err >&5
|
||||
(eval echo "\"\$as_me:3942: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
|
||||
(eval echo "\"\$as_me:3945: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
|
||||
(eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
|
||||
cat conftest.err >&5
|
||||
(eval echo "\"\$as_me:3945: output\"" >&5)
|
||||
(eval echo "\"\$as_me:3948: output\"" >&5)
|
||||
cat conftest.out >&5
|
||||
if $GREP 'External.*some_variable' conftest.out > /dev/null; then
|
||||
lt_cv_nm_interface="MS dumpbin"
|
||||
@@ -5148,7 +5151,7 @@ ia64-*-hpux*)
|
||||
;;
|
||||
*-*-irix6*)
|
||||
# Find out which ABI we are using.
|
||||
echo '#line 5151 "configure"' > conftest.$ac_ext
|
||||
echo '#line 5154 "configure"' > conftest.$ac_ext
|
||||
if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
|
||||
(eval $ac_compile) 2>&5
|
||||
ac_status=$?
|
||||
@@ -6673,11 +6676,11 @@ else
|
||||
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
|
||||
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
|
||||
-e 's:$: $lt_compiler_flag:'`
|
||||
(eval echo "\"\$as_me:6676: $lt_compile\"" >&5)
|
||||
(eval echo "\"\$as_me:6679: $lt_compile\"" >&5)
|
||||
(eval "$lt_compile" 2>conftest.err)
|
||||
ac_status=$?
|
||||
cat conftest.err >&5
|
||||
echo "$as_me:6680: \$? = $ac_status" >&5
|
||||
echo "$as_me:6683: \$? = $ac_status" >&5
|
||||
if (exit $ac_status) && test -s "$ac_outfile"; then
|
||||
# The compiler can only warn and ignore the option if not recognized
|
||||
# So say no if there are warnings other than the usual output.
|
||||
@@ -7012,11 +7015,11 @@ else
|
||||
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
|
||||
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
|
||||
-e 's:$: $lt_compiler_flag:'`
|
||||
(eval echo "\"\$as_me:7015: $lt_compile\"" >&5)
|
||||
(eval echo "\"\$as_me:7018: $lt_compile\"" >&5)
|
||||
(eval "$lt_compile" 2>conftest.err)
|
||||
ac_status=$?
|
||||
cat conftest.err >&5
|
||||
echo "$as_me:7019: \$? = $ac_status" >&5
|
||||
echo "$as_me:7022: \$? = $ac_status" >&5
|
||||
if (exit $ac_status) && test -s "$ac_outfile"; then
|
||||
# The compiler can only warn and ignore the option if not recognized
|
||||
# So say no if there are warnings other than the usual output.
|
||||
@@ -7117,11 +7120,11 @@ else
|
||||
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
|
||||
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
|
||||
-e 's:$: $lt_compiler_flag:'`
|
||||
(eval echo "\"\$as_me:7120: $lt_compile\"" >&5)
|
||||
(eval echo "\"\$as_me:7123: $lt_compile\"" >&5)
|
||||
(eval "$lt_compile" 2>out/conftest.err)
|
||||
ac_status=$?
|
||||
cat out/conftest.err >&5
|
||||
echo "$as_me:7124: \$? = $ac_status" >&5
|
||||
echo "$as_me:7127: \$? = $ac_status" >&5
|
||||
if (exit $ac_status) && test -s out/conftest2.$ac_objext
|
||||
then
|
||||
# The compiler can only warn and ignore the option if not recognized
|
||||
@@ -7172,11 +7175,11 @@ else
|
||||
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
|
||||
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
|
||||
-e 's:$: $lt_compiler_flag:'`
|
||||
(eval echo "\"\$as_me:7175: $lt_compile\"" >&5)
|
||||
(eval echo "\"\$as_me:7178: $lt_compile\"" >&5)
|
||||
(eval "$lt_compile" 2>out/conftest.err)
|
||||
ac_status=$?
|
||||
cat out/conftest.err >&5
|
||||
echo "$as_me:7179: \$? = $ac_status" >&5
|
||||
echo "$as_me:7182: \$? = $ac_status" >&5
|
||||
if (exit $ac_status) && test -s out/conftest2.$ac_objext
|
||||
then
|
||||
# The compiler can only warn and ignore the option if not recognized
|
||||
@@ -9552,7 +9555,7 @@ else
|
||||
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
|
||||
lt_status=$lt_dlunknown
|
||||
cat > conftest.$ac_ext <<_LT_EOF
|
||||
#line 9555 "configure"
|
||||
#line 9558 "configure"
|
||||
#include "confdefs.h"
|
||||
|
||||
#if HAVE_DLFCN_H
|
||||
@@ -9648,7 +9651,7 @@ else
|
||||
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
|
||||
lt_status=$lt_dlunknown
|
||||
cat > conftest.$ac_ext <<_LT_EOF
|
||||
#line 9651 "configure"
|
||||
#line 9654 "configure"
|
||||
#include "confdefs.h"
|
||||
|
||||
#if HAVE_DLFCN_H
|
||||
@@ -10320,6 +10323,14 @@ if test "${with_tcl+set}" = set; then :
|
||||
withval=$with_tcl;
|
||||
fi
|
||||
|
||||
# Check whether --enable-tcl was given.
|
||||
if test "${enable_tcl+set}" = set; then :
|
||||
enableval=$enable_tcl; use_tcl=$enableval
|
||||
else
|
||||
use_tcl=yes
|
||||
fi
|
||||
|
||||
original_use_tcl=${use_tcl}
|
||||
if test x"${with_tclsh}" == x -a x"${with_tcl}" == x; then
|
||||
for ac_prog in tclsh8.6 tclsh tclsh9.0
|
||||
do
|
||||
@@ -10370,60 +10381,74 @@ if test x"${with_tclsh}" != x -a x"${with_tclsh}" != xnone; then
|
||||
TCLSH_CMD=${with_tclsh}
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: using tclsh at \"$TCLSH_CMD\"" >&5
|
||||
$as_echo "using tclsh at \"$TCLSH_CMD\"" >&6; }
|
||||
with_tcl=`${with_tclsh} <${srcdir}/tool/find_tclconfig.tcl`
|
||||
if test x"${with_tcl}" != x; then
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $TCLSH_CMD recommends the tclConfig.sh at ${with_tcl}" >&5
|
||||
if test x"${use_tcl}" = "xyes"; then
|
||||
with_tcl=`${with_tclsh} <${srcdir}/tool/find_tclconfig.tcl`
|
||||
if test x"${with_tcl}" != x; then
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $TCLSH_CMD recommends the tclConfig.sh at ${with_tcl}" >&5
|
||||
$as_echo "$TCLSH_CMD recommends the tclConfig.sh at ${with_tcl}" >&6; }
|
||||
else
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $TCLSH_CMD is unable to recommend a tclConfig.sh" >&5
|
||||
else
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $TCLSH_CMD is unable to recommend a tclConfig.sh" >&5
|
||||
$as_echo "$as_me: WARNING: $TCLSH_CMD is unable to recommend a tclConfig.sh" >&2;}
|
||||
use_tcl=no
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
if test x"${with_tcl}" != x; then
|
||||
if test -r ${with_tcl}/tclConfig.sh; then
|
||||
tclconfig="${with_tcl}/tclConfig.sh"
|
||||
if test x"${use_tcl}" = "xyes"; then
|
||||
if test x"${with_tcl}" != x; then
|
||||
if test -r ${with_tcl}/tclConfig.sh; then
|
||||
tclconfig="${with_tcl}/tclConfig.sh"
|
||||
else
|
||||
for i in tcl8.6 tcl9.0 lib; do
|
||||
if test -r ${with_tcl}/$i/tclConfig.sh; then
|
||||
tclconfig=${with_tcl}/$i/tclConfig.sh
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
if test ! -r "${tclconfig}"; then
|
||||
as_fn_error $? "no tclConfig.sh file found under ${with_tcl}" "$LINENO" 5
|
||||
fi
|
||||
else
|
||||
for i in tcl8.6 tcl9.0 lib; do
|
||||
if test -r ${with_tcl}/$i/tclConfig.sh; then
|
||||
tclconfig=${with_tcl}/$i/tclConfig.sh
|
||||
break
|
||||
fi
|
||||
done
|
||||
# If we have not yet found a tclConfig.sh file, look in $libdir whic is
|
||||
# set automatically by autoconf or by the --prefix command-line option.
|
||||
# See https://sqlite.org/forum/forumpost/e04e693439a22457
|
||||
libdir=${prefix}/lib
|
||||
if test -r ${libdir}/tclConfig.sh; then
|
||||
tclconfig=${libdir}/tclConfig.sh
|
||||
else
|
||||
for i in tcl8.6 tcl9.0 lib; do
|
||||
if test -r ${libdir}/$i/tclConfig.sh; then
|
||||
tclconfig=${libdir}/$i/tclConfig.sh
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
if test ! -r "${tclconfig}"; then
|
||||
as_fn_error $? "cannot find a usable tclConfig.sh file.
|
||||
Use --with-tcl=DIR to specify a directory where tclConfig.sh can be found.
|
||||
SQLite does not use TCL internally, but TCL is required to build SQLite
|
||||
from canonical sources and TCL is required for testing." "$LINENO" 5
|
||||
fi
|
||||
fi
|
||||
if test ! -r "${tclconfig}"; then
|
||||
as_fn_error $? "no tclConfig.sh file found under ${with_tcl}" "$LINENO" 5
|
||||
fi
|
||||
else
|
||||
# If we have not yet found a tclConfig.sh file, look in $libdir whic is
|
||||
# set automatically by autoconf or by the --prefix command-line option.
|
||||
# See https://sqlite.org/forum/forumpost/e04e693439a22457
|
||||
libdir=${prefix}/lib
|
||||
if test -r ${libdir}/tclConfig.sh; then
|
||||
tclconfig=${libdir}/tclConfig.sh
|
||||
else
|
||||
for i in tcl8.6 tcl9.0 lib; do
|
||||
if test -r ${libdir}/$i/tclConfig.sh; then
|
||||
tclconfig=${libdir}/$i/tclConfig.sh
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
if test ! -r "${tclconfig}"; then
|
||||
as_fn_error $? "cannot find a usable tclConfig.sh file.
|
||||
Use --with-tcl=DIR to specify a directory where tclConfig.sh can be found.
|
||||
SQLite does not use TCL internally, but TCL is required to build SQLite
|
||||
from canonical sources and TCL is required for testing." "$LINENO" 5
|
||||
fi
|
||||
fi
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: loading TCL configuration from ${tclconfig}" >&5
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: loading TCL configuration from ${tclconfig}" >&5
|
||||
$as_echo "loading TCL configuration from ${tclconfig}" >&6; }
|
||||
. ${tclconfig}
|
||||
. ${tclconfig}
|
||||
|
||||
|
||||
|
||||
# There are lots of other configuration variables that are provided by the
|
||||
# tclConfig.sh file and that could be included here. But as of right now,
|
||||
# TCL_LIB_SPEC is the only what that the Makefile uses.
|
||||
# There are lots of other configuration variables that are provided by the
|
||||
# tclConfig.sh file and that could be included here. But as of right now,
|
||||
# TCL_LIB_SPEC is the only what that the Makefile uses.
|
||||
HAVE_TCL=1
|
||||
elif test x"${original_use_tcl}" = "xno"; then
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: unable to run tests because of --disable-tcl" >&5
|
||||
$as_echo "unable to run tests because of --disable-tcl" >&6; }
|
||||
HAVE_TCL=0
|
||||
else
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: unable to run tests because no tclConfig.sh file could be located" >&5
|
||||
$as_echo "unable to run tests because no tclConfig.sh file could be located" >&6; }
|
||||
HAVE_TCL=0
|
||||
fi
|
||||
|
||||
if test x"$TCLSH_CMD" == x; then
|
||||
TCLSH_CMD=${TCL_EXEC_PREFIX}/bin/tclsh${TCL_VERSION}
|
||||
@@ -10445,14 +10470,10 @@ if test "$TCLSH_CMD" = "none"; then
|
||||
$as_echo "$as_me: WARNING: Warning: can't find tclsh - defaulting to non-amalgamation build." >&2;}
|
||||
USE_AMALGAMATION=0
|
||||
TCLSH_CMD="tclsh"
|
||||
HAVE_TCL=0
|
||||
else
|
||||
HAVE_TCL=1
|
||||
fi
|
||||
|
||||
|
||||
|
||||
|
||||
if test "x${TCLLIBDIR+set}" != "xset" ; then
|
||||
for i in `echo 'puts stdout $auto_path' | ${TCLSH_CMD}` ; do
|
||||
if test -d $i ; then
|
||||
|
||||
+62
-51
@@ -121,6 +121,9 @@ USE_AMALGAMATION=1
|
||||
#
|
||||
AC_ARG_WITH(tclsh, AS_HELP_STRING([--with-tclsh=PATHNAME],[full pathname of a tclsh to use]))
|
||||
AC_ARG_WITH(tcl, AS_HELP_STRING([--with-tcl=DIR],[directory containing (tclConfig.sh)]))
|
||||
AC_ARG_ENABLE(tcl, AS_HELP_STRING([--disable-tcl],[omit building accessory programs that require TCL-dev]),
|
||||
[use_tcl=$enableval],[use_tcl=yes])
|
||||
original_use_tcl=${use_tcl}
|
||||
if test x"${with_tclsh}" == x -a x"${with_tcl}" == x; then
|
||||
AC_CHECK_PROGS(TCLSH_CMD, [tclsh8.6 tclsh tclsh9.0],none)
|
||||
with_tclsh=${TCLSH_CMD}
|
||||
@@ -128,58 +131,70 @@ fi
|
||||
if test x"${with_tclsh}" != x -a x"${with_tclsh}" != xnone; then
|
||||
TCLSH_CMD=${with_tclsh}
|
||||
AC_MSG_RESULT([using tclsh at "$TCLSH_CMD"])
|
||||
with_tcl=`${with_tclsh} <${srcdir}/tool/find_tclconfig.tcl`
|
||||
if test x"${use_tcl}" = "xyes"; then
|
||||
with_tcl=`${with_tclsh} <${srcdir}/tool/find_tclconfig.tcl`
|
||||
if test x"${with_tcl}" != x; then
|
||||
AC_MSG_RESULT([$TCLSH_CMD recommends the tclConfig.sh at ${with_tcl}])
|
||||
else
|
||||
AC_MSG_WARN([$TCLSH_CMD is unable to recommend a tclConfig.sh])
|
||||
use_tcl=no
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
if test x"${use_tcl}" = "xyes"; then
|
||||
if test x"${with_tcl}" != x; then
|
||||
AC_MSG_RESULT([$TCLSH_CMD recommends the tclConfig.sh at ${with_tcl}])
|
||||
if test -r ${with_tcl}/tclConfig.sh; then
|
||||
tclconfig="${with_tcl}/tclConfig.sh"
|
||||
else
|
||||
for i in tcl8.6 tcl9.0 lib; do
|
||||
if test -r ${with_tcl}/$i/tclConfig.sh; then
|
||||
tclconfig=${with_tcl}/$i/tclConfig.sh
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
if test ! -r "${tclconfig}"; then
|
||||
AC_MSG_ERROR([no tclConfig.sh file found under ${with_tcl}])
|
||||
fi
|
||||
else
|
||||
AC_MSG_WARN([$TCLSH_CMD is unable to recommend a tclConfig.sh])
|
||||
fi
|
||||
fi
|
||||
if test x"${with_tcl}" != x; then
|
||||
if test -r ${with_tcl}/tclConfig.sh; then
|
||||
tclconfig="${with_tcl}/tclConfig.sh"
|
||||
else
|
||||
for i in tcl8.6 tcl9.0 lib; do
|
||||
if test -r ${with_tcl}/$i/tclConfig.sh; then
|
||||
tclconfig=${with_tcl}/$i/tclConfig.sh
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
if test ! -r "${tclconfig}"; then
|
||||
AC_MSG_ERROR([no tclConfig.sh file found under ${with_tcl}])
|
||||
# If we have not yet found a tclConfig.sh file, look in $libdir whic is
|
||||
# set automatically by autoconf or by the --prefix command-line option.
|
||||
# See https://sqlite.org/forum/forumpost/e04e693439a22457
|
||||
libdir=${prefix}/lib
|
||||
if test -r ${libdir}/tclConfig.sh; then
|
||||
tclconfig=${libdir}/tclConfig.sh
|
||||
else
|
||||
for i in tcl8.6 tcl9.0 lib; do
|
||||
if test -r ${libdir}/$i/tclConfig.sh; then
|
||||
tclconfig=${libdir}/$i/tclConfig.sh
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
if test ! -r "${tclconfig}"; then
|
||||
AC_MSG_ERROR([cannot find a usable tclConfig.sh file.
|
||||
Use --with-tcl=DIR to specify a directory where tclConfig.sh can be found.
|
||||
SQLite does not use TCL internally, but TCL is required to build SQLite
|
||||
from canonical sources and TCL is required for testing.])
|
||||
fi
|
||||
fi
|
||||
AC_MSG_RESULT([loading TCL configuration from ${tclconfig}])
|
||||
. ${tclconfig}
|
||||
AC_SUBST(TCL_INCLUDE_SPEC)
|
||||
AC_SUBST(TCL_LIB_SPEC)
|
||||
AC_SUBST(TCL_STUB_LIB_SPEC)
|
||||
# There are lots of other configuration variables that are provided by the
|
||||
# tclConfig.sh file and that could be included here. But as of right now,
|
||||
# TCL_LIB_SPEC is the only what that the Makefile uses.
|
||||
HAVE_TCL=1
|
||||
elif test x"${original_use_tcl}" = "xno"; then
|
||||
AC_MSG_RESULT([unable to run tests because of --disable-tcl])
|
||||
HAVE_TCL=0
|
||||
else
|
||||
# If we have not yet found a tclConfig.sh file, look in $libdir whic is
|
||||
# set automatically by autoconf or by the --prefix command-line option.
|
||||
# See https://sqlite.org/forum/forumpost/e04e693439a22457
|
||||
libdir=${prefix}/lib
|
||||
if test -r ${libdir}/tclConfig.sh; then
|
||||
tclconfig=${libdir}/tclConfig.sh
|
||||
else
|
||||
for i in tcl8.6 tcl9.0 lib; do
|
||||
if test -r ${libdir}/$i/tclConfig.sh; then
|
||||
tclconfig=${libdir}/$i/tclConfig.sh
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
if test ! -r "${tclconfig}"; then
|
||||
AC_MSG_ERROR([cannot find a usable tclConfig.sh file.
|
||||
Use --with-tcl=DIR to specify a directory where tclConfig.sh can be found.
|
||||
SQLite does not use TCL internally, but TCL is required to build SQLite
|
||||
from canonical sources and TCL is required for testing.])
|
||||
fi
|
||||
AC_MSG_RESULT([unable to run tests because no tclConfig.sh file could be located])
|
||||
HAVE_TCL=0
|
||||
fi
|
||||
AC_MSG_RESULT([loading TCL configuration from ${tclconfig}])
|
||||
. ${tclconfig}
|
||||
AC_SUBST(TCL_INCLUDE_SPEC)
|
||||
AC_SUBST(TCL_LIB_SPEC)
|
||||
AC_SUBST(TCL_STUB_LIB_SPEC)
|
||||
# There are lots of other configuration variables that are provided by the
|
||||
# tclConfig.sh file and that could be included here. But as of right now,
|
||||
# TCL_LIB_SPEC is the only what that the Makefile uses.
|
||||
|
||||
AC_SUBST(HAVE_TCL)
|
||||
if test x"$TCLSH_CMD" == x; then
|
||||
TCLSH_CMD=${TCL_EXEC_PREFIX}/bin/tclsh${TCL_VERSION}
|
||||
if test ! -x ${TCLSH_CMD}; then
|
||||
@@ -198,12 +213,8 @@ if test "$TCLSH_CMD" = "none"; then
|
||||
AC_MSG_WARN([Warning: can't find tclsh - defaulting to non-amalgamation build.])
|
||||
USE_AMALGAMATION=0
|
||||
TCLSH_CMD="tclsh"
|
||||
HAVE_TCL=0
|
||||
else
|
||||
HAVE_TCL=1
|
||||
fi
|
||||
AC_SUBST(TCLSH_CMD)
|
||||
AC_SUBST(HAVE_TCL)
|
||||
|
||||
AC_ARG_VAR([TCLLIBDIR], [Where to install tcl plugin])
|
||||
if test "x${TCLLIBDIR+set}" != "xset" ; then
|
||||
|
||||
@@ -53,11 +53,6 @@
|
||||
# define CIO_WIN_WC_XLATE 0 /* Not exposing translation routines at all */
|
||||
#endif
|
||||
|
||||
#if CIO_WIN_WC_XLATE
|
||||
/* Character used to represent a known-incomplete UTF-8 char group (�) */
|
||||
static WCHAR cBadGroup = 0xfffd;
|
||||
#endif
|
||||
|
||||
#if CIO_WIN_WC_XLATE
|
||||
static HANDLE handleOfFile(FILE *pf){
|
||||
int fileDesc = _fileno(pf);
|
||||
|
||||
@@ -54,7 +54,7 @@ struct Fts5Expr {
|
||||
|
||||
/*
|
||||
** eType:
|
||||
** Expression node type. Always one of:
|
||||
** Expression node type. Usually one of:
|
||||
**
|
||||
** FTS5_AND (nChild, apChild valid)
|
||||
** FTS5_OR (nChild, apChild valid)
|
||||
@@ -62,6 +62,10 @@ struct Fts5Expr {
|
||||
** FTS5_STRING (pNear valid)
|
||||
** FTS5_TERM (pNear valid)
|
||||
**
|
||||
** An expression node with eType==0 may also exist. It always matches zero
|
||||
** rows. This is created when a phrase containing no tokens is parsed.
|
||||
** e.g. "".
|
||||
**
|
||||
** iHeight:
|
||||
** Distance from this node to furthest leaf. This is always 0 for nodes
|
||||
** of type FTS5_STRING and FTS5_TERM. For all other nodes it is one
|
||||
@@ -3112,6 +3116,7 @@ static int fts5ExprCheckPoslists(Fts5ExprNode *pNode, i64 iRowid){
|
||||
pNode->iRowid = iRowid;
|
||||
pNode->bEof = 0;
|
||||
switch( pNode->eType ){
|
||||
case 0:
|
||||
case FTS5_TERM:
|
||||
case FTS5_STRING:
|
||||
return (pNode->pNear->apPhrase[0]->poslist.n>0);
|
||||
|
||||
@@ -2235,11 +2235,10 @@ static void *fts5ApiGetAuxdata(Fts5Context *pCtx, int bClear){
|
||||
}
|
||||
|
||||
static void fts5ApiPhraseNext(
|
||||
Fts5Context *pUnused,
|
||||
Fts5Context *pCtx,
|
||||
Fts5PhraseIter *pIter,
|
||||
int *piCol, int *piOff
|
||||
){
|
||||
UNUSED_PARAM(pUnused);
|
||||
if( pIter->a>=pIter->b ){
|
||||
*piCol = -1;
|
||||
*piOff = -1;
|
||||
@@ -2247,8 +2246,12 @@ static void fts5ApiPhraseNext(
|
||||
int iVal;
|
||||
pIter->a += fts5GetVarint32(pIter->a, iVal);
|
||||
if( iVal==1 ){
|
||||
/* Avoid returning a (*piCol) value that is too large for the table,
|
||||
** even if the position-list is corrupt. The caller might not be
|
||||
** expecting it. */
|
||||
int nCol = ((Fts5Table*)(((Fts5Cursor*)pCtx)->base.pVtab))->pConfig->nCol;
|
||||
pIter->a += fts5GetVarint32(pIter->a, iVal);
|
||||
*piCol = iVal;
|
||||
*piCol = (iVal>=nCol ? nCol-1 : iVal);
|
||||
*piOff = 0;
|
||||
pIter->a += fts5GetVarint32(pIter->a, iVal);
|
||||
}
|
||||
|
||||
@@ -90,7 +90,7 @@ static int fts5AsciiCreate(
|
||||
rc = SQLITE_ERROR;
|
||||
}
|
||||
}
|
||||
if( i<nArg ) rc = SQLITE_ERROR;
|
||||
if( rc==SQLITE_OK && i<nArg ) rc = SQLITE_ERROR;
|
||||
if( rc!=SQLITE_OK ){
|
||||
fts5AsciiDelete((Fts5Tokenizer*)p);
|
||||
p = 0;
|
||||
@@ -416,7 +416,7 @@ static int fts5UnicodeCreate(
|
||||
rc = SQLITE_ERROR;
|
||||
}
|
||||
}
|
||||
if( i<nArg ) rc = SQLITE_ERROR;
|
||||
if( i<nArg && rc==SQLITE_OK ) rc = SQLITE_ERROR;
|
||||
|
||||
}else{
|
||||
rc = SQLITE_NOMEM;
|
||||
@@ -1317,7 +1317,7 @@ static int fts5TriCreate(
|
||||
rc = SQLITE_ERROR;
|
||||
}
|
||||
}
|
||||
if( i<nArg ) rc = SQLITE_ERROR;
|
||||
if( i<nArg && rc==SQLITE_OK ) rc = SQLITE_ERROR;
|
||||
|
||||
if( pNew->iFoldParam!=0 && pNew->bFold==0 ){
|
||||
rc = SQLITE_ERROR;
|
||||
|
||||
@@ -8958,7 +8958,6 @@ do_catchsql_test 61.2 {
|
||||
SELECT * FROM t3 ORDER BY rowid;
|
||||
} {/*malformed database schema*/}
|
||||
|
||||
breakpoint
|
||||
#-------------------------------------------------------------------------
|
||||
do_test 62.0 {
|
||||
sqlite3 db {}
|
||||
@@ -10768,6 +10767,7 @@ do_catchsql_test 73.1 {
|
||||
reset_db
|
||||
do_test 74.0 {
|
||||
sqlite3 db {}
|
||||
sqlite3_fts5_register_matchinfo db
|
||||
db deserialize [decode_hexdb {
|
||||
| size 106496 pagesize 4096 filename x.db
|
||||
| page 1 offset 0
|
||||
@@ -14587,14 +14587,19 @@ do_test 74.0 {
|
||||
| end x.db
|
||||
}]} {}
|
||||
|
||||
do_catchsql_test 74.1 {
|
||||
SELECT rowid, quote(matchinfo(t1,'p�xyb<s')) FROM t1 WHERE t1 MATCH 'e*';
|
||||
do_catchsql_test 74.0.5 {
|
||||
SELECT matchinfo(1,2);
|
||||
} {1 {unable to use function matchinfo in the requested context}}
|
||||
|
||||
do_catchsql_test 74.1 {
|
||||
SELECT rowid, quote(matchinfo(t1,'pxyb<s')) FROM t1 WHERE t1 MATCH 'e*';
|
||||
} {1 {unrecognized matchinfo flag: <}}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_test 75.0 {
|
||||
sqlite3 db {}
|
||||
sqlite3_fts5_register_matchinfo db
|
||||
db deserialize [decode_hexdb {
|
||||
| size 32768 pagesize 4096 filename crash-033d665d5caa8d.db
|
||||
| page 1 offset 0
|
||||
@@ -14791,7 +14796,7 @@ do_test 75.0 {
|
||||
|
||||
do_catchsql_test 75.1 {
|
||||
SELECT rowid, quote(matchinfo(t1,'pcxybs')) FROM t1 WHERE t1 MATCH 'e*';
|
||||
} {1 {unable to use function matchinfo in the requested context}}
|
||||
} {1 {database disk image is malformed}}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
|
||||
@@ -21,6 +21,8 @@ ifcapable !fts5 {
|
||||
return
|
||||
}
|
||||
|
||||
if 0 {
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE VIRTUAL TABLE t1 USING fts5(a);
|
||||
}
|
||||
@@ -566,5 +568,25 @@ do_execsql_test 20.5 {
|
||||
SELECT rowid FROM x1 WHERE x1 MATCH 'z' OR (x1 MATCH 'a' AND x1 MATCH 'd');
|
||||
} {3 1}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
}
|
||||
reset_db
|
||||
do_execsql_test 21.0 {
|
||||
CREATE VIRTUAL TABLE t1 USING fts5(a, detail='none');
|
||||
INSERT INTO t1(a) VALUES('a');
|
||||
}
|
||||
|
||||
do_execsql_test 21.2 {
|
||||
SELECT rank FROM ( SELECT rank FROM t1('a NOT "" NOT def') ) ORDER BY 1;
|
||||
} {-1e-06}
|
||||
|
||||
do_execsql_test 21.3 {
|
||||
SELECT rank FROM ( SELECT rank FROM t1('a NOT � NOT def') ) ORDER BY 1;
|
||||
} {-1e-06}
|
||||
|
||||
do_execsql_test 21.4 {
|
||||
SELECT rank FROM ( SELECT rank FROM t1('a NOT "" NOT def') );
|
||||
} {-1e-06}
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
+179
-50
@@ -15,10 +15,20 @@
|
||||
** Two SQL functions are implemented:
|
||||
**
|
||||
** sha3(X,SIZE)
|
||||
** sha3_query(Y,SIZE)
|
||||
** sha3_agg(Y,SIZE)
|
||||
** sha3_query(Z,SIZE)
|
||||
**
|
||||
** The sha3(X) function computes the SHA3 hash of the input X, or NULL if
|
||||
** X is NULL.
|
||||
** X is NULL. If inputs X is text, the UTF-8 rendering of that text is
|
||||
** used to compute the hash. If X is a BLOB, then the binary data of the
|
||||
** blob is used to compute the hash. If X is an integer or real number,
|
||||
** then that number if converted into UTF-8 text and the hash is computed
|
||||
** over the text.
|
||||
**
|
||||
** The sha3_agg(Y) function computes the SHA3 hash of all Y inputs. Since
|
||||
** order is important for the hash, it is recommended that the Y expression
|
||||
** by followed by an ORDER BY clause to guarantee that the inputs occur
|
||||
** in the desired order.
|
||||
**
|
||||
** The sha3_query(Y) function evaluates all queries in the SQL statements of Y
|
||||
** and returns a hash of their results.
|
||||
@@ -26,6 +36,68 @@
|
||||
** The SIZE argument is optional. If omitted, the SHA3-256 hash algorithm
|
||||
** is used. If SIZE is included it must be one of the integers 224, 256,
|
||||
** 384, or 512, to determine SHA3 hash variant that is computed.
|
||||
**
|
||||
** Because the sha3_agg() and sha3_query() functions compute a hash over
|
||||
** multiple values, the values are encode to use include type information.
|
||||
**
|
||||
** In sha3_agg(), the sequence of bytes that gets hashed for each input
|
||||
** Y depends on the datatype of Y:
|
||||
**
|
||||
** typeof(Y)='null' A single "N" is hashed. (One byte)
|
||||
**
|
||||
** typeof(Y)='integer' The data hash is the character "I" followed
|
||||
** by an 8-byte big-endian binary of the
|
||||
** 64-bit signed integer. (Nine bytes total.)
|
||||
**
|
||||
** typeof(Y)='real' The character "F" followed by an 8-byte
|
||||
** big-ending binary of the double. (Nine
|
||||
** bytes total.)
|
||||
**
|
||||
** typeof(Y)='text' The hash is over prefix "Tnnn:" followed
|
||||
** by the UTF8 encoding of the text. The "nnn"
|
||||
** in the prefix is the minimum-length decimal
|
||||
** representation of the octet_length of the text.
|
||||
** Notice the ":" at the end of the prefix, which
|
||||
** is needed to separate the prefix from the
|
||||
** content in cases where the content starts
|
||||
** with a digit.
|
||||
**
|
||||
** typeof(Y)='blob' The hash is taken over prefix "Bnnn:" followed
|
||||
** by the binary content of the blob. The "nnn"
|
||||
** in the prefix is the mimimum-length decimal
|
||||
** representation of the byte-length of the blob.
|
||||
**
|
||||
** According to the rules above, all of the following SELECT statements
|
||||
** should return TRUE:
|
||||
**
|
||||
** SELECT sha3(1) = sha3('1');
|
||||
**
|
||||
** SELECT sha3('hello') = sha3(x'68656c6c6f');
|
||||
**
|
||||
** WITH a(x) AS (VALUES('xyzzy'))
|
||||
** SELECT sha3_agg(x) = sha3('T5:xyzzy') FROM a;
|
||||
**
|
||||
** WITH a(x) AS (VALUES(x'010203'))
|
||||
** SELECT sha3_agg(x) = sha3(x'42333a010203') FROM a;
|
||||
**
|
||||
** WITH a(x) AS (VALUES(0x123456))
|
||||
** SELECT sha3_agg(x) = sha3(x'490000000000123456') FROM a;
|
||||
**
|
||||
** WITH a(x) AS (VALUES(100.015625))
|
||||
** SELECT sha3_agg(x) = sha3(x'464059010000000000') FROM a;
|
||||
**
|
||||
** WITH a(x) AS (VALUES(NULL))
|
||||
** SELECT sha3_agg(x) = sha3('N') FROM a;
|
||||
**
|
||||
**
|
||||
** In sha3_query(), individual column values are encoded as with
|
||||
** sha3_agg(), but with the addition that a single "R" character is
|
||||
** inserted at the start of each row.
|
||||
**
|
||||
** Note that sha3_agg() hashes rows for which Y is NULL. Add a FILTER
|
||||
** clause if NULL rows should be excluded:
|
||||
**
|
||||
** SELECT sha3_agg(x ORDER BY rowid) FILTER(WHERE x NOT NULL) FROM t1;
|
||||
*/
|
||||
#include "sqlite3ext.h"
|
||||
SQLITE_EXTENSION_INIT1
|
||||
@@ -75,6 +147,7 @@ struct SHA3Context {
|
||||
unsigned nRate; /* Bytes of input accepted per Keccak iteration */
|
||||
unsigned nLoaded; /* Input bytes loaded into u.x[] so far this cycle */
|
||||
unsigned ixMask; /* Insert next input into u.x[nLoaded^ixMask]. */
|
||||
unsigned iSize; /* 224, 256, 358, or 512 */
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -404,6 +477,7 @@ static void KeccakF1600Step(SHA3Context *p){
|
||||
*/
|
||||
static void SHA3Init(SHA3Context *p, int iSize){
|
||||
memset(p, 0, sizeof(*p));
|
||||
p->iSize = iSize;
|
||||
if( iSize>=128 && iSize<=512 ){
|
||||
p->nRate = (1600 - ((iSize + 31)&~31)*2)/8;
|
||||
}else{
|
||||
@@ -547,6 +621,60 @@ static void sha3_step_vformat(
|
||||
SHA3Update(p, (unsigned char*)zBuf, n);
|
||||
}
|
||||
|
||||
/*
|
||||
** Update a SHA3Context using a single sqlite3_value.
|
||||
*/
|
||||
static void sha3UpdateFromValue(SHA3Context *p, sqlite3_value *pVal){
|
||||
switch( sqlite3_value_type(pVal) ){
|
||||
case SQLITE_NULL: {
|
||||
SHA3Update(p, (const unsigned char*)"N",1);
|
||||
break;
|
||||
}
|
||||
case SQLITE_INTEGER: {
|
||||
sqlite3_uint64 u;
|
||||
int j;
|
||||
unsigned char x[9];
|
||||
sqlite3_int64 v = sqlite3_value_int64(pVal);
|
||||
memcpy(&u, &v, 8);
|
||||
for(j=8; j>=1; j--){
|
||||
x[j] = u & 0xff;
|
||||
u >>= 8;
|
||||
}
|
||||
x[0] = 'I';
|
||||
SHA3Update(p, x, 9);
|
||||
break;
|
||||
}
|
||||
case SQLITE_FLOAT: {
|
||||
sqlite3_uint64 u;
|
||||
int j;
|
||||
unsigned char x[9];
|
||||
double r = sqlite3_value_double(pVal);
|
||||
memcpy(&u, &r, 8);
|
||||
for(j=8; j>=1; j--){
|
||||
x[j] = u & 0xff;
|
||||
u >>= 8;
|
||||
}
|
||||
x[0] = 'F';
|
||||
SHA3Update(p,x,9);
|
||||
break;
|
||||
}
|
||||
case SQLITE_TEXT: {
|
||||
int n2 = sqlite3_value_bytes(pVal);
|
||||
const unsigned char *z2 = sqlite3_value_text(pVal);
|
||||
sha3_step_vformat(p,"T%d:",n2);
|
||||
SHA3Update(p, z2, n2);
|
||||
break;
|
||||
}
|
||||
case SQLITE_BLOB: {
|
||||
int n2 = sqlite3_value_bytes(pVal);
|
||||
const unsigned char *z2 = sqlite3_value_blob(pVal);
|
||||
sha3_step_vformat(p,"B%d:",n2);
|
||||
SHA3Update(p, z2, n2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Implementation of the sha3_query(SQL,SIZE) function.
|
||||
**
|
||||
@@ -636,54 +764,7 @@ static void sha3QueryFunc(
|
||||
while( SQLITE_ROW==sqlite3_step(pStmt) ){
|
||||
SHA3Update(&cx,(const unsigned char*)"R",1);
|
||||
for(i=0; i<nCol; i++){
|
||||
switch( sqlite3_column_type(pStmt,i) ){
|
||||
case SQLITE_NULL: {
|
||||
SHA3Update(&cx, (const unsigned char*)"N",1);
|
||||
break;
|
||||
}
|
||||
case SQLITE_INTEGER: {
|
||||
sqlite3_uint64 u;
|
||||
int j;
|
||||
unsigned char x[9];
|
||||
sqlite3_int64 v = sqlite3_column_int64(pStmt,i);
|
||||
memcpy(&u, &v, 8);
|
||||
for(j=8; j>=1; j--){
|
||||
x[j] = u & 0xff;
|
||||
u >>= 8;
|
||||
}
|
||||
x[0] = 'I';
|
||||
SHA3Update(&cx, x, 9);
|
||||
break;
|
||||
}
|
||||
case SQLITE_FLOAT: {
|
||||
sqlite3_uint64 u;
|
||||
int j;
|
||||
unsigned char x[9];
|
||||
double r = sqlite3_column_double(pStmt,i);
|
||||
memcpy(&u, &r, 8);
|
||||
for(j=8; j>=1; j--){
|
||||
x[j] = u & 0xff;
|
||||
u >>= 8;
|
||||
}
|
||||
x[0] = 'F';
|
||||
SHA3Update(&cx,x,9);
|
||||
break;
|
||||
}
|
||||
case SQLITE_TEXT: {
|
||||
int n2 = sqlite3_column_bytes(pStmt, i);
|
||||
const unsigned char *z2 = sqlite3_column_text(pStmt, i);
|
||||
sha3_step_vformat(&cx,"T%d:",n2);
|
||||
SHA3Update(&cx, z2, n2);
|
||||
break;
|
||||
}
|
||||
case SQLITE_BLOB: {
|
||||
int n2 = sqlite3_column_bytes(pStmt, i);
|
||||
const unsigned char *z2 = sqlite3_column_blob(pStmt, i);
|
||||
sha3_step_vformat(&cx,"B%d:",n2);
|
||||
SHA3Update(&cx, z2, n2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
sha3UpdateFromValue(&cx, sqlite3_column_value(pStmt,i));
|
||||
}
|
||||
}
|
||||
sqlite3_finalize(pStmt);
|
||||
@@ -691,6 +772,44 @@ static void sha3QueryFunc(
|
||||
sqlite3_result_blob(context, SHA3Final(&cx), iSize/8, SQLITE_TRANSIENT);
|
||||
}
|
||||
|
||||
/*
|
||||
** xStep function for sha3_agg().
|
||||
*/
|
||||
static void sha3AggStep(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
SHA3Context *p;
|
||||
p = (SHA3Context*)sqlite3_aggregate_context(context, sizeof(*p));
|
||||
if( p==0 ) return;
|
||||
if( p->nRate==0 ){
|
||||
int sz = 256;
|
||||
if( argc==2 ){
|
||||
sz = sqlite3_value_int(argv[1]);
|
||||
if( sz!=224 && sz!=384 && sz!=512 ){
|
||||
sz = 256;
|
||||
}
|
||||
}
|
||||
SHA3Init(p, sz);
|
||||
}
|
||||
sha3UpdateFromValue(p, argv[0]);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** xFinal function for sha3_agg().
|
||||
*/
|
||||
static void sha3AggFinal(sqlite3_context *context){
|
||||
SHA3Context *p;
|
||||
p = (SHA3Context*)sqlite3_aggregate_context(context, sizeof(*p));
|
||||
if( p==0 ) return;
|
||||
if( p->iSize ){
|
||||
sqlite3_result_blob(context, SHA3Final(p), p->iSize/8, SQLITE_TRANSIENT);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
__declspec(dllexport)
|
||||
@@ -711,6 +830,16 @@ int sqlite3_shathree_init(
|
||||
SQLITE_UTF8 | SQLITE_INNOCUOUS | SQLITE_DETERMINISTIC,
|
||||
0, sha3Func, 0, 0);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3_create_function(db, "sha3_agg", 1,
|
||||
SQLITE_UTF8 | SQLITE_INNOCUOUS | SQLITE_DETERMINISTIC,
|
||||
0, 0, sha3AggStep, sha3AggFinal);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3_create_function(db, "sha3_agg", 2,
|
||||
SQLITE_UTF8 | SQLITE_INNOCUOUS | SQLITE_DETERMINISTIC,
|
||||
0, 0, sha3AggStep, sha3AggFinal);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3_create_function(db, "sha3_query", 1,
|
||||
SQLITE_UTF8 | SQLITE_DIRECTONLY,
|
||||
|
||||
@@ -679,6 +679,7 @@ static int dbdataNext(sqlite3_vtab_cursor *pCursor){
|
||||
** near the end of a corrupt record. */
|
||||
rc = dbdataBufferSize(&pCsr->rec, nPayload+DBDATA_PADDING_BYTES);
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
assert( pCsr->rec.aBuf!=0 );
|
||||
assert( nPayload!=0 );
|
||||
|
||||
/* Load the nLocal bytes of payload */
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
C Ensure\ssqlite3expert.c\sunregisters\sany\sSQL\suser-functions\sit\sregisters\swith\sthe\sdatabase\shandle\sbefore\sreturning.
|
||||
D 2024-08-08T15:26:11.708
|
||||
C Fix\sa\sname\sresolution\sissue\swith\sCTEs.
|
||||
D 2024-08-20T22:44:40.653
|
||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
|
||||
F Makefile.in cf96aa7d2682650dec56dc2f03cfe463feb101a1be594e4929bcd38662bc2ea8
|
||||
F Makefile.in 209e9c64edf499b0ea7a15448699101c01d15828af35a3439d32fc25fdf1b787
|
||||
F Makefile.linux-gcc f3842a0b1efbfbb74ac0ef60e56b301836d05b4d867d014f714fa750048f1ab6
|
||||
F Makefile.msc 6c3fe8b6ce60e73f34a148c957d78b4648745c8d30e792423aa1a8d8bf12d065
|
||||
F README.md 6358805260a03ebead84e168bbf3740ddf3f683b477e478567186aa7afb490d3
|
||||
@@ -35,8 +35,8 @@ F autoconf/tea/win/nmakehlp.c b01f822eabbe1ed2b64e70882d97d48402b42d2689a1ea0034
|
||||
F autoconf/tea/win/rules.vc 7b3bb2ef32ade0f3f14d951231811678722725e3bca240dd9727ae0dfe10f6a5
|
||||
F config.guess 883205ddf25b46f10c181818bf42c09da9888884af96f79e1719264345053bd6
|
||||
F config.sub c2d0260f17f3e4bc0b6808fccf1b291cb5e9126c14fc5890efc77b9fd0175559
|
||||
F configure 8c74221e3e3af939270c27f0600281a5485ac2e5014dd7581b056e24a528d625 x
|
||||
F configure.ac 9a3d92b38ad56456d09c1272f83131794f73110437f0f53fb94c90ce0d7a351a
|
||||
F configure 956e132a3e2481e5016e9ecaa0a2bdd9df95c1d923fa4fb2aa2cf9f0b3a54ad9 x
|
||||
F configure.ac fd9ff064b142682964971fec3d867235e51e1f6de30a031e33f683b7699338ff
|
||||
F contrib/sqlitecon.tcl 210a913ad63f9f991070821e599d600bd913e0ad
|
||||
F doc/F2FS.txt c1d4a0ae9711cfe0e1d8b019d154f1c29e0d3abfe820787ba1e9ed7691160fcd
|
||||
F doc/compile-for-windows.md e8635eea9153dcd6a51fd2740666ebc4492b3813cb1ac31cd8e99150df91762d
|
||||
@@ -53,7 +53,7 @@ F ext/README.md fd5f78013b0a2bc6f0067afb19e6ad040e89a10179b4f6f03eee58fac5f169bd
|
||||
F ext/async/README.txt e12275968f6fde133a80e04387d0e839b0c51f91
|
||||
F ext/async/sqlite3async.c 6f247666b495c477628dd19364d279c78ea48cd90c72d9f9b98ad1aff3294f94
|
||||
F ext/async/sqlite3async.h 46b47c79357b97ad85d20d2795942c0020dc20c532114a49808287f04aa5309a
|
||||
F ext/consio/console_io.c f32b757c9ee7fdf68e7586bee306f8368759e7cd12febb2a6839199b1c1af395 x
|
||||
F ext/consio/console_io.c b4885dfea71ed583315de8f0792a29d5fc7c7460b4a26c0aebe5cda5da8b38f8 x
|
||||
F ext/consio/console_io.h 0548b83d7c4b7270ad544a67f2bb90cebc519637fa39b1838df4744cf0d87646
|
||||
F ext/expert/README.md b321c2762bb93c18ea102d5a5f7753a4b8bac646cb392b3b437f633caf2020c3
|
||||
F ext/expert/expert.c d548d603a4cc9e61f446cc179c120c6713511c413f82a4a32b1e1e69d3f086a4
|
||||
@@ -97,15 +97,15 @@ F ext/fts5/fts5Int.h 41fb3a2dd40e818cc96c6f4176dbdf2aaa8f57043cfc9a8f2676e7e6a72
|
||||
F ext/fts5/fts5_aux.c 4584e88878e54828bf7d4d0d83deedd232ec60628b7731be02bad6adb62304b1
|
||||
F ext/fts5/fts5_buffer.c 0eec58bff585f1a44ea9147eae5da2447292080ea435957f7488c70673cb6f09
|
||||
F ext/fts5/fts5_config.c 68cb87a49215f8e7028000b681df4057c430a4a6afbd676463886da94c9e1c37
|
||||
F ext/fts5/fts5_expr.c 3a24c6ab5b7545312a5ec03085ae705ede820a08f9a63f1d72829ed4a35da6f6
|
||||
F ext/fts5/fts5_expr.c 4b7734db98393d6f7fbc5c9c71ebcabe70110f7df08f6b136d096a1eaee0f56a
|
||||
F ext/fts5/fts5_hash.c adda4272be401566a6e0ba1acbe70ee5cb97fce944bc2e04dc707152a0ec91b1
|
||||
F ext/fts5/fts5_index.c eb9a0dda3bc6ef969a6be8d2746af56856e67251810ddba08622b45be8477abe
|
||||
F ext/fts5/fts5_main.c 77fefb37e7931095a5ff271a28fbe4f73ec46d5492ef1f35d405d98e137ad8ed
|
||||
F ext/fts5/fts5_main.c 6ec7a7d005c632d86e510ddfaca56b197a5b20b61848415764b91bd27d1e4f84
|
||||
F ext/fts5/fts5_storage.c 1d7e08d4331da2f3f7e78e70eef2ed6a013d91ba16175c651adbc5ad672235aa
|
||||
F ext/fts5/fts5_tcl.c 5ca3e3e35010d326f5b821a563e4fcde3913e052935f5c2c72c264122a26b48f
|
||||
F ext/fts5/fts5_test_mi.c 08c11ec968148d4cb4119d96d819f8c1f329812c568bac3684f5464be177d3ee
|
||||
F ext/fts5/fts5_test_tok.c 3cb0a9b508b30d17ef025ccddd26ae3dc8ddffbe76c057616e59a9aa85d36f3b
|
||||
F ext/fts5/fts5_tokenize.c b1c3dc4de28f2532d9ee7be7182a96f943fa09fcc31c6f271d69dce72874ff8c
|
||||
F ext/fts5/fts5_tokenize.c 63ebe9057ed3f4dfc49944bc4aee3d3b745cc2faff73bc152ed3554ed3bf9cf4
|
||||
F ext/fts5/fts5_unicode2.c eca63dbc797f8ff0572e97caf4631389c0ab900d6364861b915bdd4735973f00
|
||||
F ext/fts5/fts5_varint.c e64d2113f6e1bfee0032972cffc1207b77af63319746951bf1d09885d1dadf80
|
||||
F ext/fts5/fts5_vocab.c e4830b00809e5da53bc10f93adc59e321407b0f801c7f4167c0e47f5552267e0
|
||||
@@ -147,7 +147,7 @@ F ext/fts5/test/fts5contentless4.test ec34dc69ef474ca9997dae6d91e072906e0e9a5a4b
|
||||
F ext/fts5/test/fts5contentless5.test 40cdcb4fe751672450829c5a96bd32c25fc2f6076279dd2ce5c58ac9a390132a
|
||||
F ext/fts5/test/fts5corrupt.test a9bda1ded5112ebf1ee85c5381bd1fe8974952e2523cede4d5072804d2011503
|
||||
F ext/fts5/test/fts5corrupt2.test 335911e3f68b9625d850325f9e29a128db3f4276a8c9d4e32134580da8f924c4
|
||||
F ext/fts5/test/fts5corrupt3.test 3cbb18b8970c66ed4d741eb3eecf42c986bd4c430572a5050350a72030de66cf
|
||||
F ext/fts5/test/fts5corrupt3.test b5f35d72af85b1d5a092b3d5e437f7944d142dd0b0c87b928fd0436a0aec6987
|
||||
F ext/fts5/test/fts5corrupt4.test dc08d19f5b8943e95a7778a7d8da592042504faf18dd93f68f7d7a0d7d7dd733
|
||||
F ext/fts5/test/fts5corrupt5.test 11b47126f5772cc37b67e3e8b2ed05895c4d07c05338bc07e4eea225bfe32c76
|
||||
F ext/fts5/test/fts5corrupt6.test 2d72db743db7b5d9c9a6d0cfef24d799ed1aa5e8192b66c40e871a37ed9eed06
|
||||
@@ -188,7 +188,7 @@ F ext/fts5/test/fts5limits.test 8ab67cf5d311c124b6ceb0062d0297767176df4572d955fc
|
||||
F ext/fts5/test/fts5matchinfo.test 877520582feb86bbfd95ab780099bcba4526f18ac75ee34979144cf86ba3a5a3
|
||||
F ext/fts5/test/fts5merge.test 2654df0bcdb2d117c2d38b6aeb0168061be01c643f9e9194b36c43a2970e8082
|
||||
F ext/fts5/test/fts5merge2.test 3ebad1a59d6ad3fb66eff6523a09e95dc6367cbefb3cd73196801dea0425c8e2
|
||||
F ext/fts5/test/fts5misc.test b88aa28ff20238b394495b0795cddca1a62b98fa09b99e462a8abc572d04ee88
|
||||
F ext/fts5/test/fts5misc.test b1682a40061bc58dcc62bbad48938fc5214d2ac6a868a8899c0c3d1930f1115d
|
||||
F ext/fts5/test/fts5multi.test a15bc91cdb717492e6e1b66fec1c356cb57386b980c7ba5af1915f97fe878581
|
||||
F ext/fts5/test/fts5multiclient.test 5ff811c028d6108045ffef737f1e9f05028af2458e456c0937c1d1b8dea56d45
|
||||
F ext/fts5/test/fts5near.test 33d60867581066e5db7016deb5d651628125d7ff4e0233a88175aa5b65874c74
|
||||
@@ -415,7 +415,7 @@ F ext/misc/rot13.c 51ac5f51e9d5fd811db58a9c23c628ad5f333c173f1fc53c8491a3603d385
|
||||
F ext/misc/scrub.c 2a44b0d44c69584c0580ad2553f6290a307a49df4668941d2812135bfb96a946
|
||||
F ext/misc/series.c d96e5aac21658c6b5d54f918ac140460ec7197734c1a4fba806950831a7b1e7a
|
||||
F ext/misc/sha1.c 4011aef176616872b2a0d5bccf0ecfb1f7ce3fe5c3d107f3a8e949d8e1e3f08d
|
||||
F ext/misc/shathree.c 543af7ce71d391cd3a9ab6924a6a1124efc63211fd0f2e240dc4b56077ba88ac
|
||||
F ext/misc/shathree.c 1821d90a0040c9accdbe3e3527d378d30569475d758aa70f6848924c0b430e8c
|
||||
F ext/misc/showauth.c 732578f0fe4ce42d577e1c86dc89dd14a006ab52
|
||||
F ext/misc/spellfix.c c0aa7b80d6df45f7da59d912b38752bcac1af53a5766966160e6c5cdd397dbea
|
||||
F ext/misc/sqlar.c a6175790482328171da47095f87608b48a476d4fac78d8a9ff18b03a2454f634
|
||||
@@ -481,7 +481,7 @@ F ext/rbu/rbuvacuum4.test ffccd22f67e2d0b380d2889685742159dfe0d19a3880ca3d2d1d69
|
||||
F ext/rbu/sqlite3rbu.c 4a3376c0fb9a844a799ac529fb81260523f6b13c9f629bc270c632dbae5fc1f8
|
||||
F ext/rbu/sqlite3rbu.h 9d923eb135c5d04aa6afd7c39ca47b0d1d0707c100e02f19fdde6a494e414304
|
||||
F ext/rbu/test_rbu.c b9727c3394307d058e806c1da0f8bb7b24daf3c6bb94cb10cca88ea4d5c806c0
|
||||
F ext/recover/dbdata.c a22ecd689f00ff2ad33b5633c4ef84c8f088c65faeac18d4eb73c128395c7aec
|
||||
F ext/recover/dbdata.c 5295f4f922b60d7035b6b9fd5846b13071b9d97ed7fad8496837bb7640d24771
|
||||
F ext/recover/recover1.test e16d78e94183562abff569967b18b7c77451d7044365516cd0fe14713a284851
|
||||
F ext/recover/recover_common.tcl a61306c1eb45c0c3fc45652c35b2d4ec19729e340bdf65a272ce4c229cefd85a
|
||||
F ext/recover/recoverbuild.test c74170e0f7b02456af41838afeb5353fdb985a48cc2331d661bbabbca7c6b8e3
|
||||
@@ -692,34 +692,34 @@ F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
|
||||
F sqlite3.1 acdff36db796e2d00225b911d3047d580cd136547298435426ce9d40347973cc
|
||||
F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a
|
||||
F sqlite_cfg.h.in baf2e409c63d4e7a765e17769b6ff17c5a82bbd9cbf1e284fd2e4cefaff3fcf2
|
||||
F src/alter.c e1b6782b85dd758f89e5c588e4e3eb82638c2dafc0c857b79a43bb8ec1746fca
|
||||
F src/analyze.c 5c4e2bfd0aa8e5157f7fb91a17d86905510a74397326dc5767ec4e0588a4eea5
|
||||
F src/attach.c cc9d00d30da916ff656038211410ccf04ed784b7564639b9b61d1839ed69fd39
|
||||
F src/auth.c 19b7ccacae3dfba23fc6f1d0af68134fa216e9040e53b0681b4715445ea030b4
|
||||
F src/alter.c aa93e37e4a36a0525bbb2a2aeda20d2018f0aa995542c7dc658e031375e3f532
|
||||
F src/analyze.c 30bf40ec4208ead9e977bec017bccc8a9681820936e38ca5a4a7443100a6d5c5
|
||||
F src/attach.c 08235ab62ed5ccc93c22bf36e640d19effcd632319615851bccf724ec9341333
|
||||
F src/auth.c 4c1ea890e0069ad73bead5d17a5b12c34cfa4f1a24175c8147ea439b64be271c
|
||||
F src/backup.c 5c97e8023aab1ce14a42387eb3ae00ba5a0644569e3476f38661fa6f824c3523
|
||||
F src/bitvec.c 9eac5f42c11914d5ef00a75605bb205e934f435c579687f985f1f8b0995c8645
|
||||
F src/btmutex.c 79a43670447eacc651519a429f6ece9fd638563cf95b469d6891185ddae2b522
|
||||
F src/btree.c 8b42fc7d9efdb2df05c30e8f91ff6cfbd979724ae24bf90269028468b7a13333
|
||||
F src/btree.h 55066f513eb095db935169dab1dc2f7c7a747ef223c533f5d4ad4dfed346cbd0
|
||||
F src/btreeInt.h 98aadb6dcb77b012cab2574d6a728fad56b337fc946839b9898c4b4c969e30b6
|
||||
F src/build.c 237ccc0290d131d646be722f418e92ee0a38043aee25e7dfdc75f8ce5b3abe4e
|
||||
F src/build.c c5522b5faf8128227678e194275cefaeb4d063f55dbe70bcff745f1b63a187cf
|
||||
F src/callback.c db3a45e376deff6a16c0058163fe0ae2b73a2945f3f408ca32cf74960b28d490
|
||||
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
|
||||
F src/ctime.c 64e4b1227b4ed123146f0aa2989131d1fbd9b927b11e80c9d58c6a68f9cd5ce3
|
||||
F src/date.c 13dd752847afb32ed70510ad7345a5b9c841f51ad904dba5d010f1fa3a6a324e
|
||||
F src/dbpage.c 80e46e1df623ec40486da7a5086cb723b0275a6e2a7b01d9f9b5da0f04ba2782
|
||||
F src/dbstat.c 3b677254d512fcafd4d0b341bf267b38b235ccfddbef24f9154e19360fa22e43
|
||||
F src/delete.c cb766727c78e715f9fb7ec8a7d03658ed2a3016343ca687acfcec9083cdca500
|
||||
F src/expr.c fe958028b36af640b70b2174354c044f75b8c4a4645c921592122aa2a022083a
|
||||
F src/delete.c 444c4d1eaac40103461e3b6f0881846dd3aafc1cec1dd169d3482fa331667da7
|
||||
F src/expr.c 6d5f2c38fe3ec06a7eac599dac822788b36064124e20112a844e9cd5156cb239
|
||||
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
|
||||
F src/fkey.c 852f93c0ef995e0c2b8983059a2b97151c194cc8259e21f5bc2b7ac508348c2a
|
||||
F src/fkey.c 928ed2517e8732113d2b9821aa37af639688d752f4ea9ac6e0e393d713eeb76f
|
||||
F src/func.c 1f61e32e7a357e615b5d2e774bee563761fce4f2fd97ecb0f72c33e62a2ada5f
|
||||
F src/global.c 61a419dd9e993b9be0f91de4c4ccf322b053eb829868e089f0321dd669be3b90
|
||||
F src/hash.c 9ee4269fb1d6632a6fecfb9479c93a1f29271bddbbaf215dd60420bcb80c7220
|
||||
F src/hash.h 3340ab6e1d13e725571d7cee6d3e3135f0779a7d8e76a9ce0a85971fa3953c51
|
||||
F src/hwtime.h f9c2dfb84dce7acf95ce6d289e46f5f9d3d1afd328e53da8f8e9008e3b3caae6
|
||||
F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
|
||||
F src/insert.c 8ff11e9e54c5fc1fe89707b3d41cf44ad2822f712bd3b5da68338ea42518847e
|
||||
F src/insert.c f8d1a0f8ee258411009c6b7f2d93170e351bd19f5ad89d57e1180644297cbe70
|
||||
F src/json.c 5b6a1d6015997b9ee848a32948720bdb26a0ef2de5a2127ebf7355ce66dbdc0d
|
||||
F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa
|
||||
F src/loadext.c 7432c944ff197046d67a1207790a1b13eec4548c85a9457eb0896bb3641dfb36
|
||||
@@ -749,29 +749,29 @@ F src/os_win.c 6ff43bac175bd9ed79e7c0f96840b139f2f51d01689a638fd05128becf94908a
|
||||
F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
|
||||
F src/pager.c b08600ebf0db90b6d1e9b8b6577c6fa3877cbe1a100bd0b2899e4c6e9adad4b3
|
||||
F src/pager.h 4b1140d691860de0be1347474c51fee07d5420bd7f802d38cbab8ea4ab9f538a
|
||||
F src/parse.y 318ef86fbe358b1a93262a42e152f37b97b3fddae8d319dffbd24ce2300f6c88
|
||||
F src/parse.y 5972b7d00af4c8d96fdad781af1ea1d5d51fc3b907ad61bda60e49503274e5ed
|
||||
F src/pcache.c 588cc3c5ccaaadde689ed35ce5c5c891a1f7b1f4d1f56f6cf0143b74d8ee6484
|
||||
F src/pcache.h 1497ce1b823cf00094bb0cf3bac37b345937e6f910890c626b16512316d3abf5
|
||||
F src/pcache1.c 49516ad7718a3626f28f710fa7448ef1fce3c07fd169acbb4817341950264319
|
||||
F src/pragma.c 52bfbf6dfd668b69b5eb9bd1186e3a67367c8453807150d6e75239229924f684
|
||||
F src/pragma.h e690a356c18e98414d2e870ea791c1be1545a714ba623719deb63f7f226d8bb7
|
||||
F src/prepare.c d99931f45416652895e502328ca49fe782cfc4e1ebdcda13b3736d991ebf42ce
|
||||
F src/printf.c 8b250972305e14b365561be5117ed0fd364e4fd58968776df1ce64c6280b90f9
|
||||
F src/printf.c 6a87534ebfb9e5346011191b1f3a7ebc457f5938c7e4feeea478ecf53f6a41b2
|
||||
F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c
|
||||
F src/resolve.c 7e8d23ce7cdbfedf351a47e759f2722e8182ca10fd7580be43f4ce1f1a228145
|
||||
F src/resolve.c 9afed5fd7b9111633bdb74a73cdc47324e28e4dc6c27113e3e9aee38fb9422ab
|
||||
F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97
|
||||
F src/select.c 6a95a2bffa6c09584dea99db5a7ae10c813305c09c92920ffc54f6eae2ba399e
|
||||
F src/select.c c1c28650d3ea5dc0670dd658600b963c29a5c31b685941a5df583b02631d04ff
|
||||
F src/shell.c.in 94571558b0fb28c37a5cf6dbd6ea27285341023a28a8cb5795cd2768fab67704
|
||||
F src/sqlite.h.in 1ad9110150773c38ebababbad11b5cb361bcd3997676dec1c91ac5e0416a7b86
|
||||
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
|
||||
F src/sqlite3ext.h 3f046c04ea3595d6bfda99b781926b17e672fd6d27da2ba6d8d8fc39981dcb54
|
||||
F src/sqliteInt.h e3f3b3d80a666a7c5c85b4db102d41ca831c5624f0b3001814479d376f00c19d
|
||||
F src/sqliteInt.h 28c878bdf528879afefe1994ac007d094f8061f2fdacdc55d6055d7e9341151e
|
||||
F src/sqliteLimit.h 6878ab64bdeb8c24a1d762d45635e34b96da21132179023338c93f820eee6728
|
||||
F src/status.c cb11f8589a6912af2da3bb1ec509a94dd8ef27df4d4c1a97e0bcf2309ece972b
|
||||
F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
|
||||
F src/tclsqlite.c c6888598f08dee3d9112a38ef42c8f5c89ca7f3190f4694744d0b84250f4bf8c
|
||||
F src/tclsqlite.h c6af51f31a2b2172d674608763a4b98fdf5cd587e4025053e546fb8077757262
|
||||
F src/test1.c 51159784f29d3dfd4b50fd6ed9c43c8f7f36925c501a3ad3083528e5e5544bd7
|
||||
F src/test1.c 3f18399557d954bc85f4564aec8ea1777d2161a81d98a3ff6c9e9046bf3554c1
|
||||
F src/test2.c 7ebc518e6735939d8979273a6f7b1d9b5702babf059f6ad62499f7f60a9eb9a3
|
||||
F src/test3.c e7573aa0f78ee4e070a4bc8c3493941c1aa64d5c66d4825c74c0f055451f432b
|
||||
F src/test4.c 13e57ae7ec7a959ee180970aef09deed141252fe9bb07c61054f0dfa4f1dfd5d
|
||||
@@ -791,7 +791,7 @@ F src/test_demovfs.c 3efa2adf4f21e10d95521721687d5ca047aea91fa62dd8cc22ac9e5a9c9
|
||||
F src/test_devsym.c 649434ed34d0b03fbd5a6b42df80f0f9a7e53f94dd1710aad5dd8831e91c4e86
|
||||
F src/test_fs.c c411c40baba679536fc34e2679349f59d8225570aed3488b5b3ef1908525a3d5
|
||||
F src/test_func.c 8c0e89192f70fac307822d1ac2911ee51751288780b3db0c5ab5ca75fa0fe851
|
||||
F src/test_hexio.c af6db9300edd2d7b786a2d40d64177cad4b8ee22085e8ca5fe812cdeffdb6502
|
||||
F src/test_hexio.c 0f777bf9fbb2684bb4978372bacc90ef7337d5d9e3cebe067a9409941e88bacf
|
||||
F src/test_init.c 17313332d58e90defc527129d5eda4a08bd6b6e8de7207a231523c8d98fb445e
|
||||
F src/test_intarray.c e4216aadee9df2de7d1aee7e70f6b22c80ee79ece72a63d57105db74217639e5
|
||||
F src/test_intarray.h 6c3534641108cd1bea517a8e117dcba237081310a29a4c35bd2190caa8972293
|
||||
@@ -813,7 +813,7 @@ F src/test_sqllog.c 540feaea7280cd5f926168aee9deb1065ae136d0bbbe7361e2ef3541783e
|
||||
F src/test_superlock.c 18355ca274746aa6909e3744163e5deb1196a85d5bc64b9cd377273cef626da7
|
||||
F src/test_syscall.c 9ad7ab39910c16d29411678d91b0d27a7a996a718df5ee93dcd635e846d0275c
|
||||
F src/test_tclsh.c 6077f2bdc6b4ea2bace2a0cd6ea48e0a4651007ae7382c13efc0c495eb0c6956
|
||||
F src/test_tclvar.c 2c42fe9a74af0f3c8f87a339f66d9d3bd3a967fb5db1ed2500348055b954e391
|
||||
F src/test_tclvar.c ae873248a0188459b1c16ca7cc431265dacce524399e8b46725c2b3b7e048424
|
||||
F src/test_thread.c d7a8bcea7445f37cc2a1f7f81dd6059634f45e0c61bfe80182b02872fb0328bb
|
||||
F src/test_vdbecov.c 5c426d9cd2b351f5f9ceb30cabf8c64a63bfcad644c507e0bd9ce2f6ae1a3bf3
|
||||
F src/test_vfs.c f298475e468c7e14945b20af885917181090c265aa3c4ade897849c9fbd396f2
|
||||
@@ -824,14 +824,14 @@ F src/test_window.c 6d80e11fba89a1796525e6f0048ff0c7789aa2c6b0b11c80827dc1437bd8
|
||||
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
|
||||
F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c
|
||||
F src/tokenize.c 3f703cacdab728d7741e5a6ac242006d74fe1c2754d4f03ed889d7253259bd68
|
||||
F src/treeview.c 774838df4e25956ca34ff79bef150266412cfc2640620d04e22d5c8a55a98992
|
||||
F src/trigger.c 0858f75818ed1580332db274f1032bcc5effe567cb132df5c5be8b1d800ca97f
|
||||
F src/update.c 732404a04d1737ef14bb6ec6b84f74edf28b3c102a92ae46b4855438a710efe7
|
||||
F src/upsert.c 2e60567a0e9e8520c18671b30712a88dc73534474304af94f32bb5f3ef65ac65
|
||||
F src/treeview.c e98dbc8068d27f3d0bd2a4cebfce6a7c21c776edc23d80e12c67a70cd2ba3fe5
|
||||
F src/trigger.c 0bb986a5b96047fd597c6aac28588853df56064e576e6b81ba777ef2ccaac461
|
||||
F src/update.c 0e01aa6a3edf9ec112b33eb714b9016a81241497b1fb7c3e74332f4f71756508
|
||||
F src/upsert.c 215328c3f91623c520ec8672c44323553f12caeb4f01b1090ebdca99fdf7b4f1
|
||||
F src/utf.c f23165685a67b4caf8ec08fb274cb3f319103decfb2a980b7cfd55d18dfa855e
|
||||
F src/util.c 5d1a0134cf4240648d1c6bb5cc8efaca0ea2b5d5c840985aec7e947271f04375
|
||||
F src/vacuum.c 604fcdaebe76f3497c855afcbf91b8fa5046b32de3045bab89cc008d68e40104
|
||||
F src/vdbe.c de13de572eccb688b2b7cf50e2f9005c44bf9ae89e35245ef8eadfc60dfd2764
|
||||
F src/vdbe.c be5f58bc29f60252e041a618eae59e8d57d460ba136c5403cf0abf955560c457
|
||||
F src/vdbe.h c2549a215898a390de6669cfa32adba56f0d7e17ba5a7f7b14506d6fd5f0c36a
|
||||
F src/vdbeInt.h 949669dfd8a41550d27dcb905b494f2ccde9a2e6c1b0b04daa1227e2e74c2b2c
|
||||
F src/vdbeapi.c 80235ac380e9467fec1cb0883354d841f2a771976e766995f7e0c77f845406df
|
||||
@@ -845,12 +845,12 @@ F src/vtab.c 5fb499d20494b7eecaadb7584634af9afcb374cb0524912b475fcb1712458a1b
|
||||
F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
|
||||
F src/wal.c 887fc4ca3f020ebb2e376f222069570834ac63bf50111ef0cbf3ae417048ed89
|
||||
F src/wal.h ba252daaa94f889f4b2c17c027e823d9be47ce39da1d3799886bbd51f0490452
|
||||
F src/walker.c 7c7ea0115345851c3da4e04e2e239a29983b61fb5b038b94eede6aba462640e2
|
||||
F src/where.c 5bbe53db73ae6c8ee34a5eab693a5586ad8ff4f094ff0e524df965b683bec884
|
||||
F src/whereInt.h 002adc3aa2cc10733b9b27958fdbe893987cd989fab25a9853941c1f9b9b0a65
|
||||
F src/wherecode.c c9cac0b0b8e809c5e7e79d7796918907fb685ad99be2aaa9737f9787aa47349c
|
||||
F src/whereexpr.c 7d0d34b42b9edfd8e8ca66beb3a6ef63fe211c001af54caf2ccbcd989b783290
|
||||
F src/window.c 1e40ffc509bae21e466f6106382d238e91eb73edd4ba10e66ca4fd7af2b96896
|
||||
F src/walker.c d5006d6b005e4ea7302ad390957a8d41ed83faa177e412f89bc5600a7462a014
|
||||
F src/where.c b6f79b189fcba459bb80420d3b4102f42a399be36ff29a3deff4ae4888fee46d
|
||||
F src/whereInt.h 6444b888ce395cb80511284b8a73b63472d34247fcb1b125ee06a54fa6ae878e
|
||||
F src/wherecode.c 137797b0de9ddf1ff43e5b0edffcc76fb05184ed651fc4f5a0a01a45c0b89d04
|
||||
F src/whereexpr.c 6a72cf607548765a262f216e87373fd675a4646f9cc4278fc519b66cf03dbc13
|
||||
F src/window.c 499d48f315a09242dc68f2fac635ed27dcf6bbb0d9ab9084857898c64489e975
|
||||
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
|
||||
F test/affinity2.test ce1aafc86e110685b324e9a763eab4f2a73f737842ec3b687bd965867de90627
|
||||
F test/affinity3.test f094773025eddf31135c7ad4cde722b7696f8eb07b97511f98585addf2a510a9
|
||||
@@ -1113,7 +1113,7 @@ F test/enc.test 9a7be5479da985381d740b15f432800f65e2c87029ee57a318f42cb2eb43763a
|
||||
F test/enc2.test 848bf05f15b011719f478dddb7b5e9aea35e39e457493cba4c4eef75d849a5ec
|
||||
F test/enc3.test 55ef64416d72975c66167310a51dc9fc544ba3ae4858b8d5ab22f4cb6500b087
|
||||
F test/enc4.test c8f1ce3618508fd0909945beb8b8831feef2c020
|
||||
F test/eqp.test 815418b69f6be3a27037b1736c54699c72cc3e2e6b0bc878c01464d1dcec65fe
|
||||
F test/eqp.test 82f221e8cd588434d7f3bba9a0f4c78cbe7a541615a41632e12f50608bfb4a99
|
||||
F test/eqp2.test 6e8996148de88f0e7670491e92e712a2920a369b4406f21a27c3c9b6a46b68dd
|
||||
F test/errmsg.test eae9f091eb39ce7e20305de45d8e5d115b68fa856fba4ea6757b6ca3705ff7f9
|
||||
F test/eval.test 73969a2d43a511bf44080c44485a8c4d796b6a4f038d19e491867081155692c0
|
||||
@@ -1260,7 +1260,7 @@ F test/fuzz3.test 70ba57260364b83e964707b9d4b5625284239768ab907dd387c740c0370ce3
|
||||
F test/fuzz4.test c229bcdb45518a89e1d208a21343e061503460ac69fae1539320a89f572eb634
|
||||
F test/fuzz_common.tcl b7197de6ed1ee8250a4f82d67876f4561b42ee8cbbfc6160dcb66331bad3f830
|
||||
F test/fuzz_malloc.test f348276e732e814802e39f042b1f6da6362a610af73a528d8f76898fde6b22f2
|
||||
F test/fuzzcheck.c dc159967609d00b0cfe619e735cbbf8482570aca85711397034b0662b6c18fc7
|
||||
F test/fuzzcheck.c 6e87c27df3d95c556870187987dff6efdc712b5cea60abedc8ab9215f471907a
|
||||
F test/fuzzdata1.db 3e86d9cf5aea68ddb8e27c02d7dfdaa226347426c7eb814918e4d95475bf8517
|
||||
F test/fuzzdata2.db 128b3feeb78918d075c9b14b48610145a0dd4c8d6f1ca7c2870c7e425f5bf31f
|
||||
F test/fuzzdata3.db c6586d3e3cef0fbc18108f9bb649aa77bfc38aba
|
||||
@@ -1272,7 +1272,7 @@ F test/fuzzdata8.db 4a53b6d077c6a5c23b609d8d3ac66996fa55ba3f8d02f9b6efdd0214a767
|
||||
F test/fuzzer1.test 3d4c4b7e547aba5e5511a2991e3e3d07166cfbb8
|
||||
F test/fuzzer2.test a85ef814ce071293bce1ad8dffa217cbbaad4c14
|
||||
F test/fuzzerfault.test f64c4aef4c9e9edf1d6dc0d3f1e65dcc81e67c996403c88d14f09b74807a42bc
|
||||
F test/fuzzinvariants.c 0729b9d8ed77ad0f8c5c7601168a707d5803087d2da030ede9057c51c809cc6c
|
||||
F test/fuzzinvariants.c 81167c9a7e82c0539a1d704aeb3384046d01f4108cda160a2447cb2a149d6362
|
||||
F test/gcfault.test 4ea410ac161e685f17b19e1f606f58514a2850e806c65b846d05f60d436c5b0d
|
||||
F test/gencol1.test e169bdfa11c7ed5e9f322a98a7db3afe9e66235750b68c923efee8e1876b46ec
|
||||
F test/genesis.tcl 1e2e2e8e5cc4058549a154ff1892fe5c9de19f98
|
||||
@@ -1493,6 +1493,7 @@ F test/orderby7.test 3d1383d52ade5b9eb3a173b3147fdd296f0202da
|
||||
F test/orderby8.test 23ef1a5d72bd3adcc2f65561c654295d1b8047bd
|
||||
F test/orderby9.test 87fb9548debcc2cd141c5299002dd94672fa76a3
|
||||
F test/orderbyA.test df608e59efc2ef50c1eddf1a773b272de3252e9401bfec86d04b52fd973866d5
|
||||
F test/orderbyB.test 32576c7b138105bc72f7fbf33bd320ca3a7d303641fc939e0e56af6cba884b3d
|
||||
F test/oserror.test 1fc9746b83d778e70d115049747ba19c7fba154afce7cc165b09feb6ca6abbc5
|
||||
F test/ossfuzz.c 9636dad2092a05a32110df0ca06713038dd0c43dd89a77dabe4b8b0d71096715
|
||||
F test/ossshell.c f125c5bd16e537a2549aa579b328dd1c59905e7ab1338dfc210e755bb7b69f17
|
||||
@@ -1632,7 +1633,7 @@ F test/shortread1.test bb591ef20f0fd9ed26d0d12e80eee6d7ac8897a3
|
||||
F test/show_speedtest1_rtree.tcl 32e6c5f073d7426148a6936a0408f4b5b169aba5
|
||||
F test/shrink.test 2668e607dcdfa19c52828c09b69685b38da793856582ae31debf79d90c7bbbdc
|
||||
F test/sidedelete.test f0ad71abe6233e3b153100f3b8d679b19a488329
|
||||
F test/skipscan1.test e03ba5b977da6fd71662a4b0a668f04053bda4b187ff3214db7533e28c732279
|
||||
F test/skipscan1.test 9cbbb6575517b15292bd87ee85b853bbd3cd4b4735d69b0f083020cec16ff304
|
||||
F test/skipscan2.test b032ed3e0ba5caa4df6c43ef22c31566aac67783bc031869155989a7ccdb5bd5
|
||||
F test/skipscan3.test ec5bab3f81c7038b43450e7b3062e04a198bdbb5
|
||||
F test/skipscan5.test 0672103fd2c8f96bd114133f356192b35ece45c794fe3677e1d9e5e3104a608e
|
||||
@@ -1706,7 +1707,7 @@ F test/temptable.test d2c9b87a54147161bcd1822e30c1d1cd891e5b30
|
||||
F test/temptable2.test 76821347810ecc88203e6ef0dd6897b6036ac788e9dd3e6b04fd4d1631311a16
|
||||
F test/temptable3.test d11a0974e52b347e45ee54ef1923c91ed91e4637
|
||||
F test/temptrigger.test 38f0ca479b1822d3117069e014daabcaacefffcc
|
||||
F test/tester.tcl 640106bf8f7785d0ac67cda2837577eb9f2d936033bacedf9e705ca5451958ef
|
||||
F test/tester.tcl e88c498c369cff6bf0898db6d04088685066730be51821ef775ef13fd2b1d077
|
||||
F test/testrunner.tcl 5d02deeba7a53baeadae6aa7641d90aac58fdfa3a7bcac85cfcfd752b1aab87c
|
||||
F test/testrunner_data.tcl c5ae2b1f9a99210b0600d002fb3af1fee350997cee9416551e83b93501360ebf
|
||||
F test/thread001.test a0985c117eab62c0c65526e9fa5d1360dd1cac5b03bde223902763274ce21899
|
||||
@@ -2067,13 +2068,13 @@ F test/windowE.test 6ba0c8048e4cc02b942e56640f8fcd50fd7ca72c876656c40f6baf42e316
|
||||
F test/windowerr.tcl f5acd6fbc210d7b5546c0e879d157888455cd4a17a1d3f28f07c1c8a387019e0
|
||||
F test/windowerr.test a8b752402109c15aa1c5efe1b93ccb0ce1ef84fa964ae1cd6684dd0b3cc1819b
|
||||
F test/windowfault.test 15094c1529424e62f798bc679e3fe9dfab6e8ba2f7dfe8c923b6248c31660a7c
|
||||
F test/windowpushd.test d8895d08870b7226f7693665bd292eb177e62ca06799184957b3ca7dc03067df
|
||||
F test/windowpushd.test c420e2265f0e09a0e798d0513a660d71b51602088d81b3dbd038918ee1339dcc
|
||||
F test/with1.test b93833890e5d2a368e78747f124503a0159aa029b98e9ed4795ebf630b2efd3d
|
||||
F test/with2.test a1df41b987198383b9b70bf5e5fda390582e46398653858dbc6ceb24253b28df
|
||||
F test/with2.test 181674a6cc86a601ca2ac052741cdfad5b529e07e870435d2f6cdb92d589ff17
|
||||
F test/with3.test e30369ea27aa27eb1bda4c5e510c8a9f782c8afd2ab99d1a02b8a7f25a5d3e65
|
||||
F test/with4.test 257be66c0c67fee1defbbac0f685c3465e2cad037f21ce65f23f86084f198205
|
||||
F test/with5.test 6248213c41fab36290b5b73aa3f937309dfba337004d9d8434c3fabc8c7d4be8
|
||||
F test/with6.test e097a03e5c898a8cd8f3a2d6a994ec510ea4376b5d484c2b669a41001e7758c8
|
||||
F test/with6.test 9ff3503c3ff7cd459dc4852a02aaefa998dccace53f4142a0eb726174ad5984a
|
||||
F test/withM.test 693b61765f2b387b5e3e24a4536e2e82de15ff64
|
||||
F test/without_rowid1.test a5210b8770dc4736bca4e74bc96588f43025ad03ad6a80f885afd36d9890e217
|
||||
F test/without_rowid2.test af260339f79d13cb220288b67cd287fbcf81ad99
|
||||
@@ -2204,8 +2205,8 @@ F vsixtest/vsixtest.tcl 6195aba1f12a5e10efc2b8c0009532167be5e301abe5b31385638080
|
||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||
P 797b0a13fd7a42b0a48ecbf0cd1961aa932da3e9c9ccffd903a3a4d963d0cc54
|
||||
R 524433c41a8ffc46e95c387bd9dc2975
|
||||
U dan
|
||||
Z fa7382f01ce16aee65751b978df534e7
|
||||
P c1bbed19f4348ec31c3cb4723eaa8f1554bb58ef4de7feb3a0f39612785f13d5
|
||||
R 1c80ace1a0877505f5ca5ebb5b98295b
|
||||
U drh
|
||||
Z ef82496d97c0311a270f63ff1146b092
|
||||
# Remove this line to create a well-formed Fossil manifest.
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
123b154ce3b6fee1bbf483704812bd6f8538966f9687520b4470d700f0270719
|
||||
4fa8235dd59cd683d6c6c97bfe181a9637be7c054d435323c903b9dbd74aff02
|
||||
|
||||
+11
-6
@@ -1320,7 +1320,7 @@ static int renameResolveTrigger(Parse *pParse){
|
||||
/* ALWAYS() because if the table of the trigger does not exist, the
|
||||
** error would have been hit before this point */
|
||||
if( ALWAYS(pParse->pTriggerTab) ){
|
||||
rc = sqlite3ViewGetColumnNames(pParse, pParse->pTriggerTab);
|
||||
rc = sqlite3ViewGetColumnNames(pParse, pParse->pTriggerTab)!=0;
|
||||
}
|
||||
|
||||
/* Resolve symbols in WHEN clause */
|
||||
@@ -1366,8 +1366,9 @@ static int renameResolveTrigger(Parse *pParse){
|
||||
int i;
|
||||
for(i=0; i<pStep->pFrom->nSrc && rc==SQLITE_OK; i++){
|
||||
SrcItem *p = &pStep->pFrom->a[i];
|
||||
if( p->pSelect ){
|
||||
sqlite3SelectPrep(pParse, p->pSelect, 0);
|
||||
if( p->fg.isSubquery ){
|
||||
assert( p->u4.pSubq!=0 );
|
||||
sqlite3SelectPrep(pParse, p->u4.pSubq->pSelect, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1435,8 +1436,12 @@ static void renameWalkTrigger(Walker *pWalker, Trigger *pTrigger){
|
||||
}
|
||||
if( pStep->pFrom ){
|
||||
int i;
|
||||
for(i=0; i<pStep->pFrom->nSrc; i++){
|
||||
sqlite3WalkSelect(pWalker, pStep->pFrom->a[i].pSelect);
|
||||
SrcList *pFrom = pStep->pFrom;
|
||||
for(i=0; i<pFrom->nSrc; i++){
|
||||
if( pFrom->a[i].fg.isSubquery ){
|
||||
assert( pFrom->a[i].u4.pSubq!=0 );
|
||||
sqlite3WalkSelect(pWalker, pFrom->a[i].u4.pSubq->pSelect);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1683,7 +1688,7 @@ static int renameTableSelectCb(Walker *pWalker, Select *pSelect){
|
||||
}
|
||||
for(i=0; i<pSrc->nSrc; i++){
|
||||
SrcItem *pItem = &pSrc->a[i];
|
||||
if( pItem->pTab==p->pTab ){
|
||||
if( pItem->pSTab==p->pTab ){
|
||||
renameTokenFind(pWalker->pParse, p, pItem->zName);
|
||||
}
|
||||
}
|
||||
|
||||
+11
-8
@@ -1797,12 +1797,13 @@ static int loadStatTbl(
|
||||
while( sqlite3_step(pStmt)==SQLITE_ROW ){
|
||||
int nIdxCol = 1; /* Number of columns in stat4 records */
|
||||
|
||||
char *zIndex; /* Index name */
|
||||
Index *pIdx; /* Pointer to the index object */
|
||||
int nSample; /* Number of samples */
|
||||
int nByte; /* Bytes of space required */
|
||||
int i; /* Bytes of space required */
|
||||
tRowcnt *pSpace;
|
||||
char *zIndex; /* Index name */
|
||||
Index *pIdx; /* Pointer to the index object */
|
||||
int nSample; /* Number of samples */
|
||||
int nByte; /* Bytes of space required */
|
||||
int i; /* Bytes of space required */
|
||||
tRowcnt *pSpace; /* Available allocated memory space */
|
||||
u8 *pPtr; /* Available memory as a u8 for easier manipulation */
|
||||
|
||||
zIndex = (char *)sqlite3_column_text(pStmt, 0);
|
||||
if( zIndex==0 ) continue;
|
||||
@@ -1822,7 +1823,7 @@ static int loadStatTbl(
|
||||
}
|
||||
pIdx->nSampleCol = nIdxCol;
|
||||
pIdx->mxSample = nSample;
|
||||
nByte = sizeof(IndexSample) * nSample;
|
||||
nByte = ROUND8(sizeof(IndexSample) * nSample);
|
||||
nByte += sizeof(tRowcnt) * nIdxCol * 3 * nSample;
|
||||
nByte += nIdxCol * sizeof(tRowcnt); /* Space for Index.aAvgEq[] */
|
||||
|
||||
@@ -1831,7 +1832,9 @@ static int loadStatTbl(
|
||||
sqlite3_finalize(pStmt);
|
||||
return SQLITE_NOMEM_BKPT;
|
||||
}
|
||||
pSpace = (tRowcnt*)&pIdx->aSample[nSample];
|
||||
pPtr = (u8*)pIdx->aSample;
|
||||
pPtr += ROUND8(nSample*sizeof(pIdx->aSample[0]));
|
||||
pSpace = (tRowcnt*)pPtr;
|
||||
assert( EIGHT_BYTE_ALIGNMENT( pSpace ) );
|
||||
pIdx->aAvgEq = pSpace; pSpace += nIdxCol;
|
||||
pIdx->pTable->tabFlags |= TF_HasStat4;
|
||||
|
||||
+8
-7
@@ -479,20 +479,21 @@ static int fixSelectCb(Walker *p, Select *pSelect){
|
||||
|
||||
if( NEVER(pList==0) ) return WRC_Continue;
|
||||
for(i=0, pItem=pList->a; i<pList->nSrc; i++, pItem++){
|
||||
if( pFix->bTemp==0 ){
|
||||
if( pItem->zDatabase ){
|
||||
if( iDb!=sqlite3FindDbName(db, pItem->zDatabase) ){
|
||||
if( pFix->bTemp==0 && pItem->fg.isSubquery==0 ){
|
||||
if( pItem->fg.fixedSchema==0 && pItem->u4.zDatabase!=0 ){
|
||||
if( iDb!=sqlite3FindDbName(db, pItem->u4.zDatabase) ){
|
||||
sqlite3ErrorMsg(pFix->pParse,
|
||||
"%s %T cannot reference objects in database %s",
|
||||
pFix->zType, pFix->pName, pItem->zDatabase);
|
||||
pFix->zType, pFix->pName, pItem->u4.zDatabase);
|
||||
return WRC_Abort;
|
||||
}
|
||||
sqlite3DbFree(db, pItem->zDatabase);
|
||||
pItem->zDatabase = 0;
|
||||
sqlite3DbFree(db, pItem->u4.zDatabase);
|
||||
pItem->fg.notCte = 1;
|
||||
pItem->fg.hadSchema = 1;
|
||||
}
|
||||
pItem->pSchema = pFix->pSchema;
|
||||
pItem->u4.pSchema = pFix->pSchema;
|
||||
pItem->fg.fromDDL = 1;
|
||||
pItem->fg.fixedSchema = 1;
|
||||
}
|
||||
#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER)
|
||||
if( pList->a[i].fg.isUsing==0
|
||||
|
||||
+1
-1
@@ -165,7 +165,7 @@ void sqlite3AuthRead(
|
||||
assert( pTabList );
|
||||
for(iSrc=0; iSrc<pTabList->nSrc; iSrc++){
|
||||
if( pExpr->iTable==pTabList->a[iSrc].iCursor ){
|
||||
pTab = pTabList->a[iSrc].pTab;
|
||||
pTab = pTabList->a[iSrc].pSTab;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
+113
-17
@@ -497,12 +497,12 @@ Table *sqlite3LocateTableItem(
|
||||
SrcItem *p
|
||||
){
|
||||
const char *zDb;
|
||||
assert( p->pSchema==0 || p->zDatabase==0 );
|
||||
if( p->pSchema ){
|
||||
int iDb = sqlite3SchemaToIndex(pParse->db, p->pSchema);
|
||||
if( p->fg.fixedSchema ){
|
||||
int iDb = sqlite3SchemaToIndex(pParse->db, p->u4.pSchema);
|
||||
zDb = pParse->db->aDb[iDb].zDbSName;
|
||||
}else{
|
||||
zDb = p->zDatabase;
|
||||
assert( !p->fg.isSubquery );
|
||||
zDb = p->u4.zDatabase;
|
||||
}
|
||||
return sqlite3LocateTable(pParse, flags, p->zName, zDb);
|
||||
}
|
||||
@@ -3487,6 +3487,8 @@ void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, int noErr){
|
||||
}
|
||||
assert( pParse->nErr==0 );
|
||||
assert( pName->nSrc==1 );
|
||||
assert( pName->a[0].fg.fixedSchema==0 );
|
||||
assert( pName->a[0].fg.isSubquery==0 );
|
||||
if( sqlite3ReadSchema(pParse) ) goto exit_drop_table;
|
||||
if( noErr ) db->suppressErr++;
|
||||
assert( isView==0 || isView==LOCATE_VIEW );
|
||||
@@ -3495,7 +3497,7 @@ void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, int noErr){
|
||||
|
||||
if( pTab==0 ){
|
||||
if( noErr ){
|
||||
sqlite3CodeVerifyNamedSchema(pParse, pName->a[0].zDatabase);
|
||||
sqlite3CodeVerifyNamedSchema(pParse, pName->a[0].u4.zDatabase);
|
||||
sqlite3ForceNotReadOnly(pParse);
|
||||
}
|
||||
goto exit_drop_table;
|
||||
@@ -4586,15 +4588,17 @@ void sqlite3DropIndex(Parse *pParse, SrcList *pName, int ifExists){
|
||||
}
|
||||
assert( pParse->nErr==0 ); /* Never called with prior non-OOM errors */
|
||||
assert( pName->nSrc==1 );
|
||||
assert( pName->a[0].fg.fixedSchema==0 );
|
||||
assert( pName->a[0].fg.isSubquery==0 );
|
||||
if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){
|
||||
goto exit_drop_index;
|
||||
}
|
||||
pIndex = sqlite3FindIndex(db, pName->a[0].zName, pName->a[0].zDatabase);
|
||||
pIndex = sqlite3FindIndex(db, pName->a[0].zName, pName->a[0].u4.zDatabase);
|
||||
if( pIndex==0 ){
|
||||
if( !ifExists ){
|
||||
sqlite3ErrorMsg(pParse, "no such index: %S", pName->a);
|
||||
}else{
|
||||
sqlite3CodeVerifyNamedSchema(pParse, pName->a[0].zDatabase);
|
||||
sqlite3CodeVerifyNamedSchema(pParse, pName->a[0].u4.zDatabase);
|
||||
sqlite3ForceNotReadOnly(pParse);
|
||||
}
|
||||
pParse->checkSchema = 1;
|
||||
@@ -4891,12 +4895,14 @@ SrcList *sqlite3SrcListAppend(
|
||||
if( pDatabase && pDatabase->z==0 ){
|
||||
pDatabase = 0;
|
||||
}
|
||||
assert( pItem->fg.fixedSchema==0 );
|
||||
assert( pItem->fg.isSubquery==0 );
|
||||
if( pDatabase ){
|
||||
pItem->zName = sqlite3NameFromToken(db, pDatabase);
|
||||
pItem->zDatabase = sqlite3NameFromToken(db, pTable);
|
||||
pItem->u4.zDatabase = sqlite3NameFromToken(db, pTable);
|
||||
}else{
|
||||
pItem->zName = sqlite3NameFromToken(db, pTable);
|
||||
pItem->zDatabase = 0;
|
||||
pItem->u4.zDatabase = 0;
|
||||
}
|
||||
return pList;
|
||||
}
|
||||
@@ -4912,13 +4918,40 @@ void sqlite3SrcListAssignCursors(Parse *pParse, SrcList *pList){
|
||||
for(i=0, pItem=pList->a; i<pList->nSrc; i++, pItem++){
|
||||
if( pItem->iCursor>=0 ) continue;
|
||||
pItem->iCursor = pParse->nTab++;
|
||||
if( pItem->pSelect ){
|
||||
sqlite3SrcListAssignCursors(pParse, pItem->pSelect->pSrc);
|
||||
if( pItem->fg.isSubquery ){
|
||||
assert( pItem->u4.pSubq!=0 );
|
||||
assert( pItem->u4.pSubq->pSelect!=0 );
|
||||
assert( pItem->u4.pSubq->pSelect->pSrc!=0 );
|
||||
sqlite3SrcListAssignCursors(pParse, pItem->u4.pSubq->pSelect->pSrc);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Delete a Subquery object and its substructure.
|
||||
*/
|
||||
void sqlite3SubqueryDelete(sqlite3 *db, Subquery *pSubq){
|
||||
assert( pSubq!=0 && pSubq->pSelect!=0 );
|
||||
sqlite3SelectDelete(db, pSubq->pSelect);
|
||||
sqlite3DbFree(db, pSubq);
|
||||
}
|
||||
|
||||
/*
|
||||
** Remove a Subquery from a SrcItem. Return the associated Select object.
|
||||
** The returned Select becomes the responsibility of the caller.
|
||||
*/
|
||||
Select *sqlite3SubqueryDetach(sqlite3 *db, SrcItem *pItem){
|
||||
Select *pSel;
|
||||
assert( pItem!=0 );
|
||||
assert( pItem->fg.isSubquery );
|
||||
pSel = pItem->u4.pSubq->pSelect;
|
||||
sqlite3DbFree(db, pItem->u4.pSubq);
|
||||
pItem->u4.pSubq = 0;
|
||||
pItem->fg.isSubquery = 0;
|
||||
return pSel;
|
||||
}
|
||||
|
||||
/*
|
||||
** Delete an entire SrcList including all its substructure.
|
||||
*/
|
||||
@@ -4928,13 +4961,26 @@ void sqlite3SrcListDelete(sqlite3 *db, SrcList *pList){
|
||||
assert( db!=0 );
|
||||
if( pList==0 ) return;
|
||||
for(pItem=pList->a, i=0; i<pList->nSrc; i++, pItem++){
|
||||
if( pItem->zDatabase ) sqlite3DbNNFreeNN(db, pItem->zDatabase);
|
||||
|
||||
/* Check invariants on SrcItem */
|
||||
assert( !pItem->fg.isIndexedBy || !pItem->fg.isTabFunc );
|
||||
assert( !pItem->fg.isCte || !pItem->fg.isIndexedBy );
|
||||
assert( !pItem->fg.hadSchema || !pItem->fg.isSubquery );
|
||||
assert( !pItem->fg.hadSchema || pItem->fg.fixedSchema );
|
||||
assert( !pItem->fg.fixedSchema || !pItem->fg.isSubquery );
|
||||
assert( !pItem->fg.isSubquery || (pItem->u4.pSubq!=0 &&
|
||||
pItem->u4.pSubq->pSelect!=0) );
|
||||
|
||||
if( pItem->zName ) sqlite3DbNNFreeNN(db, pItem->zName);
|
||||
if( pItem->zAlias ) sqlite3DbNNFreeNN(db, pItem->zAlias);
|
||||
if( pItem->fg.isSubquery ){
|
||||
sqlite3SubqueryDelete(db, pItem->u4.pSubq);
|
||||
}else if( pItem->fg.fixedSchema==0 && pItem->u4.zDatabase!=0 ){
|
||||
sqlite3DbNNFreeNN(db, pItem->u4.zDatabase);
|
||||
}
|
||||
if( pItem->fg.isIndexedBy ) sqlite3DbFree(db, pItem->u1.zIndexedBy);
|
||||
if( pItem->fg.isTabFunc ) sqlite3ExprListDelete(db, pItem->u1.pFuncArg);
|
||||
sqlite3DeleteTable(db, pItem->pTab);
|
||||
if( pItem->pSelect ) sqlite3SelectDelete(db, pItem->pSelect);
|
||||
sqlite3DeleteTable(db, pItem->pSTab);
|
||||
if( pItem->fg.isUsing ){
|
||||
sqlite3IdListDelete(db, pItem->u3.pUsing);
|
||||
}else if( pItem->u3.pOn ){
|
||||
@@ -4944,6 +4990,54 @@ void sqlite3SrcListDelete(sqlite3 *db, SrcList *pList){
|
||||
sqlite3DbNNFreeNN(db, pList);
|
||||
}
|
||||
|
||||
/*
|
||||
** Attach a Subquery object to pItem->uv.pSubq. Set the
|
||||
** pSelect value but leave all the other values initialized
|
||||
** to zero.
|
||||
**
|
||||
** A copy of the Select object is made if dupSelect is true, and the
|
||||
** SrcItem takes responsibility for deleting the copy. If dupSelect is
|
||||
** false, ownership of the Select passes to the SrcItem. Either way,
|
||||
** the SrcItem will take responsibility for deleting the Select.
|
||||
**
|
||||
** When dupSelect is zero, that means the Select might get deleted right
|
||||
** away if there is an OOM error. Beware.
|
||||
**
|
||||
** Return non-zero on success. Return zero on an OOM error.
|
||||
*/
|
||||
int sqlite3SrcItemAttachSubquery(
|
||||
Parse *pParse, /* Parsing context */
|
||||
SrcItem *pItem, /* Item to which the subquery is to be attached */
|
||||
Select *pSelect, /* The subquery SELECT. Must be non-NULL */
|
||||
int dupSelect /* If true, attach a copy of pSelect, not pSelect itself.*/
|
||||
){
|
||||
Subquery *p;
|
||||
assert( pSelect!=0 );
|
||||
assert( pItem->fg.isSubquery==0 );
|
||||
if( pItem->fg.fixedSchema ){
|
||||
pItem->u4.pSchema = 0;
|
||||
pItem->fg.fixedSchema = 0;
|
||||
}else if( pItem->u4.zDatabase!=0 ){
|
||||
sqlite3DbFree(pParse->db, pItem->u4.zDatabase);
|
||||
pItem->u4.zDatabase = 0;
|
||||
}
|
||||
if( dupSelect ){
|
||||
pSelect = sqlite3SelectDup(pParse->db, pSelect, 0);
|
||||
if( pSelect==0 ) return 0;
|
||||
}
|
||||
p = pItem->u4.pSubq = sqlite3DbMallocRawNN(pParse->db, sizeof(Subquery));
|
||||
if( p==0 ){
|
||||
sqlite3SelectDelete(pParse->db, pSelect);
|
||||
return 0;
|
||||
}
|
||||
pItem->fg.isSubquery = 1;
|
||||
p->pSelect = pSelect;
|
||||
assert( offsetof(Subquery, pSelect)==0 );
|
||||
memset(((char*)p)+sizeof(p->pSelect), 0, sizeof(*p)-sizeof(p->pSelect));
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** This routine is called by the parser to add a new term to the
|
||||
** end of a growing FROM clause. The "p" parameter is the part of
|
||||
@@ -4993,10 +5087,12 @@ SrcList *sqlite3SrcListAppendFromTerm(
|
||||
if( pAlias->n ){
|
||||
pItem->zAlias = sqlite3NameFromToken(db, pAlias);
|
||||
}
|
||||
assert( pSubquery==0 || pDatabase==0 );
|
||||
if( pSubquery ){
|
||||
pItem->pSelect = pSubquery;
|
||||
if( pSubquery->selFlags & SF_NestedFrom ){
|
||||
pItem->fg.isNestedFrom = 1;
|
||||
if( sqlite3SrcItemAttachSubquery(pParse, pItem, pSubquery, 0) ){
|
||||
if( pSubquery->selFlags & SF_NestedFrom ){
|
||||
pItem->fg.isNestedFrom = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
assert( pOnUsing==0 || pOnUsing->pOn==0 || pOnUsing->pUsing==0 );
|
||||
|
||||
+9
-8
@@ -24,8 +24,8 @@
|
||||
**
|
||||
** The following fields are initialized appropriate in pSrc:
|
||||
**
|
||||
** pSrc->a[0].pTab Pointer to the Table object
|
||||
** pSrc->a[0].pIndex Pointer to the INDEXED BY index, if there is one
|
||||
** pSrc->a[0].spTab Pointer to the Table object
|
||||
** pSrc->a[0].u2.pIBIndex Pointer to the INDEXED BY index, if there is one
|
||||
**
|
||||
*/
|
||||
Table *sqlite3SrcListLookup(Parse *pParse, SrcList *pSrc){
|
||||
@@ -33,8 +33,8 @@ Table *sqlite3SrcListLookup(Parse *pParse, SrcList *pSrc){
|
||||
Table *pTab;
|
||||
assert( pItem && pSrc->nSrc>=1 );
|
||||
pTab = sqlite3LocateTableItem(pParse, 0, pItem);
|
||||
if( pItem->pTab ) sqlite3DeleteTable(pParse->db, pItem->pTab);
|
||||
pItem->pTab = pTab;
|
||||
if( pItem->pSTab ) sqlite3DeleteTable(pParse->db, pItem->pSTab);
|
||||
pItem->pSTab = pTab;
|
||||
pItem->fg.notCte = 1;
|
||||
if( pTab ){
|
||||
pTab->nTabRef++;
|
||||
@@ -156,7 +156,8 @@ void sqlite3MaterializeView(
|
||||
if( pFrom ){
|
||||
assert( pFrom->nSrc==1 );
|
||||
pFrom->a[0].zName = sqlite3DbStrDup(db, pView->zName);
|
||||
pFrom->a[0].zDatabase = sqlite3DbStrDup(db, db->aDb[iDb].zDbSName);
|
||||
assert( pFrom->a[0].fg.fixedSchema==0 && pFrom->a[0].fg.isSubquery==0 );
|
||||
pFrom->a[0].u4.zDatabase = sqlite3DbStrDup(db, db->aDb[iDb].zDbSName);
|
||||
assert( pFrom->a[0].fg.isUsing==0 );
|
||||
assert( pFrom->a[0].u3.pOn==0 );
|
||||
}
|
||||
@@ -218,7 +219,7 @@ Expr *sqlite3LimitWhere(
|
||||
** );
|
||||
*/
|
||||
|
||||
pTab = pSrc->a[0].pTab;
|
||||
pTab = pSrc->a[0].pSTab;
|
||||
if( HasRowid(pTab) ){
|
||||
pLhs = sqlite3PExpr(pParse, TK_ROW, 0, 0);
|
||||
pEList = sqlite3ExprListAppend(
|
||||
@@ -251,9 +252,9 @@ Expr *sqlite3LimitWhere(
|
||||
|
||||
/* duplicate the FROM clause as it is needed by both the DELETE/UPDATE tree
|
||||
** and the SELECT subtree. */
|
||||
pSrc->a[0].pTab = 0;
|
||||
pSrc->a[0].pSTab = 0;
|
||||
pSelectSrc = sqlite3SrcListDup(db, pSrc, 0);
|
||||
pSrc->a[0].pTab = pTab;
|
||||
pSrc->a[0].pSTab = pTab;
|
||||
if( pSrc->a[0].fg.isIndexedBy ){
|
||||
assert( pSrc->a[0].fg.isCte==0 );
|
||||
pSrc->a[0].u2.pIBIndex = 0;
|
||||
|
||||
+25
-12
@@ -1877,15 +1877,30 @@ SrcList *sqlite3SrcListDup(sqlite3 *db, const SrcList *p, int flags){
|
||||
SrcItem *pNewItem = &pNew->a[i];
|
||||
const SrcItem *pOldItem = &p->a[i];
|
||||
Table *pTab;
|
||||
pNewItem->pSchema = pOldItem->pSchema;
|
||||
pNewItem->zDatabase = sqlite3DbStrDup(db, pOldItem->zDatabase);
|
||||
pNewItem->fg = pOldItem->fg;
|
||||
if( pOldItem->fg.isSubquery ){
|
||||
Subquery *pNewSubq = sqlite3DbMallocRaw(db, sizeof(Subquery));
|
||||
if( pNewSubq==0 ){
|
||||
assert( db->mallocFailed );
|
||||
pNewItem->fg.isSubquery = 0;
|
||||
}else{
|
||||
memcpy(pNewSubq, pOldItem->u4.pSubq, sizeof(*pNewSubq));
|
||||
pNewSubq->pSelect = sqlite3SelectDup(db, pNewSubq->pSelect, flags);
|
||||
if( pNewSubq->pSelect==0 ){
|
||||
sqlite3DbFree(db, pNewSubq);
|
||||
pNewSubq = 0;
|
||||
pNewItem->fg.isSubquery = 0;
|
||||
}
|
||||
}
|
||||
pNewItem->u4.pSubq = pNewSubq;
|
||||
}else if( pOldItem->fg.fixedSchema ){
|
||||
pNewItem->u4.pSchema = pOldItem->u4.pSchema;
|
||||
}else{
|
||||
pNewItem->u4.zDatabase = sqlite3DbStrDup(db, pOldItem->u4.zDatabase);
|
||||
}
|
||||
pNewItem->zName = sqlite3DbStrDup(db, pOldItem->zName);
|
||||
pNewItem->zAlias = sqlite3DbStrDup(db, pOldItem->zAlias);
|
||||
pNewItem->fg = pOldItem->fg;
|
||||
pNewItem->iCursor = pOldItem->iCursor;
|
||||
pNewItem->addrFillSub = pOldItem->addrFillSub;
|
||||
pNewItem->regReturn = pOldItem->regReturn;
|
||||
pNewItem->regResult = pOldItem->regResult;
|
||||
if( pNewItem->fg.isIndexedBy ){
|
||||
pNewItem->u1.zIndexedBy = sqlite3DbStrDup(db, pOldItem->u1.zIndexedBy);
|
||||
}else if( pNewItem->fg.isTabFunc ){
|
||||
@@ -1898,11 +1913,10 @@ SrcList *sqlite3SrcListDup(sqlite3 *db, const SrcList *p, int flags){
|
||||
if( pNewItem->fg.isCte ){
|
||||
pNewItem->u2.pCteUse->nUse++;
|
||||
}
|
||||
pTab = pNewItem->pTab = pOldItem->pTab;
|
||||
pTab = pNewItem->pSTab = pOldItem->pSTab;
|
||||
if( pTab ){
|
||||
pTab->nTabRef++;
|
||||
}
|
||||
pNewItem->pSelect = sqlite3SelectDup(db, pOldItem->pSelect, flags);
|
||||
if( pOldItem->fg.isUsing ){
|
||||
assert( pNewItem->fg.isUsing );
|
||||
pNewItem->u3.pUsing = sqlite3IdListDup(db, pOldItem->u3.pUsing);
|
||||
@@ -1976,7 +1990,6 @@ Select *sqlite3SelectDup(sqlite3 *db, const Select *pDup, int flags){
|
||||
pp = &pNew->pPrior;
|
||||
pNext = pNew;
|
||||
}
|
||||
|
||||
return pRet;
|
||||
}
|
||||
#else
|
||||
@@ -2996,8 +3009,8 @@ static Select *isCandidateForInOpt(const Expr *pX){
|
||||
pSrc = p->pSrc;
|
||||
assert( pSrc!=0 );
|
||||
if( pSrc->nSrc!=1 ) return 0; /* Single term in FROM clause */
|
||||
if( pSrc->a[0].pSelect ) return 0; /* FROM is not a subquery or view */
|
||||
pTab = pSrc->a[0].pTab;
|
||||
if( pSrc->a[0].fg.isSubquery) return 0;/* FROM is not a subquery or view */
|
||||
pTab = pSrc->a[0].pSTab;
|
||||
assert( pTab!=0 );
|
||||
assert( !IsView(pTab) ); /* FROM clause is not a view */
|
||||
if( IsVirtual(pTab) ) return 0; /* FROM clause not a virtual table */
|
||||
@@ -3180,7 +3193,7 @@ int sqlite3FindInIndex(
|
||||
assert( p->pEList!=0 ); /* Because of isCandidateForInOpt(p) */
|
||||
assert( p->pEList->a[0].pExpr!=0 ); /* Because of isCandidateForInOpt(p) */
|
||||
assert( p->pSrc!=0 ); /* Because of isCandidateForInOpt(p) */
|
||||
pTab = p->pSrc->a[0].pTab;
|
||||
pTab = p->pSrc->a[0].pSTab;
|
||||
|
||||
/* Code an OP_Transaction and OP_TableLock for <table>. */
|
||||
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
|
||||
|
||||
+4
-3
@@ -1043,9 +1043,9 @@ void sqlite3FkCheck(
|
||||
pSrc = sqlite3SrcListAppend(pParse, 0, 0, 0);
|
||||
if( pSrc ){
|
||||
SrcItem *pItem = pSrc->a;
|
||||
pItem->pTab = pFKey->pFrom;
|
||||
pItem->pSTab = pFKey->pFrom;
|
||||
pItem->zName = pFKey->pFrom->zName;
|
||||
pItem->pTab->nTabRef++;
|
||||
pItem->pSTab->nTabRef++;
|
||||
pItem->iCursor = pParse->nTab++;
|
||||
|
||||
if( regNew!=0 ){
|
||||
@@ -1337,7 +1337,8 @@ static Trigger *fkActionTrigger(
|
||||
if( pSrc ){
|
||||
assert( pSrc->nSrc==1 );
|
||||
pSrc->a[0].zName = sqlite3DbStrDup(db, zFrom);
|
||||
pSrc->a[0].zDatabase = sqlite3DbStrDup(db, db->aDb[iDb].zDbSName);
|
||||
assert( pSrc->a[0].fg.fixedSchema==0 && pSrc->a[0].fg.isSubquery==0 );
|
||||
pSrc->a[0].u4.zDatabase = sqlite3DbStrDup(db, db->aDb[iDb].zDbSName);
|
||||
}
|
||||
pSelect = sqlite3SelectNew(pParse,
|
||||
sqlite3ExprListAppend(pParse, 0, pRaise),
|
||||
|
||||
+46
-27
@@ -585,8 +585,11 @@ void sqlite3AutoincrementEnd(Parse *pParse){
|
||||
void sqlite3MultiValuesEnd(Parse *pParse, Select *pVal){
|
||||
if( ALWAYS(pVal) && pVal->pSrc->nSrc>0 ){
|
||||
SrcItem *pItem = &pVal->pSrc->a[0];
|
||||
sqlite3VdbeEndCoroutine(pParse->pVdbe, pItem->regReturn);
|
||||
sqlite3VdbeJumpHere(pParse->pVdbe, pItem->addrFillSub - 1);
|
||||
assert( (pItem->fg.isSubquery && pItem->u4.pSubq!=0) || pParse->nErr );
|
||||
if( pItem->fg.isSubquery ){
|
||||
sqlite3VdbeEndCoroutine(pParse->pVdbe, pItem->u4.pSubq->regReturn);
|
||||
sqlite3VdbeJumpHere(pParse->pVdbe, pItem->u4.pSubq->addrFillSub - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -714,6 +717,7 @@ Select *sqlite3MultiValues(Parse *pParse, Select *pLeft, ExprList *pRow){
|
||||
|
||||
if( pRet ){
|
||||
SelectDest dest;
|
||||
Subquery *pSubq;
|
||||
pRet->pSrc->nSrc = 1;
|
||||
pRet->pPrior = pLeft->pPrior;
|
||||
pRet->op = pLeft->op;
|
||||
@@ -723,28 +727,32 @@ Select *sqlite3MultiValues(Parse *pParse, Select *pLeft, ExprList *pRow){
|
||||
assert( pLeft->pNext==0 );
|
||||
assert( pRet->pNext==0 );
|
||||
p = &pRet->pSrc->a[0];
|
||||
p->pSelect = pLeft;
|
||||
p->fg.viaCoroutine = 1;
|
||||
p->addrFillSub = sqlite3VdbeCurrentAddr(v) + 1;
|
||||
p->regReturn = ++pParse->nMem;
|
||||
p->iCursor = -1;
|
||||
assert( !p->fg.isIndexedBy && !p->fg.isTabFunc );
|
||||
p->u1.nRow = 2;
|
||||
sqlite3VdbeAddOp3(v,OP_InitCoroutine,p->regReturn,0,p->addrFillSub);
|
||||
sqlite3SelectDestInit(&dest, SRT_Coroutine, p->regReturn);
|
||||
if( sqlite3SrcItemAttachSubquery(pParse, p, pLeft, 0) ){
|
||||
pSubq = p->u4.pSubq;
|
||||
pSubq->addrFillSub = sqlite3VdbeCurrentAddr(v) + 1;
|
||||
pSubq->regReturn = ++pParse->nMem;
|
||||
sqlite3VdbeAddOp3(v, OP_InitCoroutine,
|
||||
pSubq->regReturn, 0, pSubq->addrFillSub);
|
||||
sqlite3SelectDestInit(&dest, SRT_Coroutine, pSubq->regReturn);
|
||||
|
||||
/* Allocate registers for the output of the co-routine. Do so so
|
||||
** that there are two unused registers immediately before those
|
||||
** used by the co-routine. This allows the code in sqlite3Insert()
|
||||
** to use these registers directly, instead of copying the output
|
||||
** of the co-routine to a separate array for processing. */
|
||||
dest.iSdst = pParse->nMem + 3;
|
||||
dest.nSdst = pLeft->pEList->nExpr;
|
||||
pParse->nMem += 2 + dest.nSdst;
|
||||
/* Allocate registers for the output of the co-routine. Do so so
|
||||
** that there are two unused registers immediately before those
|
||||
** used by the co-routine. This allows the code in sqlite3Insert()
|
||||
** to use these registers directly, instead of copying the output
|
||||
** of the co-routine to a separate array for processing. */
|
||||
dest.iSdst = pParse->nMem + 3;
|
||||
dest.nSdst = pLeft->pEList->nExpr;
|
||||
pParse->nMem += 2 + dest.nSdst;
|
||||
|
||||
pLeft->selFlags |= SF_MultiValue;
|
||||
sqlite3Select(pParse, pLeft, &dest);
|
||||
p->regResult = dest.iSdst;
|
||||
assert( pParse->nErr || dest.iSdst>0 );
|
||||
pLeft->selFlags |= SF_MultiValue;
|
||||
sqlite3Select(pParse, pLeft, &dest);
|
||||
pSubq->regResult = dest.iSdst;
|
||||
assert( pParse->nErr || dest.iSdst>0 );
|
||||
}
|
||||
pLeft = pRet;
|
||||
}
|
||||
}else{
|
||||
@@ -754,12 +762,18 @@ Select *sqlite3MultiValues(Parse *pParse, Select *pLeft, ExprList *pRow){
|
||||
}
|
||||
|
||||
if( pParse->nErr==0 ){
|
||||
Subquery *pSubq;
|
||||
assert( p!=0 );
|
||||
if( p->pSelect->pEList->nExpr!=pRow->nExpr ){
|
||||
sqlite3SelectWrongNumTermsError(pParse, p->pSelect);
|
||||
assert( p->fg.isSubquery );
|
||||
pSubq = p->u4.pSubq;
|
||||
assert( pSubq!=0 );
|
||||
assert( pSubq->pSelect!=0 );
|
||||
assert( pSubq->pSelect->pEList!=0 );
|
||||
if( pSubq->pSelect->pEList->nExpr!=pRow->nExpr ){
|
||||
sqlite3SelectWrongNumTermsError(pParse, pSubq->pSelect);
|
||||
}else{
|
||||
sqlite3ExprCodeExprList(pParse, pRow, p->regResult, 0, 0);
|
||||
sqlite3VdbeAddOp1(pParse->pVdbe, OP_Yield, p->regReturn);
|
||||
sqlite3ExprCodeExprList(pParse, pRow, pSubq->regResult, 0, 0);
|
||||
sqlite3VdbeAddOp1(pParse->pVdbe, OP_Yield, pSubq->regReturn);
|
||||
}
|
||||
}
|
||||
sqlite3ExprListDelete(pParse->db, pRow);
|
||||
@@ -1110,9 +1124,14 @@ void sqlite3Insert(
|
||||
&& pSelect->pPrior==0
|
||||
){
|
||||
SrcItem *pItem = &pSelect->pSrc->a[0];
|
||||
dest.iSDParm = pItem->regReturn;
|
||||
regFromSelect = pItem->regResult;
|
||||
nColumn = pItem->pSelect->pEList->nExpr;
|
||||
Subquery *pSubq;
|
||||
assert( pItem->fg.isSubquery );
|
||||
pSubq = pItem->u4.pSubq;
|
||||
dest.iSDParm = pSubq->regReturn;
|
||||
regFromSelect = pSubq->regResult;
|
||||
assert( pSubq->pSelect!=0 );
|
||||
assert( pSubq->pSelect->pEList!=0 );
|
||||
nColumn = pSubq->pSelect->pEList->nExpr;
|
||||
ExplainQueryPlan((pParse, 0, "SCAN %S", pItem));
|
||||
if( bIdListInOrder && nColumn==pTab->nCol ){
|
||||
regData = regFromSelect;
|
||||
@@ -3032,7 +3051,7 @@ static int xferOptimization(
|
||||
if( pSelect->pSrc->nSrc!=1 ){
|
||||
return 0; /* FROM clause must have exactly one term */
|
||||
}
|
||||
if( pSelect->pSrc->a[0].pSelect ){
|
||||
if( pSelect->pSrc->a[0].fg.isSubquery ){
|
||||
return 0; /* FROM clause cannot contain a subquery */
|
||||
}
|
||||
if( pSelect->pWhere ){
|
||||
|
||||
+15
-6
@@ -740,11 +740,21 @@ seltablist(A) ::= stl_prefix(A) nm(Y) dbnm(D) LP exprlist(E) RP as(Z) on_using(N
|
||||
if( A ){
|
||||
SrcItem *pNew = &A->a[A->nSrc-1];
|
||||
SrcItem *pOld = F->a;
|
||||
assert( pOld->fg.fixedSchema==0 );
|
||||
pNew->zName = pOld->zName;
|
||||
pNew->zDatabase = pOld->zDatabase;
|
||||
pNew->pSelect = pOld->pSelect;
|
||||
if( pNew->pSelect && (pNew->pSelect->selFlags & SF_NestedFrom)!=0 ){
|
||||
pNew->fg.isNestedFrom = 1;
|
||||
assert( pOld->fg.fixedSchema==0 );
|
||||
if( pOld->fg.isSubquery ){
|
||||
pNew->fg.isSubquery = 1;
|
||||
pNew->u4.pSubq = pOld->u4.pSubq;
|
||||
pOld->u4.pSubq = 0;
|
||||
pOld->fg.isSubquery = 0;
|
||||
assert( pNew->u4.pSubq!=0 && pNew->u4.pSubq->pSelect!=0 );
|
||||
if( (pNew->u4.pSubq->pSelect->selFlags & SF_NestedFrom)!=0 ){
|
||||
pNew->fg.isNestedFrom = 1;
|
||||
}
|
||||
}else{
|
||||
pNew->u4.zDatabase = pOld->u4.zDatabase;
|
||||
pOld->u4.zDatabase = 0;
|
||||
}
|
||||
if( pOld->fg.isTabFunc ){
|
||||
pNew->u1.pFuncArg = pOld->u1.pFuncArg;
|
||||
@@ -752,8 +762,7 @@ seltablist(A) ::= stl_prefix(A) nm(Y) dbnm(D) LP exprlist(E) RP as(Z) on_using(N
|
||||
pOld->fg.isTabFunc = 0;
|
||||
pNew->fg.isTabFunc = 1;
|
||||
}
|
||||
pOld->zName = pOld->zDatabase = 0;
|
||||
pOld->pSelect = 0;
|
||||
pOld->zName = 0;
|
||||
}
|
||||
sqlite3SrcListDelete(pParse->db, F);
|
||||
}else{
|
||||
|
||||
+8
-5
@@ -848,16 +848,19 @@ void sqlite3_str_vappendf(
|
||||
if( pItem->zAlias && !flag_altform2 ){
|
||||
sqlite3_str_appendall(pAccum, pItem->zAlias);
|
||||
}else if( pItem->zName ){
|
||||
if( pItem->zDatabase ){
|
||||
sqlite3_str_appendall(pAccum, pItem->zDatabase);
|
||||
if( pItem->fg.fixedSchema==0
|
||||
&& pItem->fg.isSubquery==0
|
||||
&& pItem->u4.zDatabase!=0
|
||||
){
|
||||
sqlite3_str_appendall(pAccum, pItem->u4.zDatabase);
|
||||
sqlite3_str_append(pAccum, ".", 1);
|
||||
}
|
||||
sqlite3_str_appendall(pAccum, pItem->zName);
|
||||
}else if( pItem->zAlias ){
|
||||
sqlite3_str_appendall(pAccum, pItem->zAlias);
|
||||
}else{
|
||||
Select *pSel = pItem->pSelect;
|
||||
assert( pSel!=0 ); /* Because of tag-20240424-1 */
|
||||
}else if( ALWAYS(pItem->fg.isSubquery) ){/* Because of tag-20240424-1 */
|
||||
Select *pSel = pItem->u4.pSubq->pSelect;
|
||||
assert( pSel!=0 );
|
||||
if( pSel->selFlags & SF_NestedFrom ){
|
||||
sqlite3_str_appendf(pAccum, "(join-%u)", pSel->selId);
|
||||
}else if( pSel->selFlags & SF_MultiValue ){
|
||||
|
||||
+40
-23
@@ -215,7 +215,7 @@ static void extendFJMatch(
|
||||
if( pNew ){
|
||||
pNew->iTable = pMatch->iCursor;
|
||||
pNew->iColumn = iColumn;
|
||||
pNew->y.pTab = pMatch->pTab;
|
||||
pNew->y.pTab = pMatch->pSTab;
|
||||
assert( (pMatch->fg.jointype & (JT_LEFT|JT_LTORJ))!=0 );
|
||||
ExprSetProperty(pNew, EP_CanBeNull);
|
||||
*ppList = sqlite3ExprListAppend(pParse, *ppList, pNew);
|
||||
@@ -346,10 +346,10 @@ static int lookupName(
|
||||
if( pSrcList ){
|
||||
for(i=0, pItem=pSrcList->a; i<pSrcList->nSrc; i++, pItem++){
|
||||
u8 hCol;
|
||||
pTab = pItem->pTab;
|
||||
pTab = pItem->pSTab;
|
||||
assert( pTab!=0 && pTab->zName!=0 );
|
||||
assert( pTab->nCol>0 || pParse->nErr );
|
||||
assert( (int)pItem->fg.isNestedFrom == IsNestedFrom(pItem->pSelect) );
|
||||
assert( (int)pItem->fg.isNestedFrom == IsNestedFrom(pItem));
|
||||
if( pItem->fg.isNestedFrom ){
|
||||
/* In this case, pItem is a subquery that has been formed from a
|
||||
** parenthesized subset of the FROM clause terms. Example:
|
||||
@@ -358,8 +358,12 @@ static int lookupName(
|
||||
** This pItem -------------^
|
||||
*/
|
||||
int hit = 0;
|
||||
assert( pItem->pSelect!=0 );
|
||||
pEList = pItem->pSelect->pEList;
|
||||
Select *pSel;
|
||||
assert( pItem->fg.isSubquery );
|
||||
assert( pItem->u4.pSubq!=0 );
|
||||
pSel = pItem->u4.pSubq->pSelect;
|
||||
assert( pSel!=0 );
|
||||
pEList = pSel->pEList;
|
||||
assert( pEList!=0 );
|
||||
assert( pEList->nExpr==pTab->nCol );
|
||||
for(j=0; j<pEList->nExpr; j++){
|
||||
@@ -483,8 +487,8 @@ static int lookupName(
|
||||
if( cntTab==0
|
||||
|| (cntTab==1
|
||||
&& ALWAYS(pMatch!=0)
|
||||
&& ALWAYS(pMatch->pTab!=0)
|
||||
&& (pMatch->pTab->tabFlags & TF_Ephemeral)!=0
|
||||
&& ALWAYS(pMatch->pSTab!=0)
|
||||
&& (pMatch->pSTab->tabFlags & TF_Ephemeral)!=0
|
||||
&& (pTab->tabFlags & TF_Ephemeral)==0)
|
||||
){
|
||||
cntTab = 1;
|
||||
@@ -505,7 +509,7 @@ static int lookupName(
|
||||
if( pMatch ){
|
||||
pExpr->iTable = pMatch->iCursor;
|
||||
assert( ExprUseYTab(pExpr) );
|
||||
pExpr->y.pTab = pMatch->pTab;
|
||||
pExpr->y.pTab = pMatch->pSTab;
|
||||
if( (pMatch->fg.jointype & (JT_LEFT|JT_LTORJ))!=0 ){
|
||||
ExprSetProperty(pExpr, EP_CanBeNull);
|
||||
}
|
||||
@@ -547,7 +551,7 @@ static int lookupName(
|
||||
if( (pNC->ncFlags & NC_UUpsert)!=0 && zTab!=0 ){
|
||||
Upsert *pUpsert = pNC->uNC.pUpsert;
|
||||
if( pUpsert && sqlite3StrICmp("excluded",zTab)==0 ){
|
||||
pTab = pUpsert->pUpsertSrc->a[0].pTab;
|
||||
pTab = pUpsert->pUpsertSrc->a[0].pSTab;
|
||||
pExpr->iTable = EXCLUDED_TABLE_NUMBER;
|
||||
}
|
||||
}
|
||||
@@ -630,11 +634,11 @@ static int lookupName(
|
||||
&& pMatch
|
||||
&& (pNC->ncFlags & (NC_IdxExpr|NC_GenCol))==0
|
||||
&& sqlite3IsRowid(zCol)
|
||||
&& ALWAYS(VisibleRowid(pMatch->pTab) || pMatch->fg.isNestedFrom)
|
||||
&& ALWAYS(VisibleRowid(pMatch->pSTab) || pMatch->fg.isNestedFrom)
|
||||
){
|
||||
cnt = cntTab;
|
||||
#if SQLITE_ALLOW_ROWID_IN_VIEW+0==2
|
||||
if( pMatch->pTab!=0 && IsView(pMatch->pTab) ){
|
||||
if( pMatch->pSTab!=0 && IsView(pMatch->pSTab) ){
|
||||
eNewExprOp = TK_NULL;
|
||||
}
|
||||
#endif
|
||||
@@ -871,7 +875,7 @@ Expr *sqlite3CreateColumnExpr(sqlite3 *db, SrcList *pSrc, int iSrc, int iCol){
|
||||
SrcItem *pItem = &pSrc->a[iSrc];
|
||||
Table *pTab;
|
||||
assert( ExprUseYTab(p) );
|
||||
pTab = p->y.pTab = pItem->pTab;
|
||||
pTab = p->y.pTab = pItem->pSTab;
|
||||
p->iTable = pItem->iCursor;
|
||||
if( p->y.pTab->iPKey==iCol ){
|
||||
p->iColumn = -1;
|
||||
@@ -990,7 +994,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
|
||||
pItem = pSrcList->a;
|
||||
pExpr->op = TK_COLUMN;
|
||||
assert( ExprUseYTab(pExpr) );
|
||||
pExpr->y.pTab = pItem->pTab;
|
||||
pExpr->y.pTab = pItem->pSTab;
|
||||
pExpr->iTable = pItem->iCursor;
|
||||
pExpr->iColumn--;
|
||||
pExpr->affExpr = SQLITE_AFF_INTEGER;
|
||||
@@ -1880,7 +1884,11 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
|
||||
** moves the pOrderBy down to the sub-query. It will be moved back
|
||||
** after the names have been resolved. */
|
||||
if( p->selFlags & SF_Converted ){
|
||||
Select *pSub = p->pSrc->a[0].pSelect;
|
||||
Select *pSub;
|
||||
assert( p->pSrc->a[0].fg.isSubquery );
|
||||
assert( p->pSrc->a[0].u4.pSubq!=0 );
|
||||
pSub = p->pSrc->a[0].u4.pSubq->pSelect;
|
||||
assert( pSub!=0 );
|
||||
assert( p->pSrc->nSrc==1 && p->pOrderBy );
|
||||
assert( pSub->pPrior && pSub->pOrderBy==0 );
|
||||
pSub->pOrderBy = p->pOrderBy;
|
||||
@@ -1892,13 +1900,16 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
|
||||
if( pOuterNC ) pOuterNC->nNestedSelect++;
|
||||
for(i=0; i<p->pSrc->nSrc; i++){
|
||||
SrcItem *pItem = &p->pSrc->a[i];
|
||||
assert( pItem->zName!=0 || pItem->pSelect!=0 );/* Test of tag-20240424-1*/
|
||||
if( pItem->pSelect && (pItem->pSelect->selFlags & SF_Resolved)==0 ){
|
||||
assert( pItem->zName!=0
|
||||
|| pItem->fg.isSubquery ); /* Test of tag-20240424-1*/
|
||||
if( pItem->fg.isSubquery
|
||||
&& (pItem->u4.pSubq->pSelect->selFlags & SF_Resolved)==0
|
||||
){
|
||||
int nRef = pOuterNC ? pOuterNC->nRef : 0;
|
||||
const char *zSavedContext = pParse->zAuthContext;
|
||||
|
||||
if( pItem->zName ) pParse->zAuthContext = pItem->zName;
|
||||
sqlite3ResolveSelectNames(pParse, pItem->pSelect, pOuterNC);
|
||||
sqlite3ResolveSelectNames(pParse, pItem->u4.pSubq->pSelect, pOuterNC);
|
||||
pParse->zAuthContext = zSavedContext;
|
||||
if( pParse->nErr ) return WRC_Abort;
|
||||
assert( db->mallocFailed==0 );
|
||||
@@ -2000,7 +2011,10 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
|
||||
** These integers will be replaced by copies of the corresponding result
|
||||
** set expressions by the call to resolveOrderGroupBy() below. */
|
||||
if( p->selFlags & SF_Converted ){
|
||||
Select *pSub = p->pSrc->a[0].pSelect;
|
||||
Select *pSub;
|
||||
assert( p->pSrc->a[0].fg.isSubquery );
|
||||
pSub = p->pSrc->a[0].u4.pSubq->pSelect;
|
||||
assert( pSub!=0 );
|
||||
p->pOrderBy = pSub->pOrderBy;
|
||||
pSub->pOrderBy = 0;
|
||||
}
|
||||
@@ -2154,6 +2168,9 @@ int sqlite3ResolveExprNames(
|
||||
** Resolve all names for all expression in an expression list. This is
|
||||
** just like sqlite3ResolveExprNames() except that it works for an expression
|
||||
** list rather than a single expression.
|
||||
**
|
||||
** The return value is SQLITE_OK (0) for success or SQLITE_ERROR (1) for a
|
||||
** failure.
|
||||
*/
|
||||
int sqlite3ResolveExprListNames(
|
||||
NameContext *pNC, /* Namespace to resolve expressions in. */
|
||||
@@ -2162,7 +2179,7 @@ int sqlite3ResolveExprListNames(
|
||||
int i;
|
||||
int savedHasAgg = 0;
|
||||
Walker w;
|
||||
if( pList==0 ) return WRC_Continue;
|
||||
if( pList==0 ) return SQLITE_OK;
|
||||
w.pParse = pNC->pParse;
|
||||
w.xExprCallback = resolveExprStep;
|
||||
w.xSelectCallback = resolveSelectStep;
|
||||
@@ -2176,7 +2193,7 @@ int sqlite3ResolveExprListNames(
|
||||
#if SQLITE_MAX_EXPR_DEPTH>0
|
||||
w.pParse->nHeight += pExpr->nHeight;
|
||||
if( sqlite3ExprCheckHeight(w.pParse, w.pParse->nHeight) ){
|
||||
return WRC_Abort;
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
#endif
|
||||
sqlite3WalkExprNN(&w, pExpr);
|
||||
@@ -2193,10 +2210,10 @@ int sqlite3ResolveExprListNames(
|
||||
(NC_HasAgg|NC_MinMaxAgg|NC_HasWin|NC_OrderAgg);
|
||||
pNC->ncFlags &= ~(NC_HasAgg|NC_MinMaxAgg|NC_HasWin|NC_OrderAgg);
|
||||
}
|
||||
if( w.pParse->nErr>0 ) return WRC_Abort;
|
||||
if( w.pParse->nErr>0 ) return SQLITE_ERROR;
|
||||
}
|
||||
pNC->ncFlags |= savedHasAgg;
|
||||
return WRC_Continue;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2264,7 +2281,7 @@ int sqlite3ResolveSelfReference(
|
||||
if( pTab ){
|
||||
sSrc.nSrc = 1;
|
||||
sSrc.a[0].zName = pTab->zName;
|
||||
sSrc.a[0].pTab = pTab;
|
||||
sSrc.a[0].pSTab = pTab;
|
||||
sSrc.a[0].iCursor = -1;
|
||||
if( pTab->pSchema!=pParse->db->aDb[1].pSchema ){
|
||||
/* Cause EP_FromDDL to be set on TK_FUNCTION nodes of non-TEMP
|
||||
|
||||
+173
-114
@@ -332,11 +332,13 @@ int sqlite3ColumnIndex(Table *pTab, const char *zCol){
|
||||
*/
|
||||
void sqlite3SrcItemColumnUsed(SrcItem *pItem, int iCol){
|
||||
assert( pItem!=0 );
|
||||
assert( (int)pItem->fg.isNestedFrom == IsNestedFrom(pItem->pSelect) );
|
||||
assert( (int)pItem->fg.isNestedFrom == IsNestedFrom(pItem) );
|
||||
if( pItem->fg.isNestedFrom ){
|
||||
ExprList *pResults;
|
||||
assert( pItem->pSelect!=0 );
|
||||
pResults = pItem->pSelect->pEList;
|
||||
assert( pItem->fg.isSubquery );
|
||||
assert( pItem->u4.pSubq!=0 );
|
||||
assert( pItem->u4.pSubq->pSelect!=0 );
|
||||
pResults = pItem->u4.pSubq->pSelect->pEList;
|
||||
assert( pResults!=0 );
|
||||
assert( iCol>=0 && iCol<pResults->nExpr );
|
||||
pResults->a[iCol].fg.bUsed = 1;
|
||||
@@ -370,9 +372,9 @@ static int tableAndColumnIndex(
|
||||
assert( (piTab==0)==(piCol==0) ); /* Both or neither are NULL */
|
||||
|
||||
for(i=iStart; i<=iEnd; i++){
|
||||
iCol = sqlite3ColumnIndex(pSrc->a[i].pTab, zCol);
|
||||
iCol = sqlite3ColumnIndex(pSrc->a[i].pSTab, zCol);
|
||||
if( iCol>=0
|
||||
&& (bIgnoreHidden==0 || IsHiddenColumn(&pSrc->a[i].pTab->aCol[iCol])==0)
|
||||
&& (bIgnoreHidden==0 || IsHiddenColumn(&pSrc->a[i].pSTab->aCol[iCol])==0)
|
||||
){
|
||||
if( piTab ){
|
||||
sqlite3SrcItemColumnUsed(&pSrc->a[i], iCol);
|
||||
@@ -501,10 +503,10 @@ static int sqlite3ProcessJoin(Parse *pParse, Select *p){
|
||||
pLeft = &pSrc->a[0];
|
||||
pRight = &pLeft[1];
|
||||
for(i=0; i<pSrc->nSrc-1; i++, pRight++, pLeft++){
|
||||
Table *pRightTab = pRight->pTab;
|
||||
Table *pRightTab = pRight->pSTab;
|
||||
u32 joinType;
|
||||
|
||||
if( NEVER(pLeft->pTab==0 || pRightTab==0) ) continue;
|
||||
if( NEVER(pLeft->pSTab==0 || pRightTab==0) ) continue;
|
||||
joinType = (pRight->fg.jointype & JT_OUTER)!=0 ? EP_OuterON : EP_InnerON;
|
||||
|
||||
/* If this is a NATURAL join, synthesize an appropriate USING clause
|
||||
@@ -1930,8 +1932,12 @@ static const char *columnTypeImpl(
|
||||
SrcList *pTabList = pNC->pSrcList;
|
||||
for(j=0;j<pTabList->nSrc && pTabList->a[j].iCursor!=pExpr->iTable;j++);
|
||||
if( j<pTabList->nSrc ){
|
||||
pTab = pTabList->a[j].pTab;
|
||||
pS = pTabList->a[j].pSelect;
|
||||
pTab = pTabList->a[j].pSTab;
|
||||
if( pTabList->a[j].fg.isSubquery ){
|
||||
pS = pTabList->a[j].u4.pSubq->pSelect;
|
||||
}else{
|
||||
pS = 0;
|
||||
}
|
||||
}else{
|
||||
pNC = pNC->pNext;
|
||||
}
|
||||
@@ -3983,7 +3989,9 @@ static void substSelect(
|
||||
pSrc = p->pSrc;
|
||||
assert( pSrc!=0 );
|
||||
for(i=pSrc->nSrc, pItem=pSrc->a; i>0; i--, pItem++){
|
||||
substSelect(pSubst, pItem->pSelect, 1);
|
||||
if( pItem->fg.isSubquery ){
|
||||
substSelect(pSubst, pItem->u4.pSubq->pSelect, 1);
|
||||
}
|
||||
if( pItem->fg.isTabFunc ){
|
||||
substExprList(pSubst, pItem->u1.pFuncArg);
|
||||
}
|
||||
@@ -4014,7 +4022,7 @@ static void recomputeColumnsUsed(
|
||||
SrcItem *pSrcItem /* Which FROM clause item to recompute */
|
||||
){
|
||||
Walker w;
|
||||
if( NEVER(pSrcItem->pTab==0) ) return;
|
||||
if( NEVER(pSrcItem->pSTab==0) ) return;
|
||||
memset(&w, 0, sizeof(w));
|
||||
w.xExprCallback = recomputeColumnsUsedExpr;
|
||||
w.xSelectCallback = sqlite3SelectWalkNoop;
|
||||
@@ -4054,8 +4062,10 @@ static void srclistRenumberCursors(
|
||||
aCsrMap[pItem->iCursor+1] = pParse->nTab++;
|
||||
}
|
||||
pItem->iCursor = aCsrMap[pItem->iCursor+1];
|
||||
for(p=pItem->pSelect; p; p=p->pPrior){
|
||||
srclistRenumberCursors(pParse, aCsrMap, p->pSrc, -1);
|
||||
if( pItem->fg.isSubquery ){
|
||||
for(p=pItem->u4.pSubq->pSelect; p; p=p->pPrior){
|
||||
srclistRenumberCursors(pParse, aCsrMap, p->pSrc, -1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4366,7 +4376,8 @@ static int flattenSubquery(
|
||||
assert( pSrc && iFrom>=0 && iFrom<pSrc->nSrc );
|
||||
pSubitem = &pSrc->a[iFrom];
|
||||
iParent = pSubitem->iCursor;
|
||||
pSub = pSubitem->pSelect;
|
||||
assert( pSubitem->fg.isSubquery );
|
||||
pSub = pSubitem->u4.pSubq->pSelect;
|
||||
assert( pSub!=0 );
|
||||
|
||||
#ifndef SQLITE_OMIT_WINDOWFUNC
|
||||
@@ -4419,7 +4430,7 @@ static int flattenSubquery(
|
||||
*/
|
||||
if( (pSubitem->fg.jointype & (JT_OUTER|JT_LTORJ))!=0 ){
|
||||
if( pSubSrc->nSrc>1 /* (3a) */
|
||||
|| IsVirtual(pSubSrc->a[0].pTab) /* (3b) */
|
||||
|| IsVirtual(pSubSrc->a[0].pSTab) /* (3b) */
|
||||
|| (p->selFlags & SF_Distinct)!=0 /* (3d) */
|
||||
|| (pSubitem->fg.jointype & JT_RIGHT)!=0 /* (26) */
|
||||
){
|
||||
@@ -4505,14 +4516,18 @@ static int flattenSubquery(
|
||||
pParse->zAuthContext = zSavedAuthContext;
|
||||
|
||||
/* Delete the transient structures associated with the subquery */
|
||||
pSub1 = pSubitem->pSelect;
|
||||
sqlite3DbFree(db, pSubitem->zDatabase);
|
||||
|
||||
if( ALWAYS(pSubitem->fg.isSubquery) ){
|
||||
pSub1 = sqlite3SubqueryDetach(db, pSubitem);
|
||||
}else{
|
||||
pSub1 = 0;
|
||||
}
|
||||
assert( pSubitem->fg.isSubquery==0 );
|
||||
assert( pSubitem->fg.fixedSchema==0 );
|
||||
sqlite3DbFree(db, pSubitem->zName);
|
||||
sqlite3DbFree(db, pSubitem->zAlias);
|
||||
pSubitem->zDatabase = 0;
|
||||
pSubitem->zName = 0;
|
||||
pSubitem->zAlias = 0;
|
||||
pSubitem->pSelect = 0;
|
||||
assert( pSubitem->fg.isUsing!=0 || pSubitem->u3.pOn==0 );
|
||||
|
||||
/* If the sub-query is a compound SELECT statement, then (by restrictions
|
||||
@@ -4553,8 +4568,8 @@ static int flattenSubquery(
|
||||
ExprList *pOrderBy = p->pOrderBy;
|
||||
Expr *pLimit = p->pLimit;
|
||||
Select *pPrior = p->pPrior;
|
||||
Table *pItemTab = pSubitem->pTab;
|
||||
pSubitem->pTab = 0;
|
||||
Table *pItemTab = pSubitem->pSTab;
|
||||
pSubitem->pSTab = 0;
|
||||
p->pOrderBy = 0;
|
||||
p->pPrior = 0;
|
||||
p->pLimit = 0;
|
||||
@@ -4562,7 +4577,7 @@ static int flattenSubquery(
|
||||
p->pLimit = pLimit;
|
||||
p->pOrderBy = pOrderBy;
|
||||
p->op = TK_ALL;
|
||||
pSubitem->pTab = pItemTab;
|
||||
pSubitem->pSTab = pItemTab;
|
||||
if( pNew==0 ){
|
||||
p->pPrior = pPrior;
|
||||
}else{
|
||||
@@ -4577,11 +4592,14 @@ static int flattenSubquery(
|
||||
TREETRACE(0x4,pParse,p,("compound-subquery flattener"
|
||||
" creates %u as peer\n",pNew->selId));
|
||||
}
|
||||
assert( pSubitem->pSelect==0 );
|
||||
assert( pSubitem->fg.isSubquery==0 );
|
||||
}
|
||||
sqlite3DbFree(db, aCsrMap);
|
||||
if( db->mallocFailed ){
|
||||
pSubitem->pSelect = pSub1;
|
||||
assert( pSubitem->fg.fixedSchema==0 );
|
||||
assert( pSubitem->fg.isSubquery==0 );
|
||||
assert( pSubitem->u4.zDatabase==0 );
|
||||
sqlite3SrcItemAttachSubquery(pParse, pSubitem, pSub1, 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -4592,8 +4610,8 @@ static int flattenSubquery(
|
||||
**
|
||||
** pSubitem->pTab is always non-NULL by test restrictions and tests above.
|
||||
*/
|
||||
if( ALWAYS(pSubitem->pTab!=0) ){
|
||||
Table *pTabToDel = pSubitem->pTab;
|
||||
if( ALWAYS(pSubitem->pSTab!=0) ){
|
||||
Table *pTabToDel = pSubitem->pSTab;
|
||||
if( pTabToDel->nTabRef==1 ){
|
||||
Parse *pToplevel = sqlite3ParseToplevel(pParse);
|
||||
sqlite3ParserAddCleanup(pToplevel, sqlite3DeleteTableGeneric, pTabToDel);
|
||||
@@ -4601,7 +4619,7 @@ static int flattenSubquery(
|
||||
}else{
|
||||
pTabToDel->nTabRef--;
|
||||
}
|
||||
pSubitem->pTab = 0;
|
||||
pSubitem->pSTab = 0;
|
||||
}
|
||||
|
||||
/* The following loop runs once for each term in a compound-subquery
|
||||
@@ -4657,8 +4675,11 @@ static int flattenSubquery(
|
||||
*/
|
||||
for(i=0; i<nSubSrc; i++){
|
||||
SrcItem *pItem = &pSrc->a[i+iFrom];
|
||||
if( pItem->fg.isUsing ) sqlite3IdListDelete(db, pItem->u3.pUsing);
|
||||
assert( pItem->fg.isTabFunc==0 );
|
||||
assert( pItem->fg.isSubquery
|
||||
|| pItem->fg.fixedSchema
|
||||
|| pItem->u4.zDatabase==0 );
|
||||
if( pItem->fg.isUsing ) sqlite3IdListDelete(db, pItem->u3.pUsing);
|
||||
*pItem = pSubSrc->a[i];
|
||||
pItem->fg.jointype |= ltorj;
|
||||
iNewParent = pSubSrc->a[i].iCursor;
|
||||
@@ -5342,10 +5363,10 @@ static int disableUnusedSubqueryResultColumns(SrcItem *pItem){
|
||||
if( pItem->fg.isCorrelated || pItem->fg.isCte ){
|
||||
return 0;
|
||||
}
|
||||
assert( pItem->pTab!=0 );
|
||||
pTab = pItem->pTab;
|
||||
assert( pItem->pSelect!=0 );
|
||||
pSub = pItem->pSelect;
|
||||
assert( pItem->pSTab!=0 );
|
||||
pTab = pItem->pSTab;
|
||||
assert( pItem->fg.isSubquery );
|
||||
pSub = pItem->u4.pSubq->pSelect;
|
||||
assert( pSub->pEList->nExpr==pTab->nCol );
|
||||
for(pX=pSub; pX; pX=pX->pPrior){
|
||||
if( (pX->selFlags & (SF_Distinct|SF_Aggregate))!=0 ){
|
||||
@@ -5474,13 +5495,13 @@ static Table *isSimpleCount(Select *p, AggInfo *pAggInfo){
|
||||
if( p->pWhere
|
||||
|| p->pEList->nExpr!=1
|
||||
|| p->pSrc->nSrc!=1
|
||||
|| p->pSrc->a[0].pSelect
|
||||
|| p->pSrc->a[0].fg.isSubquery
|
||||
|| pAggInfo->nFunc!=1
|
||||
|| p->pHaving
|
||||
){
|
||||
return 0;
|
||||
}
|
||||
pTab = p->pSrc->a[0].pTab;
|
||||
pTab = p->pSrc->a[0].pSTab;
|
||||
assert( pTab!=0 );
|
||||
assert( !IsView(pTab) );
|
||||
if( !IsOrdinaryTable(pTab) ) return 0;
|
||||
@@ -5505,7 +5526,7 @@ static Table *isSimpleCount(Select *p, AggInfo *pAggInfo){
|
||||
** pFrom->pIndex and return SQLITE_OK.
|
||||
*/
|
||||
int sqlite3IndexedByLookup(Parse *pParse, SrcItem *pFrom){
|
||||
Table *pTab = pFrom->pTab;
|
||||
Table *pTab = pFrom->pSTab;
|
||||
char *zIndexedBy = pFrom->u1.zIndexedBy;
|
||||
Index *pIdx;
|
||||
assert( pTab!=0 );
|
||||
@@ -5582,7 +5603,11 @@ static int convertCompoundSelectToSubquery(Walker *pWalker, Select *p){
|
||||
if( pNew==0 ) return WRC_Abort;
|
||||
memset(&dummy, 0, sizeof(dummy));
|
||||
pNewSrc = sqlite3SrcListAppendFromTerm(pParse,0,0,0,&dummy,pNew,0);
|
||||
if( pNewSrc==0 ) return WRC_Abort;
|
||||
assert( pNewSrc!=0 || pParse->nErr );
|
||||
if( pParse->nErr ){
|
||||
sqlite3SrcListDelete(db, pNewSrc);
|
||||
return WRC_Abort;
|
||||
}
|
||||
*pNew = *p;
|
||||
p->pSrc = pNewSrc;
|
||||
p->pEList = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(db, TK_ASTERISK, 0));
|
||||
@@ -5637,7 +5662,7 @@ static struct Cte *searchWith(
|
||||
){
|
||||
const char *zName = pItem->zName;
|
||||
With *p;
|
||||
assert( pItem->zDatabase==0 );
|
||||
assert( pItem->fg.fixedSchema || pItem->u4.zDatabase==0 );
|
||||
assert( zName!=0 );
|
||||
for(p=pWith; p; p=p->pOuter){
|
||||
int i;
|
||||
@@ -5707,7 +5732,7 @@ static int resolveFromTermToCte(
|
||||
Cte *pCte; /* Matched CTE (or NULL if no match) */
|
||||
With *pWith; /* The matching WITH */
|
||||
|
||||
assert( pFrom->pTab==0 );
|
||||
assert( pFrom->pSTab==0 );
|
||||
if( pParse->pWith==0 ){
|
||||
/* There are no WITH clauses in the stack. No match is possible */
|
||||
return 0;
|
||||
@@ -5717,7 +5742,8 @@ static int resolveFromTermToCte(
|
||||
** go no further. */
|
||||
return 0;
|
||||
}
|
||||
if( pFrom->zDatabase!=0 ){
|
||||
assert( pFrom->fg.hadSchema==0 || pFrom->fg.notCte!=0 );
|
||||
if( pFrom->fg.fixedSchema==0 && pFrom->u4.zDatabase!=0 ){
|
||||
/* The FROM term contains a schema qualifier (ex: main.t1) and so
|
||||
** it cannot possibly be a CTE reference. */
|
||||
return 0;
|
||||
@@ -5753,7 +5779,7 @@ static int resolveFromTermToCte(
|
||||
}
|
||||
if( cannotBeFunction(pParse, pFrom) ) return 2;
|
||||
|
||||
assert( pFrom->pTab==0 );
|
||||
assert( pFrom->pSTab==0 );
|
||||
pTab = sqlite3DbMallocZero(db, sizeof(Table));
|
||||
if( pTab==0 ) return 2;
|
||||
pCteUse = pCte->pUse;
|
||||
@@ -5767,26 +5793,29 @@ static int resolveFromTermToCte(
|
||||
}
|
||||
pCteUse->eM10d = pCte->eM10d;
|
||||
}
|
||||
pFrom->pTab = pTab;
|
||||
pFrom->pSTab = pTab;
|
||||
pTab->nTabRef = 1;
|
||||
pTab->zName = sqlite3DbStrDup(db, pCte->zName);
|
||||
pTab->iPKey = -1;
|
||||
pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) );
|
||||
pTab->tabFlags |= TF_Ephemeral | TF_NoVisibleRowid;
|
||||
pFrom->pSelect = sqlite3SelectDup(db, pCte->pSelect, 0);
|
||||
sqlite3SrcItemAttachSubquery(pParse, pFrom, pCte->pSelect, 1);
|
||||
if( db->mallocFailed ) return 2;
|
||||
pFrom->pSelect->selFlags |= SF_CopyCte;
|
||||
assert( pFrom->pSelect );
|
||||
assert( pFrom->fg.isSubquery && pFrom->u4.pSubq );
|
||||
pSel = pFrom->u4.pSubq->pSelect;
|
||||
assert( pSel!=0 );
|
||||
pSel->selFlags |= SF_CopyCte;
|
||||
if( pFrom->fg.isIndexedBy ){
|
||||
sqlite3ErrorMsg(pParse, "no such index: \"%s\"", pFrom->u1.zIndexedBy);
|
||||
return 2;
|
||||
}
|
||||
assert( !pFrom->fg.isIndexedBy );
|
||||
pFrom->fg.isCte = 1;
|
||||
pFrom->u2.pCteUse = pCteUse;
|
||||
pCteUse->nUse++;
|
||||
|
||||
/* Check if this is a recursive CTE. */
|
||||
pRecTerm = pSel = pFrom->pSelect;
|
||||
pRecTerm = pSel;
|
||||
bMayRecursive = ( pSel->op==TK_ALL || pSel->op==TK_UNION );
|
||||
while( bMayRecursive && pRecTerm->op==pSel->op ){
|
||||
int i;
|
||||
@@ -5794,11 +5823,13 @@ static int resolveFromTermToCte(
|
||||
assert( pRecTerm->pPrior!=0 );
|
||||
for(i=0; i<pSrc->nSrc; i++){
|
||||
SrcItem *pItem = &pSrc->a[i];
|
||||
if( pItem->zDatabase==0
|
||||
&& pItem->zName!=0
|
||||
if( pItem->zName!=0
|
||||
&& !pItem->fg.hadSchema
|
||||
&& ALWAYS( !pItem->fg.isSubquery )
|
||||
&& (pItem->fg.fixedSchema || pItem->u4.zDatabase==0)
|
||||
&& 0==sqlite3StrICmp(pItem->zName, pCte->zName)
|
||||
){
|
||||
pItem->pTab = pTab;
|
||||
pItem->pSTab = pTab;
|
||||
pTab->nTabRef++;
|
||||
pItem->fg.isRecursive = 1;
|
||||
if( pRecTerm->selFlags & SF_Recursive ){
|
||||
@@ -5900,11 +5931,14 @@ void sqlite3SelectPopWith(Walker *pWalker, Select *p){
|
||||
** SQLITE_NOMEM.
|
||||
*/
|
||||
int sqlite3ExpandSubquery(Parse *pParse, SrcItem *pFrom){
|
||||
Select *pSel = pFrom->pSelect;
|
||||
Select *pSel;
|
||||
Table *pTab;
|
||||
|
||||
assert( pFrom->fg.isSubquery );
|
||||
assert( pFrom->u4.pSubq!=0 );
|
||||
pSel = pFrom->u4.pSubq->pSelect;
|
||||
assert( pSel );
|
||||
pFrom->pTab = pTab = sqlite3DbMallocZero(pParse->db, sizeof(Table));
|
||||
pFrom->pSTab = pTab = sqlite3DbMallocZero(pParse->db, sizeof(Table));
|
||||
if( pTab==0 ) return SQLITE_NOMEM;
|
||||
pTab->nTabRef = 1;
|
||||
if( pFrom->zAlias ){
|
||||
@@ -6024,33 +6058,35 @@ static int selectExpander(Walker *pWalker, Select *p){
|
||||
*/
|
||||
for(i=0, pFrom=pTabList->a; i<pTabList->nSrc; i++, pFrom++){
|
||||
Table *pTab;
|
||||
assert( pFrom->fg.isRecursive==0 || pFrom->pTab!=0 );
|
||||
if( pFrom->pTab ) continue;
|
||||
assert( pFrom->fg.isRecursive==0 || pFrom->pSTab!=0 );
|
||||
if( pFrom->pSTab ) continue;
|
||||
assert( pFrom->fg.isRecursive==0 );
|
||||
if( pFrom->zName==0 ){
|
||||
#ifndef SQLITE_OMIT_SUBQUERY
|
||||
Select *pSel = pFrom->pSelect;
|
||||
Select *pSel;
|
||||
assert( pFrom->fg.isSubquery && pFrom->u4.pSubq!=0 );
|
||||
pSel = pFrom->u4.pSubq->pSelect;
|
||||
/* A sub-query in the FROM clause of a SELECT */
|
||||
assert( pSel!=0 );
|
||||
assert( pFrom->pTab==0 );
|
||||
assert( pFrom->pSTab==0 );
|
||||
if( sqlite3WalkSelect(pWalker, pSel) ) return WRC_Abort;
|
||||
if( sqlite3ExpandSubquery(pParse, pFrom) ) return WRC_Abort;
|
||||
#endif
|
||||
#ifndef SQLITE_OMIT_CTE
|
||||
}else if( (rc = resolveFromTermToCte(pParse, pWalker, pFrom))!=0 ){
|
||||
if( rc>1 ) return WRC_Abort;
|
||||
pTab = pFrom->pTab;
|
||||
pTab = pFrom->pSTab;
|
||||
assert( pTab!=0 );
|
||||
#endif
|
||||
}else{
|
||||
/* An ordinary table or view name in the FROM clause */
|
||||
assert( pFrom->pTab==0 );
|
||||
pFrom->pTab = pTab = sqlite3LocateTableItem(pParse, 0, pFrom);
|
||||
assert( pFrom->pSTab==0 );
|
||||
pFrom->pSTab = pTab = sqlite3LocateTableItem(pParse, 0, pFrom);
|
||||
if( pTab==0 ) return WRC_Abort;
|
||||
if( pTab->nTabRef>=0xffff ){
|
||||
sqlite3ErrorMsg(pParse, "too many references to \"%s\": max 65535",
|
||||
pTab->zName);
|
||||
pFrom->pTab = 0;
|
||||
pFrom->pSTab = 0;
|
||||
return WRC_Abort;
|
||||
}
|
||||
pTab->nTabRef++;
|
||||
@@ -6062,7 +6098,7 @@ static int selectExpander(Walker *pWalker, Select *p){
|
||||
i16 nCol;
|
||||
u8 eCodeOrig = pWalker->eCode;
|
||||
if( sqlite3ViewGetColumnNames(pParse, pTab) ) return WRC_Abort;
|
||||
assert( pFrom->pSelect==0 );
|
||||
assert( pFrom->fg.isSubquery==0 );
|
||||
if( IsView(pTab) ){
|
||||
if( (db->flags & SQLITE_EnableView)==0
|
||||
&& pTab->pSchema!=db->aDb[1].pSchema
|
||||
@@ -6070,7 +6106,7 @@ static int selectExpander(Walker *pWalker, Select *p){
|
||||
sqlite3ErrorMsg(pParse, "access to view \"%s\" prohibited",
|
||||
pTab->zName);
|
||||
}
|
||||
pFrom->pSelect = sqlite3SelectDup(db, pTab->u.view.pSelect, 0);
|
||||
sqlite3SrcItemAttachSubquery(pParse, pFrom, pTab->u.view.pSelect, 1);
|
||||
}
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
else if( ALWAYS(IsVirtual(pTab))
|
||||
@@ -6086,7 +6122,9 @@ static int selectExpander(Walker *pWalker, Select *p){
|
||||
nCol = pTab->nCol;
|
||||
pTab->nCol = -1;
|
||||
pWalker->eCode = 1; /* Turn on Select.selId renumbering */
|
||||
sqlite3WalkSelect(pWalker, pFrom->pSelect);
|
||||
if( pFrom->fg.isSubquery ){
|
||||
sqlite3WalkSelect(pWalker, pFrom->u4.pSubq->pSelect);
|
||||
}
|
||||
pWalker->eCode = eCodeOrig;
|
||||
pTab->nCol = nCol;
|
||||
}
|
||||
@@ -6173,7 +6211,7 @@ static int selectExpander(Walker *pWalker, Select *p){
|
||||
}
|
||||
for(i=0, pFrom=pTabList->a; i<pTabList->nSrc; i++, pFrom++){
|
||||
int nAdd; /* Number of cols including rowid */
|
||||
Table *pTab = pFrom->pTab; /* Table for this data source */
|
||||
Table *pTab = pFrom->pSTab; /* Table for this data source */
|
||||
ExprList *pNestedFrom; /* Result-set of a nested FROM clause */
|
||||
char *zTabName; /* AS name for this data source */
|
||||
const char *zSchemaName = 0; /* Schema name for this data source */
|
||||
@@ -6184,10 +6222,11 @@ static int selectExpander(Walker *pWalker, Select *p){
|
||||
zTabName = pTab->zName;
|
||||
}
|
||||
if( db->mallocFailed ) break;
|
||||
assert( (int)pFrom->fg.isNestedFrom == IsNestedFrom(pFrom->pSelect) );
|
||||
assert( (int)pFrom->fg.isNestedFrom == IsNestedFrom(pFrom) );
|
||||
if( pFrom->fg.isNestedFrom ){
|
||||
assert( pFrom->pSelect!=0 );
|
||||
pNestedFrom = pFrom->pSelect->pEList;
|
||||
assert( pFrom->fg.isSubquery && pFrom->u4.pSubq );
|
||||
assert( pFrom->u4.pSubq->pSelect!=0 );
|
||||
pNestedFrom = pFrom->u4.pSubq->pSelect->pEList;
|
||||
assert( pNestedFrom!=0 );
|
||||
assert( pNestedFrom->nExpr==pTab->nCol );
|
||||
assert( VisibleRowid(pTab)==0 || ViewCanHaveRowid );
|
||||
@@ -6426,14 +6465,12 @@ static void selectAddSubqueryTypeInfo(Walker *pWalker, Select *p){
|
||||
assert( (p->selFlags & SF_Resolved) );
|
||||
pTabList = p->pSrc;
|
||||
for(i=0, pFrom=pTabList->a; i<pTabList->nSrc; i++, pFrom++){
|
||||
Table *pTab = pFrom->pTab;
|
||||
Table *pTab = pFrom->pSTab;
|
||||
assert( pTab!=0 );
|
||||
if( (pTab->tabFlags & TF_Ephemeral)!=0 ){
|
||||
if( (pTab->tabFlags & TF_Ephemeral)!=0 && pFrom->fg.isSubquery ){
|
||||
/* A sub-query in the FROM clause of a SELECT */
|
||||
Select *pSel = pFrom->pSelect;
|
||||
if( pSel ){
|
||||
sqlite3SubqueryColumnTypes(pParse, pTab, pSel, SQLITE_AFF_NONE);
|
||||
}
|
||||
Select *pSel = pFrom->u4.pSubq->pSelect;
|
||||
sqlite3SubqueryColumnTypes(pParse, pTab, pSel, SQLITE_AFF_NONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7080,25 +7117,28 @@ static SrcItem *isSelfJoinView(
|
||||
int iFirst, int iEnd /* Range of FROM-clause entries to search. */
|
||||
){
|
||||
SrcItem *pItem;
|
||||
assert( pThis->pSelect!=0 );
|
||||
if( pThis->pSelect->selFlags & SF_PushDown ) return 0;
|
||||
Select *pSel;
|
||||
assert( pThis->fg.isSubquery );
|
||||
pSel = pThis->u4.pSubq->pSelect;
|
||||
assert( pSel!=0 );
|
||||
if( pSel->selFlags & SF_PushDown ) return 0;
|
||||
while( iFirst<iEnd ){
|
||||
Select *pS1;
|
||||
pItem = &pTabList->a[iFirst++];
|
||||
if( pItem->pSelect==0 ) continue;
|
||||
if( !pItem->fg.isSubquery ) continue;
|
||||
if( pItem->fg.viaCoroutine ) continue;
|
||||
if( pItem->zName==0 ) continue;
|
||||
assert( pItem->pTab!=0 );
|
||||
assert( pThis->pTab!=0 );
|
||||
if( pItem->pTab->pSchema!=pThis->pTab->pSchema ) continue;
|
||||
assert( pItem->pSTab!=0 );
|
||||
assert( pThis->pSTab!=0 );
|
||||
if( pItem->pSTab->pSchema!=pThis->pSTab->pSchema ) continue;
|
||||
if( sqlite3_stricmp(pItem->zName, pThis->zName)!=0 ) continue;
|
||||
pS1 = pItem->pSelect;
|
||||
if( pItem->pTab->pSchema==0 && pThis->pSelect->selId!=pS1->selId ){
|
||||
pS1 = pItem->u4.pSubq->pSelect;
|
||||
if( pItem->pSTab->pSchema==0 && pSel->selId!=pS1->selId ){
|
||||
/* The query flattener left two different CTE tables with identical
|
||||
** names in the same FROM clause. */
|
||||
continue;
|
||||
}
|
||||
if( pItem->pSelect->selFlags & SF_PushDown ){
|
||||
if( pS1->selFlags & SF_PushDown ){
|
||||
/* The view was modified by some other optimization such as
|
||||
** pushDownWhereTerms() */
|
||||
continue;
|
||||
@@ -7142,6 +7182,7 @@ static int countOfViewOptimization(Parse *pParse, Select *p){
|
||||
Expr *pExpr;
|
||||
Expr *pCount;
|
||||
sqlite3 *db;
|
||||
SrcItem *pFrom;
|
||||
if( (p->selFlags & SF_Aggregate)==0 ) return 0; /* This is an aggregate */
|
||||
if( p->pEList->nExpr!=1 ) return 0; /* Single result column */
|
||||
if( p->pWhere ) return 0;
|
||||
@@ -7156,8 +7197,9 @@ static int countOfViewOptimization(Parse *pParse, Select *p){
|
||||
if( pExpr->x.pList!=0 ) return 0; /* Must be count(*) */
|
||||
if( p->pSrc->nSrc!=1 ) return 0; /* One table in FROM */
|
||||
if( ExprHasProperty(pExpr, EP_WinFunc) ) return 0;/* Not a window function */
|
||||
pSub = p->pSrc->a[0].pSelect;
|
||||
if( pSub==0 ) return 0; /* The FROM is a subquery */
|
||||
pFrom = p->pSrc->a;
|
||||
if( pFrom->fg.isSubquery==0 ) return 0; /* FROM is a subquery */
|
||||
pSub = pFrom->u4.pSubq->pSelect;
|
||||
if( pSub->pPrior==0 ) return 0; /* Must be a compound */
|
||||
if( pSub->selFlags & SF_CopyCte ) return 0; /* Not a CTE */
|
||||
do{
|
||||
@@ -7166,7 +7208,7 @@ static int countOfViewOptimization(Parse *pParse, Select *p){
|
||||
if( pSub->pLimit ) return 0; /* No LIMIT clause */
|
||||
if( pSub->selFlags & SF_Aggregate ) return 0; /* Not an aggregate */
|
||||
assert( pSub->pHaving==0 ); /* Due to the previous */
|
||||
pSub = pSub->pPrior; /* Repeat over compound */
|
||||
pSub = pSub->pPrior; /* Repeat over compound */
|
||||
}while( pSub );
|
||||
|
||||
/* If we reach this point then it is OK to perform the transformation */
|
||||
@@ -7174,8 +7216,7 @@ static int countOfViewOptimization(Parse *pParse, Select *p){
|
||||
db = pParse->db;
|
||||
pCount = pExpr;
|
||||
pExpr = 0;
|
||||
pSub = p->pSrc->a[0].pSelect;
|
||||
p->pSrc->a[0].pSelect = 0;
|
||||
pSub = sqlite3SubqueryDetach(db, pFrom);
|
||||
sqlite3SrcListDelete(db, p->pSrc);
|
||||
p->pSrc = sqlite3DbMallocZero(pParse->db, sizeof(*p->pSrc));
|
||||
while( pSub ){
|
||||
@@ -7220,12 +7261,12 @@ static int sameSrcAlias(SrcItem *p0, SrcList *pSrc){
|
||||
for(i=0; i<pSrc->nSrc; i++){
|
||||
SrcItem *p1 = &pSrc->a[i];
|
||||
if( p1==p0 ) continue;
|
||||
if( p0->pTab==p1->pTab && 0==sqlite3_stricmp(p0->zAlias, p1->zAlias) ){
|
||||
if( p0->pSTab==p1->pSTab && 0==sqlite3_stricmp(p0->zAlias, p1->zAlias) ){
|
||||
return 1;
|
||||
}
|
||||
if( p1->pSelect
|
||||
&& (p1->pSelect->selFlags & SF_NestedFrom)!=0
|
||||
&& sameSrcAlias(p0, p1->pSelect->pSrc)
|
||||
if( p1->fg.isSubquery
|
||||
&& (p1->u4.pSubq->pSelect->selFlags & SF_NestedFrom)!=0
|
||||
&& sameSrcAlias(p0, p1->u4.pSubq->pSelect->pSrc)
|
||||
){
|
||||
return 1;
|
||||
}
|
||||
@@ -7290,7 +7331,7 @@ static int fromClauseTermCanBeCoroutine(
|
||||
if( i==0 ) break;
|
||||
i--;
|
||||
pItem--;
|
||||
if( pItem->pSelect!=0 ) return 0; /* (1c-i) */
|
||||
if( pItem->fg.isSubquery ) return 0; /* (1c-i) */
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
@@ -7401,7 +7442,7 @@ int sqlite3Select(
|
||||
if( sameSrcAlias(p0, p->pSrc) ){
|
||||
sqlite3ErrorMsg(pParse,
|
||||
"target object/alias may not appear in FROM clause: %s",
|
||||
p0->zAlias ? p0->zAlias : p0->pTab->zName
|
||||
p0->zAlias ? p0->zAlias : p0->pSTab->zName
|
||||
);
|
||||
goto select_end;
|
||||
}
|
||||
@@ -7440,8 +7481,8 @@ int sqlite3Select(
|
||||
#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
|
||||
for(i=0; !p->pPrior && i<pTabList->nSrc; i++){
|
||||
SrcItem *pItem = &pTabList->a[i];
|
||||
Select *pSub = pItem->pSelect;
|
||||
Table *pTab = pItem->pTab;
|
||||
Select *pSub = pItem->fg.isSubquery ? pItem->u4.pSubq->pSelect : 0;
|
||||
Table *pTab = pItem->pSTab;
|
||||
|
||||
/* The expander should have already created transient Table objects
|
||||
** even for FROM clause elements such as subqueries that do not correspond
|
||||
@@ -7659,6 +7700,7 @@ int sqlite3Select(
|
||||
SrcItem *pItem = &pTabList->a[i];
|
||||
SrcItem *pPrior;
|
||||
SelectDest dest;
|
||||
Subquery *pSubq;
|
||||
Select *pSub;
|
||||
#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
|
||||
const char *zSavedAuthContext;
|
||||
@@ -7681,17 +7723,29 @@ int sqlite3Select(
|
||||
** string for the fake column name seems safer.
|
||||
*/
|
||||
if( pItem->colUsed==0 && pItem->zName!=0 ){
|
||||
sqlite3AuthCheck(pParse, SQLITE_READ, pItem->zName, "", pItem->zDatabase);
|
||||
const char *zDb;
|
||||
if( pItem->fg.fixedSchema ){
|
||||
int iDb = sqlite3SchemaToIndex(pParse->db, pItem->u4.pSchema);
|
||||
zDb = db->aDb[iDb].zDbSName;
|
||||
}else if( pItem->fg.isSubquery ){
|
||||
zDb = 0;
|
||||
}else{
|
||||
zDb = pItem->u4.zDatabase;
|
||||
}
|
||||
sqlite3AuthCheck(pParse, SQLITE_READ, pItem->zName, "", zDb);
|
||||
}
|
||||
|
||||
#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 || pItem->addrFillSub!=0 ) continue;
|
||||
if( pItem->fg.isSubquery==0 ) continue;
|
||||
pSubq = pItem->u4.pSubq;
|
||||
assert( pSubq!=0 );
|
||||
pSub = pSubq->pSelect;
|
||||
if( pSubq->addrFillSub!=0 ) continue;
|
||||
|
||||
/* The code for a subquery should only be generated once. */
|
||||
assert( pItem->addrFillSub==0 );
|
||||
assert( pSubq->addrFillSub==0 );
|
||||
|
||||
/* Increment Parse.nHeight by the height of the largest expression
|
||||
** tree referred to by this, the parent select. The child select
|
||||
@@ -7717,7 +7771,7 @@ int sqlite3Select(
|
||||
sqlite3TreeViewSelect(0, p, 0);
|
||||
}
|
||||
#endif
|
||||
assert( pItem->pSelect && (pItem->pSelect->selFlags & SF_PushDown)!=0 );
|
||||
assert( pSubq->pSelect && (pSub->selFlags & SF_PushDown)!=0 );
|
||||
}else{
|
||||
TREETRACE(0x4000,pParse,p,("WHERE-lcause push-down not possible\n"));
|
||||
}
|
||||
@@ -7749,17 +7803,17 @@ int sqlite3Select(
|
||||
*/
|
||||
int addrTop = sqlite3VdbeCurrentAddr(v)+1;
|
||||
|
||||
pItem->regReturn = ++pParse->nMem;
|
||||
sqlite3VdbeAddOp3(v, OP_InitCoroutine, pItem->regReturn, 0, addrTop);
|
||||
pSubq->regReturn = ++pParse->nMem;
|
||||
sqlite3VdbeAddOp3(v, OP_InitCoroutine, pSubq->regReturn, 0, addrTop);
|
||||
VdbeComment((v, "%!S", pItem));
|
||||
pItem->addrFillSub = addrTop;
|
||||
sqlite3SelectDestInit(&dest, SRT_Coroutine, pItem->regReturn);
|
||||
pSubq->addrFillSub = addrTop;
|
||||
sqlite3SelectDestInit(&dest, SRT_Coroutine, pSubq->regReturn);
|
||||
ExplainQueryPlan((pParse, 1, "CO-ROUTINE %!S", pItem));
|
||||
sqlite3Select(pParse, pSub, &dest);
|
||||
pItem->pTab->nRowLogEst = pSub->nSelectRow;
|
||||
pItem->pSTab->nRowLogEst = pSub->nSelectRow;
|
||||
pItem->fg.viaCoroutine = 1;
|
||||
pItem->regResult = dest.iSdst;
|
||||
sqlite3VdbeEndCoroutine(v, pItem->regReturn);
|
||||
pSubq->regResult = dest.iSdst;
|
||||
sqlite3VdbeEndCoroutine(v, pSubq->regReturn);
|
||||
sqlite3VdbeJumpHere(v, addrTop-1);
|
||||
sqlite3ClearTempRegCache(pParse);
|
||||
}else if( pItem->fg.isCte && pItem->u2.pCteUse->addrM9e>0 ){
|
||||
@@ -7777,11 +7831,16 @@ int sqlite3Select(
|
||||
}else if( (pPrior = isSelfJoinView(pTabList, pItem, 0, i))!=0 ){
|
||||
/* This view has already been materialized by a prior entry in
|
||||
** this same FROM clause. Reuse it. */
|
||||
if( pPrior->addrFillSub ){
|
||||
sqlite3VdbeAddOp2(v, OP_Gosub, pPrior->regReturn, pPrior->addrFillSub);
|
||||
Subquery *pPriorSubq;
|
||||
assert( pPrior->fg.isSubquery );
|
||||
pPriorSubq = pPrior->u4.pSubq;
|
||||
assert( pPriorSubq!=0 );
|
||||
if( pPriorSubq->addrFillSub ){
|
||||
sqlite3VdbeAddOp2(v, OP_Gosub, pPriorSubq->regReturn,
|
||||
pPriorSubq->addrFillSub);
|
||||
}
|
||||
sqlite3VdbeAddOp2(v, OP_OpenDup, pItem->iCursor, pPrior->iCursor);
|
||||
pSub->nSelectRow = pPrior->pSelect->nSelectRow;
|
||||
pSub->nSelectRow = pPriorSubq->pSelect->nSelectRow;
|
||||
}else{
|
||||
/* Materialize the view. If the view is not correlated, generate a
|
||||
** subroutine to do the materialization so that subsequent uses of
|
||||
@@ -7792,9 +7851,9 @@ int sqlite3Select(
|
||||
int addrExplain;
|
||||
#endif
|
||||
|
||||
pItem->regReturn = ++pParse->nMem;
|
||||
pSubq->regReturn = ++pParse->nMem;
|
||||
topAddr = sqlite3VdbeAddOp0(v, OP_Goto);
|
||||
pItem->addrFillSub = topAddr+1;
|
||||
pSubq->addrFillSub = topAddr+1;
|
||||
pItem->fg.isMaterialized = 1;
|
||||
if( pItem->fg.isCorrelated==0 ){
|
||||
/* If the subquery is not correlated and if we are not inside of
|
||||
@@ -7809,17 +7868,17 @@ int sqlite3Select(
|
||||
|
||||
ExplainQueryPlan2(addrExplain, (pParse, 1, "MATERIALIZE %!S", pItem));
|
||||
sqlite3Select(pParse, pSub, &dest);
|
||||
pItem->pTab->nRowLogEst = pSub->nSelectRow;
|
||||
pItem->pSTab->nRowLogEst = pSub->nSelectRow;
|
||||
if( onceAddr ) sqlite3VdbeJumpHere(v, onceAddr);
|
||||
sqlite3VdbeAddOp2(v, OP_Return, pItem->regReturn, topAddr+1);
|
||||
sqlite3VdbeAddOp2(v, OP_Return, pSubq->regReturn, topAddr+1);
|
||||
VdbeComment((v, "end %!S", pItem));
|
||||
sqlite3VdbeScanStatusRange(v, addrExplain, addrExplain, -1);
|
||||
sqlite3VdbeJumpHere(v, topAddr);
|
||||
sqlite3ClearTempRegCache(pParse);
|
||||
if( pItem->fg.isCte && pItem->fg.isCorrelated==0 ){
|
||||
CteUse *pCteUse = pItem->u2.pCteUse;
|
||||
pCteUse->addrM9e = pItem->addrFillSub;
|
||||
pCteUse->regRtn = pItem->regReturn;
|
||||
pCteUse->addrM9e = pSubq->addrFillSub;
|
||||
pCteUse->regRtn = pSubq->regReturn;
|
||||
pCteUse->iCur = pItem->iCursor;
|
||||
pCteUse->nRowEst = pSub->nSelectRow;
|
||||
}
|
||||
|
||||
+53
-18
@@ -1335,6 +1335,7 @@ typedef struct Savepoint Savepoint;
|
||||
typedef struct Select Select;
|
||||
typedef struct SQLiteThread SQLiteThread;
|
||||
typedef struct SelectDest SelectDest;
|
||||
typedef struct Subquery Subquery;
|
||||
typedef struct SrcItem SrcItem;
|
||||
typedef struct SrcList SrcList;
|
||||
typedef struct sqlite3_str StrAccum; /* Internal alias for sqlite3_str */
|
||||
@@ -1927,6 +1928,7 @@ struct sqlite3 {
|
||||
#define SQLITE_Coroutines 0x02000000 /* Co-routines for subqueries */
|
||||
#define SQLITE_NullUnusedCols 0x04000000 /* NULL unused columns in subqueries */
|
||||
#define SQLITE_OnePass 0x08000000 /* Single-pass DELETE and UPDATE */
|
||||
#define SQLITE_OrderBySubq 0x10000000 /* ORDER BY in subquery helps outer */
|
||||
#define SQLITE_AllOpts 0xffffffff /* All optimizations */
|
||||
|
||||
/*
|
||||
@@ -3274,6 +3276,16 @@ struct IdList {
|
||||
#define EU4_IDX 1 /* Uses IdList.a.u4.idx */
|
||||
#define EU4_EXPR 2 /* Uses IdList.a.u4.pExpr -- NOT CURRENTLY USED */
|
||||
|
||||
/*
|
||||
** Details of the implementation of a subquery.
|
||||
*/
|
||||
struct Subquery {
|
||||
Select *pSelect; /* A SELECT statement used in place of a table name */
|
||||
int addrFillSub; /* Address of subroutine to initialize a subquery */
|
||||
int regReturn; /* Register holding return address of addrFillSub */
|
||||
int regResult; /* Registers holding results of a co-routine */
|
||||
};
|
||||
|
||||
/*
|
||||
** The SrcItem object represents a single term in the FROM clause of a query.
|
||||
** The SrcList object is mostly an array of SrcItems.
|
||||
@@ -3286,29 +3298,40 @@ struct IdList {
|
||||
** In the colUsed field, the high-order bit (bit 63) is set if the table
|
||||
** contains more than 63 columns and the 64-th or later column is used.
|
||||
**
|
||||
** Union member validity:
|
||||
** Aggressive use of "union" helps keep the size of the object small. This
|
||||
** has been shown to boost performance, in addition to saving memory.
|
||||
** Access to union elements is gated by the following rules which should
|
||||
** always be checked, either by an if-statement or by an assert().
|
||||
**
|
||||
** u1.zIndexedBy fg.isIndexedBy && !fg.isTabFunc
|
||||
** u1.pFuncArg fg.isTabFunc && !fg.isIndexedBy
|
||||
** Field Only access if this is true
|
||||
** --------------- -----------------------------------
|
||||
** u1.zIndexedBy fg.isIndexedBy
|
||||
** u1.pFuncArg fg.isTabFunc
|
||||
** u1.nRow !fg.isTabFunc && !fg.isIndexedBy
|
||||
**
|
||||
** u2.pIBIndex fg.isIndexedBy && !fg.isCte
|
||||
** u2.pCteUse fg.isCte && !fg.isIndexedBy
|
||||
** u2.pIBIndex fg.isIndexedBy
|
||||
** u2.pCteUse fg.isCte
|
||||
**
|
||||
** u3.pOn !fg.isUsing
|
||||
** u3.pUsing fg.isUsing
|
||||
**
|
||||
** u4.zDatabase !fg.fixedSchema && !fg.isSubquery
|
||||
** u4.pSchema fg.fixedSchema
|
||||
** u4.pSubq fg.isSubquery
|
||||
**
|
||||
** See also the sqlite3SrcListDelete() routine for assert() statements that
|
||||
** check invariants on the fields of this object, especially the flags
|
||||
** inside the fg struct.
|
||||
*/
|
||||
struct SrcItem {
|
||||
Schema *pSchema; /* Schema to which this item is fixed */
|
||||
char *zDatabase; /* Name of database holding this table */
|
||||
char *zName; /* Name of the table */
|
||||
char *zAlias; /* The "B" part of a "A AS B" phrase. zName is the "A" */
|
||||
Table *pTab; /* An SQL table corresponding to zName */
|
||||
Select *pSelect; /* A SELECT statement used in place of a table name */
|
||||
int addrFillSub; /* Address of subroutine to manifest a subquery */
|
||||
int regReturn; /* Register holding return address of addrFillSub */
|
||||
int regResult; /* Registers holding results of a co-routine */
|
||||
Table *pSTab; /* Table object for zName. Mnemonic: Srcitem-TABle */
|
||||
struct {
|
||||
u8 jointype; /* Type of join between this table and the previous */
|
||||
unsigned notIndexed :1; /* True if there is a NOT INDEXED clause */
|
||||
unsigned isIndexedBy :1; /* True if there is an INDEXED BY clause */
|
||||
unsigned isSubquery :1; /* True if this term is a subquery */
|
||||
unsigned isTabFunc :1; /* True if table-valued-function syntax */
|
||||
unsigned isCorrelated :1; /* True if sub-query is correlated */
|
||||
unsigned isMaterialized:1; /* This is a materialized view */
|
||||
@@ -3322,12 +3345,10 @@ struct SrcItem {
|
||||
unsigned isSynthUsing :1; /* u3.pUsing is synthesized from NATURAL */
|
||||
unsigned isNestedFrom :1; /* pSelect is a SF_NestedFrom subquery */
|
||||
unsigned rowidUsed :1; /* The ROWID of this table is referenced */
|
||||
unsigned fixedSchema :1; /* Uses u4.pSchema, not u4.zDatabase */
|
||||
unsigned hadSchema :1; /* Had u4.zDatabase before u4.pSchema */
|
||||
} fg;
|
||||
int iCursor; /* The VDBE cursor number used to access this table */
|
||||
union {
|
||||
Expr *pOn; /* fg.isUsing==0 => The ON clause of a join */
|
||||
IdList *pUsing; /* fg.isUsing==1 => The USING clause of a join */
|
||||
} u3;
|
||||
Bitmask colUsed; /* Bit N set if column N used. Details above for N>62 */
|
||||
union {
|
||||
char *zIndexedBy; /* Identifier from "INDEXED BY <zIndex>" clause */
|
||||
@@ -3338,6 +3359,15 @@ struct SrcItem {
|
||||
Index *pIBIndex; /* Index structure corresponding to u1.zIndexedBy */
|
||||
CteUse *pCteUse; /* CTE Usage info when fg.isCte is true */
|
||||
} u2;
|
||||
union {
|
||||
Expr *pOn; /* fg.isUsing==0 => The ON clause of a join */
|
||||
IdList *pUsing; /* fg.isUsing==1 => The USING clause of a join */
|
||||
} u3;
|
||||
union {
|
||||
Schema *pSchema; /* Schema to which this item is fixed */
|
||||
char *zDatabase; /* Name of database holding this table */
|
||||
Subquery *pSubq; /* Description of a subquery */
|
||||
} u4;
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -3597,8 +3627,10 @@ struct Select {
|
||||
#define SF_UpdateFrom 0x10000000 /* Query originates with UPDATE FROM */
|
||||
#define SF_Correlated 0x20000000 /* True if references the outer context */
|
||||
|
||||
/* True if S exists and has SF_NestedFrom */
|
||||
#define IsNestedFrom(S) ((S)!=0 && ((S)->selFlags&SF_NestedFrom)!=0)
|
||||
/* True if SrcItem X is a subquery that has SF_NestedFrom */
|
||||
#define IsNestedFrom(X) \
|
||||
((X)->fg.isSubquery && \
|
||||
((X)->u4.pSubq->pSelect->selFlags&SF_NestedFrom)!=0)
|
||||
|
||||
/*
|
||||
** The results of a SELECT can be distributed in several ways, as defined
|
||||
@@ -4990,6 +5022,9 @@ int sqlite3IdListIndex(IdList*,const char*);
|
||||
SrcList *sqlite3SrcListEnlarge(Parse*, SrcList*, int, int);
|
||||
SrcList *sqlite3SrcListAppendList(Parse *pParse, SrcList *p1, SrcList *p2);
|
||||
SrcList *sqlite3SrcListAppend(Parse*, SrcList*, Token*, Token*);
|
||||
void sqlite3SubqueryDelete(sqlite3*,Subquery*);
|
||||
Select *sqlite3SubqueryDetach(sqlite3*,SrcItem*);
|
||||
int sqlite3SrcItemAttachSubquery(Parse*, SrcItem*, Select*, int);
|
||||
SrcList *sqlite3SrcListAppendFromTerm(Parse*, SrcList*, Token*, Token*,
|
||||
Token*, Select*, OnOrUsing*);
|
||||
void sqlite3SrcListIndexedBy(Parse *, SrcList *, Token *);
|
||||
|
||||
+8
-7
@@ -8100,6 +8100,7 @@ static int SQLITE_TCLAPI optimization_control(
|
||||
{ "distinct-opt", SQLITE_DistinctOpt },
|
||||
{ "cover-idx-scan", SQLITE_CoverIdxScan },
|
||||
{ "order-by-idx-join", SQLITE_OrderByIdxJoin },
|
||||
{ "order-by-subquery", SQLITE_OrderBySubq },
|
||||
{ "transitive", SQLITE_Transitive },
|
||||
{ "omit-noop-join", SQLITE_OmitNoopJoin },
|
||||
{ "stat4", SQLITE_Stat4 },
|
||||
@@ -8324,7 +8325,7 @@ static int SQLITE_TCLAPI sorter_test_sort4_helper(
|
||||
for(iStep=0; iStep<nStep && SQLITE_ROW==sqlite3_step(pStmt); iStep++){
|
||||
int a = sqlite3_column_int(pStmt, 0);
|
||||
if( a!=sqlite3_column_int(pStmt, iB) ){
|
||||
Tcl_AppendResult(interp, "data error: (a!=b)", 0);
|
||||
Tcl_AppendResult(interp, "data error: (a!=b)", (void*)0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
@@ -8343,13 +8344,13 @@ static int SQLITE_TCLAPI sorter_test_sort4_helper(
|
||||
if( rc!=SQLITE_OK ) goto sql_error;
|
||||
|
||||
if( iCksum1!=iCksum2 ){
|
||||
Tcl_AppendResult(interp, "checksum mismatch", 0);
|
||||
Tcl_AppendResult(interp, "checksum mismatch", (void*)0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
return TCL_OK;
|
||||
sql_error:
|
||||
Tcl_AppendResult(interp, "sql error: ", sqlite3_errmsg(db), 0);
|
||||
Tcl_AppendResult(interp, "sql error: ", sqlite3_errmsg(db), (void*)0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
@@ -8398,7 +8399,7 @@ static int SQLITE_TCLAPI test_user_add(
|
||||
){
|
||||
char *zUser = 0;
|
||||
char *zPasswd = 0;
|
||||
int nPasswd = 0;
|
||||
Tcl_Size nPasswd = 0;
|
||||
int isAdmin = 0;
|
||||
sqlite3 *db;
|
||||
int rc;
|
||||
@@ -8413,7 +8414,7 @@ static int SQLITE_TCLAPI test_user_add(
|
||||
zUser = Tcl_GetString(objv[2]);
|
||||
zPasswd = Tcl_GetStringFromObj(objv[3], &nPasswd);
|
||||
Tcl_GetBooleanFromObj(interp, objv[4], &isAdmin);
|
||||
rc = sqlite3_user_add(db, zUser, zPasswd, nPasswd, isAdmin);
|
||||
rc = sqlite3_user_add(db, zUser, zPasswd, (int)nPasswd, isAdmin);
|
||||
Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC);
|
||||
return TCL_OK;
|
||||
}
|
||||
@@ -8431,7 +8432,7 @@ static int SQLITE_TCLAPI test_user_change(
|
||||
){
|
||||
char *zUser = 0;
|
||||
char *zPasswd = 0;
|
||||
int nPasswd = 0;
|
||||
Tcl_Size nPasswd = 0;
|
||||
int isAdmin = 0;
|
||||
sqlite3 *db;
|
||||
int rc;
|
||||
@@ -8446,7 +8447,7 @@ static int SQLITE_TCLAPI test_user_change(
|
||||
zUser = Tcl_GetString(objv[2]);
|
||||
zPasswd = Tcl_GetStringFromObj(objv[3], &nPasswd);
|
||||
Tcl_GetBooleanFromObj(interp, objv[4], &isAdmin);
|
||||
rc = sqlite3_user_change(db, zUser, zPasswd, nPasswd, isAdmin);
|
||||
rc = sqlite3_user_change(db, zUser, zPasswd, (int)nPasswd, isAdmin);
|
||||
Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC);
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
+1
-1
@@ -401,7 +401,7 @@ static int SQLITE_TCLAPI make_fts3record(
|
||||
}
|
||||
|
||||
for(i=0; i<(int)nArg; i++){
|
||||
sqlite3_int64 iVal;
|
||||
Tcl_WideInt iVal;
|
||||
if( TCL_OK==Tcl_GetWideIntFromObj(0, aArg[i], &iVal) ){
|
||||
if( nOut+10>nAlloc ){
|
||||
int nNew = nAlloc?nAlloc*2:128;
|
||||
|
||||
+4
-4
@@ -68,8 +68,8 @@ struct tclvar_cursor {
|
||||
|
||||
Tcl_Obj *pList1; /* Result of [info vars ?pattern?] */
|
||||
Tcl_Obj *pList2; /* Result of [array names [lindex $pList1 $i1]] */
|
||||
int i1; /* Current item in pList1 */
|
||||
int i2; /* Current item (if any) in pList2 */
|
||||
Tcl_Size i1; /* Current item in pList1 */
|
||||
Tcl_Size i2; /* Current item (if any) in pList2 */
|
||||
};
|
||||
|
||||
/* Methods for the tclvar module */
|
||||
@@ -149,7 +149,7 @@ static int next2(Tcl_Interp *interp, tclvar_cursor *pCur, Tcl_Obj *pObj){
|
||||
Tcl_Size n = 0;
|
||||
pCur->i2++;
|
||||
Tcl_ListObjLength(0, pCur->pList2, &n);
|
||||
if( pCur->i2>=(int)n ){
|
||||
if( pCur->i2>=n ){
|
||||
Tcl_DecrRefCount(pCur->pList2);
|
||||
pCur->pList2 = 0;
|
||||
pCur->i2 = 0;
|
||||
@@ -170,7 +170,7 @@ static int tclvarNext(sqlite3_vtab_cursor *cur){
|
||||
Tcl_Interp *interp = ((tclvar_vtab *)(cur->pVtab))->interp;
|
||||
|
||||
Tcl_ListObjLength(0, pCur->pList1, &n);
|
||||
while( !ok && pCur->i1<(int)n ){
|
||||
while( !ok && pCur->i1<n ){
|
||||
Tcl_ListObjIndex(0, pCur->pList1, pCur->i1, &pObj);
|
||||
ok = next2(interp, pCur, pObj);
|
||||
if( !ok ){
|
||||
|
||||
+8
-8
@@ -193,9 +193,9 @@ void sqlite3TreeViewSrcList(TreeView *pView, const SrcList *pSrc){
|
||||
sqlite3StrAccumInit(&x, 0, zLine, sizeof(zLine), 0);
|
||||
x.printfFlags |= SQLITE_PRINTF_INTERNAL;
|
||||
sqlite3_str_appendf(&x, "{%d:*} %!S", pItem->iCursor, pItem);
|
||||
if( pItem->pTab ){
|
||||
if( pItem->pSTab ){
|
||||
sqlite3_str_appendf(&x, " tab=%Q nCol=%d ptr=%p used=%llx%s",
|
||||
pItem->pTab->zName, pItem->pTab->nCol, pItem->pTab,
|
||||
pItem->pSTab->zName, pItem->pSTab->nCol, pItem->pSTab,
|
||||
pItem->colUsed,
|
||||
pItem->fg.rowidUsed ? "+rowid" : "");
|
||||
}
|
||||
@@ -230,19 +230,19 @@ void sqlite3TreeViewSrcList(TreeView *pView, const SrcList *pSrc){
|
||||
sqlite3StrAccumFinish(&x);
|
||||
sqlite3TreeViewItem(pView, zLine, i<pSrc->nSrc-1);
|
||||
n = 0;
|
||||
if( pItem->pSelect ) n++;
|
||||
if( pItem->fg.isSubquery ) n++;
|
||||
if( pItem->fg.isTabFunc ) n++;
|
||||
if( pItem->fg.isUsing ) n++;
|
||||
if( pItem->fg.isUsing ){
|
||||
sqlite3TreeViewIdList(pView, pItem->u3.pUsing, (--n)>0, "USING");
|
||||
}
|
||||
if( pItem->pSelect ){
|
||||
if( pItem->pTab ){
|
||||
Table *pTab = pItem->pTab;
|
||||
if( pItem->fg.isSubquery ){
|
||||
if( pItem->pSTab ){
|
||||
Table *pTab = pItem->pSTab;
|
||||
sqlite3TreeViewColumnList(pView, pTab->aCol, pTab->nCol, 1);
|
||||
}
|
||||
assert( (int)pItem->fg.isNestedFrom == IsNestedFrom(pItem->pSelect) );
|
||||
sqlite3TreeViewSelect(pView, pItem->pSelect, (--n)>0);
|
||||
assert( (int)pItem->fg.isNestedFrom == IsNestedFrom(pItem) );
|
||||
sqlite3TreeViewSelect(pView, pItem->u4.pSubq->pSelect, (--n)>0);
|
||||
}
|
||||
if( pItem->fg.isTabFunc ){
|
||||
sqlite3TreeViewExprList(pView, pItem->u1.pFuncArg, 0, "func-args:");
|
||||
|
||||
+11
-6
@@ -152,8 +152,10 @@ void sqlite3BeginTrigger(
|
||||
** name on pTableName if we are reparsing out of the schema table
|
||||
*/
|
||||
if( db->init.busy && iDb!=1 ){
|
||||
sqlite3DbFree(db, pTableName->a[0].zDatabase);
|
||||
pTableName->a[0].zDatabase = 0;
|
||||
assert( pTableName->a[0].fg.fixedSchema==0 );
|
||||
assert( pTableName->a[0].fg.isSubquery==0 );
|
||||
sqlite3DbFree(db, pTableName->a[0].u4.zDatabase);
|
||||
pTableName->a[0].u4.zDatabase = 0;
|
||||
}
|
||||
|
||||
/* If the trigger name was unqualified, and the table is a temp table,
|
||||
@@ -631,7 +633,8 @@ void sqlite3DropTrigger(Parse *pParse, SrcList *pName, int noErr){
|
||||
}
|
||||
|
||||
assert( pName->nSrc==1 );
|
||||
zDb = pName->a[0].zDatabase;
|
||||
assert( pName->a[0].fg.fixedSchema==0 && pName->a[0].fg.isSubquery==0 );
|
||||
zDb = pName->a[0].u4.zDatabase;
|
||||
zName = pName->a[0].zName;
|
||||
assert( zDb!=0 || sqlite3BtreeHoldsAllMutexes(db) );
|
||||
for(i=OMIT_TEMPDB; i<db->nDb; i++){
|
||||
@@ -868,7 +871,9 @@ SrcList *sqlite3TriggerStepSrc(
|
||||
Schema *pSchema = pStep->pTrig->pSchema;
|
||||
pSrc->a[0].zName = zName;
|
||||
if( pSchema!=db->aDb[1].pSchema ){
|
||||
pSrc->a[0].pSchema = pSchema;
|
||||
assert( pSrc->a[0].fg.fixedSchema || pSrc->a[0].u4.zDatabase==0 );
|
||||
pSrc->a[0].u4.pSchema = pSchema;
|
||||
pSrc->a[0].fg.fixedSchema = 1;
|
||||
}
|
||||
if( pStep->pFrom ){
|
||||
SrcList *pDup = sqlite3SrcListDup(db, pStep->pFrom, 0);
|
||||
@@ -981,7 +986,7 @@ static int sqlite3ReturningSubqueryCorrelated(Walker *pWalker, Select *pSelect){
|
||||
pSrc = pSelect->pSrc;
|
||||
assert( pSrc!=0 );
|
||||
for(i=0; i<pSrc->nSrc; i++){
|
||||
if( pSrc->a[i].pTab==pWalker->u.pTab ){
|
||||
if( pSrc->a[i].pSTab==pWalker->u.pTab ){
|
||||
testcase( pSelect->selFlags & SF_Correlated );
|
||||
pSelect->selFlags |= SF_Correlated;
|
||||
pWalker->eCode = 1;
|
||||
@@ -1052,7 +1057,7 @@ static void codeReturningTrigger(
|
||||
sSelect.pEList = sqlite3ExprListDup(db, pReturning->pReturnEL, 0);
|
||||
sSelect.pSrc = &sFrom;
|
||||
sFrom.nSrc = 1;
|
||||
sFrom.a[0].pTab = pTab;
|
||||
sFrom.a[0].pSTab = pTab;
|
||||
sFrom.a[0].zName = pTab->zName; /* tag-20240424-1 */
|
||||
sFrom.a[0].iCursor = -1;
|
||||
sqlite3SelectPrep(pParse, &sSelect, 0);
|
||||
|
||||
+3
-3
@@ -202,7 +202,7 @@ static void updateFromSelect(
|
||||
Expr *pLimit2 = 0;
|
||||
ExprList *pOrderBy2 = 0;
|
||||
sqlite3 *db = pParse->db;
|
||||
Table *pTab = pTabList->a[0].pTab;
|
||||
Table *pTab = pTabList->a[0].pSTab;
|
||||
SrcList *pSrc;
|
||||
Expr *pWhere2;
|
||||
int eDest;
|
||||
@@ -226,8 +226,8 @@ static void updateFromSelect(
|
||||
if( pSrc ){
|
||||
assert( pSrc->a[0].fg.notCte );
|
||||
pSrc->a[0].iCursor = -1;
|
||||
pSrc->a[0].pTab->nTabRef--;
|
||||
pSrc->a[0].pTab = 0;
|
||||
pSrc->a[0].pSTab->nTabRef--;
|
||||
pSrc->a[0].pSTab = 0;
|
||||
}
|
||||
if( pPk ){
|
||||
for(i=0; i<pPk->nKeyCol; i++){
|
||||
|
||||
+2
-2
@@ -104,7 +104,7 @@ int sqlite3UpsertAnalyzeTarget(
|
||||
int nClause = 0; /* Counter of ON CONFLICT clauses */
|
||||
|
||||
assert( pTabList->nSrc==1 );
|
||||
assert( pTabList->a[0].pTab!=0 );
|
||||
assert( pTabList->a[0].pSTab!=0 );
|
||||
assert( pUpsert!=0 );
|
||||
assert( pUpsert->pUpsertTarget!=0 );
|
||||
|
||||
@@ -123,7 +123,7 @@ int sqlite3UpsertAnalyzeTarget(
|
||||
if( rc ) return rc;
|
||||
|
||||
/* Check to see if the conflict target matches the rowid. */
|
||||
pTab = pTabList->a[0].pTab;
|
||||
pTab = pTabList->a[0].pSTab;
|
||||
pTarget = pUpsert->pUpsertTarget;
|
||||
iCursor = pTabList->a[0].iCursor;
|
||||
if( HasRowid(pTab)
|
||||
|
||||
+1
-1
@@ -2096,7 +2096,7 @@ case OP_RealAffinity: { /* in1 */
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(SQLITE_OMIT_CAST) && !defined(SQLITE_OMIT_ANALYZE)
|
||||
#if !defined(SQLITE_OMIT_CAST) || !defined(SQLITE_OMIT_ANALYZE)
|
||||
/* Opcode: Cast P1 P2 * * *
|
||||
** Synopsis: affinity(r[P1])
|
||||
**
|
||||
|
||||
+3
-1
@@ -171,7 +171,9 @@ int sqlite3WalkSelectFrom(Walker *pWalker, Select *p){
|
||||
pSrc = p->pSrc;
|
||||
if( ALWAYS(pSrc) ){
|
||||
for(i=pSrc->nSrc, pItem=pSrc->a; i>0; i--, pItem++){
|
||||
if( pItem->pSelect && sqlite3WalkSelect(pWalker, pItem->pSelect) ){
|
||||
if( pItem->fg.isSubquery
|
||||
&& sqlite3WalkSelect(pWalker, pItem->u4.pSubq->pSelect)
|
||||
){
|
||||
return WRC_Abort;
|
||||
}
|
||||
if( pItem->fg.isTabFunc
|
||||
|
||||
+169
-78
@@ -644,7 +644,7 @@ static int isDistinctRedundant(
|
||||
** clause is redundant. */
|
||||
if( pTabList->nSrc!=1 ) return 0;
|
||||
iBase = pTabList->a[0].iCursor;
|
||||
pTab = pTabList->a[0].pTab;
|
||||
pTab = pTabList->a[0].pSTab;
|
||||
|
||||
/* If any of the expressions is an IPK column on table iBase, then return
|
||||
** true. Note: The (p->iTable==iBase) part of this test may be false if the
|
||||
@@ -908,10 +908,10 @@ static int termCanDriveIndex(
|
||||
assert( (pTerm->eOperator & (WO_OR|WO_AND))==0 );
|
||||
leftCol = pTerm->u.x.leftColumn;
|
||||
if( leftCol<0 ) return 0;
|
||||
aff = pSrc->pTab->aCol[leftCol].affinity;
|
||||
aff = pSrc->pSTab->aCol[leftCol].affinity;
|
||||
if( !sqlite3IndexAffinityOk(pTerm->pExpr, aff) ) return 0;
|
||||
testcase( pTerm->pExpr->op==TK_IS );
|
||||
return columnIsGoodIndexCandidate(pSrc->pTab, leftCol);
|
||||
return columnIsGoodIndexCandidate(pSrc->pSTab, leftCol);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1019,7 +1019,7 @@ static SQLITE_NOINLINE void constructAutomaticIndex(
|
||||
nKeyCol = 0;
|
||||
pTabList = pWC->pWInfo->pTabList;
|
||||
pSrc = &pTabList->a[pLevel->iFrom];
|
||||
pTable = pSrc->pTab;
|
||||
pTable = pSrc->pSTab;
|
||||
pWCEnd = &pWC->a[pWC->nTerm];
|
||||
pLoop = pLevel->pWLoop;
|
||||
idxCols = 0;
|
||||
@@ -1161,12 +1161,17 @@ static SQLITE_NOINLINE void constructAutomaticIndex(
|
||||
/* Fill the automatic index with content */
|
||||
assert( pSrc == &pWC->pWInfo->pTabList->a[pLevel->iFrom] );
|
||||
if( pSrc->fg.viaCoroutine ){
|
||||
int regYield = pSrc->regReturn;
|
||||
int regYield;
|
||||
Subquery *pSubq;
|
||||
assert( pSrc->fg.isSubquery );
|
||||
pSubq = pSrc->u4.pSubq;
|
||||
assert( pSubq!=0 );
|
||||
regYield = pSubq->regReturn;
|
||||
addrCounter = sqlite3VdbeAddOp2(v, OP_Integer, 0, 0);
|
||||
sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, pSrc->addrFillSub);
|
||||
sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, pSubq->addrFillSub);
|
||||
addrTop = sqlite3VdbeAddOp1(v, OP_Yield, regYield);
|
||||
VdbeCoverage(v);
|
||||
VdbeComment((v, "next row of %s", pSrc->pTab->zName));
|
||||
VdbeComment((v, "next row of %s", pSrc->pSTab->zName));
|
||||
}else{
|
||||
addrTop = sqlite3VdbeAddOp1(v, OP_Rewind, pLevel->iTabCur); VdbeCoverage(v);
|
||||
}
|
||||
@@ -1188,11 +1193,12 @@ static SQLITE_NOINLINE void constructAutomaticIndex(
|
||||
sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT);
|
||||
if( pPartial ) sqlite3VdbeResolveLabel(v, iContinue);
|
||||
if( pSrc->fg.viaCoroutine ){
|
||||
assert( pSrc->fg.isSubquery && pSrc->u4.pSubq!=0 );
|
||||
sqlite3VdbeChangeP2(v, addrCounter, regBase+n);
|
||||
testcase( pParse->db->mallocFailed );
|
||||
assert( pLevel->iIdxCur>0 );
|
||||
translateColumnToCopy(pParse, addrTop, pLevel->iTabCur,
|
||||
pSrc->regResult, pLevel->iIdxCur);
|
||||
pSrc->u4.pSubq->regResult, pLevel->iIdxCur);
|
||||
sqlite3VdbeGoto(v, addrTop);
|
||||
pSrc->fg.viaCoroutine = 0;
|
||||
}else{
|
||||
@@ -1283,7 +1289,7 @@ static SQLITE_NOINLINE void sqlite3ConstructBloomFilter(
|
||||
iSrc = pLevel->iFrom;
|
||||
pItem = &pTabList->a[iSrc];
|
||||
assert( pItem!=0 );
|
||||
pTab = pItem->pTab;
|
||||
pTab = pItem->pSTab;
|
||||
assert( pTab!=0 );
|
||||
sz = sqlite3LogEstToInt(pTab->nRowLogEst);
|
||||
if( sz<10000 ){
|
||||
@@ -1314,7 +1320,7 @@ static SQLITE_NOINLINE void sqlite3ConstructBloomFilter(
|
||||
int r1 = sqlite3GetTempRange(pParse, n);
|
||||
int jj;
|
||||
for(jj=0; jj<n; jj++){
|
||||
assert( pIdx->pTable==pItem->pTab );
|
||||
assert( pIdx->pTable==pItem->pSTab );
|
||||
sqlite3ExprCodeLoadIndexColumn(pParse, pIdx, iCur, jj, r1+jj);
|
||||
}
|
||||
sqlite3VdbeAddOp4Int(v, OP_FilterAdd, pLevel->regFilter, 0, r1, n);
|
||||
@@ -1395,7 +1401,7 @@ static sqlite3_index_info *allocateIndexInfo(
|
||||
WhereClause *p;
|
||||
|
||||
assert( pSrc!=0 );
|
||||
pTab = pSrc->pTab;
|
||||
pTab = pSrc->pSTab;
|
||||
assert( pTab!=0 );
|
||||
assert( IsVirtual(pTab) );
|
||||
|
||||
@@ -2403,7 +2409,7 @@ void sqlite3WhereLoopPrint(const WhereLoop *p, const WhereClause *pWC){
|
||||
WhereInfo *pWInfo = pWC->pWInfo;
|
||||
int nb = 1+(pWInfo->pTabList->nSrc+3)/4;
|
||||
SrcItem *pItem = pWInfo->pTabList->a + p->iTab;
|
||||
Table *pTab = pItem->pTab;
|
||||
Table *pTab = pItem->pSTab;
|
||||
Bitmask mAll = (((Bitmask)1)<<(nb*4)) - 1;
|
||||
sqlite3DebugPrintf("%c%2d.%0*llx.%0*llx", p->cId,
|
||||
p->iTab, nb, p->maskSelf, nb, p->prereq & mAll);
|
||||
@@ -3391,7 +3397,7 @@ static int whereLoopAddBtreeIndex(
|
||||
** 2. Stepping forward in the index pNew->nOut times to find all
|
||||
** additional matching entries.
|
||||
*/
|
||||
assert( pSrc->pTab->szTabRow>0 );
|
||||
assert( pSrc->pSTab->szTabRow>0 );
|
||||
if( pProbe->idxType==SQLITE_IDXTYPE_IPK ){
|
||||
/* The pProbe->szIdxRow is low for an IPK table since the interior
|
||||
** pages are small. Thus szIdxRow gives a good estimate of seek cost.
|
||||
@@ -3399,7 +3405,7 @@ static int whereLoopAddBtreeIndex(
|
||||
** under-estimate the scanning cost. */
|
||||
rCostIdx = pNew->nOut + 16;
|
||||
}else{
|
||||
rCostIdx = pNew->nOut + 1 + (15*pProbe->szIdxRow)/pSrc->pTab->szTabRow;
|
||||
rCostIdx = pNew->nOut + 1 + (15*pProbe->szIdxRow)/pSrc->pSTab->szTabRow;
|
||||
}
|
||||
rCostIdx = sqlite3LogEstAdd(rLogSize, rCostIdx);
|
||||
|
||||
@@ -3864,9 +3870,9 @@ static int whereLoopAddBtree(
|
||||
pWInfo = pBuilder->pWInfo;
|
||||
pTabList = pWInfo->pTabList;
|
||||
pSrc = pTabList->a + pNew->iTab;
|
||||
pTab = pSrc->pTab;
|
||||
pTab = pSrc->pSTab;
|
||||
pWC = pBuilder->pWC;
|
||||
assert( !IsVirtual(pSrc->pTab) );
|
||||
assert( !IsVirtual(pSrc->pSTab) );
|
||||
|
||||
if( pSrc->fg.isIndexedBy ){
|
||||
assert( pSrc->fg.isCte==0 );
|
||||
@@ -3891,7 +3897,7 @@ static int whereLoopAddBtree(
|
||||
sPk.idxType = SQLITE_IDXTYPE_IPK;
|
||||
aiRowEstPk[0] = pTab->nRowLogEst;
|
||||
aiRowEstPk[1] = 0;
|
||||
pFirst = pSrc->pTab->pIndex;
|
||||
pFirst = pSrc->pSTab->pIndex;
|
||||
if( pSrc->fg.notIndexed==0 ){
|
||||
/* The real indices of the table are only considered if the
|
||||
** NOT INDEXED qualifier is omitted from the FROM clause */
|
||||
@@ -4010,6 +4016,10 @@ static int whereLoopAddBtree(
|
||||
#endif
|
||||
ApplyCostMultiplier(pNew->rRun, pTab->costMult);
|
||||
whereLoopOutputAdjust(pWC, pNew, rSize);
|
||||
if( pSrc->fg.isSubquery ){
|
||||
if( pSrc->fg.viaCoroutine ) pNew->wsFlags |= WHERE_COROUTINE;
|
||||
pNew->u.btree.pOrderBy = pSrc->u4.pSubq->pSelect->pOrderBy;
|
||||
}
|
||||
rc = whereLoopInsert(pBuilder, pNew);
|
||||
pNew->nOut = rSize;
|
||||
if( rc ) break;
|
||||
@@ -4047,7 +4057,9 @@ static int whereLoopAddBtree(
|
||||
" according to whereIsCoveringIndex()\n", pProbe->zName));
|
||||
}
|
||||
}
|
||||
}else if( m==0 ){
|
||||
}else if( m==0
|
||||
&& (HasRowid(pTab) || pWInfo->pSelect!=0 || sqlite3FaultSim(700))
|
||||
){
|
||||
WHERETRACE(0x200,
|
||||
("-> %s a covering index according to bitmasks\n",
|
||||
pProbe->zName, m==0 ? "is" : "is not"));
|
||||
@@ -4232,7 +4244,7 @@ static int whereLoopAddVirtualOne(
|
||||
pHidden->mHandleIn = 0;
|
||||
|
||||
/* Invoke the virtual table xBestIndex() method */
|
||||
rc = vtabBestIndex(pParse, pSrc->pTab, pIdxInfo);
|
||||
rc = vtabBestIndex(pParse, pSrc->pSTab, pIdxInfo);
|
||||
if( rc ){
|
||||
if( rc==SQLITE_CONSTRAINT ){
|
||||
/* If the xBestIndex method returns SQLITE_CONSTRAINT, that means
|
||||
@@ -4262,7 +4274,7 @@ static int whereLoopAddVirtualOne(
|
||||
|| pNew->aLTerm[iTerm]!=0
|
||||
|| pIdxCons->usable==0
|
||||
){
|
||||
sqlite3ErrorMsg(pParse,"%s.xBestIndex malfunction",pSrc->pTab->zName);
|
||||
sqlite3ErrorMsg(pParse,"%s.xBestIndex malfunction",pSrc->pSTab->zName);
|
||||
freeIdxStr(pIdxInfo);
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
@@ -4325,7 +4337,7 @@ static int whereLoopAddVirtualOne(
|
||||
if( pNew->aLTerm[i]==0 ){
|
||||
/* The non-zero argvIdx values must be contiguous. Raise an
|
||||
** error if they are not */
|
||||
sqlite3ErrorMsg(pParse,"%s.xBestIndex malfunction",pSrc->pTab->zName);
|
||||
sqlite3ErrorMsg(pParse,"%s.xBestIndex malfunction",pSrc->pSTab->zName);
|
||||
freeIdxStr(pIdxInfo);
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
@@ -4527,7 +4539,7 @@ static int whereLoopAddVirtual(
|
||||
pWC = pBuilder->pWC;
|
||||
pNew = pBuilder->pNew;
|
||||
pSrc = &pWInfo->pTabList->a[pNew->iTab];
|
||||
assert( IsVirtual(pSrc->pTab) );
|
||||
assert( IsVirtual(pSrc->pSTab) );
|
||||
p = allocateIndexInfo(pWInfo, pWC, mUnusable, pSrc, &mNoOmit);
|
||||
if( p==0 ) return SQLITE_NOMEM_BKPT;
|
||||
pNew->rSetup = 0;
|
||||
@@ -4541,7 +4553,7 @@ static int whereLoopAddVirtual(
|
||||
}
|
||||
|
||||
/* First call xBestIndex() with all constraints usable. */
|
||||
WHERETRACE(0x800, ("BEGIN %s.addVirtual()\n", pSrc->pTab->zName));
|
||||
WHERETRACE(0x800, ("BEGIN %s.addVirtual()\n", pSrc->pSTab->zName));
|
||||
WHERETRACE(0x800, (" VirtualOne: all usable\n"));
|
||||
rc = whereLoopAddVirtualOne(
|
||||
pBuilder, mPrereq, ALLBITS, 0, p, mNoOmit, &bIn, &bRetry
|
||||
@@ -4623,7 +4635,7 @@ static int whereLoopAddVirtual(
|
||||
}
|
||||
|
||||
freeIndexInfo(pParse->db, p);
|
||||
WHERETRACE(0x800, ("END %s.addVirtual(), rc=%d\n", pSrc->pTab->zName, rc));
|
||||
WHERETRACE(0x800, ("END %s.addVirtual(), rc=%d\n", pSrc->pSTab->zName, rc));
|
||||
return rc;
|
||||
}
|
||||
#endif /* SQLITE_OMIT_VIRTUALTABLE */
|
||||
@@ -4695,7 +4707,7 @@ static int whereLoopAddOr(
|
||||
}
|
||||
#endif
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
if( IsVirtual(pItem->pTab) ){
|
||||
if( IsVirtual(pItem->pSTab) ){
|
||||
rc = whereLoopAddVirtual(&sSubBuild, mPrereq, mUnusable);
|
||||
}else
|
||||
#endif
|
||||
@@ -4809,7 +4821,7 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){
|
||||
mPrereq = 0;
|
||||
}
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
if( IsVirtual(pItem->pTab) ){
|
||||
if( IsVirtual(pItem->pSTab) ){
|
||||
SrcItem *p;
|
||||
for(p=&pItem[1]; p<pEnd; p++){
|
||||
if( mUnusable || (p->fg.jointype & (JT_OUTER|JT_CROSS)) ){
|
||||
@@ -4841,6 +4853,97 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Implementation of the order-by-subquery optimization:
|
||||
**
|
||||
** WhereLoop pLoop, which the iLoop-th term of the nested loop, is really
|
||||
** a subquery or CTE that has an ORDER BY clause. See if any of the terms
|
||||
** in the subquery ORDER BY clause will satisfy pOrderBy from the outer
|
||||
** query. Mark off all satisfied terms (by setting bits in *pOBSat) and
|
||||
** return TRUE if they do. If not, return false.
|
||||
**
|
||||
** Example:
|
||||
**
|
||||
** CREATE TABLE t1(a,b,c, PRIMARY KEY(a,b));
|
||||
** CREATE TABLE t2(x,y);
|
||||
** WITH t3(p,q) AS MATERIALIZED (SELECT x+y, x-y FROM t2 ORDER BY x+y)
|
||||
** SELECT * FROM t3 JOIN t1 ON a=q ORDER BY p, b;
|
||||
**
|
||||
** The CTE named "t3" comes out in the natural order of "p", so the first
|
||||
** first them of "ORDER BY p,b" is satisfied by a sequential scan of "t3"
|
||||
** and sorting only needs to occur on the second term "b".
|
||||
**
|
||||
** Limitations:
|
||||
**
|
||||
** (1) The optimization is not applied if the outer ORDER BY contains
|
||||
** a COLLATE clause. The optimization might be applied if the
|
||||
** outer ORDER BY uses NULLS FIRST, NULLS LAST, ASC, and/or DESC as
|
||||
** long as the subquery ORDER BY does the same. But if the
|
||||
** outer ORDER BY uses COLLATE, even a redundant COLLATE, the
|
||||
** optimization is bypassed.
|
||||
**
|
||||
** (2) The subquery ORDER BY terms must exactly match subquery result
|
||||
** columns, including any COLLATE annotations. This routine relies
|
||||
** on iOrderByCol to do matching between order by terms and result
|
||||
** columns, and iOrderByCol will not be set if the result column
|
||||
** and ORDER BY collations differ.
|
||||
**
|
||||
** (3) The subquery and outer ORDER BY can be in opposite directions as
|
||||
** long as the subquery is materialized. If the subquery is
|
||||
** implemented as a co-routine, the sort orders must be in the same
|
||||
** direction because there is no way to run a co-routine backwards.
|
||||
*/
|
||||
static SQLITE_NOINLINE int wherePathMatchSubqueryOB(
|
||||
WhereInfo *pWInfo, /* The WHERE clause */
|
||||
WhereLoop *pLoop, /* The nested loop term that is a subquery */
|
||||
int iLoop, /* Which level of the nested loop. 0==outermost */
|
||||
int iCur, /* Cursor used by the this loop */
|
||||
ExprList *pOrderBy, /* The ORDER BY clause on the whole query */
|
||||
Bitmask *pRevMask, /* When loops need to go in reverse order */
|
||||
Bitmask *pOBSat /* Which terms of pOrderBy are satisfied so far */
|
||||
){
|
||||
int iOB; /* Index into pOrderBy->a[] */
|
||||
int jSub; /* Index into pSubOB->a[] */
|
||||
u8 rev = 0; /* True if iOB and jSub sort in opposite directions */
|
||||
u8 revIdx = 0; /* Sort direction for jSub */
|
||||
Expr *pOBExpr; /* Current term of outer ORDER BY */
|
||||
ExprList *pSubOB; /* Complete ORDER BY on the subquery */
|
||||
|
||||
pSubOB = pLoop->u.btree.pOrderBy;
|
||||
assert( pSubOB!=0 );
|
||||
for(iOB=0; (MASKBIT(iOB) & *pOBSat)!=0; iOB++){}
|
||||
for(jSub=0; jSub<pSubOB->nExpr && iOB<pOrderBy->nExpr; jSub++, iOB++){
|
||||
if( pSubOB->a[jSub].u.x.iOrderByCol==0 ) break;
|
||||
pOBExpr = pOrderBy->a[iOB].pExpr;
|
||||
if( pOBExpr->op!=TK_COLUMN && pOBExpr->op!=TK_AGG_COLUMN ) break;
|
||||
if( pOBExpr->iTable!=iCur ) break;
|
||||
if( pOBExpr->iColumn!=pSubOB->a[jSub].u.x.iOrderByCol-1 ) break;
|
||||
if( (pWInfo->wctrlFlags & WHERE_GROUPBY)==0 ){
|
||||
u8 sfOB = pOrderBy->a[iOB].fg.sortFlags; /* sortFlags for iOB */
|
||||
u8 sfSub = pSubOB->a[jSub].fg.sortFlags; /* sortFlags for jSub */
|
||||
if( (sfSub & KEYINFO_ORDER_BIGNULL) != (sfOB & KEYINFO_ORDER_BIGNULL) ){
|
||||
break;
|
||||
}
|
||||
revIdx = sfSub & KEYINFO_ORDER_DESC;
|
||||
if( jSub>0 ){
|
||||
if( (rev^revIdx)!=(sfOB & KEYINFO_ORDER_DESC) ){
|
||||
break;
|
||||
}
|
||||
}else{
|
||||
rev = revIdx ^ (sfOB & KEYINFO_ORDER_DESC);
|
||||
if( rev ){
|
||||
if( (pLoop->wsFlags & WHERE_COROUTINE)!=0 ){
|
||||
/* Cannot run a co-routine in reverse order */
|
||||
break;
|
||||
}
|
||||
*pRevMask |= MASKBIT(iLoop);
|
||||
}
|
||||
}
|
||||
}
|
||||
*pOBSat |= MASKBIT(iOB);
|
||||
}
|
||||
return jSub>0;
|
||||
}
|
||||
|
||||
/*
|
||||
** 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
|
||||
@@ -4986,9 +5089,18 @@ static i8 wherePathSatisfiesOrderBy(
|
||||
|
||||
if( (pLoop->wsFlags & WHERE_ONEROW)==0 ){
|
||||
if( pLoop->wsFlags & WHERE_IPK ){
|
||||
if( pLoop->u.btree.pOrderBy
|
||||
&& OptimizationEnabled(db, SQLITE_OrderBySubq)
|
||||
&& wherePathMatchSubqueryOB(pWInfo,pLoop,iLoop,iCur,
|
||||
pOrderBy,pRevMask, &obSat)
|
||||
){
|
||||
nColumn = 0;
|
||||
isOrderDistinct = 0;
|
||||
}else{
|
||||
nColumn = 1;
|
||||
}
|
||||
pIndex = 0;
|
||||
nKeyCol = 0;
|
||||
nColumn = 1;
|
||||
}else if( (pIndex = pLoop->u.btree.pIndex)==0 || pIndex->bUnordered ){
|
||||
return 0;
|
||||
}else{
|
||||
@@ -5083,7 +5195,7 @@ static i8 wherePathSatisfiesOrderBy(
|
||||
}
|
||||
|
||||
/* Find the ORDER BY term that corresponds to the j-th column
|
||||
** of the index and mark that ORDER BY term off
|
||||
** of the index and mark that ORDER BY term having been satisfied.
|
||||
*/
|
||||
isMatch = 0;
|
||||
for(i=0; bOnce && i<nOrderBy; i++){
|
||||
@@ -5345,7 +5457,7 @@ static int computeMxChoice(WhereInfo *pWInfo, LogEst nRowEst){
|
||||
if( sqlite3WhereTrace&0x4 ){
|
||||
SrcItem *pItem = pWInfo->pTabList->a + iLoop;
|
||||
sqlite3DebugPrintf("Fact-table %s: %d dimensions, cost reduced %d\n",
|
||||
pItem->zAlias ? pItem->zAlias : pItem->pTab->zName,
|
||||
pItem->zAlias ? pItem->zAlias : pItem->pSTab->zName,
|
||||
nDep, rDelta);
|
||||
}
|
||||
#endif
|
||||
@@ -5895,7 +6007,7 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){
|
||||
if( pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE ) return 0;
|
||||
assert( pWInfo->pTabList->nSrc>=1 );
|
||||
pItem = pWInfo->pTabList->a;
|
||||
pTab = pItem->pTab;
|
||||
pTab = pItem->pSTab;
|
||||
if( IsVirtual(pTab) ) return 0;
|
||||
if( pItem->fg.isIndexedBy || pItem->fg.notIndexed ){
|
||||
testcase( pItem->fg.isIndexedBy );
|
||||
@@ -6158,7 +6270,7 @@ static SQLITE_NOINLINE void whereCheckIfBloomFilterIsUseful(
|
||||
WhereLoop *pLoop = pWInfo->a[i].pWLoop;
|
||||
const unsigned int reqFlags = (WHERE_SELFCULL|WHERE_COLUMN_EQ);
|
||||
SrcItem *pItem = &pWInfo->pTabList->a[pLoop->iTab];
|
||||
Table *pTab = pItem->pTab;
|
||||
Table *pTab = pItem->pSTab;
|
||||
if( (pTab->tabFlags & TF_HasStat1)==0 ) break;
|
||||
pTab->tabFlags |= TF_MaybeReanalyze;
|
||||
if( i>=1
|
||||
@@ -6315,8 +6427,8 @@ static SQLITE_NOINLINE void whereReverseScanOrder(WhereInfo *pWInfo){
|
||||
SrcItem *pItem = &pWInfo->pTabList->a[ii];
|
||||
if( !pItem->fg.isCte
|
||||
|| pItem->u2.pCteUse->eM10d!=M10d_Yes
|
||||
|| NEVER(pItem->pSelect==0)
|
||||
|| pItem->pSelect->pOrderBy==0
|
||||
|| NEVER(pItem->fg.isSubquery==0)
|
||||
|| pItem->u4.pSubq->pSelect->pOrderBy==0
|
||||
){
|
||||
pWInfo->revMask |= MASKBIT(ii);
|
||||
}
|
||||
@@ -6806,15 +6918,15 @@ WhereInfo *sqlite3WhereBegin(
|
||||
if( (wctrlFlags & WHERE_ONEPASS_DESIRED)!=0 ){
|
||||
int wsFlags = pWInfo->a[0].pWLoop->wsFlags;
|
||||
int bOnerow = (wsFlags & WHERE_ONEROW)!=0;
|
||||
assert( !(wsFlags & WHERE_VIRTUALTABLE) || IsVirtual(pTabList->a[0].pTab) );
|
||||
assert( !(wsFlags&WHERE_VIRTUALTABLE) || IsVirtual(pTabList->a[0].pSTab) );
|
||||
if( bOnerow || (
|
||||
0!=(wctrlFlags & WHERE_ONEPASS_MULTIROW)
|
||||
&& !IsVirtual(pTabList->a[0].pTab)
|
||||
&& !IsVirtual(pTabList->a[0].pSTab)
|
||||
&& (0==(wsFlags & WHERE_MULTI_OR) || (wctrlFlags & WHERE_DUPLICATES_OK))
|
||||
&& OptimizationEnabled(db, SQLITE_OnePass)
|
||||
)){
|
||||
pWInfo->eOnePass = bOnerow ? ONEPASS_SINGLE : ONEPASS_MULTI;
|
||||
if( HasRowid(pTabList->a[0].pTab) && (wsFlags & WHERE_IDX_ONLY) ){
|
||||
if( HasRowid(pTabList->a[0].pSTab) && (wsFlags & WHERE_IDX_ONLY) ){
|
||||
if( wctrlFlags & WHERE_ONEPASS_MULTIROW ){
|
||||
bFordelete = OPFLAG_FORDELETE;
|
||||
}
|
||||
@@ -6832,7 +6944,7 @@ WhereInfo *sqlite3WhereBegin(
|
||||
SrcItem *pTabItem;
|
||||
|
||||
pTabItem = &pTabList->a[pLevel->iFrom];
|
||||
pTab = pTabItem->pTab;
|
||||
pTab = pTabItem->pSTab;
|
||||
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
|
||||
pLoop = pLevel->pWLoop;
|
||||
if( (pTab->tabFlags & TF_Ephemeral)!=0 || IsView(pTab) ){
|
||||
@@ -6903,7 +7015,7 @@ WhereInfo *sqlite3WhereBegin(
|
||||
iIndexCur = pLevel->iTabCur;
|
||||
op = 0;
|
||||
}else if( pWInfo->eOnePass!=ONEPASS_OFF ){
|
||||
Index *pJ = pTabItem->pTab->pIndex;
|
||||
Index *pJ = pTabItem->pSTab->pIndex;
|
||||
iIndexCur = iAuxArg;
|
||||
assert( wctrlFlags & WHERE_ONEPASS_DESIRED );
|
||||
while( ALWAYS(pJ) && pJ!=pIx ){
|
||||
@@ -6970,7 +7082,7 @@ WhereInfo *sqlite3WhereBegin(
|
||||
sqlite3VdbeAddOp2(v, OP_Blob, 65536, pRJ->regBloom);
|
||||
pRJ->regReturn = ++pParse->nMem;
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, pRJ->regReturn);
|
||||
assert( pTab==pTabItem->pTab );
|
||||
assert( pTab==pTabItem->pSTab );
|
||||
if( HasRowid(pTab) ){
|
||||
KeyInfo *pInfo;
|
||||
sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pRJ->iMatch, 1);
|
||||
@@ -7009,11 +7121,14 @@ WhereInfo *sqlite3WhereBegin(
|
||||
wsFlags = pLevel->pWLoop->wsFlags;
|
||||
pSrc = &pTabList->a[pLevel->iFrom];
|
||||
if( pSrc->fg.isMaterialized ){
|
||||
Subquery *pSubq;
|
||||
assert( pSrc->fg.isSubquery );
|
||||
pSubq = pSrc->u4.pSubq;
|
||||
if( pSrc->fg.isCorrelated ){
|
||||
sqlite3VdbeAddOp2(v, OP_Gosub, pSrc->regReturn, pSrc->addrFillSub);
|
||||
sqlite3VdbeAddOp2(v, OP_Gosub, pSubq->regReturn, pSubq->addrFillSub);
|
||||
}else{
|
||||
int iOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp2(v, OP_Gosub, pSrc->regReturn, pSrc->addrFillSub);
|
||||
sqlite3VdbeAddOp2(v, OP_Gosub, pSubq->regReturn, pSubq->addrFillSub);
|
||||
sqlite3VdbeJumpHere(v, iOnce);
|
||||
}
|
||||
}
|
||||
@@ -7078,26 +7193,6 @@ whereBeginError:
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_DEBUG
|
||||
/*
|
||||
** Return true if cursor iCur is opened by instruction k of the
|
||||
** bytecode. Used inside of assert() only.
|
||||
*/
|
||||
static int cursorIsOpen(Vdbe *v, int iCur, int k){
|
||||
while( k>=0 ){
|
||||
VdbeOp *pOp = sqlite3VdbeGetOp(v,k--);
|
||||
if( pOp->p1!=iCur ) continue;
|
||||
if( pOp->opcode==OP_Close ) return 0;
|
||||
if( pOp->opcode==OP_OpenRead ) return 1;
|
||||
if( pOp->opcode==OP_OpenWrite ) return 1;
|
||||
if( pOp->opcode==OP_OpenDup ) return 1;
|
||||
if( pOp->opcode==OP_OpenAutoindex ) return 1;
|
||||
if( pOp->opcode==OP_OpenEphemeral ) return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif /* SQLITE_DEBUG */
|
||||
|
||||
/*
|
||||
** Generate the end of the WHERE loop. See comments on
|
||||
** sqlite3WhereBegin() for additional information.
|
||||
@@ -7248,9 +7343,10 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
|
||||
assert( pLevel->iTabCur==pSrc->iCursor );
|
||||
if( pSrc->fg.viaCoroutine ){
|
||||
int m, n;
|
||||
n = pSrc->regResult;
|
||||
assert( pSrc->pTab!=0 );
|
||||
m = pSrc->pTab->nCol;
|
||||
assert( pSrc->fg.isSubquery );
|
||||
n = pSrc->u4.pSubq->regResult;
|
||||
assert( pSrc->pSTab!=0 );
|
||||
m = pSrc->pSTab->nCol;
|
||||
sqlite3VdbeAddOp3(v, OP_Null, 0, n, n+m-1);
|
||||
}
|
||||
sqlite3VdbeAddOp1(v, OP_NullRow, pLevel->iTabCur);
|
||||
@@ -7274,7 +7370,7 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
|
||||
sqlite3VdbeJumpHere(v, addr);
|
||||
}
|
||||
VdbeModuleComment((v, "End WHERE-loop%d: %s", i,
|
||||
pWInfo->pTabList->a[pLevel->iFrom].pTab->zName));
|
||||
pWInfo->pTabList->a[pLevel->iFrom].pSTab->zName));
|
||||
}
|
||||
|
||||
assert( pWInfo->nLevel<=pTabList->nSrc );
|
||||
@@ -7283,7 +7379,7 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
|
||||
VdbeOp *pOp, *pLastOp;
|
||||
Index *pIdx = 0;
|
||||
SrcItem *pTabItem = &pTabList->a[pLevel->iFrom];
|
||||
Table *pTab = pTabItem->pTab;
|
||||
Table *pTab = pTabItem->pSTab;
|
||||
assert( pTab!=0 );
|
||||
pLoop = pLevel->pWLoop;
|
||||
|
||||
@@ -7302,9 +7398,10 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
|
||||
*/
|
||||
if( pTabItem->fg.viaCoroutine ){
|
||||
testcase( pParse->db->mallocFailed );
|
||||
assert( pTabItem->regResult>=0 );
|
||||
assert( pTabItem->fg.isSubquery );
|
||||
assert( pTabItem->u4.pSubq->regResult>=0 );
|
||||
translateColumnToCopy(pParse, pLevel->addrBody, pLevel->iTabCur,
|
||||
pTabItem->regResult, 0);
|
||||
pTabItem->u4.pSubq->regResult, 0);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -7397,16 +7494,10 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
|
||||
** reference. Verify that this is harmless - that the
|
||||
** table being referenced really is open.
|
||||
*/
|
||||
#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
|
||||
assert( (pLoop->wsFlags & WHERE_IDX_ONLY)==0
|
||||
|| cursorIsOpen(v,pOp->p1,k)
|
||||
|| pOp->opcode==OP_Offset
|
||||
);
|
||||
#else
|
||||
assert( (pLoop->wsFlags & WHERE_IDX_ONLY)==0
|
||||
|| cursorIsOpen(v,pOp->p1,k)
|
||||
);
|
||||
#endif
|
||||
if( pLoop->wsFlags & WHERE_IDX_ONLY ){
|
||||
sqlite3ErrorMsg(pParse, "internal query planner error");
|
||||
pParse->rc = SQLITE_INTERNAL;
|
||||
}
|
||||
}
|
||||
}else if( pOp->opcode==OP_Rowid ){
|
||||
pOp->p1 = pLevel->iIdxCur;
|
||||
|
||||
+3
-1
@@ -143,6 +143,7 @@ struct WhereLoop {
|
||||
u16 nTop; /* Size of TOP vector */
|
||||
u16 nDistinctCol; /* Index columns used to sort for DISTINCT */
|
||||
Index *pIndex; /* Index used, or NULL */
|
||||
ExprList *pOrderBy; /* ORDER BY clause if this is really a subquery */
|
||||
} btree;
|
||||
struct { /* Information for virtual tables */
|
||||
int idxNum; /* Index number */
|
||||
@@ -636,7 +637,8 @@ void sqlite3WhereTabFuncArgs(Parse*, SrcItem*, WhereClause*);
|
||||
#define WHERE_BLOOMFILTER 0x00400000 /* Consider using a Bloom-filter */
|
||||
#define WHERE_SELFCULL 0x00800000 /* nOut reduced by extra WHERE terms */
|
||||
#define WHERE_OMIT_OFFSET 0x01000000 /* Set offset counter to zero */
|
||||
/* 0x02000000 -- available for reuse */
|
||||
#define WHERE_COROUTINE 0x02000000 /* Implemented by co-routine.
|
||||
** NB: False-negatives are possible */
|
||||
#define WHERE_EXPRIDX 0x04000000 /* Uses an index-on-expressions */
|
||||
|
||||
#endif /* !defined(SQLITE_WHEREINT_H) */
|
||||
|
||||
+24
-13
@@ -157,7 +157,7 @@ int sqlite3WhereExplainOneScan(
|
||||
assert( pLoop->u.btree.pIndex!=0 );
|
||||
pIdx = pLoop->u.btree.pIndex;
|
||||
assert( !(flags&WHERE_AUTO_INDEX) || (flags&WHERE_IDX_ONLY) );
|
||||
if( !HasRowid(pItem->pTab) && IsPrimaryKeyIndex(pIdx) ){
|
||||
if( !HasRowid(pItem->pSTab) && IsPrimaryKeyIndex(pIdx) ){
|
||||
if( isSearch ){
|
||||
zFmt = "PRIMARY KEY";
|
||||
}
|
||||
@@ -254,7 +254,7 @@ int sqlite3WhereExplainBloomFilter(
|
||||
sqlite3_str_appendf(&str, "BLOOM FILTER ON %S (", pItem);
|
||||
pLoop = pLevel->pWLoop;
|
||||
if( pLoop->wsFlags & WHERE_IPK ){
|
||||
const Table *pTab = pItem->pTab;
|
||||
const Table *pTab = pItem->pSTab;
|
||||
if( pTab->iPKey>=0 ){
|
||||
sqlite3_str_appendf(&str, "%s=?", pTab->aCol[pTab->iPKey].zCnName);
|
||||
}else{
|
||||
@@ -317,7 +317,9 @@ void sqlite3WhereAddScanStatus(
|
||||
sqlite3VdbeScanStatusRange(v, addrExplain, -1, pLvl->iIdxCur);
|
||||
}
|
||||
}else{
|
||||
int addr = pSrclist->a[pLvl->iFrom].addrFillSub;
|
||||
int addr;
|
||||
assert( pSrclist->a[pLvl->iFrom].fg.isSubquery );
|
||||
addr = pSrclist->a[pLvl->iFrom].u4.pSubq->addrFillSub;
|
||||
VdbeOp *pOp = sqlite3VdbeGetOp(v, addr-1);
|
||||
assert( sqlite3VdbeDb(v)->mallocFailed || pOp->opcode==OP_InitCoroutine );
|
||||
assert( sqlite3VdbeDb(v)->mallocFailed || pOp->p2>addr );
|
||||
@@ -1454,7 +1456,8 @@ Bitmask sqlite3WhereCodeOneLoopStart(
|
||||
iCur = pTabItem->iCursor;
|
||||
pLevel->notReady = notReady & ~sqlite3WhereGetMask(&pWInfo->sMaskSet, iCur);
|
||||
bRev = (pWInfo->revMask>>iLevel)&1;
|
||||
VdbeModuleComment((v, "Begin WHERE-loop%d: %s",iLevel,pTabItem->pTab->zName));
|
||||
VdbeModuleComment((v, "Begin WHERE-loop%d: %s",
|
||||
iLevel, pTabItem->pSTab->zName));
|
||||
#if WHERETRACE_ENABLED /* 0x4001 */
|
||||
if( sqlite3WhereTrace & 0x1 ){
|
||||
sqlite3DebugPrintf("Coding level %d of %d: notReady=%llx iFrom=%d\n",
|
||||
@@ -1509,11 +1512,15 @@ Bitmask sqlite3WhereCodeOneLoopStart(
|
||||
|
||||
/* Special case of a FROM clause subquery implemented as a co-routine */
|
||||
if( pTabItem->fg.viaCoroutine ){
|
||||
int regYield = pTabItem->regReturn;
|
||||
sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, pTabItem->addrFillSub);
|
||||
int regYield;
|
||||
Subquery *pSubq;
|
||||
assert( pTabItem->fg.isSubquery && pTabItem->u4.pSubq!=0 );
|
||||
pSubq = pTabItem->u4.pSubq;
|
||||
regYield = pSubq->regReturn;
|
||||
sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, pSubq->addrFillSub);
|
||||
pLevel->p2 = sqlite3VdbeAddOp2(v, OP_Yield, regYield, addrBrk);
|
||||
VdbeCoverage(v);
|
||||
VdbeComment((v, "next row of %s", pTabItem->pTab->zName));
|
||||
VdbeComment((v, "next row of %s", pTabItem->pSTab->zName));
|
||||
pLevel->op = OP_Goto;
|
||||
}else
|
||||
|
||||
@@ -2242,7 +2249,7 @@ Bitmask sqlite3WhereCodeOneLoopStart(
|
||||
int untestedTerms = 0; /* Some terms not completely tested */
|
||||
int ii; /* Loop counter */
|
||||
Expr *pAndExpr = 0; /* An ".. AND (...)" expression */
|
||||
Table *pTab = pTabItem->pTab;
|
||||
Table *pTab = pTabItem->pSTab;
|
||||
|
||||
pTerm = pLoop->aLTerm[0];
|
||||
assert( pTerm!=0 );
|
||||
@@ -2701,7 +2708,7 @@ Bitmask sqlite3WhereCodeOneLoopStart(
|
||||
** least once. This is accomplished by storing the PK for the row in
|
||||
** both the iMatch index and the regBloom Bloom filter.
|
||||
*/
|
||||
pTab = pWInfo->pTabList->a[pLevel->iFrom].pTab;
|
||||
pTab = pWInfo->pTabList->a[pLevel->iFrom].pSTab;
|
||||
if( HasRowid(pTab) ){
|
||||
r = sqlite3GetTempRange(pParse, 2);
|
||||
sqlite3ExprCodeGetColumnOfTable(v, pTab, pLevel->iTabCur, -1, r+1);
|
||||
@@ -2808,7 +2815,7 @@ SQLITE_NOINLINE void sqlite3WhereRightJoinLoop(
|
||||
Bitmask mAll = 0;
|
||||
int k;
|
||||
|
||||
ExplainQueryPlan((pParse, 1, "RIGHT-JOIN %s", pTabItem->pTab->zName));
|
||||
ExplainQueryPlan((pParse, 1, "RIGHT-JOIN %s", pTabItem->pSTab->zName));
|
||||
sqlite3VdbeNoJumpsOutsideSubrtn(v, pRJ->addrSubrtn, pRJ->endSubrtn,
|
||||
pRJ->regReturn);
|
||||
for(k=0; k<iLevel; k++){
|
||||
@@ -2818,9 +2825,13 @@ SQLITE_NOINLINE void sqlite3WhereRightJoinLoop(
|
||||
pRight = &pWInfo->pTabList->a[pWInfo->a[k].iFrom];
|
||||
mAll |= pWInfo->a[k].pWLoop->maskSelf;
|
||||
if( pRight->fg.viaCoroutine ){
|
||||
Subquery *pSubq;
|
||||
assert( pRight->fg.isSubquery && pRight->u4.pSubq!=0 );
|
||||
pSubq = pRight->u4.pSubq;
|
||||
assert( pSubq->pSelect!=0 && pSubq->pSelect->pEList!=0 );
|
||||
sqlite3VdbeAddOp3(
|
||||
v, OP_Null, 0, pRight->regResult,
|
||||
pRight->regResult + pRight->pSelect->pEList->nExpr-1
|
||||
v, OP_Null, 0, pSubq->regResult,
|
||||
pSubq->regResult + pSubq->pSelect->pEList->nExpr-1
|
||||
);
|
||||
}
|
||||
sqlite3VdbeAddOp1(v, OP_NullRow, pWInfo->a[k].iTabCur);
|
||||
@@ -2858,7 +2869,7 @@ SQLITE_NOINLINE void sqlite3WhereRightJoinLoop(
|
||||
int nPk;
|
||||
int jmp;
|
||||
int addrCont = sqlite3WhereContinueLabel(pSubWInfo);
|
||||
Table *pTab = pTabItem->pTab;
|
||||
Table *pTab = pTabItem->pSTab;
|
||||
if( HasRowid(pTab) ){
|
||||
sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, -1, r);
|
||||
nPk = 1;
|
||||
|
||||
+7
-5
@@ -958,7 +958,9 @@ static Bitmask exprSelectUsage(WhereMaskSet *pMaskSet, Select *pS){
|
||||
if( ALWAYS(pSrc!=0) ){
|
||||
int i;
|
||||
for(i=0; i<pSrc->nSrc; i++){
|
||||
mask |= exprSelectUsage(pMaskSet, pSrc->a[i].pSelect);
|
||||
if( pSrc->a[i].fg.isSubquery ){
|
||||
mask |= exprSelectUsage(pMaskSet, pSrc->a[i].u4.pSubq->pSelect);
|
||||
}
|
||||
if( pSrc->a[i].fg.isUsing==0 ){
|
||||
mask |= sqlite3WhereExprUsage(pMaskSet, pSrc->a[i].u3.pOn);
|
||||
}
|
||||
@@ -996,7 +998,7 @@ static SQLITE_NOINLINE int exprMightBeIndexed2(
|
||||
int iCur;
|
||||
do{
|
||||
iCur = pFrom->a[j].iCursor;
|
||||
for(pIdx=pFrom->a[j].pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
||||
for(pIdx=pFrom->a[j].pSTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
||||
if( pIdx->aColExpr==0 ) continue;
|
||||
for(i=0; i<pIdx->nKeyCol; i++){
|
||||
if( pIdx->aiColumn[i]!=XN_EXPR ) continue;
|
||||
@@ -1040,7 +1042,7 @@ static int exprMightBeIndexed(
|
||||
|
||||
for(i=0; i<pFrom->nSrc; i++){
|
||||
Index *pIdx;
|
||||
for(pIdx=pFrom->a[i].pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
||||
for(pIdx=pFrom->a[i].pSTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
||||
if( pIdx->aColExpr ){
|
||||
return exprMightBeIndexed2(pFrom,aiCurCol,pExpr,i);
|
||||
}
|
||||
@@ -1628,7 +1630,7 @@ void SQLITE_NOINLINE sqlite3WhereAddLimit(WhereClause *pWC, Select *p){
|
||||
assert( p!=0 && p->pLimit!=0 ); /* 1 -- checked by caller */
|
||||
if( p->pGroupBy==0
|
||||
&& (p->selFlags & (SF_Distinct|SF_Aggregate))==0 /* 2 */
|
||||
&& (p->pSrc->nSrc==1 && IsVirtual(p->pSrc->a[0].pTab)) /* 3 */
|
||||
&& (p->pSrc->nSrc==1 && IsVirtual(p->pSrc->a[0].pSTab)) /* 3 */
|
||||
){
|
||||
ExprList *pOrderBy = p->pOrderBy;
|
||||
int iCsr = p->pSrc->a[0].iCursor;
|
||||
@@ -1849,7 +1851,7 @@ void sqlite3WhereTabFuncArgs(
|
||||
Expr *pColRef;
|
||||
Expr *pTerm;
|
||||
if( pItem->fg.isTabFunc==0 ) return;
|
||||
pTab = pItem->pTab;
|
||||
pTab = pItem->pSTab;
|
||||
assert( pTab!=0 );
|
||||
pArgs = pItem->u1.pFuncArg;
|
||||
if( pArgs==0 ) return;
|
||||
|
||||
+13
-9
@@ -1077,9 +1077,10 @@ int sqlite3WindowRewrite(Parse *pParse, Select *p){
|
||||
assert( pSub!=0 || p->pSrc==0 ); /* Due to db->mallocFailed test inside
|
||||
** of sqlite3DbMallocRawNN() called from
|
||||
** sqlite3SrcListAppend() */
|
||||
if( p->pSrc ){
|
||||
if( p->pSrc==0 ){
|
||||
sqlite3SelectDelete(db, pSub);
|
||||
}else if( sqlite3SrcItemAttachSubquery(pParse, &p->pSrc->a[0], pSub, 0) ){
|
||||
Table *pTab2;
|
||||
p->pSrc->a[0].pSelect = pSub;
|
||||
p->pSrc->a[0].fg.isCorrelated = 1;
|
||||
sqlite3SrcListAssignCursors(pParse, p->pSrc);
|
||||
pSub->selFlags |= SF_Expanded|SF_OrderByReqd;
|
||||
@@ -1093,7 +1094,7 @@ int sqlite3WindowRewrite(Parse *pParse, Select *p){
|
||||
}else{
|
||||
memcpy(pTab, pTab2, sizeof(Table));
|
||||
pTab->tabFlags |= TF_Ephemeral;
|
||||
p->pSrc->a[0].pTab = pTab;
|
||||
p->pSrc->a[0].pSTab = pTab;
|
||||
pTab = pTab2;
|
||||
memset(&w, 0, sizeof(w));
|
||||
w.xExprCallback = sqlite3WindowExtraAggFuncDepth;
|
||||
@@ -1101,8 +1102,6 @@ int sqlite3WindowRewrite(Parse *pParse, Select *p){
|
||||
w.xSelectCallback2 = sqlite3WalkerDepthDecrease;
|
||||
sqlite3WalkSelect(&w, pSub);
|
||||
}
|
||||
}else{
|
||||
sqlite3SelectDelete(db, pSub);
|
||||
}
|
||||
if( db->mallocFailed ) rc = SQLITE_NOMEM;
|
||||
|
||||
@@ -1389,10 +1388,15 @@ int sqlite3WindowCompare(
|
||||
** and initialize registers and cursors used by sqlite3WindowCodeStep().
|
||||
*/
|
||||
void sqlite3WindowCodeInit(Parse *pParse, Select *pSelect){
|
||||
int nEphExpr = pSelect->pSrc->a[0].pSelect->pEList->nExpr;
|
||||
Window *pMWin = pSelect->pWin;
|
||||
Window *pWin;
|
||||
Vdbe *v = sqlite3GetVdbe(pParse);
|
||||
int nEphExpr;
|
||||
Window *pMWin;
|
||||
Vdbe *v;
|
||||
|
||||
assert( pSelect->pSrc->a[0].fg.isSubquery );
|
||||
nEphExpr = pSelect->pSrc->a[0].u4.pSubq->pSelect->pEList->nExpr;
|
||||
pMWin = pSelect->pWin;
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
|
||||
sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pMWin->iEphCsr, nEphExpr);
|
||||
sqlite3VdbeAddOp2(v, OP_OpenDup, pMWin->iEphCsr+1, pMWin->iEphCsr);
|
||||
@@ -2789,7 +2793,7 @@ void sqlite3WindowCodeStep(
|
||||
Vdbe *v = sqlite3GetVdbe(pParse);
|
||||
int csrWrite; /* Cursor used to write to eph. table */
|
||||
int csrInput = p->pSrc->a[0].iCursor; /* Cursor of sub-select */
|
||||
int nInput = p->pSrc->a[0].pTab->nCol; /* Number of cols returned by sub */
|
||||
int nInput = p->pSrc->a[0].pSTab->nCol; /* Number of cols returned by sub */
|
||||
int iInput; /* To iterate through sub cols */
|
||||
int addrNe; /* Address of OP_Ne */
|
||||
int addrGosubFlush = 0; /* Address of OP_Gosub to flush: */
|
||||
|
||||
@@ -288,6 +288,7 @@ det 3.2.1 {
|
||||
|--SCAN (subquery-xxxxxx)
|
||||
`--USE TEMP B-TREE FOR ORDER BY
|
||||
}
|
||||
|
||||
det 3.2.2 {
|
||||
SELECT * FROM
|
||||
(SELECT * FROM t1 ORDER BY x LIMIT 10) AS x1,
|
||||
@@ -305,6 +306,16 @@ det 3.2.2 {
|
||||
`--USE TEMP B-TREE FOR ORDER BY
|
||||
}
|
||||
|
||||
det 3.2.3 {
|
||||
SELECT * FROM (SELECT * FROM t1 ORDER BY x LIMIT 10) ORDER BY x LIMIT 5
|
||||
} {
|
||||
QUERY PLAN
|
||||
|--CO-ROUTINE (subquery-xxxxxx)
|
||||
| |--SCAN t1
|
||||
| `--USE TEMP B-TREE FOR ORDER BY
|
||||
`--SCAN (subquery-xxxxxx)
|
||||
}
|
||||
|
||||
det 3.3.1 {
|
||||
SELECT * FROM t1 WHERE y IN (SELECT y FROM t2)
|
||||
} {
|
||||
@@ -807,6 +818,7 @@ do_execsql_test 9.0 {
|
||||
CREATE INDEX event_i1 ON event(mtime);
|
||||
CREATE TABLE private(rid INTEGER PRIMARY KEY);
|
||||
}
|
||||
optimization_control db order-by-subquery off
|
||||
do_eqp_test 9.1 {
|
||||
WITH thread(age,duration,cnt,root,last) AS (
|
||||
SELECT
|
||||
@@ -847,5 +859,46 @@ do_eqp_test 9.1 {
|
||||
|--SEARCH event USING INTEGER PRIMARY KEY (rowid=?)
|
||||
`--USE TEMP B-TREE FOR ORDER BY
|
||||
}
|
||||
optimization_control db all on
|
||||
db cache flush
|
||||
do_eqp_test 9.2 {
|
||||
WITH thread(age,duration,cnt,root,last) AS (
|
||||
SELECT
|
||||
julianday('now') - max(fmtime) AS age,
|
||||
max(fmtime) - min(fmtime) AS duration,
|
||||
sum(fprev IS NULL) AS msg_count,
|
||||
froot,
|
||||
(SELECT fpid FROM forumpost
|
||||
WHERE froot=x.froot
|
||||
AND fpid NOT IN private
|
||||
ORDER BY fmtime DESC LIMIT 1)
|
||||
FROM forumpost AS x
|
||||
WHERE fpid NOT IN private --- Ensure this table mentioned in EQP output!
|
||||
GROUP BY froot
|
||||
ORDER BY 1 LIMIT 26 OFFSET 5
|
||||
)
|
||||
SELECT
|
||||
thread.age,
|
||||
thread.duration,
|
||||
thread.cnt,
|
||||
blob.uuid,
|
||||
substr(event.comment,instr(event.comment,':')+1)
|
||||
FROM thread, blob, event
|
||||
WHERE blob.rid=thread.last
|
||||
AND event.objid=thread.last
|
||||
ORDER BY 1;
|
||||
} {
|
||||
QUERY PLAN
|
||||
|--CO-ROUTINE thread
|
||||
| |--SCAN x USING INDEX forumthread
|
||||
| |--USING ROWID SEARCH ON TABLE private FOR IN-OPERATOR
|
||||
| |--CORRELATED SCALAR SUBQUERY xxxxxx
|
||||
| | |--SEARCH forumpost USING COVERING INDEX forumthread (froot=?)
|
||||
| | `--USING ROWID SEARCH ON TABLE private FOR IN-OPERATOR
|
||||
| `--USE TEMP B-TREE FOR ORDER BY
|
||||
|--SCAN thread
|
||||
|--SEARCH blob USING INTEGER PRIMARY KEY (rowid=?)
|
||||
`--SEARCH event USING INTEGER PRIMARY KEY (rowid=?)
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -1028,6 +1028,30 @@ static int recoverDatabase(sqlite3 *db){
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
/*
|
||||
** Special parameter binding, for testing and debugging purposes.
|
||||
**
|
||||
** $int_NNN -> integer value NNN
|
||||
** $text_TTTT -> floating point value TTT with destructor
|
||||
*/
|
||||
static void bindDebugParameters(sqlite3_stmt *pStmt){
|
||||
int nVar = sqlite3_bind_parameter_count(pStmt);
|
||||
int i;
|
||||
for(i=0; i<nVar; i++){
|
||||
const char *zVar = sqlite3_bind_parameter_name(pStmt, i+1);
|
||||
if( zVar==0 ) continue;
|
||||
if( strncmp(zVar, "$int_", 5)==0 ){
|
||||
sqlite3_bind_int(pStmt, i+1, atoi(&zVar[5]));
|
||||
}else
|
||||
if( strncmp(zVar, "$text_", 6)==0 ){
|
||||
char *zBuf = sqlite3_malloc64( strlen(zVar)-5 );
|
||||
if( zBuf ){
|
||||
memcpy(zBuf, &zVar[6], strlen(zVar)-5);
|
||||
sqlite3_bind_text64(pStmt, i+1, zBuf, -1, sqlite3_free, SQLITE_UTF8);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Run the SQL text
|
||||
@@ -1051,6 +1075,7 @@ static int runDbSql(
|
||||
rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
int nRow = 0;
|
||||
bindDebugParameters(pStmt);
|
||||
while( (rc = sqlite3_step(pStmt))==SQLITE_ROW ){
|
||||
nRow++;
|
||||
if( eVerbosity>=4 ){
|
||||
|
||||
@@ -38,6 +38,31 @@ static void reportInvariantFailed(
|
||||
int noOpt /* True if opt flags inverted for pTest */
|
||||
);
|
||||
|
||||
/*
|
||||
** Special parameter binding, for testing and debugging purposes.
|
||||
**
|
||||
** $int_NNN -> integer value NNN
|
||||
** $text_TTTT -> floating point value TTT with destructor
|
||||
*/
|
||||
static void bindDebugParameters(sqlite3_stmt *pStmt){
|
||||
int nVar = sqlite3_bind_parameter_count(pStmt);
|
||||
int i;
|
||||
for(i=0; i<nVar; i++){
|
||||
const char *zVar = sqlite3_bind_parameter_name(pStmt, i+1);
|
||||
if( zVar==0 ) continue;
|
||||
if( strncmp(zVar, "$int_", 5)==0 ){
|
||||
sqlite3_bind_int(pStmt, i+1, atoi(&zVar[5]));
|
||||
}else
|
||||
if( strncmp(zVar, "$text_", 6)==0 ){
|
||||
char *zBuf = sqlite3_malloc64( strlen(zVar)-5 );
|
||||
if( zBuf ){
|
||||
memcpy(zBuf, &zVar[6], strlen(zVar)-5);
|
||||
sqlite3_bind_text64(pStmt, i+1, zBuf, -1, sqlite3_free, SQLITE_UTF8);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Do an invariant check on pStmt. iCnt determines which invariant check to
|
||||
** perform. The first check is iCnt==0.
|
||||
@@ -107,6 +132,7 @@ int fuzz_invariant(
|
||||
return rc;
|
||||
}
|
||||
sqlite3_free(zTest);
|
||||
bindDebugParameters(pTestStmt);
|
||||
nCol = sqlite3_column_count(pStmt);
|
||||
for(i=0; i<nCol; i++){
|
||||
rc = sqlite3_bind_value(pTestStmt,i+1+nParam,sqlite3_column_value(pStmt,i));
|
||||
@@ -171,6 +197,7 @@ int fuzz_invariant(
|
||||
printf("invariant-validity-check #2:\n%s\n", zSql);
|
||||
sqlite3_free(zSql);
|
||||
}
|
||||
bindDebugParameters(pCk);
|
||||
while( (rc = sqlite3_step(pCk))==SQLITE_ROW ){
|
||||
for(i=0; i<nCol; i++){
|
||||
if( !sameValue(pStmt, i, pTestStmt, i, 0) ) break;
|
||||
@@ -199,6 +226,7 @@ int fuzz_invariant(
|
||||
}
|
||||
|
||||
sqlite3_reset(pTestStmt);
|
||||
bindDebugParameters(pCk);
|
||||
while( (rc = sqlite3_step(pTestStmt))==SQLITE_ROW ){
|
||||
for(i=0; i<nCol; i++){
|
||||
if( !sameValue(pStmt, i, pTestStmt, i, pCk) ) break;
|
||||
@@ -298,6 +326,7 @@ static char *fuzz_invariant_sql(sqlite3_stmt *pStmt, int iCnt){
|
||||
sqlite3_finalize(pBase);
|
||||
pBase = pStmt;
|
||||
}
|
||||
bindDebugParameters(pBase);
|
||||
for(i=0; i<sqlite3_column_count(pStmt); i++){
|
||||
const char *zColName = sqlite3_column_name(pBase,i);
|
||||
const char *zSuffix = zColName ? strrchr(zColName, ':') : 0;
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
# 2024-08-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.
|
||||
#
|
||||
# Specifically, it tests cases with order-by-subquery optimization in which
|
||||
# an ORDER BY in a subquery is used to help resolve an ORDER BY in the
|
||||
# outer query without having to do an extra sort.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set ::testprefix orderbyb
|
||||
|
||||
db null NULL
|
||||
do_execsql_test 1.0 {
|
||||
CREATE TABLE t1(a TEXT, b TEXT, c INT);
|
||||
INSERT INTO t1 VALUES(NULL,NULL,NULL);
|
||||
WITH RECURSIVE c(n) AS (VALUES(1) UNION ALL SELECT n+1 FROM c WHERE n<7)
|
||||
INSERT INTO t1(a,b,c) SELECT char(p,p), char(q,q), n FROM
|
||||
(SELECT ((n-1)%4)+0x61 AS p, abs(n*2-9+(n>=5))+0x60 AS q, n FROM c);
|
||||
UPDATE t1 SET b=upper(b) WHERE c=1;
|
||||
CREATE TABLE t2(k TEXT PRIMARY KEY, v INT) WITHOUT ROWID;
|
||||
WITH RECURSIVE c(n) AS (VALUES(1) UNION ALL SELECT n+1 FROM c WHERE n<7)
|
||||
INSERT INTO t2(k,v) SELECT char(0x60+n,0x60+n), n FROM c;
|
||||
WITH RECURSIVE c(n) AS (VALUES(1) UNION ALL SELECT n+1 FROM c WHERE n<7)
|
||||
INSERT INTO t2(k,v) SELECT char(0x40+n,0x40+n), n FROM c;
|
||||
SELECT a,b,c,tx.v AS 'v-a', ty.v AS 'v-b'
|
||||
FROM t1 LEFT JOIN t2 AS tx ON tx.k=a
|
||||
LEFT JOIN t2 AS ty ON ty.k=b
|
||||
ORDER BY c;
|
||||
} {
|
||||
NULL NULL NULL NULL NULL
|
||||
aa GG 1 1 7
|
||||
bb ee 2 2 5
|
||||
cc cc 3 3 3
|
||||
dd aa 4 4 1
|
||||
aa bb 5 1 2
|
||||
bb dd 6 2 4
|
||||
cc ff 7 3 6
|
||||
}
|
||||
|
||||
do_eqp_execsql_test 1.1 {
|
||||
WITH t3(x,y) AS (SELECT a, b FROM t1 ORDER BY a, b LIMIT 8)
|
||||
SELECT x, y, v FROM t3 LEFT JOIN t2 ON k=t3.y ORDER BY x, y COLLATE nocase;
|
||||
} {
|
||||
QUERY PLAN
|
||||
|--CO-ROUTINE t3
|
||||
| |--SCAN t1
|
||||
| `--USE TEMP B-TREE FOR ORDER BY
|
||||
|--SCAN t3
|
||||
|--SEARCH t2 USING PRIMARY KEY (k=?) LEFT-JOIN
|
||||
`--USE TEMP B-TREE FOR LAST TERM OF ORDER BY
|
||||
} {
|
||||
NULL NULL NULL
|
||||
aa bb 2
|
||||
aa GG 7
|
||||
bb dd 4
|
||||
bb ee 5
|
||||
cc cc 3
|
||||
cc ff 6
|
||||
dd aa 1
|
||||
}
|
||||
|
||||
do_eqp_execsql_test 1.2 {
|
||||
WITH t3(x,y) AS MATERIALIZED (SELECT a, b COLLATE nocase FROM t1 ORDER BY 1,2)
|
||||
SELECT x, y, v FROM t3 LEFT JOIN t2 ON k=t3.y ORDER BY x,y;
|
||||
} {
|
||||
QUERY PLAN
|
||||
|--MATERIALIZE t3
|
||||
| |--SCAN t1
|
||||
| `--USE TEMP B-TREE FOR ORDER BY
|
||||
|--SCAN t3
|
||||
`--SEARCH t2 USING PRIMARY KEY (k=?) LEFT-JOIN
|
||||
} {
|
||||
NULL NULL NULL
|
||||
aa bb 2
|
||||
aa GG 7
|
||||
bb dd 4
|
||||
bb ee 5
|
||||
cc cc 3
|
||||
cc ff 6
|
||||
dd aa 1
|
||||
}
|
||||
|
||||
|
||||
finish_test
|
||||
+2
-2
@@ -337,12 +337,12 @@ do_execsql_test skipscan1-9.2 {
|
||||
} {/USING INDEX t9a_ab .ANY.a. AND b=./}
|
||||
|
||||
|
||||
optimization_control db skip-scan 0
|
||||
optimization_control db skip-scan off
|
||||
do_execsql_test skipscan1-9.3 {
|
||||
EXPLAIN QUERY PLAN
|
||||
SELECT * FROM t9a WHERE b IN (SELECT x FROM t9b WHERE y!=5);
|
||||
} {/{SCAN t9a}/}
|
||||
optimization_control db skip-scan 1
|
||||
optimization_control db all on
|
||||
|
||||
do_execsql_test skipscan1-2.1 {
|
||||
CREATE TABLE t6(a TEXT, b INT, c INT, d INT);
|
||||
|
||||
@@ -1056,6 +1056,29 @@ proc do_eqp_test {name sql res} {
|
||||
}
|
||||
}
|
||||
|
||||
# Do both an eqp_test and an execsql_test on the same SQL.
|
||||
#
|
||||
proc do_eqp_execsql_test {name sql res1 res2} {
|
||||
if {[regexp {^\s+QUERY PLAN\n} $res1]} {
|
||||
|
||||
set query_plan [query_plan_graph $sql]
|
||||
|
||||
if {[list {*}$query_plan]==[list {*}$res1]} {
|
||||
uplevel [list do_test ${name}a [list set {} ok] ok]
|
||||
} else {
|
||||
uplevel [list \
|
||||
do_test ${name}a [list query_plan_graph $sql] $res1
|
||||
]
|
||||
}
|
||||
} else {
|
||||
if {[string index $res 0]!="/"} {
|
||||
set res1 "/*$res1*/"
|
||||
}
|
||||
uplevel do_execsql_test ${name}a [list "EXPLAIN QUERY PLAN $sql"] [list $res1]
|
||||
}
|
||||
uplevel do_execsql_test ${name}b [list $sql] [list $res2]
|
||||
}
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Usage: do_select_tests PREFIX ?SWITCHES? TESTLIST
|
||||
|
||||
@@ -97,7 +97,11 @@ do_execsql_test 2.0 {
|
||||
}
|
||||
|
||||
foreach tn {0 1} {
|
||||
optimization_control db push-down $tn
|
||||
if {$tn} {
|
||||
optimization_control db all on
|
||||
} else {
|
||||
optimization_control db push-down off
|
||||
}
|
||||
|
||||
do_execsql_test 2.$tn.1.1 {
|
||||
SELECT * FROM v1;
|
||||
|
||||
@@ -156,6 +156,16 @@ do_execsql_test 1.15 {
|
||||
SELECT * FROM t4;
|
||||
} {4 5}
|
||||
|
||||
do_execsql_test 1.15.2 {
|
||||
WITH
|
||||
t4(x) AS (
|
||||
VALUES(4)
|
||||
UNION ALL
|
||||
SELECT x+1 FROM (SELECT * FROM main.t4) WHERE x<10
|
||||
)
|
||||
SELECT * FROM t4;
|
||||
} {4 5}
|
||||
|
||||
do_catchsql_test 1.16 {
|
||||
WITH
|
||||
t4(x) AS (
|
||||
|
||||
@@ -350,6 +350,50 @@ do_eqp_test 400 {
|
||||
FROM (SELECT f.*, exp(b) - 1 AS nFin, exp(a* (-1) + b) - 1 AS nPrev
|
||||
FROM fit f JOIN init i on i.country = f.country AND f.date <= date(i.fin,'-3 days'))
|
||||
WHERE nPrev > 0 AND nFin > 0;
|
||||
} {
|
||||
QUERY PLAN
|
||||
|--MATERIALIZE sums
|
||||
| |--MATERIALIZE src
|
||||
| | |--MATERIALIZE init
|
||||
| | | `--SCAN raw USING INDEX sqlite_autoindex_raw_1
|
||||
| | |--SCAN i
|
||||
| | |--SEARCH raw USING COVERING INDEX sqlite_autoindex_raw_1 (country=? AND date>?)
|
||||
| | `--USE TEMP B-TREE FOR ORDER BY
|
||||
| |--SCAN src
|
||||
| `--SEARCH raw USING INDEX sqlite_autoindex_raw_1 (country=? AND date>? AND date<?)
|
||||
|--SCAN sums
|
||||
|--BLOOM FILTER ON sums (country=? AND date=?)
|
||||
|--SEARCH sums USING AUTOMATIC COVERING INDEX (country=? AND date=?)
|
||||
|--BLOOM FILTER ON sums (country=? AND date=?)
|
||||
|--SEARCH sums USING AUTOMATIC COVERING INDEX (country=? AND date=?)
|
||||
|--BLOOM FILTER ON sums (country=? AND date=?)
|
||||
|--SEARCH sums USING AUTOMATIC COVERING INDEX (country=? AND date=?)
|
||||
|--BLOOM FILTER ON i (country=?)
|
||||
`--SEARCH i USING AUTOMATIC COVERING INDEX (country=?)
|
||||
}
|
||||
optimization_control db order-by-subquery off
|
||||
db cache flush
|
||||
do_eqp_test 410 {
|
||||
with recursive
|
||||
init(country, date, fin) AS (SELECT country, min(date), max(date) FROM raw WHERE total > 0 GROUP BY country),
|
||||
src(country, date) AS (SELECT raw.country, raw.date
|
||||
FROM raw JOIN init i on raw.country = i.country AND raw.date > i.date
|
||||
ORDER BY raw.country, raw.date),
|
||||
vals(country, date, x, y) AS (SELECT src.country, src.date, julianday(raw.date) - julianday(src.date), log(delta+1)
|
||||
FROM src JOIN raw on raw.country = src.country AND raw.date > date(src.date,'-7 days') AND raw.date <= src.date AND delta >= 0),
|
||||
sums(country, date, x2, x, n, xy, y) AS (SELECT country, date, sum(x*x*1.0), sum(x*1.0), sum(1.0), sum(x*y*1.0), sum(y*1.0) FROM vals GROUP BY 1, 2),
|
||||
mult(country, date, m) AS (SELECT country, date, 1.0/(x2 * n - x * x) FROM sums),
|
||||
inv(country, date, a,b,c,d) AS (SELECT mult.country, mult.date, n * m, -x * m, -x * m, x2 * m
|
||||
FROM mult JOIN sums on sums.country=mult.country AND mult.date=sums.date),
|
||||
fit(country, date, a, b) AS (SELECT inv.country, inv.date, a * xy + b * y, c * xy + d * y
|
||||
FROM inv
|
||||
JOIN mult on mult.country = inv.country AND mult.date = inv.date
|
||||
JOIN sums on sums.country = mult.country AND sums.date = mult.date
|
||||
)
|
||||
SELECT *, nFin/nPrev - 1 AS growth, log(2)/log(nFin/nPrev) AS doubling
|
||||
FROM (SELECT f.*, exp(b) - 1 AS nFin, exp(a* (-1) + b) - 1 AS nPrev
|
||||
FROM fit f JOIN init i on i.country = f.country AND f.date <= date(i.fin,'-3 days'))
|
||||
WHERE nPrev > 0 AND nFin > 0;
|
||||
} {
|
||||
QUERY PLAN
|
||||
|--MATERIALIZE sums
|
||||
|
||||
Reference in New Issue
Block a user