Compare commits
152 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c5cd124900 | |||
| a9cb5be49a | |||
| 36ca5359dc | |||
| 4a1f4ff53b | |||
| 61b7060c4f | |||
| 89a75397e0 | |||
| 1d2b3c1f8a | |||
| 0259bc3da2 | |||
| d36e104112 | |||
| 0d31dc37ac | |||
| 8ff2d9561a | |||
| 74dade2155 | |||
| af0d8bcf4b | |||
| 55a1b30875 | |||
| 2b1a64a120 | |||
| c2cfb51525 | |||
| 30f07042df | |||
| fbc38de980 | |||
| b13af4c5dd | |||
| 67a5ec7b54 | |||
| 05db3c7743 | |||
| b49d1047c6 | |||
| 84f48296fa | |||
| 575ab2f8f6 | |||
| 1df556e6f2 | |||
| 1a88b14e5d | |||
| 4a1aa3851a | |||
| 28159a5ee9 | |||
| 3fa2a82b8b | |||
| 2a43c28f06 | |||
| 3fb4b6df07 | |||
| 9f11ef1232 | |||
| d95a3d3527 | |||
| ad4c7aa10f | |||
| 79e8445f63 | |||
| e56dd3ad7b | |||
| f46af73720 | |||
| 77a3fdc1b0 | |||
| 43398081a8 | |||
| 5128d009c6 | |||
| 00ea0e1133 | |||
| 35a0379a05 | |||
| 0c9a8e345e | |||
| 8bff07a55f | |||
| cd40abb297 | |||
| 1d406e0dfd | |||
| 8bcd3fa75a | |||
| 1d2b70e3d2 | |||
| e4f9b9b7c0 | |||
| fe27b08934 | |||
| 3259fe7910 | |||
| d41d39f24d | |||
| 38e587779d | |||
| 868ccf2679 | |||
| f7f8de5fb2 | |||
| 6d57bbfe25 | |||
| 70e9ffa3bb | |||
| 3741827ea1 | |||
| b324bc79e9 | |||
| 533fb6de5b | |||
| f64188910d | |||
| 1435a9a126 | |||
| 9fecc546cb | |||
| 0dd8b87955 | |||
| 59b08dd449 | |||
| 4496a2329a | |||
| 2f53b90665 | |||
| 31706a2d94 | |||
| 09b404419a | |||
| 4dd5144366 | |||
| f68060839c | |||
| e49d98fb0a | |||
| b5ca3cbcd3 | |||
| e98844f723 | |||
| feb56e0e17 | |||
| 1efd81f7cf | |||
| 7dd8d0a87b | |||
| cc04afdad0 | |||
| b00fc3b14e | |||
| 9d1ab0794e | |||
| cf5ff12105 | |||
| b49bc86a1a | |||
| c63e880bdb | |||
| 47b2995983 | |||
| e7ecdfabd2 | |||
| 016f7811f2 | |||
| 13c77bf86b | |||
| 2505a5fee2 | |||
| 36e78309de | |||
| 22c745a9c9 | |||
| c3c16cbd61 | |||
| e934e633a5 | |||
| d0aa2f3afd | |||
| 4044906210 | |||
| 9b47ee3f09 | |||
| f66f26a311 | |||
| 2c18788ffa | |||
| e704713cb8 | |||
| 290703091e | |||
| 4ccc419b3c | |||
| 9e48788e9d | |||
| 77dfd5bb44 | |||
| 92707acfd0 | |||
| 45e3215db0 | |||
| d3605a4f20 | |||
| d4b5c60eca | |||
| 40c3941cfa | |||
| 0e8194a9c7 | |||
| 202ca9075f | |||
| cf9f83dca2 | |||
| 0e1f0029c0 | |||
| 22d73b1cbe | |||
| 585c823256 | |||
| c367d4c052 | |||
| 61b3440603 | |||
| d94f512f58 | |||
| 0af16ab2c2 | |||
| e35463b312 | |||
| fc7df53aee | |||
| 0adbed8a60 | |||
| af2583c83c | |||
| 3bc9f74fe9 | |||
| f0459fc410 | |||
| 1f616ad8fa | |||
| 26080d9241 | |||
| f00e902580 | |||
| 8ad169abb4 | |||
| 86f69d98d2 | |||
| 6b0ae91930 | |||
| 0106e378f1 | |||
| 5133c78cae | |||
| 568cd51b79 | |||
| dd6e1f193e | |||
| 84d4fcc52d | |||
| c8af850479 | |||
| b3c02e210f | |||
| 84c309b6ae | |||
| ad45ed7414 | |||
| 6cb8d76ccb | |||
| eea568d68e | |||
| 3d40759803 | |||
| 32c693a6e6 | |||
| 1f28eaddc4 | |||
| 7ed103210d | |||
| 4bfd4ad9a7 | |||
| 87cd93215e | |||
| ddc2d6e8f5 | |||
| 7a4192358a | |||
| c612970c9d | |||
| e043201d3d | |||
| c55521a60b | |||
| f52bb8d385 |
+34
-7
@@ -94,6 +94,14 @@ WIN32HEAP = 0
|
||||
DEBUG = 0
|
||||
!ENDIF
|
||||
|
||||
# Enable use of available compiler optimizations? Normally, this should be
|
||||
# non-zero. Setting this to zero, thus disabling all compiler optimizations,
|
||||
# can be useful for testing.
|
||||
#
|
||||
!IFNDEF OPTIMIZATIONS
|
||||
OPTIMIZATIONS = 2
|
||||
!ENDIF
|
||||
|
||||
# Check for the predefined command macro CC. This should point to the compiler
|
||||
# binary for the target platform. If it is not defined, simply define it to
|
||||
# the legacy default value 'cl.exe'.
|
||||
@@ -343,11 +351,15 @@ TCLSH_CMD = tclsh85
|
||||
|
||||
# Compiler options needed for programs that use the readline() library.
|
||||
#
|
||||
!IFNDEF READLINE_FLAGS
|
||||
READLINE_FLAGS = -DHAVE_READLINE=0
|
||||
!ENDIF
|
||||
|
||||
# The library that programs using readline() must link against.
|
||||
#
|
||||
!IFNDEF LIBREADLINE
|
||||
LIBREADLINE =
|
||||
!ENDIF
|
||||
|
||||
# Should the database engine be compiled threadsafe
|
||||
#
|
||||
@@ -397,17 +409,30 @@ RCC = $(RCC) $(OPT_FEATURE_FLAGS)
|
||||
TCC = $(TCC) $(OPTS)
|
||||
RCC = $(RCC) $(OPTS)
|
||||
|
||||
# If symbols are enabled, enable PDBs.
|
||||
# If debugging is enabled, disable all optimizations and enable PDBs.
|
||||
# If compiling for debugging, add some defines.
|
||||
!IF $(DEBUG)>0
|
||||
TCC = $(TCC) -Od -D_DEBUG
|
||||
BCC = $(BCC) -Od -D_DEBUG
|
||||
TCC = $(TCC) -D_DEBUG
|
||||
BCC = $(BCC) -D_DEBUG
|
||||
RCC = $(RCC) -D_DEBUG
|
||||
!ELSE
|
||||
TCC = $(TCC) -O2
|
||||
BCC = $(BCC) -O2
|
||||
!ENDIF
|
||||
|
||||
# If optimizations are enabled or disabled (either implicitly or
|
||||
# explicitly), add the necessary flags.
|
||||
!IF $(DEBUG)>0 || $(OPTIMIZATIONS)==0
|
||||
TCC = $(TCC) -Od
|
||||
BCC = $(BCC) -Od
|
||||
!ELSEIF $(OPTIMIZATIONS)>=3
|
||||
TCC = $(TCC) -Ox
|
||||
BCC = $(BCC) -Ox
|
||||
!ELSEIF $(OPTIMIZATIONS)==2
|
||||
TCC = $(TCC) -O2
|
||||
BCC = $(BCC) -O2
|
||||
!ELSEIF $(OPTIMIZATIONS)==1
|
||||
TCC = $(TCC) -O1
|
||||
BCC = $(BCC) -O1
|
||||
!ENDIF
|
||||
|
||||
# If symbols are enabled (or compiling for debugging), enable PDBs.
|
||||
!IF $(DEBUG)>0 || $(SYMBOLS)!=0
|
||||
TCC = $(TCC) -Zi
|
||||
BCC = $(BCC) -Zi
|
||||
@@ -465,7 +490,9 @@ LTLIBS = $(LTLIBS) $(LIBICU)
|
||||
!ENDIF
|
||||
|
||||
# nawk compatible awk.
|
||||
!IFNDEF NAWK
|
||||
NAWK = gawk.exe
|
||||
!ENDIF
|
||||
|
||||
# You should not have to change anything below this line
|
||||
###############################################################################
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#! /bin/sh
|
||||
# Guess values for system-dependent variables and create Makefiles.
|
||||
# Generated by GNU Autoconf 2.62 for sqlite 3.8.0.
|
||||
# Generated by GNU Autoconf 2.62 for sqlite 3.8.1.
|
||||
#
|
||||
# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
|
||||
# 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
|
||||
@@ -743,8 +743,8 @@ SHELL=${CONFIG_SHELL-/bin/sh}
|
||||
# Identity of this package.
|
||||
PACKAGE_NAME='sqlite'
|
||||
PACKAGE_TARNAME='sqlite'
|
||||
PACKAGE_VERSION='3.8.0'
|
||||
PACKAGE_STRING='sqlite 3.8.0'
|
||||
PACKAGE_VERSION='3.8.1'
|
||||
PACKAGE_STRING='sqlite 3.8.1'
|
||||
PACKAGE_BUGREPORT=''
|
||||
|
||||
# Factoring default headers for most tests.
|
||||
@@ -874,7 +874,6 @@ TEMP_STORE
|
||||
BUILD_EXEEXT
|
||||
SQLITE_OS_UNIX
|
||||
SQLITE_OS_WIN
|
||||
SQLITE_OS_OS2
|
||||
TARGET_EXEEXT
|
||||
TCL_VERSION
|
||||
TCL_BIN_DIR
|
||||
@@ -1484,7 +1483,7 @@ if test "$ac_init_help" = "long"; then
|
||||
# Omit some internal or obsolete options to make the list less imposing.
|
||||
# This message is too long to be a string in the A/UX 3.1 sh.
|
||||
cat <<_ACEOF
|
||||
\`configure' configures sqlite 3.8.0 to adapt to many kinds of systems.
|
||||
\`configure' configures sqlite 3.8.1 to adapt to many kinds of systems.
|
||||
|
||||
Usage: $0 [OPTION]... [VAR=VALUE]...
|
||||
|
||||
@@ -1549,7 +1548,7 @@ fi
|
||||
|
||||
if test -n "$ac_init_help"; then
|
||||
case $ac_init_help in
|
||||
short | recursive ) echo "Configuration of sqlite 3.8.0:";;
|
||||
short | recursive ) echo "Configuration of sqlite 3.8.1:";;
|
||||
esac
|
||||
cat <<\_ACEOF
|
||||
|
||||
@@ -1665,7 +1664,7 @@ fi
|
||||
test -n "$ac_init_help" && exit $ac_status
|
||||
if $ac_init_version; then
|
||||
cat <<\_ACEOF
|
||||
sqlite configure 3.8.0
|
||||
sqlite configure 3.8.1
|
||||
generated by GNU Autoconf 2.62
|
||||
|
||||
Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
|
||||
@@ -1679,7 +1678,7 @@ cat >config.log <<_ACEOF
|
||||
This file contains any messages produced by compilers while
|
||||
running configure, to aid debugging if configure makes a mistake.
|
||||
|
||||
It was created by sqlite $as_me 3.8.0, which was
|
||||
It was created by sqlite $as_me 3.8.1, which was
|
||||
generated by GNU Autoconf 2.62. Invocation command line was
|
||||
|
||||
$ $0 $@
|
||||
@@ -3733,13 +3732,13 @@ if test "${lt_cv_nm_interface+set}" = set; then
|
||||
else
|
||||
lt_cv_nm_interface="BSD nm"
|
||||
echo "int some_variable = 0;" > conftest.$ac_ext
|
||||
(eval echo "\"\$as_me:3736: $ac_compile\"" >&5)
|
||||
(eval echo "\"\$as_me:3735: $ac_compile\"" >&5)
|
||||
(eval "$ac_compile" 2>conftest.err)
|
||||
cat conftest.err >&5
|
||||
(eval echo "\"\$as_me:3739: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
|
||||
(eval echo "\"\$as_me:3738: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
|
||||
(eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
|
||||
cat conftest.err >&5
|
||||
(eval echo "\"\$as_me:3742: output\"" >&5)
|
||||
(eval echo "\"\$as_me:3741: output\"" >&5)
|
||||
cat conftest.out >&5
|
||||
if $GREP 'External.*some_variable' conftest.out > /dev/null; then
|
||||
lt_cv_nm_interface="MS dumpbin"
|
||||
@@ -4961,7 +4960,7 @@ ia64-*-hpux*)
|
||||
;;
|
||||
*-*-irix6*)
|
||||
# Find out which ABI we are using.
|
||||
echo '#line 4964 "configure"' > conftest.$ac_ext
|
||||
echo '#line 4963 "configure"' > conftest.$ac_ext
|
||||
if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
|
||||
(eval $ac_compile) 2>&5
|
||||
ac_status=$?
|
||||
@@ -6830,11 +6829,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:6833: $lt_compile\"" >&5)
|
||||
(eval echo "\"\$as_me:6832: $lt_compile\"" >&5)
|
||||
(eval "$lt_compile" 2>conftest.err)
|
||||
ac_status=$?
|
||||
cat conftest.err >&5
|
||||
echo "$as_me:6837: \$? = $ac_status" >&5
|
||||
echo "$as_me:6836: \$? = $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.
|
||||
@@ -7169,11 +7168,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:7172: $lt_compile\"" >&5)
|
||||
(eval echo "\"\$as_me:7171: $lt_compile\"" >&5)
|
||||
(eval "$lt_compile" 2>conftest.err)
|
||||
ac_status=$?
|
||||
cat conftest.err >&5
|
||||
echo "$as_me:7176: \$? = $ac_status" >&5
|
||||
echo "$as_me:7175: \$? = $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.
|
||||
@@ -7274,11 +7273,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:7277: $lt_compile\"" >&5)
|
||||
(eval echo "\"\$as_me:7276: $lt_compile\"" >&5)
|
||||
(eval "$lt_compile" 2>out/conftest.err)
|
||||
ac_status=$?
|
||||
cat out/conftest.err >&5
|
||||
echo "$as_me:7281: \$? = $ac_status" >&5
|
||||
echo "$as_me:7280: \$? = $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
|
||||
@@ -7329,11 +7328,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:7332: $lt_compile\"" >&5)
|
||||
(eval echo "\"\$as_me:7331: $lt_compile\"" >&5)
|
||||
(eval "$lt_compile" 2>out/conftest.err)
|
||||
ac_status=$?
|
||||
cat out/conftest.err >&5
|
||||
echo "$as_me:7336: \$? = $ac_status" >&5
|
||||
echo "$as_me:7335: \$? = $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
|
||||
@@ -10142,7 +10141,7 @@ else
|
||||
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
|
||||
lt_status=$lt_dlunknown
|
||||
cat > conftest.$ac_ext <<_LT_EOF
|
||||
#line 10145 "configure"
|
||||
#line 10144 "configure"
|
||||
#include "confdefs.h"
|
||||
|
||||
#if HAVE_DLFCN_H
|
||||
@@ -10238,7 +10237,7 @@ else
|
||||
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
|
||||
lt_status=$lt_dlunknown
|
||||
cat > conftest.$ac_ext <<_LT_EOF
|
||||
#line 10241 "configure"
|
||||
#line 10240 "configure"
|
||||
#include "confdefs.h"
|
||||
|
||||
#if HAVE_DLFCN_H
|
||||
@@ -12257,7 +12256,7 @@ USE_AMALGAMATION=1
|
||||
# if not, then we fall back to plain tclsh.
|
||||
# TODO: try other versions before falling back?
|
||||
#
|
||||
for ac_prog in tclsh8.5 tclsh
|
||||
for ac_prog in tclsh8.6 tclsh8.5 tclsh
|
||||
do
|
||||
# Extract the first word of "$ac_prog", so it can be a program name with args.
|
||||
set dummy $ac_prog; ac_word=$2
|
||||
@@ -12713,21 +12712,12 @@ else
|
||||
TARGET_EXEEXT=$config_TARGET_EXEEXT
|
||||
fi
|
||||
if test "$TARGET_EXEEXT" = ".exe"; then
|
||||
if test $OS2_SHELL ; then
|
||||
SQLITE_OS_UNIX=0
|
||||
SQLITE_OS_WIN=0
|
||||
SQLITE_OS_OS2=1
|
||||
CFLAGS="$CFLAGS -DSQLITE_OS_OS2=1"
|
||||
else
|
||||
SQLITE_OS_UNIX=0
|
||||
SQLITE_OS_WIN=1
|
||||
SQLITE_OS_OS2=0
|
||||
CFLAGS="$CFLAGS -DSQLITE_OS_WIN=1"
|
||||
fi
|
||||
SQLITE_OS_UNIX=0
|
||||
SQLITE_OS_WIN=1
|
||||
CFLAGS="$CFLAGS -DSQLITE_OS_WIN=1"
|
||||
else
|
||||
SQLITE_OS_UNIX=1
|
||||
SQLITE_OS_WIN=0
|
||||
SQLITE_OS_OS2=0
|
||||
CFLAGS="$CFLAGS -DSQLITE_OS_UNIX=1"
|
||||
fi
|
||||
|
||||
@@ -12736,7 +12726,6 @@ fi
|
||||
|
||||
|
||||
|
||||
|
||||
##########
|
||||
# Figure out all the parameters needed to compile against Tcl.
|
||||
#
|
||||
@@ -14032,7 +14021,7 @@ exec 6>&1
|
||||
# report actual input values of CONFIG_FILES etc. instead of their
|
||||
# values after options handling.
|
||||
ac_log="
|
||||
This file was extended by sqlite $as_me 3.8.0, which was
|
||||
This file was extended by sqlite $as_me 3.8.1, which was
|
||||
generated by GNU Autoconf 2.62. Invocation command line was
|
||||
|
||||
CONFIG_FILES = $CONFIG_FILES
|
||||
@@ -14085,7 +14074,7 @@ Report bugs to <bug-autoconf@gnu.org>."
|
||||
_ACEOF
|
||||
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
|
||||
ac_cs_version="\\
|
||||
sqlite config.status 3.8.0
|
||||
sqlite config.status 3.8.1
|
||||
configured by $0, generated by GNU Autoconf 2.62,
|
||||
with options \\"`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"
|
||||
|
||||
|
||||
+4
-14
@@ -139,7 +139,7 @@ USE_AMALGAMATION=1
|
||||
# if not, then we fall back to plain tclsh.
|
||||
# TODO: try other versions before falling back?
|
||||
#
|
||||
AC_CHECK_PROGS(TCLSH_CMD, [tclsh8.5 tclsh], none)
|
||||
AC_CHECK_PROGS(TCLSH_CMD, [tclsh8.6 tclsh8.5 tclsh], none)
|
||||
if test "$TCLSH_CMD" = "none"; then
|
||||
# If we can't find a local tclsh, then building the amalgamation will fail.
|
||||
# We act as though --disable-amalgamation has been used.
|
||||
@@ -340,28 +340,18 @@ else
|
||||
TARGET_EXEEXT=$config_TARGET_EXEEXT
|
||||
fi
|
||||
if test "$TARGET_EXEEXT" = ".exe"; then
|
||||
if test $OS2_SHELL ; then
|
||||
SQLITE_OS_UNIX=0
|
||||
SQLITE_OS_WIN=0
|
||||
SQLITE_OS_OS2=1
|
||||
CFLAGS="$CFLAGS -DSQLITE_OS_OS2=1"
|
||||
else
|
||||
SQLITE_OS_UNIX=0
|
||||
SQLITE_OS_WIN=1
|
||||
SQLITE_OS_OS2=0
|
||||
CFLAGS="$CFLAGS -DSQLITE_OS_WIN=1"
|
||||
fi
|
||||
SQLITE_OS_UNIX=0
|
||||
SQLITE_OS_WIN=1
|
||||
CFLAGS="$CFLAGS -DSQLITE_OS_WIN=1"
|
||||
else
|
||||
SQLITE_OS_UNIX=1
|
||||
SQLITE_OS_WIN=0
|
||||
SQLITE_OS_OS2=0
|
||||
CFLAGS="$CFLAGS -DSQLITE_OS_UNIX=1"
|
||||
fi
|
||||
|
||||
AC_SUBST(BUILD_EXEEXT)
|
||||
AC_SUBST(SQLITE_OS_UNIX)
|
||||
AC_SUBST(SQLITE_OS_WIN)
|
||||
AC_SUBST(SQLITE_OS_OS2)
|
||||
AC_SUBST(TARGET_EXEEXT)
|
||||
|
||||
##########
|
||||
|
||||
@@ -504,6 +504,7 @@ static int fts3StringAppend(
|
||||
pStr->z = zNew;
|
||||
pStr->nAlloc = nAlloc;
|
||||
}
|
||||
assert( pStr->z!=0 && (pStr->nAlloc >= pStr->n+nAppend+1) );
|
||||
|
||||
/* Append the data to the string buffer. */
|
||||
memcpy(&pStr->z[pStr->n], zAppend, nAppend);
|
||||
|
||||
@@ -1461,7 +1461,7 @@ static int fts3SegReaderNextDocid(
|
||||
/* The following line of code (and the "p++" below the while() loop) is
|
||||
** normally all that is required to move pointer p to the desired
|
||||
** position. The exception is if this node is being loaded from disk
|
||||
** incrementally and pointer "p" now points to the first byte passed
|
||||
** incrementally and pointer "p" now points to the first byte past
|
||||
** the populated part of pReader->aNode[].
|
||||
*/
|
||||
while( *p | c ) c = *p++ & 0x80;
|
||||
@@ -2848,8 +2848,8 @@ int sqlite3Fts3SegReaderStep(
|
||||
fts3SegReaderSort(apSegment, nMerge, nMerge, xCmp);
|
||||
while( apSegment[0]->pOffsetList ){
|
||||
int j; /* Number of segments that share a docid */
|
||||
char *pList;
|
||||
int nList;
|
||||
char *pList = 0;
|
||||
int nList = 0;
|
||||
int nByte;
|
||||
sqlite3_int64 iDocid = apSegment[0]->iDocid;
|
||||
fts3SegReaderNextDocid(p, apSegment[0], &pList, &nList);
|
||||
@@ -5135,11 +5135,11 @@ int sqlite3Fts3CacheDeferredDoclists(Fts3Cursor *pCsr){
|
||||
if( pTC ) pModule->xClose(pTC);
|
||||
if( rc==SQLITE_DONE ) rc = SQLITE_OK;
|
||||
}
|
||||
}
|
||||
|
||||
for(pDef=pCsr->pDeferred; pDef && rc==SQLITE_OK; pDef=pDef->pNext){
|
||||
if( pDef->pList ){
|
||||
rc = fts3PendingListAppendVarint(&pDef->pList, 0);
|
||||
}
|
||||
for(pDef=pCsr->pDeferred; pDef && rc==SQLITE_OK; pDef=pDef->pNext){
|
||||
if( pDef->pList ){
|
||||
rc = fts3PendingListAppendVarint(&pDef->pList, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
C Make\sit\seasy\sto\sattach\sa\sdebugger\sthe\stest\sfixture\sprocess\sprior\sto\sany\stests\sbeing\srun.
|
||||
D 2013-08-15T08:06:15.562
|
||||
C Increase\sthe\snumber\sof\sbits\savailable\sin\sExpr.flags.\s\sOther\stweaks\saimed\sat\nmaking\sexpression\sprocessing\smore\srobust.
|
||||
D 2013-09-12T16:50:49.178
|
||||
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
||||
F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e
|
||||
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
||||
F Makefile.msc e9f41f89111627baaabd95cab4988b8d1c3e47c9
|
||||
F Makefile.msc a97163524522cd829cb91bcf900d07608e025502
|
||||
F Makefile.vxworks db21ed42a01d5740e656b16f92cb5d8d5e5dd315
|
||||
F README cd04a36fbc7ea56932a4052d7d0b7f09f27c33d6
|
||||
F VERSION f135b651727f978b7191bd6fa12c7fc1e13e13ac
|
||||
F VERSION a8d1f6839521130dc73c5408cdd24bcfd791df34
|
||||
F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50
|
||||
F addopcodes.awk 17dc593f791f874d2c23a0f9360850ded0286531
|
||||
F art/sqlite370.eps aa97a671332b432a54e1d74ff5e8775be34200c2
|
||||
@@ -38,8 +38,8 @@ F autoconf/tea/win/rules.vc c511f222b80064096b705dbeb97060ee1d6b6d63
|
||||
F config.guess 226d9a188c6196f3033ffc651cbc9dcee1a42977
|
||||
F config.h.in 0921066a13130082764ab4ab6456f7b5bebe56de
|
||||
F config.sub 9ebe4c3b3dab6431ece34f16828b594fb420da55
|
||||
F configure 27e9279a219b652bd1c53439353a5e5be70214b2 x
|
||||
F configure.ac 81c43d151d0b0e406be056394cc9ff4cb3fd0444
|
||||
F configure d9bb8485d40dd905e09c895692a0699628abace8 x
|
||||
F configure.ac 4cf9f60785143fa141b10962ccc885d973792e9a
|
||||
F contrib/sqlitecon.tcl 210a913ad63f9f991070821e599d600bd913e0ad
|
||||
F doc/lemon.html 334dbf6621b8fb8790297ec1abf3cfa4621709d1
|
||||
F doc/pager-invariants.txt 27fed9a70ddad2088750c4a2b493b63853da2710
|
||||
@@ -87,7 +87,7 @@ F ext/fts3/fts3_hash.c 8dd2d06b66c72c628c2732555a32bc0943114914
|
||||
F ext/fts3/fts3_hash.h 39cf6874dc239d6b4e30479b1975fe5b22a3caaf
|
||||
F ext/fts3/fts3_icu.c e319e108661147bcca8dd511cd562f33a1ba81b5
|
||||
F ext/fts3/fts3_porter.c a465b49fcb8249a755792f87516eff182efa42b3
|
||||
F ext/fts3/fts3_snippet.c 5fcfcafff46a2a3a63b8e59fcb51987d01c74695
|
||||
F ext/fts3/fts3_snippet.c e8ee8c101dd9cfbc9568d134e869d2bd2f7f6d4d
|
||||
F ext/fts3/fts3_term.c a521f75132f9a495bdca1bdd45949b3191c52763
|
||||
F ext/fts3/fts3_test.c f9a1a1702db1bfad3e2d0064746eeb808f125489
|
||||
F ext/fts3/fts3_tokenize_vtab.c 011170fe9eba5ff062f1a31d3188e00267716706
|
||||
@@ -96,7 +96,7 @@ F ext/fts3/fts3_tokenizer.h 64c6ef6c5272c51ebe60fc607a896e84288fcbc3
|
||||
F ext/fts3/fts3_tokenizer1.c 5c98225a53705e5ee34824087478cf477bdb7004
|
||||
F ext/fts3/fts3_unicode.c 92391b4b4fb043564c6539ea9b8661e3bcba47b9
|
||||
F ext/fts3/fts3_unicode2.c 0113d3acf13429e6dc38e0647d1bc71211c31a4d
|
||||
F ext/fts3/fts3_write.c cd264daa4f92b8eb6d61245333d0e3b147e8fd80
|
||||
F ext/fts3/fts3_write.c ce45c3ea578464f26b0293ea8e54a39694f18b64
|
||||
F ext/fts3/fts3speed.tcl b54caf6a18d38174f1a6e84219950d85e98bb1e9
|
||||
F ext/fts3/mkfts3amal.tcl 252ecb7fe6467854f2aa237bf2c390b74e71f100
|
||||
F ext/fts3/tool/fts3view.c 6cfc5b67a5f0e09c0d698f9fd012c784bfaa9197
|
||||
@@ -155,41 +155,41 @@ F mptest/multiwrite01.test 499ad0310da8dff8e8f98d2e272fc2a8aa741b2e
|
||||
F spec.template 86a4a43b99ebb3e75e6b9a735d5fd293a24e90ca
|
||||
F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
|
||||
F sqlite3.1 6be1ad09113570e1fc8dcaff84c9b0b337db5ffc
|
||||
F sqlite3.pc.in ae6f59a76e862f5c561eb32a380228a02afc3cad
|
||||
F src/alter.c f8db986c03eb0bfb221523fc9bbb9d0b70de3168
|
||||
F src/analyze.c a33fcb0b3a399d966951feb9f32115106b3ecc2e
|
||||
F src/attach.c 1816f5a9eea8d2010fc2b22b44f0f63eb3a62704
|
||||
F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a
|
||||
F src/alter.c 2af0330bb1b601af7a7789bf7229675fd772a083
|
||||
F src/analyze.c d322972af09e3f8debb45f420dfe3ded142b108b
|
||||
F src/attach.c 4a2b6a6d9b5f9fd55a8b59488ff7929fef73a195
|
||||
F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34
|
||||
F src/backup.c 43b348822db3e4cef48b2ae5a445fbeb6c73a165
|
||||
F src/backup.c 2f1987981139bd2f6d8c728d64bf09fb387443c3
|
||||
F src/bitvec.c 19a4ba637bd85f8f63fc8c9bae5ade9fb05ec1cb
|
||||
F src/btmutex.c 976f45a12e37293e32cae0281b15a21d48a8aaa7
|
||||
F src/btree.c 3f7bbfd72efb1cbf6a49515c376a031767ec930a
|
||||
F src/btree.h 6fa8a3ff2483d0bb64a9f0105a8cedeac9e00cca
|
||||
F src/btreeInt.h eecc84f02375b2bb7a44abbcbbe3747dde73edb2
|
||||
F src/build.c cee4724668ebc09bb482c1be30f96e0ae2474f9b
|
||||
F src/callback.c d7e46f40c3cf53c43550b7da7a1d0479910b62cc
|
||||
F src/btree.c b9b57df546df2636294bfb21a986f5707b417df2
|
||||
F src/btree.h bfe0e8c5759b4ec77b0d18390064a6ef3cdffaaf
|
||||
F src/btreeInt.h 51cf220a9b9223354770883e93a859dc377aa27f
|
||||
F src/build.c f63e8929c7f89c0074fbc74929bc946ea117b2f8
|
||||
F src/callback.c f99a8957ba2adf369645fac0db09ad8adcf1caa2
|
||||
F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac
|
||||
F src/ctime.c 4262c227bc91cecc61ae37ed3a40f08069cfa267
|
||||
F src/ctime.c ea4b7f3623a0fcb1146e7f245d7410033e86859c
|
||||
F src/date.c 067a81c9942c497aafd2c260e13add8a7d0c7dd4
|
||||
F src/delete.c 2317c814866d9aa71fea16b3faf4fdd4d6a49b94
|
||||
F src/expr.c 0bbb44462a19169189b2709fbbd800950521b5ae
|
||||
F src/delete.c 2dc64ca360b7d7da481183ea920a813a0c203c97
|
||||
F src/expr.c 7f93e51fd7ca0d3ea1be2715a29c86a69e7b1e93
|
||||
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
|
||||
F src/fkey.c 914a6bbd987d857c41ac9d244efa6641f36faadb
|
||||
F src/func.c 5c50c1ea31fd864b0fe921fe1a8d4c55acd609ef
|
||||
F src/fkey.c be866cd8c4fa6cae98ba33109578fd1a3311ee5b
|
||||
F src/func.c 7650d35651bb0ca903d24f4e5e944bfdaac9f152
|
||||
F src/global.c 5caf4deab621abb45b4c607aad1bd21c20aac759
|
||||
F src/hash.c ac3470bbf1ca4ae4e306a8ecb0fdf1731810ffe4
|
||||
F src/hash.h 8890a25af81fb85a9ad7790d32eedab4b994da22
|
||||
F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08
|
||||
F src/insert.c a66bcdc956145369c1a876709f47f69476973e15
|
||||
F src/insert.c a271771db927873c850da8928d6ee9fc058fb9fe
|
||||
F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d
|
||||
F src/legacy.c 0df0b1550b9cc1f58229644735e317ac89131f12
|
||||
F src/lempar.c cdf0a000315332fc9b50b62f3b5e22e080a0952b
|
||||
F src/loadext.c 867c7b330b740c6c917af9956b13b81d0a048303
|
||||
F src/main.c 4e4cd5c2ee09db496c0dde79b507bba6b8bcbdcb
|
||||
F src/main.c 35931467ec026b05babb279cb8a573e62f6fe1a3
|
||||
F src/malloc.c fe085aa851b666b7c375c1ff957643dc20a04bf6
|
||||
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
|
||||
F src/mem1.c 437c7c4af964895d4650f29881df63535caaa1fa
|
||||
F src/mem2.c e307323e86b5da1853d7111b68fd6b84ad6f09cf
|
||||
F src/mem2.c dce31758da87ec2cfa52ba4c5df1aed6e07d8e8f
|
||||
F src/mem3.c 61c9d47b792908c532ca3a62b999cf21795c6534
|
||||
F src/mem5.c 0025308a93838022bd5696cf9627ff4e40b19918
|
||||
F src/memjournal.c 0683aac6cab6ec2b5374c0db37c0deb2436a3785
|
||||
@@ -197,36 +197,36 @@ F src/mutex.c d3b66a569368015e0fcb1ac15f81c119f504d3bc
|
||||
F src/mutex.h 5bc526e19dccc412b7ff04642f6fdad3fdfdabea
|
||||
F src/mutex_noop.c 7682796b7d8d39bf1c138248858efcd10c9e1553
|
||||
F src/mutex_unix.c c3a4e00f96ba068a8dbef34084465979aaf369cc
|
||||
F src/mutex_w32.c 32a9b3841e2d757355f0012b860b1bc5e01eafa0
|
||||
F src/mutex_w32.c 6108c88e1cb38d8fbb3534b170793815cbedbf97
|
||||
F src/notify.c 976dd0f6171d4588e89e874fcc765e92914b6d30
|
||||
F src/os.c b4ad71336fd96f97776f75587cd9e8218288f5be
|
||||
F src/os.h 4a46270a64e9193af4a0aaa3bc2c66dc07c29b3f
|
||||
F src/os_common.h 92815ed65f805560b66166e3583470ff94478f04
|
||||
F src/os_unix.c 9eafa5458cf2ff684ddccff82c9bb113c7cad847
|
||||
F src/os_win.c 1d84f2079d9b91f91a4b5dbfa5e08f1b1a0ed0ff
|
||||
F src/pager.c 5d2f7475260a8588f9c441bb309d2b7eaa7ded3b
|
||||
F src/pager.h 5cb78b8e1adfd5451e600be7719f5a99d87ac3b1
|
||||
F src/parse.y 27c6b4138497d6f8360ba7847da6ed48033f957f
|
||||
F src/os_unix.c 243fb37f47dc072fc59839ea241ff0a17c8d76e6
|
||||
F src/os_win.c 0e73f891dd806b82a76d4e19179c532f02236b86
|
||||
F src/pager.c 2aa4444ffe86e9282d03bc349a4a5e49bd77c0e8
|
||||
F src/pager.h f094af9f6ececfaa8a1e93876905a4f34233fb0c
|
||||
F src/parse.y a97566d6da75075589a7c716d1bda14b586cf8da
|
||||
F src/pcache.c f8043b433a57aba85384a531e3937a804432a346
|
||||
F src/pcache.h a5e4f5d9f5d592051d91212c5949517971ae6222
|
||||
F src/pcache1.c d23d07716de96c7c0c2503ec5051a4384c3fb938
|
||||
F src/pragma.c 590c75750d93ec5a1f903e4bb0dc6d2a0845bf8b
|
||||
F src/pcache1.c a467393909a4ed7ca9de066d85ba5c5b04a5be63
|
||||
F src/pragma.c 3aa3d8c8623b7b71c5b1bfb72dcc31fb0c25665f
|
||||
F src/prepare.c fa6988589f39af8504a61731614cd4f6ae71554f
|
||||
F src/printf.c 41c49dac366a3a411190001a8ab495fa8887974e
|
||||
F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50
|
||||
F src/resolve.c 17e670996729ac41aadf6a31f57b4e6f29b3d819
|
||||
F src/printf.c da9119eb31a187a4b99f60aa4a225141c0ebb74b
|
||||
F src/random.c 0b2dbc37fdfbfa6bd455b091dfcef5bdb32dba68
|
||||
F src/resolve.c d336be12493bb376c6756c214379c727cd8c01a8
|
||||
F src/rowset.c 64655f1a627c9c212d9ab497899e7424a34222e0
|
||||
F src/select.c 8b148eb851f384412aea57091659d14b369918ca
|
||||
F src/shell.c 927e17b37b63b24461e372d982138fb22c4df321
|
||||
F src/sqlite.h.in bd1451ba1ab681022a53bccc3c39580ba094a3ff
|
||||
F src/select.c d96bcdbc2e7de89cb72febeccd232746f67839fd
|
||||
F src/shell.c d920a891ca09b8bd262cced7fb0ab9d723f7a747
|
||||
F src/sqlite.h.in ec40aa958a270416fb04b4f72210357bf163d2c5
|
||||
F src/sqlite3.rc fea433eb0a59f4c9393c8e6d76a6e2596b1fe0c0
|
||||
F src/sqlite3ext.h 886f5a34de171002ad46fae8c36a7d8051c190fc
|
||||
F src/sqliteInt.h def0e436c0d4ca5084305ca6ae898020fbafaae4
|
||||
F src/sqliteInt.h e4cb0c8700ca77889570bf30cf75a5c56f297615
|
||||
F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
|
||||
F src/status.c 7ac05a5c7017d0b9f0b4bcd701228b784f987158
|
||||
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
|
||||
F src/tclsqlite.c 659dad8ef30b54831306a244b43e37af4725a444
|
||||
F src/test1.c 870fc648a48cb6d6808393174f7ebe82b8c840fa
|
||||
F src/test1.c 26226cfd2b6dc3f77d2eb27f07ffcf236b4e728b
|
||||
F src/test2.c 7355101c085304b90024f2261e056cdff13c6c35
|
||||
F src/test3.c 1c0e5d6f080b8e33c1ce8b3078e7013fdbcd560c
|
||||
F src/test4.c 9b32d22f5f150abe23c1830e2057c4037c45b3df
|
||||
@@ -239,18 +239,18 @@ F src/test_async.c 21e11293a2f72080eda70e1124e9102044531cd8
|
||||
F src/test_autoext.c dea8a01a7153b9adc97bd26161e4226329546e12
|
||||
F src/test_backup.c 3875e899222b651e18b662f86e0e50daa946344e
|
||||
F src/test_btree.c 5b89601dcb42a33ba8b820a6b763cc9cb48bac16
|
||||
F src/test_config.c 95bb33e9dcaa340a296c0bf0e0ba3d1a1c8004c0
|
||||
F src/test_config.c 3d148e338b575bd937f7746824f36a9c6682d238
|
||||
F src/test_demovfs.c 69b2085076654ebc18014cbc6386f04409c959a9
|
||||
F src/test_devsym.c e7498904e72ba7491d142d5c83b476c4e76993bc
|
||||
F src/test_fs.c ced436e3d4b8e4681328409b8081051ce614e28f
|
||||
F src/test_func.c 3a8dd37c08ab43b76d38eea2836e34a3897bf170
|
||||
F src/test_func.c f8235719dff4bf9ffee04c55a190af8782ce9ab5
|
||||
F src/test_hexio.c abfdecb6fa58c354623978efceb088ca18e379cd
|
||||
F src/test_init.c 3cbad7ce525aec925f8fda2192d576d47f0d478a
|
||||
F src/test_intarray.c 87847c71c3c36889c0bcc9c4baf9d31881665d61
|
||||
F src/test_intarray.h 2ece66438cfd177b78d1bfda7a4180cd3a10844d
|
||||
F src/test_journal.c f5c0a05b7b3d5930db769b5ee6c3766dc2221a64
|
||||
F src/test_loadext.c df586c27176e3c2cb2e099c78da67bf14379a56e
|
||||
F src/test_malloc.c a105801222c0514f8befa2a1712a95505cce099a
|
||||
F src/test_malloc.c eba4e1c5847cc98e7edc98f62265cd2abafba7a6
|
||||
F src/test_multiplex.c 5d691eeb6cb6aa7888da28eba5e62a9a857d3c0f
|
||||
F src/test_multiplex.h 110a8c4d356e0aa464ca8730375608a9a0b61ae1
|
||||
F src/test_mutex.c 293042d623ebba969160f471a82aa1551626454f
|
||||
@@ -273,41 +273,44 @@ F src/test_vfstrace.c 34b544e80ba7fb77be15395a609c669df2e660a2
|
||||
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
|
||||
F src/tokenize.c 70061085a51f2f4fc15ece94f32c03bcb78e63b2
|
||||
F src/trigger.c 5c0ea9b8755e7c5e1a700f3e27ac4f8d92dd221e
|
||||
F src/update.c 7f3fe64d8f3b44c44a1eac293f0f85f87c355b7a
|
||||
F src/utf.c 8d819e2e5104a430fc2005f018db14347c95a38f
|
||||
F src/update.c f5182157f5d0d0a97bc5f5e3c9bdba0dfbe08f08
|
||||
F src/utf.c 6fc6c88d50448c469c5c196acf21617a24f90269
|
||||
F src/util.c f566b5138099a2df8533b190d0dcc74b7dfbe0c9
|
||||
F src/vacuum.c d9c5759f4c5a438bb43c2086f72c5d2edabc36c8
|
||||
F src/vdbe.c 4914ae1d00045a5310aea9e0f7c9a8edd3d9f856
|
||||
F src/vdbe.c a393a94c0d77b86c7c4ad2cfb43ec4ba278d9596
|
||||
F src/vdbe.h 4f554b5627f26710c4c36d919110a3fc611ca5c4
|
||||
F src/vdbeInt.h e9b7c6b165a31a4715c5aa97223d20d265515231
|
||||
F src/vdbeapi.c 4d13580bd058b39623e8fcfc233b7df4b8191e8b
|
||||
F src/vdbeaux.c a6ea36a9dc714e1128a0173249a0532ddcab0489
|
||||
F src/vdbeInt.h cbe71b8b36d8b3bba5709cc3f436c7e3b47b7b08
|
||||
F src/vdbeapi.c 96b24b946cf21894f63d9393e821baa2f0a80979
|
||||
F src/vdbeaux.c 88beca92f2ed0bbe2c6f87946d0e999a6807ea1b
|
||||
F src/vdbeblob.c 5dc79627775bd9a9b494dd956e26297946417d69
|
||||
F src/vdbemem.c 833005f1cbbf447289f1973dba2a0c2228c7b8ab
|
||||
F src/vdbemem.c 817ce21ab4ca57f902619bb8fef3f8a51bbd0ed8
|
||||
F src/vdbesort.c 3937e06b2a0e354500e17dc206ef4c35770a5017
|
||||
F src/vdbetrace.c e7ec40e1999ff3c6414424365d5941178966dcbc
|
||||
F src/vtab.c 2e8b489db47e20ae36cd247932dc671c9ded0624
|
||||
F src/vtab.c 5a423b042eb1402ef77697d03d6a67378d97bc8d
|
||||
F src/wal.c 7dc3966ef98b74422267e7e6e46e07ff6c6eb1b4
|
||||
F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4
|
||||
F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73
|
||||
F src/where.c ea01a52eb31e54dda97b8e39c2e5b38faa13dce5
|
||||
F src/walker.c e9e593d5bb798c3e67fc3893dfe7055c9e7d8d74
|
||||
F src/where.c b5d59b899b85aa03800905ecdc0a17565d51a6ab
|
||||
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
|
||||
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
|
||||
F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6
|
||||
F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87
|
||||
F test/all.test 6ff7b43c2b4b905c74dc4a813d201d0fa64c5783
|
||||
F test/alter.test 57d96ec9b320bd07af77567034488dcb6642c748
|
||||
F test/alter.test 775a1dded3f8247983c9a3e767b011d9a5114442
|
||||
F test/alter2.test 7ea05c7d92ac99349a802ef7ada17294dd647060
|
||||
F test/alter3.test 49c9d9fba2b8fcdce2dedeca97bbf1f369cc548d
|
||||
F test/alter4.test b2debc14d8cbe4c1d12ccd6a41eef88a8c1f15d5
|
||||
F test/alter4.test 8e93bf7a7e6919b14b0c9a6c1e4908bcf21b0165
|
||||
F test/altermalloc.test e81ac9657ed25c6c5bb09bebfa5a047cd8e4acfc
|
||||
F test/analyze.test f8ab7d15858b4093b06caf5e57e2a5ff7104bdae
|
||||
F test/analyze3.test 53cfd07625d110e70b92b57a6ff656ea844dfbee
|
||||
F test/analyze.test 1772936d66471c65221e437b6d1999c3a03166c4
|
||||
F test/analyze3.test 412f690dfe95b337475e3e78a84a85d25f6f125d
|
||||
F test/analyze4.test eff2df19b8dd84529966420f29ea52edc6b56213
|
||||
F test/analyze5.test 3e57f192307be931f9ab2f6ff456f9063358ac77
|
||||
F test/analyze6.test cdbf9887d40ab41301f570fe85c6e1525dd3b1c9
|
||||
F test/analyze7.test 7de3ab66e1981303e783102a012d62cb876bf1d5
|
||||
F test/analyze8.test ea4972c76820ac8d6a0754e6f5b851292f0f5a61
|
||||
F test/analyze5.test 765c4e284aa69ca172772aa940946f55629bc8c4
|
||||
F test/analyze6.test 19151da2c4e918905d2081b74ac5c4d47fc850ab
|
||||
F test/analyze7.test bb1409afc9e8629e414387ef048b8e0e3e0bdc4f
|
||||
F test/analyze8.test 093d15c1c888eed5034304a98c992f7360130b88
|
||||
F test/analyze9.test ed70f0c10502f6bcd6e1ec347edc3c0e114f4b53
|
||||
F test/analyzeA.test 1a5c40079894847976d983ca39c707aaa44b6944
|
||||
F test/analyzeB.test 8bf35ee0a548aea831bf56762cb8e7fdb1db083d
|
||||
F test/async.test 1d0e056ba1bb9729283a0f22718d3a25e82c277b
|
||||
F test/async2.test c0a9bd20816d7d6a2ceca7b8c03d3d69c28ffb8b
|
||||
F test/async3.test d73a062002376d7edc1fe3edff493edbec1fc2f7
|
||||
@@ -319,7 +322,7 @@ F test/attach2.test e54436ed956d3d88bdee61221da59bf3935a0966
|
||||
F test/attach3.test d89ccfe4fe6e2b5e368d480fcdfe4b496c54cf4e
|
||||
F test/attach4.test 53bf502f17647c6d6c5add46dda6bac8b6f4665c
|
||||
F test/attachmalloc.test 3a4bfca9545bfe906a8d2e622de10fbac5b711b0
|
||||
F test/auth.test 4a4c3b034fff7750513520defa910f376c96ab49
|
||||
F test/auth.test 9bea29041871807d9f289ee679d05d3ed103642f
|
||||
F test/auth2.test a2a371aa6df15f8b0c8109b33d3d7f0f73e4c9aa
|
||||
F test/auth3.test a4755e6a2a2fea547ffe63c874eb569e60a28eb5
|
||||
F test/autoinc.test bd30d372d00045252f6c2e41b5f41455e1975acf
|
||||
@@ -367,7 +370,7 @@ F test/close.test 340bd24cc58b16c6bc01967402755027c37eb815
|
||||
F test/closure01.test dbb28f1ea9eeaf0a53ec5bc0fed352e479def8c7
|
||||
F test/coalesce.test cee0dccb9fbd2d494b77234bccf9dc6c6786eb91
|
||||
F test/collate1.test b709989e6e6ff6e1d2bd64231c2c1d8146846c9e
|
||||
F test/collate2.test 285cef1b58ce2b3cf074a386f763ce753c81c97f
|
||||
F test/collate2.test 9aaa410a00734e48bcb27f3872617d6f69b2a621
|
||||
F test/collate3.test 79558a286362cb9ed603c6fa543f1cda7f563f0f
|
||||
F test/collate4.test 031f7265c13308b724ba3c49f41cc04612bd92b1
|
||||
F test/collate5.test 65d928034d30d2d263a80f6359f7549ee1598ec6
|
||||
@@ -395,7 +398,7 @@ F test/corruptC.test 62a767fe64acb1975f58cc6171192839c783edbb
|
||||
F test/corruptD.test 3b09903a2e2fe07ecafe775fea94177f8a4bb34f
|
||||
F test/corruptE.test d3a3d7e864a95978195741744dda4abfd8286018
|
||||
F test/corruptF.test 1c7b6f77cf3f237fb7fbb5b61d6c921fd4c7b993
|
||||
F test/corruptG.test d18ee5169e10a76bccb7b115e551bc31087a525e
|
||||
F test/corruptG.test c67fd860e9e3943bc90b856a3049c9a28827167e
|
||||
F test/count.test 454e1ce985c94d13efeac405ce54439f49336163
|
||||
F test/coveridxscan.test cdb47d01acc4a634a34fd25abe85189e0d0f1e62
|
||||
F test/crash.test fb9dc4a02dcba30d4aa5c2c226f98b220b2b959f
|
||||
@@ -411,7 +414,7 @@ F test/createtab.test b5de160630b209c4b8925bdcbbaf48cc90b67fe8
|
||||
F test/cse.test 277350a26264495e86b1785f34d2d0c8600e021c
|
||||
F test/ctime.test 7bd009071e242aac4f18521581536b652b789a47
|
||||
F test/date.test f3228180c87bbe5d39c9397bf001c0095c3821b9
|
||||
F test/dbstatus.test 207e5b63fcb7b9c3bb8e1fdf38ebd4654ad0e54b
|
||||
F test/dbstatus.test aee30c3f337e6c217ff06df59fb8fe6e6448dce2
|
||||
F test/dbstatus2.test 10418e62b3db5dca070f0c3eef3ea13946f339c2
|
||||
F test/default.test 6faf23ccb300114924353007795aa9a8ec0aa9dc
|
||||
F test/delete.test a065b05d2ebf60fd16639c579a4adfb7c381c701
|
||||
@@ -430,7 +433,7 @@ F test/e_dropview.test 0c9f7f60989164a70a67a9d9c26d1083bc808306
|
||||
F test/e_expr.test d5cdda0e4ffb17760858ed4c7c4ece07efc40f71
|
||||
F test/e_fkey.test 17cfb40002d165299681f39aac0cb5890c359935
|
||||
F test/e_fts3.test 5c02288842e4f941896fd44afdef564dd5fc1459
|
||||
F test/e_insert.test ea84688f3b27a6a3728e4ae7a7d9ad342579d7a4
|
||||
F test/e_insert.test 291e056e1a442a5e5166a989a8a03a46e38225ca
|
||||
F test/e_reindex.test e175794fc41f8e8aef34772e87a7d7b7a9251dd3
|
||||
F test/e_resolve.test dcce9308fb13b934ce29591105d031d3e14fbba6
|
||||
F test/e_select.test f2358d074bd82240bc79a8348f284a2a8909dc1f
|
||||
@@ -459,6 +462,7 @@ F test/fkey3.test 5ec899d12b13bcf1e9ef40eff7fb692fdb91392e
|
||||
F test/fkey4.test 86446017011273aad8f9a99c1a65019e7bd9ca9d
|
||||
F test/fkey5.test 0bf64f2d19ad80433ca0b24edbf604a18b353d5f
|
||||
F test/fkey6.test c555f7fc45d842cc84b0d3ff93951ce2b8c25fc8
|
||||
F test/fkey7.test e31d0e71a41c1d29349a16448d6c420e2c53a8fc
|
||||
F test/fkey_malloc.test bb74c9cb8f8fceed03b58f8a7ef2df98520bbd51
|
||||
F test/format4.test 1f0cac8ff3895e9359ed87e41aaabee982a812eb
|
||||
F test/fts-9fd058691.test 78b887e30ae6816df0e1fed6259de4b5a64ad33c
|
||||
@@ -535,7 +539,7 @@ F test/fts3fault.test cb72dccb0a3b9f730f16c5240f3fcb9303eb1660
|
||||
F test/fts3fault2.test 3198eef2804deea7cac8403e771d9cbcb752d887
|
||||
F test/fts3first.test dbdedd20914c8d539aa3206c9b34a23775644641
|
||||
F test/fts3malloc.test b0e4c133b8d61d4f6d112d8110f8320e9e453ef6
|
||||
F test/fts3matchinfo.test 3f297e14e3f0d5be8595246f5fcd426625cc5881
|
||||
F test/fts3matchinfo.test ff423e73faab8fc6d7adeefedf74dd8e2b0b14e0
|
||||
F test/fts3near.test 12895557870b0f9af7cc0be81a0171abb2d12f12
|
||||
F test/fts3prefix.test b36d4f00b128a51e7b386cc013a874246d9d7dc1
|
||||
F test/fts3prefix2.test e1f0a822ca661dced7f12ce392e14eaf65609dce
|
||||
@@ -555,7 +559,7 @@ F test/fts4merge2.test 5faa558d1b672f82b847d2a337465fa745e46891
|
||||
F test/fts4merge3.test aab02a09f50fe6baaddc2e159c3eabc116d45fc7
|
||||
F test/fts4merge4.test c19c85ca1faa7b6d536832b49c12e1867235f584
|
||||
F test/fts4noti.test aed33ba44808852dcb24bf70fa132e7bf530f057
|
||||
F test/fts4unicode.test c8ac44217bf6c17812b03eaafa6c06995ad304c2
|
||||
F test/fts4unicode.test 5fa8e0a7899d906d114345c605250ebfa9d8ed28
|
||||
F test/full.test 6b3c8fb43c6beab6b95438c1675374b95fab245d
|
||||
F test/func.test cd25cf605c5a345d038dc7b84232204c6a901c84
|
||||
F test/func2.test 772d66227e4e6684b86053302e2d74a2500e1e0f
|
||||
@@ -590,8 +594,8 @@ F test/index2.test ee83c6b5e3173a3d7137140d945d9a5d4fdfb9d6
|
||||
F test/index3.test 423a25c789fc8cc51aaf2a4370bbdde2d9e9eed7
|
||||
F test/index4.test 2983216eb8c86ee62d9ed7cb206b5cc3331c0026
|
||||
F test/index5.test fc07c14193c0430814e7a08b5da46888ee795c33
|
||||
F test/index6.test f53a788b813eb6937346867bae9e587c434dd9a1
|
||||
F test/indexedby.test 0e959308707c808515c3a51363f7a9835027108c
|
||||
F test/index6.test e96324d8c1ade4b30a4c6cee14b1fc2e5a367cda
|
||||
F test/indexedby.test b2f22f3e693a53813aa3f50b812eb609ba6df1ec
|
||||
F test/indexfault.test 31d4ab9a7d2f6e9616933eb079722362a883eb1d
|
||||
F test/init.test 15c823093fdabbf7b531fe22cf037134d09587a7
|
||||
F test/insert.test 489aa12a027c83d291f5034a83c8c32e6be1dca2
|
||||
@@ -644,12 +648,12 @@ F test/make-where7.tcl 05c16b5d4f5d6512881dfec560cb793915932ef9
|
||||
F test/malloc.test fd368e31fe98d4779ed80442f311ed9f03bcd1f7
|
||||
F test/malloc3.test e3b32c724b5a124b57cb0ed177f675249ad0c66a
|
||||
F test/malloc4.test 957337613002b7058a85116493a262f679f3a261
|
||||
F test/malloc5.test a577cbbcc1594c7763b9b3515b3633555751c7f0
|
||||
F test/malloc5.test fafce0aa9157060445cd1a56ad50fc79d82f28c3
|
||||
F test/malloc6.test 2f039d9821927eacae43e1831f815e157659a151
|
||||
F test/malloc7.test 7c68a32942858bc715284856c5507446bba88c3a
|
||||
F test/malloc8.test 9b7a3f8cb9cf0b12fff566e80a980b1767bd961d
|
||||
F test/malloc9.test 2307c6ee3703b0a21391f3ea92388b4b73f9105e
|
||||
F test/mallocA.test 47006c8d70f29b030652e251cb9d35ba60289198
|
||||
F test/mallocA.test 1ba0367fb5434e7bc2fa4afcb30b14174d91b160
|
||||
F test/mallocAll.test 98f1be74bc9f49a858bc4f361fc58e26486798be
|
||||
F test/mallocB.test bc475ab850cda896142ab935bbfbc74c24e51ed6
|
||||
F test/mallocC.test 3dffe16532f109293ce1ccecd0c31dca55ef08c4
|
||||
@@ -661,7 +665,7 @@ F test/mallocH.test 79b65aed612c9b3ed2dcdaa727c85895fd1bfbdb
|
||||
F test/mallocI.test a88c2b9627c8506bf4703d8397420043a786cdb6
|
||||
F test/mallocJ.test b5d1839da331d96223e5f458856f8ffe1366f62e
|
||||
F test/mallocK.test d79968641d1b70d88f6c01bdb9a7eb4a55582cc9
|
||||
F test/malloc_common.tcl 9a98856549bfb3fab205edbc1317216edc52e70d
|
||||
F test/malloc_common.tcl 58e54229c4132ef882a11fab6419ec4cd3073589
|
||||
F test/manydb.test 28385ae2087967aa05c38624cec7d96ec74feb3e
|
||||
F test/mem5.test c6460fba403c5703141348cd90de1c294188c68f
|
||||
F test/memdb.test db5260330676de007be8530d6ecc7c9ab2b06ad3
|
||||
@@ -714,11 +718,11 @@ F test/pagesize.test 1dd51367e752e742f58e861e65ed7390603827a0
|
||||
F test/pcache.test b09104b03160aca0d968d99e8cd2c5b1921a993d
|
||||
F test/pcache2.test a83efe2dec0d392f814bfc998def1d1833942025
|
||||
F test/percentile.test b98fc868d71eb5619d42a1702e9ab91718cbed54
|
||||
F test/permutations.test 461ef4ea10db02cd421dfe5f988eac3e99b5cd9a
|
||||
F test/permutations.test 72f4f8881d388163ddbbeec0a6ed812e863ea2e6
|
||||
F test/pragma.test 5e7de6c32a5d764f09437d2025f07e4917b9e178
|
||||
F test/pragma2.test 3a55f82b954242c642f8342b17dffc8b47472947
|
||||
F test/pragma2.test 224f0381f9411a78ae685cac24c13656a62021b7
|
||||
F test/printf.test ec9870c4dce8686a37818e0bf1aba6e6a1863552
|
||||
F test/progress.test 552dc1edc37333a8d3098b8c26a2b7f06f5799d7
|
||||
F test/progress.test a282973d1d17f08071bc58a77d6b80f2a81c354d
|
||||
F test/ptrchng.test ef1aa72d6cf35a2bbd0869a649b744e9d84977fc
|
||||
F test/queryonly.test 5f653159e0f552f0552d43259890c1089391dcca
|
||||
F test/quick.test 1681febc928d686362d50057c642f77a02c62e57
|
||||
@@ -733,7 +737,7 @@ F test/regexp1.test 497ea812f264d12b6198d6e50a76be4a1973a9d8
|
||||
F test/reindex.test 44edd3966b474468b823d481eafef0c305022254
|
||||
F test/releasetest.mk 2eced2f9ae701fd0a29e714a241760503ccba25a
|
||||
F test/releasetest.tcl 06d289d8255794073a58d2850742f627924545ce
|
||||
F test/resolver01.test d1b487fc567bdb70b5dd09ccaaa877ddc61a233e
|
||||
F test/resolver01.test 33abf37ff8335e6bf98f2b45a0af3e06996ccd9a
|
||||
F test/rollback.test a1b4784b864331eae8b2a98c189efa2a8b11ff07
|
||||
F test/rowhash.test 0bc1d31415e4575d10cacf31e1a66b5cc0f8be81
|
||||
F test/rowid.test f777404492adb0e00868fd706a3721328fd3af48
|
||||
@@ -778,11 +782,11 @@ F test/shared9.test 5f2a8f79b4d6c7d107a01ffa1ed05ae7e6333e21
|
||||
F test/sharedA.test 0cdf1a76dfa00e6beee66af5b534b1e8df2720f5
|
||||
F test/shared_err.test 0079c05c97d88cfa03989b7c20a8b266983087aa
|
||||
F test/sharedlock.test 927a4b6da11978c82b857dbdb20a932aad732123
|
||||
F test/shell1.test 928547277d385038c696428e9d791cbbad098974
|
||||
F test/shell1.test 474ed53bb461c4ba9b6468d3a74e86eb8ee0d9d0
|
||||
F test/shell2.test 037d6ad16e873354195d30bb2dc4b5321788154a
|
||||
F test/shell3.test 9196c42772d575685e722c92b4b39053c6ebba59
|
||||
F test/shell4.test aa4eef8118b412d1a01477a53426ece169ea86a9
|
||||
F test/shell5.test 946e620a41b64f90d45dcf91c36e8d408d435cfd
|
||||
F test/shell5.test bfa21ecc173adcbc15db2c075baa468778f67f88
|
||||
F test/shortread1.test bb591ef20f0fd9ed26d0d12e80eee6d7ac8897a3
|
||||
F test/shrink.test 8c70f62b6e8eb4d54533de6d65bd06b1b9a17868
|
||||
F test/sidedelete.test f0ad71abe6233e3b153100f3b8d679b19a488329
|
||||
@@ -809,13 +813,13 @@ F test/superlock.test 1cde669f68d2dd37d6c9bd35eee1d95491ae3fc2
|
||||
F test/sync.test a34cd43e98b7fb84eabbf38f7ed8f7349b3f3d85
|
||||
F test/syscall.test a653783d985108c4912cc64d341ffbbb55ad2806
|
||||
F test/sysfault.test fa776e60bf46bdd3ae69f0b73e46ee3977a58ae6
|
||||
F test/table.test a59d985ca366e39b17b175f387f9d5db5a18d4e2
|
||||
F test/table.test 30423211108121884588d24d6776c7f38702ad7b
|
||||
F test/tableapi.test 2674633fa95d80da917571ebdd759a14d9819126
|
||||
F test/tclsqlite.test 37a61c2da7e3bfe3b8c1a2867199f6b860df5d43
|
||||
F test/tempdb.test 19d0f66e2e3eeffd68661a11c83ba5e6ace9128c
|
||||
F test/temptable.test d2c9b87a54147161bcd1822e30c1d1cd891e5b30
|
||||
F test/temptrigger.test 26670ed7a39cf2296a7f0a9e0a1d7bdb7abe936d
|
||||
F test/tester.tcl 63b24679c75a952c51f924de2802b2b57cddd22d
|
||||
F test/tester.tcl 5e97d1fe08f45fa3cc2320cee437e315c75ce995
|
||||
F test/thread001.test 9f22fd3525a307ff42a326b6bc7b0465be1745a5
|
||||
F test/thread002.test e630504f8a06c00bf8bbe68528774dd96aeb2e58
|
||||
F test/thread003.test ee4c9efc3b86a6a2767516a37bd64251272560a7
|
||||
@@ -857,6 +861,7 @@ F test/tkt-868145d012.test a5f941107ece6a64410ca4755c6329b7eb57a356
|
||||
F test/tkt-91e2e8ba6f.test 08c4f94ae07696b05c9b822da0b4e5337a2f54c5
|
||||
F test/tkt-94c04eaadb.test fa9c71192f7e2ea2d51bf078bc34e8da6088bf71
|
||||
F test/tkt-9d68c883.test 458f7d82a523d7644b54b497c986378a7d8c8b67
|
||||
F test/tkt-9f2eb3abac.test 85bc63e749f050e6a61c8f9207f1eee65c9d3395
|
||||
F test/tkt-a7b7803e.test 159ef554234fa1f9fb318c751b284bd1cf858da4
|
||||
F test/tkt-b1d3a2e531.test 610ef582413171b379652663111b1f996d9f8f78
|
||||
F test/tkt-b351d95f9.test d14a503c414c5c58fdde3e80f9a3cfef986498c0
|
||||
@@ -864,7 +869,7 @@ F test/tkt-b72787b1.test a95e8cdad0b98af1853ac7f0afd4ab27b77bf5f3
|
||||
F test/tkt-bd484a090c.test 60460bf946f79a79712b71f202eda501ca99b898
|
||||
F test/tkt-bdc6bbbb38.test fc38bb09bdd440e3513a1f5f98fc60a075182d7d
|
||||
F test/tkt-c48d99d690.test ba61977d62ab612fc515b3c488a6fbd6464a2447
|
||||
F test/tkt-cbd054fa6b.test 9c27ed07b333eed458e5d4543f91ecdcf05aeb19
|
||||
F test/tkt-cbd054fa6b.test 06ccd57af3c0c7895d0f7dc844f13c51f8258885
|
||||
F test/tkt-d11f09d36e.test d999b548fef885d1d1afa49a0e8544ecf436869d
|
||||
F test/tkt-d635236375.test 9d37e988b47d87505bc9445be0ca447002df5d09
|
||||
F test/tkt-d82e3f3721.test bcc0dfba658d15bab30fd4a9320c9e35d214ce30
|
||||
@@ -906,7 +911,7 @@ F test/tkt2686.test 6ee01c9b9e9c48f6d3a1fdd553b1cc4258f903d6
|
||||
F test/tkt2767.test 569000d842678f9cf2db7e0d1b27cbc9011381b0
|
||||
F test/tkt2817.test f31839e01f4243cff7399ef654d3af3558cb8d8d
|
||||
F test/tkt2820.test 39940276b3436d125deb7d8ebeee053e4cf13213
|
||||
F test/tkt2822.test c3589494fba643e039bcf0bfde7554ff6028406d
|
||||
F test/tkt2822.test f391776423a7c0d0949edfce375708bfb0f3141e
|
||||
F test/tkt2832.test a9b0b74a02dca166a04d9e37739c414b10929caa
|
||||
F test/tkt2854.test e432965db29e27e16f539b2ba7f502eb2ccc49af
|
||||
F test/tkt2920.test a8737380e4ae6424e00c0273dc12775704efbebf
|
||||
@@ -959,6 +964,7 @@ F test/tkt3992.test f3e7d548ac26f763b47bc0f750da3d03c81071da
|
||||
F test/tkt3997.test a335fa41ca3985660a139df7b734a26ef53284bd
|
||||
F test/tkt4018.test 7c2c9ba4df489c676a0a7a0e809a1fb9b2185bd1
|
||||
F test/tokenize.test ce430a7aed48fc98301611429595883fdfcab5d7
|
||||
F test/tpch01.test 8f4ac52f62f3e9f6bce0889105aecdf0275e331b
|
||||
F test/trace.test 4b36a41a3e9c7842151af6da5998f5080cdad9e5
|
||||
F test/trace2.test e7a988fdd982cdec62f1f1f34b0360e6476d01a0
|
||||
F test/trans.test 6e1b4c6a42dba31bd65f8fa5e61a2708e08ddde6
|
||||
@@ -1038,25 +1044,26 @@ F test/walro.test 6cc247a0cc9b36aeea2057dd28a922a1cdfbd630
|
||||
F test/walshared.test 0befc811dcf0b287efae21612304d15576e35417
|
||||
F test/walslow.test e7be6d9888f83aa5d3d3c7c08aa9b5c28b93609a
|
||||
F test/walthread.test de8dbaf6d9e41481c460ba31ca61e163d7348f8e
|
||||
F test/where.test da54153a4c1571ea1b95659e5bec8119edf786aa
|
||||
F test/where2.test b1830f762f837153a4c9743adaab90a5761f73e7
|
||||
F test/where3.test a0682ba3dc8c8f46ffcc95a3d9f58c4327fc129f
|
||||
F test/where.test 8d66dfbfd4d12816f74f854dbf67dee492c06267
|
||||
F test/where2.test 76d5346f7edb2a6a0442dcf3e9d088ac6903e0b5
|
||||
F test/where3.test d28c51f257e60be30f74308fa385ceeddfb54a6e
|
||||
F test/where4.test e9b9e2f2f98f00379e6031db6a6fca29bae782a2
|
||||
F test/where5.test fdf66f96d29a064b63eb543e28da4dfdccd81ad2
|
||||
F test/where6.test 5da5a98cec820d488e82708301b96cb8c18a258b
|
||||
F test/where7.test 5a4b0abc207d71da4deecd734ad8579e8dd40aa8
|
||||
F test/where8.test 6f95896633cf2d307b5263145b942b7d33e837c6
|
||||
F test/where8m.test da346596e19d54f0aba35ebade032a7c47d79739
|
||||
F test/where9.test 9a7fda4a4512abc26a855e8b2b6572b200f6019b
|
||||
F test/whereA.test 24c234263c8fe358f079d5e57d884fb569d2da0a
|
||||
F test/where9.test 4f3eab951353a3ae164befc521c777dfa903e46c
|
||||
F test/whereA.test 4d253178d135ec46d1671e440cd8f2b916aa6e6b
|
||||
F test/whereB.test 0def95db3bdec220a731c7e4bec5930327c1d8c5
|
||||
F test/whereC.test d6f4ecd4fa2d9429681a5b22a25d2bda8e86ab8a
|
||||
F test/whereD.test 6c2feb79ef1f68381b07f39017fe5f9b96da8d62
|
||||
F test/whereE.test b3a055eef928c992b0a33198a7b8dc10eea5ad2f
|
||||
F test/whereF.test 136a7301512d72a08a272806c8767066311b7bc1
|
||||
F test/whereF.test 5b2ba0dbe8074aa13e416b37c753991f0a2492d7
|
||||
F test/wherelimit.test 5e9fd41e79bb2b2d588ed999d641d9c965619b31
|
||||
F test/wild001.test bca33f499866f04c24510d74baf1e578d4e44b1c
|
||||
F test/win32lock.test 7a6bd73a5dcdee39b5bb93e92395e1773a194361
|
||||
F test/win32longpath.test e2aafc07e6990fe86c69be22a3d1a0e210cd329b
|
||||
F test/zeroblob.test caaecfb4f908f7bc086ed238668049f96774d688
|
||||
F test/zerodamage.test 209d7ed441f44cc5299e4ebffbef06fd5aabfefd
|
||||
F tool/build-all-msvc.bat c55f64ca200308fb5fa5c1ee751ea95a13977b5a x
|
||||
@@ -1070,12 +1077,12 @@ F tool/genfkey.test 4196a8928b78f51d54ef58e99e99401ab2f0a7e5
|
||||
F tool/getlock.c f4c39b651370156cae979501a7b156bdba50e7ce
|
||||
F tool/lemon.c 680980c7935bfa1edec20c804c9e5ba4b1dd96f5
|
||||
F tool/lempar.c 01ca97f87610d1dac6d8cd96ab109ab1130e76dc
|
||||
F tool/mkautoconfamal.sh 9ef9ad69bc3021a6fd2dac53a2e8cf5b97e0df05
|
||||
F tool/mkautoconfamal.sh f8d8dbf7d62f409ebed5134998bf5b51d7266383
|
||||
F tool/mkkeywordhash.c bb52064aa614e1426445e4b2b9b00eeecd23cc79
|
||||
F tool/mkopts.tcl 66ac10d240cc6e86abd37dc908d50382f84ff46e
|
||||
F tool/mkspeedsql.tcl a1a334d288f7adfe6e996f2e712becf076745c97
|
||||
F tool/mksqlite3c-noext.tcl 8bce31074e4cbe631bb7676526a048335f4c9f02
|
||||
F tool/mksqlite3c.tcl a61fe62a2895ca6458c463fccf1211ca1c000fcf
|
||||
F tool/mksqlite3c.tcl d344cc3144a0271cd853c5e3df36e9f31d78d619
|
||||
F tool/mksqlite3h.tcl ba24038056f51fde07c0079c41885ab85e2cff12
|
||||
F tool/mksqlite3internalh.tcl 3dca7bb5374cee003379b8cbac73714f610ef795
|
||||
F tool/mkvsix.tcl 0be7f7a591f1e83f9199cb82911b66668ca484c9
|
||||
@@ -1105,10 +1112,10 @@ F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
|
||||
F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381
|
||||
F tool/wherecosttest.c f407dc4c79786982a475261866a161cd007947ae
|
||||
F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac
|
||||
P 9e999081a59b161a0a1f968fbc01a1db9ea43b93
|
||||
R c32412a10fe0450296a67115895879b1
|
||||
T *branch * dbgTestFixture
|
||||
T *sym-dbgTestFixture *
|
||||
P 75a8a8c1b39725d36db627536d0c69401f8e0815
|
||||
R 14e40117cf5ed4a868935b4adf8b8b0d
|
||||
T *branch * expr-tuning
|
||||
T *sym-expr-tuning *
|
||||
T -sym-trunk *
|
||||
U mistachkin
|
||||
Z 7b47b87c7211179488e7ecca78b01825
|
||||
U drh
|
||||
Z e578fc31598c846285e1a40bbc280fc4
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
c23acba11bfefc019b5945cfb345f9afcf4b6242
|
||||
579a512538528cf4bb4381ba393c5d9e7310086b
|
||||
+1
-1
@@ -7,7 +7,7 @@ includedir=@includedir@
|
||||
|
||||
Name: SQLite
|
||||
Description: SQL database engine
|
||||
Version: @RELEASE@
|
||||
Version: @PACKAGE_VERSION@
|
||||
Libs: -L${libdir} -lsqlite3
|
||||
Libs.private: @LIBS@
|
||||
Cflags: -I${includedir}
|
||||
|
||||
+1
-1
@@ -687,7 +687,7 @@ void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
|
||||
** can handle (i.e. not CURRENT_TIME etc.)
|
||||
*/
|
||||
if( pDflt ){
|
||||
sqlite3_value *pVal;
|
||||
sqlite3_value *pVal = 0;
|
||||
if( sqlite3ValueFromExpr(db, pDflt, SQLITE_UTF8, SQLITE_AFF_NONE, &pVal) ){
|
||||
db->mallocFailed = 1;
|
||||
return;
|
||||
|
||||
+1019
-519
File diff suppressed because it is too large
Load Diff
+6
-5
@@ -158,6 +158,9 @@ static void attachFunc(
|
||||
sqlite3PagerLockingMode(pPager, db->dfltLockMode);
|
||||
sqlite3BtreeSecureDelete(aNew->pBt,
|
||||
sqlite3BtreeSecureDelete(db->aDb[0].pBt,-1) );
|
||||
#ifndef SQLITE_OMIT_PAGER_PRAGMAS
|
||||
sqlite3BtreeSetPagerFlags(aNew->pBt, 3 | (db->flags & PAGER_FLAGS_MASK));
|
||||
#endif
|
||||
}
|
||||
aNew->safety_level = 3;
|
||||
aNew->zName = sqlite3DbStrDup(db, zName);
|
||||
@@ -376,8 +379,7 @@ attach_end:
|
||||
void sqlite3Detach(Parse *pParse, Expr *pDbname){
|
||||
static const FuncDef detach_func = {
|
||||
1, /* nArg */
|
||||
SQLITE_UTF8, /* iPrefEnc */
|
||||
0, /* flags */
|
||||
SQLITE_UTF8, /* funcFlags */
|
||||
0, /* pUserData */
|
||||
0, /* pNext */
|
||||
detachFunc, /* xFunc */
|
||||
@@ -398,8 +400,7 @@ void sqlite3Detach(Parse *pParse, Expr *pDbname){
|
||||
void sqlite3Attach(Parse *pParse, Expr *p, Expr *pDbname, Expr *pKey){
|
||||
static const FuncDef attach_func = {
|
||||
3, /* nArg */
|
||||
SQLITE_UTF8, /* iPrefEnc */
|
||||
0, /* flags */
|
||||
SQLITE_UTF8, /* funcFlags */
|
||||
0, /* pUserData */
|
||||
0, /* pNext */
|
||||
attachFunc, /* xFunc */
|
||||
@@ -508,7 +509,7 @@ int sqlite3FixExpr(
|
||||
Expr *pExpr /* The expression to be fixed to one database */
|
||||
){
|
||||
while( pExpr ){
|
||||
if( ExprHasAnyProperty(pExpr, EP_TokenOnly) ) break;
|
||||
if( ExprHasProperty(pExpr, EP_TokenOnly) ) break;
|
||||
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
|
||||
if( sqlite3FixSelect(pFix, pExpr->x.pSelect) ) return 1;
|
||||
}else{
|
||||
|
||||
+1
-1
@@ -392,7 +392,7 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){
|
||||
if( iSrcPg!=PENDING_BYTE_PAGE(p->pSrc->pBt) ){
|
||||
DbPage *pSrcPg; /* Source page object */
|
||||
rc = sqlite3PagerAcquire(pSrcPager, iSrcPg, &pSrcPg,
|
||||
PAGER_ACQUIRE_READONLY);
|
||||
PAGER_GET_READONLY);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = backupOnePage(p, iSrcPg, sqlite3PagerGetData(pSrcPg), 0);
|
||||
sqlite3PagerUnref(pSrcPg);
|
||||
|
||||
+92
-67
@@ -724,6 +724,9 @@ static int btreeRestoreCursorPosition(BtCursor *pCur){
|
||||
sqlite3_free(pCur->pKey);
|
||||
pCur->pKey = 0;
|
||||
assert( pCur->eState==CURSOR_VALID || pCur->eState==CURSOR_INVALID );
|
||||
if( pCur->skipNext && pCur->eState==CURSOR_VALID ){
|
||||
pCur->eState = CURSOR_SKIPNEXT;
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
@@ -749,7 +752,7 @@ int sqlite3BtreeCursorHasMoved(BtCursor *pCur, int *pHasMoved){
|
||||
*pHasMoved = 1;
|
||||
return rc;
|
||||
}
|
||||
if( pCur->eState!=CURSOR_VALID || pCur->skipNext!=0 ){
|
||||
if( pCur->eState!=CURSOR_VALID || NEVER(pCur->skipNext!=0) ){
|
||||
*pHasMoved = 1;
|
||||
}else{
|
||||
*pHasMoved = 0;
|
||||
@@ -937,7 +940,8 @@ static void btreeParseCellPtr(
|
||||
assert( n==4-4*pPage->leaf );
|
||||
if( pPage->intKey ){
|
||||
if( pPage->hasData ){
|
||||
n += getVarint32(&pCell[n], nPayload);
|
||||
assert( n==0 );
|
||||
n = getVarint32(pCell, nPayload);
|
||||
}else{
|
||||
nPayload = 0;
|
||||
}
|
||||
@@ -1581,15 +1585,12 @@ static int btreeGetPage(
|
||||
BtShared *pBt, /* The btree */
|
||||
Pgno pgno, /* Number of the page to fetch */
|
||||
MemPage **ppPage, /* Return the page in this parameter */
|
||||
int noContent, /* Do not load page content if true */
|
||||
int bReadonly /* True if a read-only (mmap) page is ok */
|
||||
int flags /* PAGER_GET_NOCONTENT or PAGER_GET_READONLY */
|
||||
){
|
||||
int rc;
|
||||
DbPage *pDbPage;
|
||||
int flags = (noContent ? PAGER_ACQUIRE_NOCONTENT : 0)
|
||||
| (bReadonly ? PAGER_ACQUIRE_READONLY : 0);
|
||||
|
||||
assert( noContent==0 || bReadonly==0 );
|
||||
assert( flags==0 || flags==PAGER_GET_NOCONTENT || flags==PAGER_GET_READONLY );
|
||||
assert( sqlite3_mutex_held(pBt->mutex) );
|
||||
rc = sqlite3PagerAcquire(pBt->pPager, pgno, (DbPage**)&pDbPage, flags);
|
||||
if( rc ) return rc;
|
||||
@@ -1637,15 +1638,16 @@ static int getAndInitPage(
|
||||
BtShared *pBt, /* The database file */
|
||||
Pgno pgno, /* Number of the page to get */
|
||||
MemPage **ppPage, /* Write the page pointer here */
|
||||
int bReadonly /* True if a read-only (mmap) page is ok */
|
||||
int bReadonly /* PAGER_GET_READONLY or 0 */
|
||||
){
|
||||
int rc;
|
||||
assert( sqlite3_mutex_held(pBt->mutex) );
|
||||
assert( bReadonly==PAGER_GET_READONLY || bReadonly==0 );
|
||||
|
||||
if( pgno>btreePagecount(pBt) ){
|
||||
rc = SQLITE_CORRUPT_BKPT;
|
||||
}else{
|
||||
rc = btreeGetPage(pBt, pgno, ppPage, 0, bReadonly);
|
||||
rc = btreeGetPage(pBt, pgno, ppPage, bReadonly);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = btreeInitPage(*ppPage);
|
||||
if( rc!=SQLITE_OK ){
|
||||
@@ -2165,17 +2167,14 @@ int sqlite3BtreeSetMmapLimit(Btree *p, sqlite3_int64 szMmap){
|
||||
** probability of damage to near zero but with a write performance reduction.
|
||||
*/
|
||||
#ifndef SQLITE_OMIT_PAGER_PRAGMAS
|
||||
int sqlite3BtreeSetSafetyLevel(
|
||||
int sqlite3BtreeSetPagerFlags(
|
||||
Btree *p, /* The btree to set the safety level on */
|
||||
int level, /* PRAGMA synchronous. 1=OFF, 2=NORMAL, 3=FULL */
|
||||
int fullSync, /* PRAGMA fullfsync. */
|
||||
int ckptFullSync /* PRAGMA checkpoint_fullfync */
|
||||
unsigned pgFlags /* Various PAGER_* flags */
|
||||
){
|
||||
BtShared *pBt = p->pBt;
|
||||
assert( sqlite3_mutex_held(p->db->mutex) );
|
||||
assert( level>=1 && level<=3 );
|
||||
sqlite3BtreeEnter(p);
|
||||
sqlite3PagerSetSafetyLevel(pBt->pPager, level, fullSync, ckptFullSync);
|
||||
sqlite3PagerSetFlags(pBt->pPager, pgFlags);
|
||||
sqlite3BtreeLeave(p);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
@@ -2381,7 +2380,7 @@ static int lockBtree(BtShared *pBt){
|
||||
assert( pBt->pPage1==0 );
|
||||
rc = sqlite3PagerSharedLock(pBt->pPager);
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
rc = btreeGetPage(pBt, 1, &pPage1, 0, 0);
|
||||
rc = btreeGetPage(pBt, 1, &pPage1, 0);
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
|
||||
/* Do some checking to help insure the file we opened really is
|
||||
@@ -2509,6 +2508,7 @@ static int lockBtree(BtShared *pBt){
|
||||
assert( pBt->maxLeaf + 23 <= MX_CELL_SIZE(pBt) );
|
||||
pBt->pPage1 = pPage1;
|
||||
pBt->nPage = nPage;
|
||||
assert( pPage1->leaf==0 || pPage1->leaf==1 );
|
||||
return SQLITE_OK;
|
||||
|
||||
page1_init_failed:
|
||||
@@ -2963,7 +2963,7 @@ static int relocatePage(
|
||||
** iPtrPage.
|
||||
*/
|
||||
if( eType!=PTRMAP_ROOTPAGE ){
|
||||
rc = btreeGetPage(pBt, iPtrPage, &pPtrPage, 0, 0);
|
||||
rc = btreeGetPage(pBt, iPtrPage, &pPtrPage, 0);
|
||||
if( rc!=SQLITE_OK ){
|
||||
return rc;
|
||||
}
|
||||
@@ -3047,7 +3047,7 @@ static int incrVacuumStep(BtShared *pBt, Pgno nFin, Pgno iLastPg, int bCommit){
|
||||
u8 eMode = BTALLOC_ANY; /* Mode parameter for allocateBtreePage() */
|
||||
Pgno iNear = 0; /* nearby parameter for allocateBtreePage() */
|
||||
|
||||
rc = btreeGetPage(pBt, iLastPg, &pLastPg, 0, 0);
|
||||
rc = btreeGetPage(pBt, iLastPg, &pLastPg, 0);
|
||||
if( rc!=SQLITE_OK ){
|
||||
return rc;
|
||||
}
|
||||
@@ -3446,7 +3446,7 @@ int sqlite3BtreeRollback(Btree *p, int tripCode){
|
||||
/* The rollback may have destroyed the pPage1->aData value. So
|
||||
** call btreeGetPage() on page 1 again to make
|
||||
** sure pPage1->aData is set correctly. */
|
||||
if( btreeGetPage(pBt, 1, &pPage1, 0, 0)==SQLITE_OK ){
|
||||
if( btreeGetPage(pBt, 1, &pPage1, 0)==SQLITE_OK ){
|
||||
int nPage = get4byte(28+(u8*)pPage1->aData);
|
||||
testcase( nPage==0 );
|
||||
if( nPage==0 ) sqlite3PagerPagecount(pBt->pPager, &nPage);
|
||||
@@ -3881,7 +3881,7 @@ static int getOverflowPage(
|
||||
|
||||
assert( next==0 || rc==SQLITE_DONE );
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = btreeGetPage(pBt, ovfl, &pPage, 0, (ppPage==0));
|
||||
rc = btreeGetPage(pBt, ovfl, &pPage, (ppPage==0) ? PAGER_GET_READONLY : 0);
|
||||
assert( rc==SQLITE_OK || pPage==0 );
|
||||
if( rc==SQLITE_OK ){
|
||||
next = get4byte(pPage->aData);
|
||||
@@ -4103,7 +4103,7 @@ static int accessPayload(
|
||||
{
|
||||
DbPage *pDbPage;
|
||||
rc = sqlite3PagerAcquire(pBt->pPager, nextPage, &pDbPage,
|
||||
(eOp==0 ? PAGER_ACQUIRE_READONLY : 0)
|
||||
(eOp==0 ? PAGER_GET_READONLY : 0)
|
||||
);
|
||||
if( rc==SQLITE_OK ){
|
||||
aPayload = sqlite3PagerGetData(pDbPage);
|
||||
@@ -4287,7 +4287,8 @@ static int moveToChild(BtCursor *pCur, u32 newPgno){
|
||||
if( pCur->iPage>=(BTCURSOR_MAX_DEPTH-1) ){
|
||||
return SQLITE_CORRUPT_BKPT;
|
||||
}
|
||||
rc = getAndInitPage(pBt, newPgno, &pNewPage, (pCur->wrFlag==0));
|
||||
rc = getAndInitPage(pBt, newPgno, &pNewPage,
|
||||
pCur->wrFlag==0 ? PAGER_GET_READONLY : 0);
|
||||
if( rc ) return rc;
|
||||
pCur->apPage[i+1] = pNewPage;
|
||||
pCur->aiIdx[i+1] = 0;
|
||||
@@ -4404,7 +4405,8 @@ static int moveToRoot(BtCursor *pCur){
|
||||
pCur->eState = CURSOR_INVALID;
|
||||
return SQLITE_OK;
|
||||
}else{
|
||||
rc = getAndInitPage(pBt, pCur->pgnoRoot, &pCur->apPage[0], pCur->wrFlag==0);
|
||||
rc = getAndInitPage(pBt, pCur->pgnoRoot, &pCur->apPage[0],
|
||||
pCur->wrFlag==0 ? PAGER_GET_READONLY : 0);
|
||||
if( rc!=SQLITE_OK ){
|
||||
pCur->eState = CURSOR_INVALID;
|
||||
return rc;
|
||||
@@ -4799,21 +4801,29 @@ int sqlite3BtreeNext(BtCursor *pCur, int *pRes){
|
||||
MemPage *pPage;
|
||||
|
||||
assert( cursorHoldsMutex(pCur) );
|
||||
rc = restoreCursorPosition(pCur);
|
||||
if( rc!=SQLITE_OK ){
|
||||
return rc;
|
||||
}
|
||||
assert( pRes!=0 );
|
||||
if( CURSOR_INVALID==pCur->eState ){
|
||||
*pRes = 1;
|
||||
return SQLITE_OK;
|
||||
assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID );
|
||||
if( pCur->eState!=CURSOR_VALID ){
|
||||
rc = restoreCursorPosition(pCur);
|
||||
if( rc!=SQLITE_OK ){
|
||||
*pRes = 0;
|
||||
return rc;
|
||||
}
|
||||
if( CURSOR_INVALID==pCur->eState ){
|
||||
*pRes = 1;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
if( pCur->skipNext ){
|
||||
assert( pCur->eState==CURSOR_VALID || pCur->eState==CURSOR_SKIPNEXT );
|
||||
pCur->eState = CURSOR_VALID;
|
||||
if( pCur->skipNext>0 ){
|
||||
pCur->skipNext = 0;
|
||||
*pRes = 0;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
pCur->skipNext = 0;
|
||||
}
|
||||
}
|
||||
if( pCur->skipNext>0 ){
|
||||
pCur->skipNext = 0;
|
||||
*pRes = 0;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
pCur->skipNext = 0;
|
||||
|
||||
pPage = pCur->apPage[pCur->iPage];
|
||||
idx = ++pCur->aiIdx[pCur->iPage];
|
||||
@@ -4831,7 +4841,10 @@ int sqlite3BtreeNext(BtCursor *pCur, int *pRes){
|
||||
if( idx>=pPage->nCell ){
|
||||
if( !pPage->leaf ){
|
||||
rc = moveToChild(pCur, get4byte(&pPage->aData[pPage->hdrOffset+8]));
|
||||
if( rc ) return rc;
|
||||
if( rc ){
|
||||
*pRes = 0;
|
||||
return rc;
|
||||
}
|
||||
rc = moveToLeftmost(pCur);
|
||||
*pRes = 0;
|
||||
return rc;
|
||||
@@ -4873,21 +4886,32 @@ int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){
|
||||
MemPage *pPage;
|
||||
|
||||
assert( cursorHoldsMutex(pCur) );
|
||||
rc = restoreCursorPosition(pCur);
|
||||
if( rc!=SQLITE_OK ){
|
||||
return rc;
|
||||
}
|
||||
assert( pRes!=0 );
|
||||
assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID );
|
||||
pCur->atLast = 0;
|
||||
if( CURSOR_INVALID==pCur->eState ){
|
||||
*pRes = 1;
|
||||
return SQLITE_OK;
|
||||
if( pCur->eState!=CURSOR_VALID ){
|
||||
if( ALWAYS(pCur->eState>=CURSOR_REQUIRESEEK) ){
|
||||
rc = btreeRestoreCursorPosition(pCur);
|
||||
if( rc!=SQLITE_OK ){
|
||||
*pRes = 0;
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
if( CURSOR_INVALID==pCur->eState ){
|
||||
*pRes = 1;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
if( pCur->skipNext ){
|
||||
assert( pCur->eState==CURSOR_VALID || pCur->eState==CURSOR_SKIPNEXT );
|
||||
pCur->eState = CURSOR_VALID;
|
||||
if( pCur->skipNext<0 ){
|
||||
pCur->skipNext = 0;
|
||||
*pRes = 0;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
pCur->skipNext = 0;
|
||||
}
|
||||
}
|
||||
if( pCur->skipNext<0 ){
|
||||
pCur->skipNext = 0;
|
||||
*pRes = 0;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
pCur->skipNext = 0;
|
||||
|
||||
pPage = pCur->apPage[pCur->iPage];
|
||||
assert( pPage->isInit );
|
||||
@@ -4895,6 +4919,7 @@ int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){
|
||||
int idx = pCur->aiIdx[pCur->iPage];
|
||||
rc = moveToChild(pCur, get4byte(findCell(pPage, idx)));
|
||||
if( rc ){
|
||||
*pRes = 0;
|
||||
return rc;
|
||||
}
|
||||
rc = moveToRightmost(pCur);
|
||||
@@ -5018,7 +5043,7 @@ static int allocateBtreePage(
|
||||
if( iTrunk>mxPage ){
|
||||
rc = SQLITE_CORRUPT_BKPT;
|
||||
}else{
|
||||
rc = btreeGetPage(pBt, iTrunk, &pTrunk, 0, 0);
|
||||
rc = btreeGetPage(pBt, iTrunk, &pTrunk, 0);
|
||||
}
|
||||
if( rc ){
|
||||
pTrunk = 0;
|
||||
@@ -5082,7 +5107,7 @@ static int allocateBtreePage(
|
||||
goto end_allocate_page;
|
||||
}
|
||||
testcase( iNewTrunk==mxPage );
|
||||
rc = btreeGetPage(pBt, iNewTrunk, &pNewTrunk, 0, 0);
|
||||
rc = btreeGetPage(pBt, iNewTrunk, &pNewTrunk, 0);
|
||||
if( rc!=SQLITE_OK ){
|
||||
goto end_allocate_page;
|
||||
}
|
||||
@@ -5161,8 +5186,8 @@ static int allocateBtreePage(
|
||||
memcpy(&aData[8+closest*4], &aData[4+k*4], 4);
|
||||
}
|
||||
put4byte(&aData[4], k-1);
|
||||
noContent = !btreeGetHasContent(pBt, *pPgno);
|
||||
rc = btreeGetPage(pBt, *pPgno, ppPage, noContent, 0);
|
||||
noContent = !btreeGetHasContent(pBt, *pPgno) ? PAGER_GET_NOCONTENT : 0;
|
||||
rc = btreeGetPage(pBt, *pPgno, ppPage, noContent);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3PagerWrite((*ppPage)->pDbPage);
|
||||
if( rc!=SQLITE_OK ){
|
||||
@@ -5194,7 +5219,7 @@ static int allocateBtreePage(
|
||||
** here are confined to those pages that lie between the end of the
|
||||
** database image and the end of the database file.
|
||||
*/
|
||||
int bNoContent = (0==IfNotOmitAV(pBt->bDoTruncate));
|
||||
int bNoContent = (0==IfNotOmitAV(pBt->bDoTruncate)) ? PAGER_GET_NOCONTENT : 0;
|
||||
|
||||
rc = sqlite3PagerWrite(pBt->pPage1->pDbPage);
|
||||
if( rc ) return rc;
|
||||
@@ -5210,7 +5235,7 @@ static int allocateBtreePage(
|
||||
MemPage *pPg = 0;
|
||||
TRACE(("ALLOCATE: %d from end of file (pointer-map page)\n", pBt->nPage));
|
||||
assert( pBt->nPage!=PENDING_BYTE_PAGE(pBt) );
|
||||
rc = btreeGetPage(pBt, pBt->nPage, &pPg, bNoContent, 0);
|
||||
rc = btreeGetPage(pBt, pBt->nPage, &pPg, bNoContent);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3PagerWrite(pPg->pDbPage);
|
||||
releasePage(pPg);
|
||||
@@ -5224,7 +5249,7 @@ static int allocateBtreePage(
|
||||
*pPgno = pBt->nPage;
|
||||
|
||||
assert( *pPgno!=PENDING_BYTE_PAGE(pBt) );
|
||||
rc = btreeGetPage(pBt, *pPgno, ppPage, bNoContent, 0);
|
||||
rc = btreeGetPage(pBt, *pPgno, ppPage, bNoContent);
|
||||
if( rc ) return rc;
|
||||
rc = sqlite3PagerWrite((*ppPage)->pDbPage);
|
||||
if( rc!=SQLITE_OK ){
|
||||
@@ -5292,7 +5317,7 @@ static int freePage2(BtShared *pBt, MemPage *pMemPage, Pgno iPage){
|
||||
/* If the secure_delete option is enabled, then
|
||||
** always fully overwrite deleted information with zeros.
|
||||
*/
|
||||
if( (!pPage && ((rc = btreeGetPage(pBt, iPage, &pPage, 0, 0))!=0) )
|
||||
if( (!pPage && ((rc = btreeGetPage(pBt, iPage, &pPage, 0))!=0) )
|
||||
|| ((rc = sqlite3PagerWrite(pPage->pDbPage))!=0)
|
||||
){
|
||||
goto freepage_out;
|
||||
@@ -5319,7 +5344,7 @@ static int freePage2(BtShared *pBt, MemPage *pMemPage, Pgno iPage){
|
||||
u32 nLeaf; /* Initial number of leaf cells on trunk page */
|
||||
|
||||
iTrunk = get4byte(&pPage1->aData[32]);
|
||||
rc = btreeGetPage(pBt, iTrunk, &pTrunk, 0, 0);
|
||||
rc = btreeGetPage(pBt, iTrunk, &pTrunk, 0);
|
||||
if( rc!=SQLITE_OK ){
|
||||
goto freepage_out;
|
||||
}
|
||||
@@ -5365,7 +5390,7 @@ static int freePage2(BtShared *pBt, MemPage *pMemPage, Pgno iPage){
|
||||
** first trunk in the free-list is full. Either way, the page being freed
|
||||
** will become the new first trunk page in the free-list.
|
||||
*/
|
||||
if( pPage==0 && SQLITE_OK!=(rc = btreeGetPage(pBt, iPage, &pPage, 0, 0)) ){
|
||||
if( pPage==0 && SQLITE_OK!=(rc = btreeGetPage(pBt, iPage, &pPage, 0)) ){
|
||||
goto freepage_out;
|
||||
}
|
||||
rc = sqlite3PagerWrite(pPage->pDbPage);
|
||||
@@ -7264,7 +7289,7 @@ static int btreeCreateTable(Btree *p, int *piTable, int createTabFlags){
|
||||
}
|
||||
|
||||
/* Move the page currently at pgnoRoot to pgnoMove. */
|
||||
rc = btreeGetPage(pBt, pgnoRoot, &pRoot, 0, 0);
|
||||
rc = btreeGetPage(pBt, pgnoRoot, &pRoot, 0);
|
||||
if( rc!=SQLITE_OK ){
|
||||
return rc;
|
||||
}
|
||||
@@ -7285,7 +7310,7 @@ static int btreeCreateTable(Btree *p, int *piTable, int createTabFlags){
|
||||
if( rc!=SQLITE_OK ){
|
||||
return rc;
|
||||
}
|
||||
rc = btreeGetPage(pBt, pgnoRoot, &pRoot, 0, 0);
|
||||
rc = btreeGetPage(pBt, pgnoRoot, &pRoot, 0);
|
||||
if( rc!=SQLITE_OK ){
|
||||
return rc;
|
||||
}
|
||||
@@ -7463,7 +7488,7 @@ static int btreeDropTable(Btree *p, Pgno iTable, int *piMoved){
|
||||
return SQLITE_LOCKED_SHAREDCACHE;
|
||||
}
|
||||
|
||||
rc = btreeGetPage(pBt, (Pgno)iTable, &pPage, 0, 0);
|
||||
rc = btreeGetPage(pBt, (Pgno)iTable, &pPage, 0);
|
||||
if( rc ) return rc;
|
||||
rc = sqlite3BtreeClearTable(p, iTable, 0);
|
||||
if( rc ){
|
||||
@@ -7498,7 +7523,7 @@ static int btreeDropTable(Btree *p, Pgno iTable, int *piMoved){
|
||||
*/
|
||||
MemPage *pMove;
|
||||
releasePage(pPage);
|
||||
rc = btreeGetPage(pBt, maxRootPgno, &pMove, 0, 0);
|
||||
rc = btreeGetPage(pBt, maxRootPgno, &pMove, 0);
|
||||
if( rc!=SQLITE_OK ){
|
||||
return rc;
|
||||
}
|
||||
@@ -7508,7 +7533,7 @@ static int btreeDropTable(Btree *p, Pgno iTable, int *piMoved){
|
||||
return rc;
|
||||
}
|
||||
pMove = 0;
|
||||
rc = btreeGetPage(pBt, maxRootPgno, &pMove, 0, 0);
|
||||
rc = btreeGetPage(pBt, maxRootPgno, &pMove, 0);
|
||||
freePage(pMove, &rc);
|
||||
releasePage(pMove);
|
||||
if( rc!=SQLITE_OK ){
|
||||
@@ -7723,7 +7748,7 @@ static void checkAppendMsg(
|
||||
}
|
||||
sqlite3VXPrintf(&pCheck->errMsg, 1, zFormat, ap);
|
||||
va_end(ap);
|
||||
if( pCheck->errMsg.mallocFailed ){
|
||||
if( pCheck->errMsg.accError==STRACCUM_NOMEM ){
|
||||
pCheck->mallocFailed = 1;
|
||||
}
|
||||
}
|
||||
@@ -7920,7 +7945,7 @@ static int checkTreePage(
|
||||
usableSize = pBt->usableSize;
|
||||
if( iPage==0 ) return 0;
|
||||
if( checkRef(pCheck, iPage, zParentContext) ) return 0;
|
||||
if( (rc = btreeGetPage(pBt, (Pgno)iPage, &pPage, 0, 0))!=0 ){
|
||||
if( (rc = btreeGetPage(pBt, (Pgno)iPage, &pPage, 0))!=0 ){
|
||||
checkAppendMsg(pCheck, zContext,
|
||||
"unable to get the page. error code=%d", rc);
|
||||
return 0;
|
||||
|
||||
+1
-1
@@ -64,7 +64,7 @@ int sqlite3BtreeOpen(
|
||||
int sqlite3BtreeClose(Btree*);
|
||||
int sqlite3BtreeSetCacheSize(Btree*,int);
|
||||
int sqlite3BtreeSetMmapLimit(Btree*,sqlite3_int64);
|
||||
int sqlite3BtreeSetSafetyLevel(Btree*,int,int,int);
|
||||
int sqlite3BtreeSetPagerFlags(Btree*,unsigned);
|
||||
int sqlite3BtreeSyncDisabled(Btree*);
|
||||
int sqlite3BtreeSetPageSize(Btree *p, int nPagesize, int nReserve, int eFix);
|
||||
int sqlite3BtreeGetPageSize(Btree*);
|
||||
|
||||
+11
-5
@@ -520,14 +520,19 @@ struct BtCursor {
|
||||
/*
|
||||
** Potential values for BtCursor.eState.
|
||||
**
|
||||
** CURSOR_VALID:
|
||||
** Cursor points to a valid entry. getPayload() etc. may be called.
|
||||
**
|
||||
** CURSOR_INVALID:
|
||||
** Cursor does not point to a valid entry. This can happen (for example)
|
||||
** because the table is empty or because BtreeCursorFirst() has not been
|
||||
** called.
|
||||
**
|
||||
** CURSOR_VALID:
|
||||
** Cursor points to a valid entry. getPayload() etc. may be called.
|
||||
**
|
||||
** CURSOR_SKIPNEXT:
|
||||
** Cursor is valid except that the Cursor.skipNext field is non-zero
|
||||
** indicating that the next sqlite3BtreeNext() or sqlite3BtreePrevious()
|
||||
** operation should be a no-op.
|
||||
**
|
||||
** CURSOR_REQUIRESEEK:
|
||||
** The table that this cursor was opened on still exists, but has been
|
||||
** modified since the cursor was last used. The cursor position is saved
|
||||
@@ -544,8 +549,9 @@ struct BtCursor {
|
||||
*/
|
||||
#define CURSOR_INVALID 0
|
||||
#define CURSOR_VALID 1
|
||||
#define CURSOR_REQUIRESEEK 2
|
||||
#define CURSOR_FAULT 3
|
||||
#define CURSOR_SKIPNEXT 2
|
||||
#define CURSOR_REQUIRESEEK 3
|
||||
#define CURSOR_FAULT 4
|
||||
|
||||
/*
|
||||
** The database page the PENDING_BYTE occupies. This page is never used.
|
||||
|
||||
+2
-2
@@ -2024,7 +2024,7 @@ static void sqlite3ClearStatTables(
|
||||
){
|
||||
int i;
|
||||
const char *zDbName = pParse->db->aDb[iDb].zName;
|
||||
for(i=1; i<=3; i++){
|
||||
for(i=1; i<=4; i++){
|
||||
char zTab[24];
|
||||
sqlite3_snprintf(sizeof(zTab),zTab,"sqlite_stat%d",i);
|
||||
if( sqlite3FindTable(pParse->db, zTab, zDbName) ){
|
||||
@@ -2866,7 +2866,7 @@ Index *sqlite3CreateIndex(
|
||||
** the zStmt variable
|
||||
*/
|
||||
if( pStart ){
|
||||
int n = (pParse->sLastToken.z - pName->z) + pParse->sLastToken.n;
|
||||
int n = (int)(pParse->sLastToken.z - pName->z) + pParse->sLastToken.n;
|
||||
if( pName->z[n-1]==';' ) n--;
|
||||
/* A named index with an explicit CREATE INDEX statement */
|
||||
zStmt = sqlite3MPrintf(db, "CREATE%s INDEX %.*s",
|
||||
|
||||
+3
-3
@@ -270,9 +270,9 @@ static int matchQuality(
|
||||
}
|
||||
|
||||
/* Bonus points if the text encoding matches */
|
||||
if( enc==p->iPrefEnc ){
|
||||
if( enc==(p->funcFlags & SQLITE_FUNC_ENCMASK) ){
|
||||
match += 2; /* Exact encoding match */
|
||||
}else if( (enc & p->iPrefEnc & 2)!=0 ){
|
||||
}else if( (enc & p->funcFlags & 2)!=0 ){
|
||||
match += 1; /* Both are UTF16, but with different byte orders */
|
||||
}
|
||||
|
||||
@@ -406,7 +406,7 @@ FuncDef *sqlite3FindFunction(
|
||||
(pBest = sqlite3DbMallocZero(db, sizeof(*pBest)+nName+1))!=0 ){
|
||||
pBest->zName = (char *)&pBest[1];
|
||||
pBest->nArg = (u16)nArg;
|
||||
pBest->iPrefEnc = enc;
|
||||
pBest->funcFlags = enc;
|
||||
memcpy(pBest->zName, zName, nName);
|
||||
pBest->zName[nName] = 0;
|
||||
sqlite3FuncDefInsert(&db->aFunc, pBest);
|
||||
|
||||
+3
-1
@@ -117,7 +117,9 @@ static const char * const azCompileOpt[] = {
|
||||
#ifdef SQLITE_ENABLE_RTREE
|
||||
"ENABLE_RTREE",
|
||||
#endif
|
||||
#ifdef SQLITE_ENABLE_STAT3
|
||||
#if defined(SQLITE_ENABLE_STAT4)
|
||||
"ENABLE_STAT4",
|
||||
#elif defined(SQLITE_ENABLE_STAT3)
|
||||
"ENABLE_STAT3",
|
||||
#endif
|
||||
#ifdef SQLITE_ENABLE_UNLOCK_NOTIFY
|
||||
|
||||
+2
-2
@@ -536,7 +536,7 @@ void sqlite3GenerateRowDelete(
|
||||
/* Do FK processing. This call checks that any FK constraints that
|
||||
** refer to this table (i.e. constraints attached to other tables)
|
||||
** are not violated by deleting this row. */
|
||||
sqlite3FkCheck(pParse, pTab, iOld, 0);
|
||||
sqlite3FkCheck(pParse, pTab, iOld, 0, 0, 0);
|
||||
}
|
||||
|
||||
/* Delete the index and table entries. Skip this step if pTab is really
|
||||
@@ -553,7 +553,7 @@ void sqlite3GenerateRowDelete(
|
||||
/* Do any ON CASCADE, SET NULL or SET DEFAULT operations required to
|
||||
** handle rows (possibly in other tables) that refer via a foreign key
|
||||
** to the row just deleted. */
|
||||
sqlite3FkActions(pParse, pTab, 0, iOld);
|
||||
sqlite3FkActions(pParse, pTab, 0, iOld, 0, 0);
|
||||
|
||||
/* Invoke AFTER DELETE trigger programs. */
|
||||
sqlite3CodeRowTrigger(pParse, pTrigger,
|
||||
|
||||
+36
-36
@@ -114,8 +114,7 @@ CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr){
|
||||
p = p->pLeft;
|
||||
continue;
|
||||
}
|
||||
assert( op!=TK_REGISTER || p->op2!=TK_COLLATE );
|
||||
if( op==TK_COLLATE ){
|
||||
if( op==TK_COLLATE || (op==TK_REGISTER && p->op2==TK_COLLATE) ){
|
||||
pColl = sqlite3GetCollSeq(pParse, ENC(db), 0, p->u.zToken);
|
||||
break;
|
||||
}
|
||||
@@ -597,7 +596,7 @@ void sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pExpr){
|
||||
const char *z;
|
||||
|
||||
if( pExpr==0 ) return;
|
||||
assert( !ExprHasAnyProperty(pExpr, EP_IntValue|EP_Reduced|EP_TokenOnly) );
|
||||
assert( !ExprHasProperty(pExpr, EP_IntValue|EP_Reduced|EP_TokenOnly) );
|
||||
z = pExpr->u.zToken;
|
||||
assert( z!=0 );
|
||||
assert( z[0]!=0 );
|
||||
@@ -667,12 +666,12 @@ void sqlite3ExprDelete(sqlite3 *db, Expr *p){
|
||||
if( p==0 ) return;
|
||||
/* Sanity check: Assert that the IntValue is non-negative if it exists */
|
||||
assert( !ExprHasProperty(p, EP_IntValue) || p->u.iValue>=0 );
|
||||
if( !ExprHasAnyProperty(p, EP_TokenOnly) ){
|
||||
if( !ExprHasProperty(p, EP_TokenOnly) ){
|
||||
/* The Expr.x union is never used at the same time as Expr.pRight */
|
||||
assert( p->x.pList==0 || p->pRight==0 );
|
||||
sqlite3ExprDelete(db, p->pLeft);
|
||||
sqlite3ExprDelete(db, p->pRight);
|
||||
if( !ExprHasProperty(p, EP_Reduced) && (p->flags2 & EP2_MallocedToken)!=0 ){
|
||||
sqlite3DbFree(db, p->u.zToken);
|
||||
}
|
||||
if( ExprHasProperty(p, EP_MemToken) ) sqlite3DbFree(db, p->u.zToken);
|
||||
if( ExprHasProperty(p, EP_xIsSelect) ){
|
||||
sqlite3SelectDelete(db, p->x.pSelect);
|
||||
}else{
|
||||
@@ -735,10 +734,10 @@ static int dupedExprStructSize(Expr *p, int flags){
|
||||
if( 0==(flags&EXPRDUP_REDUCE) ){
|
||||
nSize = EXPR_FULLSIZE;
|
||||
}else{
|
||||
assert( !ExprHasAnyProperty(p, EP_TokenOnly|EP_Reduced) );
|
||||
assert( !ExprHasProperty(p, EP_TokenOnly|EP_Reduced) );
|
||||
assert( !ExprHasProperty(p, EP_FromJoin) );
|
||||
assert( (p->flags2 & EP2_MallocedToken)==0 );
|
||||
assert( (p->flags2 & EP2_Irreducible)==0 );
|
||||
assert( !ExprHasProperty(p, EP_MemToken) );
|
||||
assert( !ExprHasProperty(p, EP_Irreduce) );
|
||||
if( p->pLeft || p->pRight || p->x.pList ){
|
||||
nSize = EXPR_REDUCEDSIZE | EP_Reduced;
|
||||
}else{
|
||||
@@ -835,7 +834,7 @@ static Expr *exprDup(sqlite3 *db, Expr *p, int flags, u8 **pzBuffer){
|
||||
}
|
||||
|
||||
/* Set the EP_Reduced, EP_TokenOnly, and EP_Static flags appropriately. */
|
||||
pNew->flags &= ~(EP_Reduced|EP_TokenOnly|EP_Static);
|
||||
pNew->flags &= ~(EP_Reduced|EP_TokenOnly|EP_Static|EP_MemToken);
|
||||
pNew->flags |= nStructSize & (EP_Reduced|EP_TokenOnly);
|
||||
pNew->flags |= staticFlag;
|
||||
|
||||
@@ -855,7 +854,7 @@ static Expr *exprDup(sqlite3 *db, Expr *p, int flags, u8 **pzBuffer){
|
||||
}
|
||||
|
||||
/* Fill in pNew->pLeft and pNew->pRight. */
|
||||
if( ExprHasAnyProperty(pNew, EP_Reduced|EP_TokenOnly) ){
|
||||
if( ExprHasProperty(pNew, EP_Reduced|EP_TokenOnly) ){
|
||||
zAlloc += dupedExprNodeSize(p, flags);
|
||||
if( ExprHasProperty(pNew, EP_Reduced) ){
|
||||
pNew->pLeft = exprDup(db, p->pLeft, EXPRDUP_REDUCE, &zAlloc);
|
||||
@@ -865,8 +864,7 @@ static Expr *exprDup(sqlite3 *db, Expr *p, int flags, u8 **pzBuffer){
|
||||
*pzBuffer = zAlloc;
|
||||
}
|
||||
}else{
|
||||
pNew->flags2 = 0;
|
||||
if( !ExprHasAnyProperty(p, EP_TokenOnly) ){
|
||||
if( !ExprHasProperty(p, EP_TokenOnly) ){
|
||||
pNew->pLeft = sqlite3ExprDup(db, p->pLeft, 0);
|
||||
pNew->pRight = sqlite3ExprDup(db, p->pRight, 0);
|
||||
}
|
||||
@@ -1176,7 +1174,7 @@ static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){
|
||||
/* If pWalker->u.i is 3 then any term of the expression that comes from
|
||||
** the ON or USING clauses of a join disqualifies the expression
|
||||
** from being considered constant. */
|
||||
if( pWalker->u.i==3 && ExprHasAnyProperty(pExpr, EP_FromJoin) ){
|
||||
if( pWalker->u.i==3 && ExprHasProperty(pExpr, EP_FromJoin) ){
|
||||
pWalker->u.i = 0;
|
||||
return WRC_Abort;
|
||||
}
|
||||
@@ -1279,6 +1277,7 @@ int sqlite3ExprIsInteger(Expr *p, int *pValue){
|
||||
case TK_UMINUS: {
|
||||
int v;
|
||||
if( sqlite3ExprIsInteger(p->pLeft, &v) ){
|
||||
assert( v!=(-2147483647-1) );
|
||||
*pValue = -v;
|
||||
rc = 1;
|
||||
}
|
||||
@@ -1606,7 +1605,7 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){
|
||||
}else{
|
||||
testcase( pParse->nQueryLoop>0 );
|
||||
pParse->nQueryLoop = 0;
|
||||
if( pX->pLeft->iColumn<0 && !ExprHasAnyProperty(pX, EP_xIsSelect) ){
|
||||
if( pX->pLeft->iColumn<0 && !ExprHasProperty(pX, EP_xIsSelect) ){
|
||||
eType = IN_INDEX_ROWID;
|
||||
}
|
||||
}
|
||||
@@ -1675,7 +1674,7 @@ int sqlite3CodeSubselect(
|
||||
** If all of the above are false, then we can run this code just once
|
||||
** save the results, and reuse the same result on subsequent invocations.
|
||||
*/
|
||||
if( !ExprHasAnyProperty(pExpr, EP_VarSelect) ){
|
||||
if( !ExprHasProperty(pExpr, EP_VarSelect) ){
|
||||
testAddr = sqlite3CodeOnce(pParse);
|
||||
}
|
||||
|
||||
@@ -2615,7 +2614,7 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
|
||||
assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
|
||||
testcase( op==TK_CONST_FUNC );
|
||||
testcase( op==TK_FUNCTION );
|
||||
if( ExprHasAnyProperty(pExpr, EP_TokenOnly) ){
|
||||
if( ExprHasProperty(pExpr, EP_TokenOnly) ){
|
||||
pFarg = 0;
|
||||
}else{
|
||||
pFarg = pExpr->x.pList;
|
||||
@@ -2634,7 +2633,7 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
|
||||
** IFNULL() functions. This avoids unnecessary evalation of
|
||||
** arguments past the first non-NULL argument.
|
||||
*/
|
||||
if( pDef->flags & SQLITE_FUNC_COALESCE ){
|
||||
if( pDef->funcFlags & SQLITE_FUNC_COALESCE ){
|
||||
int endCoalesce = sqlite3VdbeMakeLabel(v);
|
||||
assert( nFarg>=2 );
|
||||
sqlite3ExprCode(pParse, pFarg->a[0].pExpr, target);
|
||||
@@ -2658,7 +2657,7 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
|
||||
** or OPFLAG_TYPEOFARG respectively, to avoid unnecessary data
|
||||
** loading.
|
||||
*/
|
||||
if( (pDef->flags & (SQLITE_FUNC_LENGTH|SQLITE_FUNC_TYPEOF))!=0 ){
|
||||
if( (pDef->funcFlags & (SQLITE_FUNC_LENGTH|SQLITE_FUNC_TYPEOF))!=0 ){
|
||||
u8 exprOp;
|
||||
assert( nFarg==1 );
|
||||
assert( pFarg->a[0].pExpr!=0 );
|
||||
@@ -2666,8 +2665,9 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
|
||||
if( exprOp==TK_COLUMN || exprOp==TK_AGG_COLUMN ){
|
||||
assert( SQLITE_FUNC_LENGTH==OPFLAG_LENGTHARG );
|
||||
assert( SQLITE_FUNC_TYPEOF==OPFLAG_TYPEOFARG );
|
||||
testcase( pDef->flags==SQLITE_FUNC_LENGTH );
|
||||
pFarg->a[0].pExpr->op2 = pDef->flags;
|
||||
testcase( (pDef->funcFlags&~SQLITE_FUNC_ENCMASK)
|
||||
==SQLITE_FUNC_LENGTH );
|
||||
pFarg->a[0].pExpr->op2 = pDef->funcFlags&~SQLITE_FUNC_ENCMASK;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2700,11 +2700,11 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
|
||||
if( i<32 && sqlite3ExprIsConstant(pFarg->a[i].pExpr) ){
|
||||
constMask |= (1<<i);
|
||||
}
|
||||
if( (pDef->flags & SQLITE_FUNC_NEEDCOLL)!=0 && !pColl ){
|
||||
if( (pDef->funcFlags & SQLITE_FUNC_NEEDCOLL)!=0 && !pColl ){
|
||||
pColl = sqlite3ExprCollSeq(pParse, pFarg->a[i].pExpr);
|
||||
}
|
||||
}
|
||||
if( pDef->flags & SQLITE_FUNC_NEEDCOLL ){
|
||||
if( pDef->funcFlags & SQLITE_FUNC_NEEDCOLL ){
|
||||
if( !pColl ) pColl = db->pDfltColl;
|
||||
sqlite3VdbeAddOp4(v, OP_CollSeq, 0, 0, 0, (char *)pColl, P4_COLLSEQ);
|
||||
}
|
||||
@@ -2845,9 +2845,9 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
|
||||
** WHEN x=eN THEN rN ELSE y END
|
||||
**
|
||||
** X (if it exists) is in pExpr->pLeft.
|
||||
** Y is in pExpr->pRight. The Y is also optional. If there is no
|
||||
** ELSE clause and no other term matches, then the result of the
|
||||
** exprssion is NULL.
|
||||
** Y is in the last element of pExpr->x.pList if pExpr->x.pList->nExpr is
|
||||
** odd. The Y is also optional. If the number of elements in x.pList
|
||||
** is even, then Y is omitted and the "otherwise" result is NULL.
|
||||
** Ei is in pExpr->pList->a[i*2] and Ri is pExpr->pList->a[i*2+1].
|
||||
**
|
||||
** The result of the expression is the Ri for the first matching Ei,
|
||||
@@ -2868,7 +2868,6 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
|
||||
VVA_ONLY( int iCacheLevel = pParse->iCacheLevel; )
|
||||
|
||||
assert( !ExprHasProperty(pExpr, EP_xIsSelect) && pExpr->x.pList );
|
||||
assert((pExpr->x.pList->nExpr % 2) == 0);
|
||||
assert(pExpr->x.pList->nExpr > 0);
|
||||
pEList = pExpr->x.pList;
|
||||
aListelem = pEList->a;
|
||||
@@ -2890,7 +2889,7 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
|
||||
** purposes and possibly overwritten. */
|
||||
regFree1 = 0;
|
||||
}
|
||||
for(i=0; i<nExpr; i=i+2){
|
||||
for(i=0; i<nExpr-1; i=i+2){
|
||||
sqlite3ExprCachePush(pParse);
|
||||
if( pX ){
|
||||
assert( pTest!=0 );
|
||||
@@ -2908,9 +2907,9 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
|
||||
sqlite3ExprCachePop(pParse, 1);
|
||||
sqlite3VdbeResolveLabel(v, nextCase);
|
||||
}
|
||||
if( pExpr->pRight ){
|
||||
if( (nExpr&1)!=0 ){
|
||||
sqlite3ExprCachePush(pParse);
|
||||
sqlite3ExprCode(pParse, pExpr->pRight, target);
|
||||
sqlite3ExprCode(pParse, pEList->a[nExpr-1].pExpr, target);
|
||||
sqlite3ExprCachePop(pParse, 1);
|
||||
}else{
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, target);
|
||||
@@ -3154,7 +3153,7 @@ void sqlite3ExplainExpr(Vdbe *pOut, Expr *pExpr){
|
||||
case TK_CONST_FUNC:
|
||||
case TK_FUNCTION: {
|
||||
ExprList *pFarg; /* List of function arguments */
|
||||
if( ExprHasAnyProperty(pExpr, EP_TokenOnly) ){
|
||||
if( ExprHasProperty(pExpr, EP_TokenOnly) ){
|
||||
pFarg = 0;
|
||||
}else{
|
||||
pFarg = pExpr->x.pList;
|
||||
@@ -3504,6 +3503,7 @@ static void exprCodeBetween(
|
||||
compRight.pLeft = &exprX;
|
||||
compRight.pRight = pExpr->x.pList->a[1].pExpr;
|
||||
exprX.iTable = sqlite3ExprCodeTemp(pParse, &exprX, ®Free1);
|
||||
exprX.op2 = exprX.op;
|
||||
exprX.op = TK_REGISTER;
|
||||
if( jumpIfTrue ){
|
||||
sqlite3ExprIfTrue(pParse, &exprAnd, dest, jumpIfNull);
|
||||
@@ -3819,8 +3819,8 @@ int sqlite3ExprCompare(Expr *pA, Expr *pB, int iTab){
|
||||
if( pA==0||pB==0 ){
|
||||
return pB==pA ? 0 : 2;
|
||||
}
|
||||
assert( !ExprHasAnyProperty(pA, EP_TokenOnly|EP_Reduced) );
|
||||
assert( !ExprHasAnyProperty(pB, EP_TokenOnly|EP_Reduced) );
|
||||
assert( !ExprHasProperty(pA, EP_TokenOnly|EP_Reduced) );
|
||||
assert( !ExprHasProperty(pB, EP_TokenOnly|EP_Reduced) );
|
||||
if( ExprHasProperty(pA, EP_xIsSelect) || ExprHasProperty(pB, EP_xIsSelect) ){
|
||||
return 2;
|
||||
}
|
||||
@@ -4034,7 +4034,7 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){
|
||||
struct SrcList_item *pItem = pSrcList->a;
|
||||
for(i=0; i<pSrcList->nSrc; i++, pItem++){
|
||||
struct AggInfo_col *pCol;
|
||||
assert( !ExprHasAnyProperty(pExpr, EP_TokenOnly|EP_Reduced) );
|
||||
assert( !ExprHasProperty(pExpr, EP_TokenOnly|EP_Reduced) );
|
||||
if( pExpr->iTable==pItem->iCursor ){
|
||||
/* If we reach this point, it means that pExpr refers to a table
|
||||
** that is in the FROM clause of the aggregate query.
|
||||
@@ -4129,7 +4129,7 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){
|
||||
}
|
||||
/* Make pExpr point to the appropriate pAggInfo->aFunc[] entry
|
||||
*/
|
||||
assert( !ExprHasAnyProperty(pExpr, EP_TokenOnly|EP_Reduced) );
|
||||
assert( !ExprHasProperty(pExpr, EP_TokenOnly|EP_Reduced) );
|
||||
ExprSetIrreducible(pExpr);
|
||||
pExpr->iAgg = (i16)i;
|
||||
pExpr->pAggInfo = pAggInfo;
|
||||
|
||||
+89
-23
@@ -682,6 +682,70 @@ void sqlite3FkDropTable(Parse *pParse, SrcList *pName, Table *pTab){
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** The second argument points to an FKey object representing a foreign key
|
||||
** for which pTab is the child table. An UPDATE statement against pTab
|
||||
** is currently being processed. For each column of the table that is
|
||||
** actually updated, the corresponding element in the aChange[] array
|
||||
** is zero or greater (if a column is unmodified the corresponding element
|
||||
** is set to -1). If the rowid column is modified by the UPDATE statement
|
||||
** the bChngRowid argument is non-zero.
|
||||
**
|
||||
** This function returns true if any of the columns that are part of the
|
||||
** child key for FK constraint *p are modified.
|
||||
*/
|
||||
static int fkChildIsModified(
|
||||
Table *pTab, /* Table being updated */
|
||||
FKey *p, /* Foreign key for which pTab is the child */
|
||||
int *aChange, /* Array indicating modified columns */
|
||||
int bChngRowid /* True if rowid is modified by this update */
|
||||
){
|
||||
int i;
|
||||
for(i=0; i<p->nCol; i++){
|
||||
int iChildKey = p->aCol[i].iFrom;
|
||||
if( aChange[iChildKey]>=0 ) return 1;
|
||||
if( iChildKey==pTab->iPKey && bChngRowid ) return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** The second argument points to an FKey object representing a foreign key
|
||||
** for which pTab is the parent table. An UPDATE statement against pTab
|
||||
** is currently being processed. For each column of the table that is
|
||||
** actually updated, the corresponding element in the aChange[] array
|
||||
** is zero or greater (if a column is unmodified the corresponding element
|
||||
** is set to -1). If the rowid column is modified by the UPDATE statement
|
||||
** the bChngRowid argument is non-zero.
|
||||
**
|
||||
** This function returns true if any of the columns that are part of the
|
||||
** parent key for FK constraint *p are modified.
|
||||
*/
|
||||
static int fkParentIsModified(
|
||||
Table *pTab,
|
||||
FKey *p,
|
||||
int *aChange,
|
||||
int bChngRowid
|
||||
){
|
||||
int i;
|
||||
for(i=0; i<p->nCol; i++){
|
||||
char *zKey = p->aCol[i].zCol;
|
||||
int iKey;
|
||||
for(iKey=0; iKey<pTab->nCol; iKey++){
|
||||
if( aChange[iKey]>=0 || (iKey==pTab->iPKey && bChngRowid) ){
|
||||
Column *pCol = &pTab->aCol[iKey];
|
||||
if( zKey ){
|
||||
if( 0==sqlite3StrICmp(pCol->zName, zKey) ) return 1;
|
||||
}else if( pCol->colFlags & COLFLAG_PRIMKEY ){
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** This function is called when inserting, deleting or updating a row of
|
||||
** table pTab to generate VDBE code to perform foreign key constraint
|
||||
@@ -706,7 +770,9 @@ void sqlite3FkCheck(
|
||||
Parse *pParse, /* Parse context */
|
||||
Table *pTab, /* Row is being deleted from this table */
|
||||
int regOld, /* Previous row data is stored here */
|
||||
int regNew /* New row data is stored here */
|
||||
int regNew, /* New row data is stored here */
|
||||
int *aChange, /* Array indicating UPDATEd columns (or 0) */
|
||||
int bChngRowid /* True if rowid is UPDATEd */
|
||||
){
|
||||
sqlite3 *db = pParse->db; /* Database handle */
|
||||
FKey *pFKey; /* Used to iterate through FKs */
|
||||
@@ -734,6 +800,13 @@ void sqlite3FkCheck(
|
||||
int i;
|
||||
int isIgnore = 0;
|
||||
|
||||
if( aChange
|
||||
&& sqlite3_stricmp(pTab->zName, pFKey->zTo)!=0
|
||||
&& fkChildIsModified(pTab, pFKey, aChange, bChngRowid)==0
|
||||
){
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Find the parent table of this foreign key. Also find a unique index
|
||||
** on the parent key columns in the parent table. If either of these
|
||||
** schema items cannot be located, set an error in pParse and return
|
||||
@@ -816,6 +889,10 @@ void sqlite3FkCheck(
|
||||
SrcList *pSrc;
|
||||
int *aiCol = 0;
|
||||
|
||||
if( aChange && fkParentIsModified(pTab, pFKey, aChange, bChngRowid)==0 ){
|
||||
continue;
|
||||
}
|
||||
|
||||
if( !pFKey->isDeferred && !(db->flags & SQLITE_DeferFKs)
|
||||
&& !pParse->pToplevel && !pParse->isMultiWrite
|
||||
){
|
||||
@@ -889,6 +966,7 @@ u32 sqlite3FkOldmask(
|
||||
return mask;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** This function is called before generating code to update or delete a
|
||||
** row contained in table pTab. If the operation is a DELETE, then
|
||||
@@ -918,32 +996,16 @@ int sqlite3FkRequired(
|
||||
}else{
|
||||
/* This is an UPDATE. Foreign key processing is only required if the
|
||||
** operation modifies one or more child or parent key columns. */
|
||||
int i;
|
||||
FKey *p;
|
||||
|
||||
/* Check if any child key columns are being modified. */
|
||||
for(p=pTab->pFKey; p; p=p->pNextFrom){
|
||||
for(i=0; i<p->nCol; i++){
|
||||
int iChildKey = p->aCol[i].iFrom;
|
||||
if( aChange[iChildKey]>=0 ) return 1;
|
||||
if( iChildKey==pTab->iPKey && chngRowid ) return 1;
|
||||
}
|
||||
if( fkChildIsModified(pTab, p, aChange, chngRowid) ) return 1;
|
||||
}
|
||||
|
||||
/* Check if any parent key columns are being modified. */
|
||||
for(p=sqlite3FkReferences(pTab); p; p=p->pNextTo){
|
||||
for(i=0; i<p->nCol; i++){
|
||||
char *zKey = p->aCol[i].zCol;
|
||||
int iKey;
|
||||
for(iKey=0; iKey<pTab->nCol; iKey++){
|
||||
Column *pCol = &pTab->aCol[iKey];
|
||||
if( (zKey ? !sqlite3StrICmp(pCol->zName, zKey)
|
||||
: (pCol->colFlags & COLFLAG_PRIMKEY)!=0) ){
|
||||
if( aChange[iKey]>=0 ) return 1;
|
||||
if( iKey==pTab->iPKey && chngRowid ) return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if( fkParentIsModified(pTab, p, aChange, chngRowid) ) return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1169,7 +1231,9 @@ void sqlite3FkActions(
|
||||
Parse *pParse, /* Parse context */
|
||||
Table *pTab, /* Table being updated or deleted from */
|
||||
ExprList *pChanges, /* Change-list for UPDATE, NULL for DELETE */
|
||||
int regOld /* Address of array containing old row */
|
||||
int regOld, /* Address of array containing old row */
|
||||
int *aChange, /* Array indicating UPDATEd columns (or 0) */
|
||||
int bChngRowid /* True if rowid is UPDATEd */
|
||||
){
|
||||
/* If foreign-key support is enabled, iterate through all FKs that
|
||||
** refer to table pTab. If there is an action associated with the FK
|
||||
@@ -1178,9 +1242,11 @@ void sqlite3FkActions(
|
||||
if( pParse->db->flags&SQLITE_ForeignKeys ){
|
||||
FKey *pFKey; /* Iterator variable */
|
||||
for(pFKey = sqlite3FkReferences(pTab); pFKey; pFKey=pFKey->pNextTo){
|
||||
Trigger *pAction = fkActionTrigger(pParse, pTab, pFKey, pChanges);
|
||||
if( pAction ){
|
||||
sqlite3CodeRowTriggerDirect(pParse, pAction, pTab, regOld, OE_Abort, 0);
|
||||
if( aChange==0 || fkParentIsModified(pTab, pFKey, aChange, bChngRowid) ){
|
||||
Trigger *pAct = fkActionTrigger(pParse, pTab, pFKey, pChanges);
|
||||
if( pAct ){
|
||||
sqlite3CodeRowTriggerDirect(pParse, pAct, pTab, regOld, OE_Abort, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+9
-6
@@ -1522,9 +1522,9 @@ static void groupConcatFinalize(sqlite3_context *context){
|
||||
StrAccum *pAccum;
|
||||
pAccum = sqlite3_aggregate_context(context, 0);
|
||||
if( pAccum ){
|
||||
if( pAccum->tooBig ){
|
||||
if( pAccum->accError==STRACCUM_TOOBIG ){
|
||||
sqlite3_result_error_toobig(context);
|
||||
}else if( pAccum->mallocFailed ){
|
||||
}else if( pAccum->accError==STRACCUM_NOMEM ){
|
||||
sqlite3_result_error_nomem(context);
|
||||
}else{
|
||||
sqlite3_result_text(context, sqlite3StrAccumFinish(pAccum), -1,
|
||||
@@ -1554,7 +1554,7 @@ static void setLikeOptFlag(sqlite3 *db, const char *zName, u8 flagVal){
|
||||
pDef = sqlite3FindFunction(db, zName, sqlite3Strlen30(zName),
|
||||
2, SQLITE_UTF8, 0);
|
||||
if( ALWAYS(pDef) ){
|
||||
pDef->flags = flagVal;
|
||||
pDef->funcFlags |= flagVal;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1598,7 +1598,7 @@ int sqlite3IsLikeFunction(sqlite3 *db, Expr *pExpr, int *pIsNocase, char *aWc){
|
||||
pDef = sqlite3FindFunction(db, pExpr->u.zToken,
|
||||
sqlite3Strlen30(pExpr->u.zToken),
|
||||
2, SQLITE_UTF8, 0);
|
||||
if( NEVER(pDef==0) || (pDef->flags & SQLITE_FUNC_LIKE)==0 ){
|
||||
if( NEVER(pDef==0) || (pDef->funcFlags & SQLITE_FUNC_LIKE)==0 ){
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1610,7 +1610,7 @@ int sqlite3IsLikeFunction(sqlite3 *db, Expr *pExpr, int *pIsNocase, char *aWc){
|
||||
assert( (char*)&likeInfoAlt == (char*)&likeInfoAlt.matchAll );
|
||||
assert( &((char*)&likeInfoAlt)[1] == (char*)&likeInfoAlt.matchOne );
|
||||
assert( &((char*)&likeInfoAlt)[2] == (char*)&likeInfoAlt.matchSet );
|
||||
*pIsNocase = (pDef->flags & SQLITE_FUNC_CASE)==0;
|
||||
*pIsNocase = (pDef->funcFlags & SQLITE_FUNC_CASE)==0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -1689,7 +1689,7 @@ void sqlite3RegisterGlobalFunctions(void){
|
||||
AGGREGATE(total, 1, 0, 0, sumStep, totalFinalize ),
|
||||
AGGREGATE(avg, 1, 0, 0, sumStep, avgFinalize ),
|
||||
/* AGGREGATE(count, 0, 0, 0, countStep, countFinalize ), */
|
||||
{0,SQLITE_UTF8,SQLITE_FUNC_COUNT,0,0,0,countStep,countFinalize,"count",0,0},
|
||||
{0,SQLITE_UTF8|SQLITE_FUNC_COUNT,0,0,0,countStep,countFinalize,"count",0,0},
|
||||
AGGREGATE(count, 1, 0, 0, countStep, countFinalize ),
|
||||
AGGREGATE(group_concat, 1, 0, 0, groupConcatStep, groupConcatFinalize),
|
||||
AGGREGATE(group_concat, 2, 0, 0, groupConcatStep, groupConcatFinalize),
|
||||
@@ -1715,4 +1715,7 @@ void sqlite3RegisterGlobalFunctions(void){
|
||||
#ifndef SQLITE_OMIT_ALTERTABLE
|
||||
sqlite3AlterFunctions();
|
||||
#endif
|
||||
#if defined(SQLITE_ENABLE_STAT3) || defined(SQLITE_ENABLE_STAT4)
|
||||
sqlite3AnalyzeFunctions();
|
||||
#endif
|
||||
}
|
||||
|
||||
+1
-1
@@ -1031,7 +1031,7 @@ void sqlite3Insert(
|
||||
sqlite3GenerateConstraintChecks(pParse, pTab, baseCur, regIns, aRegIdx,
|
||||
keyColumn>=0, 0, onError, endOfLoop, &isReplace
|
||||
);
|
||||
sqlite3FkCheck(pParse, pTab, 0, regIns);
|
||||
sqlite3FkCheck(pParse, pTab, 0, regIns, 0, 0);
|
||||
sqlite3CompleteInsertion(
|
||||
pParse, pTab, baseCur, regIns, aRegIdx, 0, appendFlag, isReplace==0
|
||||
);
|
||||
|
||||
+5
-3
@@ -1107,6 +1107,7 @@ const char *sqlite3ErrName(int rc){
|
||||
case SQLITE_IOERR_DELETE_NOENT: zName = "SQLITE_IOERR_DELETE_NOENT";break;
|
||||
case SQLITE_IOERR_MMAP: zName = "SQLITE_IOERR_MMAP"; break;
|
||||
case SQLITE_IOERR_GETTEMPPATH: zName = "SQLITE_IOERR_GETTEMPPATH"; break;
|
||||
case SQLITE_IOERR_CONVPATH: zName = "SQLITE_IOERR_CONVPATH"; break;
|
||||
case SQLITE_CORRUPT: zName = "SQLITE_CORRUPT"; break;
|
||||
case SQLITE_CORRUPT_VTAB: zName = "SQLITE_CORRUPT_VTAB"; break;
|
||||
case SQLITE_NOTFOUND: zName = "SQLITE_NOTFOUND"; break;
|
||||
@@ -1115,6 +1116,7 @@ const char *sqlite3ErrName(int rc){
|
||||
case SQLITE_CANTOPEN_NOTEMPDIR: zName = "SQLITE_CANTOPEN_NOTEMPDIR";break;
|
||||
case SQLITE_CANTOPEN_ISDIR: zName = "SQLITE_CANTOPEN_ISDIR"; break;
|
||||
case SQLITE_CANTOPEN_FULLPATH: zName = "SQLITE_CANTOPEN_FULLPATH"; break;
|
||||
case SQLITE_CANTOPEN_CONVPATH: zName = "SQLITE_CANTOPEN_CONVPATH"; break;
|
||||
case SQLITE_PROTOCOL: zName = "SQLITE_PROTOCOL"; break;
|
||||
case SQLITE_EMPTY: zName = "SQLITE_EMPTY"; break;
|
||||
case SQLITE_SCHEMA: zName = "SQLITE_SCHEMA"; break;
|
||||
@@ -1404,7 +1406,7 @@ int sqlite3CreateFunc(
|
||||
** operation to continue but invalidate all precompiled statements.
|
||||
*/
|
||||
p = sqlite3FindFunction(db, zFunctionName, nName, nArg, (u8)enc, 0);
|
||||
if( p && p->iPrefEnc==enc && p->nArg==nArg ){
|
||||
if( p && (p->funcFlags & SQLITE_FUNC_ENCMASK)==enc && p->nArg==nArg ){
|
||||
if( db->nVdbeActive ){
|
||||
sqlite3Error(db, SQLITE_BUSY,
|
||||
"unable to delete/modify user-function due to active statements");
|
||||
@@ -1429,7 +1431,7 @@ int sqlite3CreateFunc(
|
||||
pDestructor->nRef++;
|
||||
}
|
||||
p->pDestructor = pDestructor;
|
||||
p->flags = 0;
|
||||
p->funcFlags &= SQLITE_FUNC_ENCMASK;
|
||||
p->xFunc = xFunc;
|
||||
p->xStep = xStep;
|
||||
p->xFinalize = xFinal;
|
||||
@@ -2461,7 +2463,7 @@ static int openDatabase(
|
||||
db->nextAutovac = -1;
|
||||
db->szMmap = sqlite3GlobalConfig.szMmap;
|
||||
db->nextPagesize = 0;
|
||||
db->flags |= SQLITE_ShortColNames | SQLITE_EnableTrigger
|
||||
db->flags |= SQLITE_ShortColNames | SQLITE_EnableTrigger | SQLITE_CacheSpill
|
||||
#if !defined(SQLITE_DEFAULT_AUTOMATIC_INDEX) || SQLITE_DEFAULT_AUTOMATIC_INDEX
|
||||
| SQLITE_AutoIndex
|
||||
#endif
|
||||
|
||||
+8
-8
@@ -179,7 +179,7 @@ static int sqlite3MemSize(void *p){
|
||||
return 0;
|
||||
}
|
||||
pHdr = sqlite3MemsysGetHeader(p);
|
||||
return pHdr->iSize;
|
||||
return (int)pHdr->iSize;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -221,7 +221,7 @@ static void randomFill(char *pBuf, int nByte){
|
||||
x = SQLITE_PTR_TO_INT(pBuf);
|
||||
y = nByte | 1;
|
||||
while( nByte >= 4 ){
|
||||
x = (x>>1) ^ (-(x&1) & 0xd0000001);
|
||||
x = (x>>1) ^ (-(int)(x&1) & 0xd0000001);
|
||||
y = y*1103515245 + 12345;
|
||||
r = x ^ y;
|
||||
*(int*)pBuf = r;
|
||||
@@ -229,7 +229,7 @@ static void randomFill(char *pBuf, int nByte){
|
||||
nByte -= 4;
|
||||
}
|
||||
while( nByte-- > 0 ){
|
||||
x = (x>>1) ^ (-(x&1) & 0xd0000001);
|
||||
x = (x>>1) ^ (-(int)(x&1) & 0xd0000001);
|
||||
y = y*1103515245 + 12345;
|
||||
r = x ^ y;
|
||||
*(pBuf++) = r & 0xff;
|
||||
@@ -324,9 +324,9 @@ static void sqlite3MemFree(void *pPrior){
|
||||
}
|
||||
z = (char*)pBt;
|
||||
z -= pHdr->nTitle;
|
||||
adjustStats(pHdr->iSize, -1);
|
||||
adjustStats((int)pHdr->iSize, -1);
|
||||
randomFill(z, sizeof(void*)*pHdr->nBacktraceSlots + sizeof(*pHdr) +
|
||||
pHdr->iSize + sizeof(int) + pHdr->nTitle);
|
||||
(int)pHdr->iSize + sizeof(int) + pHdr->nTitle);
|
||||
free(z);
|
||||
sqlite3_mutex_leave(mem.mutex);
|
||||
}
|
||||
@@ -348,9 +348,9 @@ static void *sqlite3MemRealloc(void *pPrior, int nByte){
|
||||
pOldHdr = sqlite3MemsysGetHeader(pPrior);
|
||||
pNew = sqlite3MemMalloc(nByte);
|
||||
if( pNew ){
|
||||
memcpy(pNew, pPrior, nByte<pOldHdr->iSize ? nByte : pOldHdr->iSize);
|
||||
memcpy(pNew, pPrior, (int)(nByte<pOldHdr->iSize ? nByte : pOldHdr->iSize));
|
||||
if( nByte>pOldHdr->iSize ){
|
||||
randomFill(&((char*)pNew)[pOldHdr->iSize], nByte - pOldHdr->iSize);
|
||||
randomFill(&((char*)pNew)[pOldHdr->iSize], nByte - (int)pOldHdr->iSize);
|
||||
}
|
||||
sqlite3MemFree(pPrior);
|
||||
}
|
||||
@@ -465,7 +465,7 @@ void sqlite3MemdebugSync(){
|
||||
for(pHdr=mem.pFirst; pHdr; pHdr=pHdr->pNext){
|
||||
void **pBt = (void**)pHdr;
|
||||
pBt -= pHdr->nBacktraceSlots;
|
||||
mem.xBacktrace(pHdr->iSize, pHdr->nBacktrace-1, &pBt[1]);
|
||||
mem.xBacktrace((int)pHdr->iSize, pHdr->nBacktrace-1, &pBt[1]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -69,7 +69,7 @@ struct sqlite3_mutex {
|
||||
}
|
||||
return osType==2;
|
||||
}
|
||||
#endif /* SQLITE_OS_WINCE */
|
||||
#endif /* SQLITE_OS_WINCE || SQLITE_OS_WINRT */
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_DEBUG
|
||||
@@ -107,7 +107,7 @@ static int winMutex_isInit = 0;
|
||||
** processing, the "interlocked" magic is probably not
|
||||
** strictly necessary.
|
||||
*/
|
||||
static long winMutex_lock = 0;
|
||||
static LONG winMutex_lock = 0;
|
||||
|
||||
void sqlite3_win32_sleep(DWORD milliseconds); /* os_win.c */
|
||||
|
||||
|
||||
+46
-11
@@ -218,11 +218,13 @@ struct unixFile {
|
||||
const char *zPath; /* Name of the file */
|
||||
unixShm *pShm; /* Shared memory segment information */
|
||||
int szChunk; /* Configured by FCNTL_CHUNK_SIZE */
|
||||
#if SQLITE_MAX_MMAP_SIZE>0
|
||||
int nFetchOut; /* Number of outstanding xFetch refs */
|
||||
sqlite3_int64 mmapSize; /* Usable size of mapping at pMapRegion */
|
||||
sqlite3_int64 mmapSizeActual; /* Actual size of mapping at pMapRegion */
|
||||
sqlite3_int64 mmapSizeMax; /* Configured FCNTL_MMAP_SIZE value */
|
||||
void *pMapRegion; /* Memory mapped region */
|
||||
#endif
|
||||
#ifdef __QNXNTO__
|
||||
int sectorSize; /* Device sector size */
|
||||
int deviceCharacteristics; /* Precomputed device characteristics */
|
||||
@@ -449,6 +451,7 @@ static struct unix_syscall {
|
||||
{ "fchown", (sqlite3_syscall_ptr)posixFchown, 0 },
|
||||
#define osFchown ((int(*)(int,uid_t,gid_t))aSyscall[20].pCurrent)
|
||||
|
||||
#if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0
|
||||
{ "mmap", (sqlite3_syscall_ptr)mmap, 0 },
|
||||
#define osMmap ((void*(*)(void*,size_t,int,int,int,off_t))aSyscall[21].pCurrent)
|
||||
|
||||
@@ -461,6 +464,7 @@ static struct unix_syscall {
|
||||
{ "mremap", (sqlite3_syscall_ptr)0, 0 },
|
||||
#endif
|
||||
#define osMremap ((void*(*)(void*,size_t,size_t,int,...))aSyscall[23].pCurrent)
|
||||
#endif
|
||||
|
||||
}; /* End of the overrideable system calls */
|
||||
|
||||
@@ -547,6 +551,15 @@ static const char *unixNextSystemCall(sqlite3_vfs *p, const char *zName){
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Do not accept any file descriptor less than this value, in order to avoid
|
||||
** opening database file using file descriptors that are commonly used for
|
||||
** standard input, output, and error.
|
||||
*/
|
||||
#ifndef SQLITE_MINIMUM_FILE_DESCRIPTOR
|
||||
# define SQLITE_MINIMUM_FILE_DESCRIPTOR 3
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Invoke open(). Do so multiple times, until it either succeeds or
|
||||
** fails for some reason other than EINTR.
|
||||
@@ -567,13 +580,23 @@ static const char *unixNextSystemCall(sqlite3_vfs *p, const char *zName){
|
||||
static int robust_open(const char *z, int f, mode_t m){
|
||||
int fd;
|
||||
mode_t m2 = m ? m : SQLITE_DEFAULT_FILE_PERMISSIONS;
|
||||
do{
|
||||
while(1){
|
||||
#if defined(O_CLOEXEC)
|
||||
fd = osOpen(z,f|O_CLOEXEC,m2);
|
||||
#else
|
||||
fd = osOpen(z,f,m2);
|
||||
#endif
|
||||
}while( fd<0 && errno==EINTR );
|
||||
if( fd<0 ){
|
||||
if( errno==EINTR ) continue;
|
||||
break;
|
||||
}
|
||||
if( fd>=SQLITE_MINIMUM_FILE_DESCRIPTOR ) break;
|
||||
osClose(fd);
|
||||
sqlite3_log(SQLITE_WARNING,
|
||||
"attempt to open \"%s\" as file descriptor %d", z, fd);
|
||||
fd = -1;
|
||||
if( osOpen("/dev/null", f, m)<0 ) break;
|
||||
}
|
||||
if( fd>=0 ){
|
||||
if( m!=0 ){
|
||||
struct stat statbuf;
|
||||
@@ -1871,8 +1894,10 @@ static int unixUnlock(sqlite3_file *id, int eFileLock){
|
||||
return posixUnlock(id, eFileLock, 0);
|
||||
}
|
||||
|
||||
#if SQLITE_MAX_MMAP_SIZE>0
|
||||
static int unixMapfile(unixFile *pFd, i64 nByte);
|
||||
static void unixUnmapfile(unixFile *pFd);
|
||||
#endif
|
||||
|
||||
/*
|
||||
** This function performs the parts of the "close file" operation
|
||||
@@ -1886,7 +1911,9 @@ static void unixUnmapfile(unixFile *pFd);
|
||||
*/
|
||||
static int closeUnixFile(sqlite3_file *id){
|
||||
unixFile *pFile = (unixFile*)id;
|
||||
#if SQLITE_MAX_MMAP_SIZE>0
|
||||
unixUnmapfile(pFile);
|
||||
#endif
|
||||
if( pFile->h>=0 ){
|
||||
robust_close(pFile, pFile->h, __LINE__);
|
||||
pFile->h = -1;
|
||||
@@ -3091,6 +3118,7 @@ static int seekAndRead(unixFile *id, sqlite3_int64 offset, void *pBuf, int cnt){
|
||||
#endif
|
||||
TIMER_START;
|
||||
assert( cnt==(cnt&0x1ffff) );
|
||||
assert( id->h>2 );
|
||||
cnt &= 0x1ffff;
|
||||
do{
|
||||
#if defined(USE_PREAD)
|
||||
@@ -3205,6 +3233,7 @@ static int seekAndWriteFd(
|
||||
int rc = 0; /* Value returned by system call */
|
||||
|
||||
assert( nBuf==(nBuf&0x1ffff) );
|
||||
assert( fd>2 );
|
||||
nBuf &= 0x1ffff;
|
||||
TIMER_START;
|
||||
|
||||
@@ -3590,6 +3619,7 @@ static int unixTruncate(sqlite3_file *id, i64 nByte){
|
||||
}
|
||||
#endif
|
||||
|
||||
#if SQLITE_MAX_MMAP_SIZE>0
|
||||
/* If the file was just truncated to a size smaller than the currently
|
||||
** mapped region, reduce the effective mapping size as well. SQLite will
|
||||
** use read() and write() to access data beyond this point from now on.
|
||||
@@ -3597,6 +3627,7 @@ static int unixTruncate(sqlite3_file *id, i64 nByte){
|
||||
if( nByte<pFile->mmapSize ){
|
||||
pFile->mmapSize = nByte;
|
||||
}
|
||||
#endif
|
||||
|
||||
return SQLITE_OK;
|
||||
}
|
||||
@@ -3686,6 +3717,7 @@ static int fcntlSizeHint(unixFile *pFile, i64 nByte){
|
||||
}
|
||||
}
|
||||
|
||||
#if SQLITE_MAX_MMAP_SIZE>0
|
||||
if( pFile->mmapSizeMax>0 && nByte>pFile->mmapSize ){
|
||||
int rc;
|
||||
if( pFile->szChunk<=0 ){
|
||||
@@ -3698,6 +3730,7 @@ static int fcntlSizeHint(unixFile *pFile, i64 nByte){
|
||||
rc = unixMapfile(pFile, nByte);
|
||||
return rc;
|
||||
}
|
||||
#endif
|
||||
|
||||
return SQLITE_OK;
|
||||
}
|
||||
@@ -3766,6 +3799,7 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
#if SQLITE_MAX_MMAP_SIZE>0
|
||||
case SQLITE_FCNTL_MMAP_SIZE: {
|
||||
i64 newLimit = *(i64*)pArg;
|
||||
int rc = SQLITE_OK;
|
||||
@@ -3782,6 +3816,7 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
#endif
|
||||
#ifdef SQLITE_DEBUG
|
||||
/* The pager calls this method to signal that it has done
|
||||
** a rollback and that the database is therefore unchanged and
|
||||
@@ -4592,22 +4627,20 @@ static int unixShmUnmap(
|
||||
# define unixShmUnmap 0
|
||||
#endif /* #ifndef SQLITE_OMIT_WAL */
|
||||
|
||||
#if SQLITE_MAX_MMAP_SIZE>0
|
||||
/*
|
||||
** If it is currently memory mapped, unmap file pFd.
|
||||
*/
|
||||
static void unixUnmapfile(unixFile *pFd){
|
||||
assert( pFd->nFetchOut==0 );
|
||||
#if SQLITE_MAX_MMAP_SIZE>0
|
||||
if( pFd->pMapRegion ){
|
||||
osMunmap(pFd->pMapRegion, pFd->mmapSizeActual);
|
||||
pFd->pMapRegion = 0;
|
||||
pFd->mmapSize = 0;
|
||||
pFd->mmapSizeActual = 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if SQLITE_MAX_MMAP_SIZE>0
|
||||
/*
|
||||
** Return the system page size.
|
||||
*/
|
||||
@@ -4620,9 +4653,7 @@ static int unixGetPagesize(void){
|
||||
return (int)sysconf(_SC_PAGESIZE);
|
||||
#endif
|
||||
}
|
||||
#endif /* SQLITE_MAX_MMAP_SIZE>0 */
|
||||
|
||||
#if SQLITE_MAX_MMAP_SIZE>0
|
||||
/*
|
||||
** Attempt to set the size of the memory mapping maintained by file
|
||||
** descriptor pFd to nNew bytes. Any existing mapping is discarded.
|
||||
@@ -4707,7 +4738,6 @@ static void unixRemapfile(
|
||||
pFd->pMapRegion = (void *)pNew;
|
||||
pFd->mmapSize = pFd->mmapSizeActual = nNew;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Memory map or remap the file opened by file-descriptor pFd (if the file
|
||||
@@ -4726,7 +4756,6 @@ static void unixRemapfile(
|
||||
** code otherwise.
|
||||
*/
|
||||
static int unixMapfile(unixFile *pFd, i64 nByte){
|
||||
#if SQLITE_MAX_MMAP_SIZE>0
|
||||
i64 nMap = nByte;
|
||||
int rc;
|
||||
|
||||
@@ -4752,10 +4781,10 @@ static int unixMapfile(unixFile *pFd, i64 nByte){
|
||||
unixUnmapfile(pFd);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return SQLITE_OK;
|
||||
}
|
||||
#endif /* SQLITE_MAX_MMAP_SIZE>0 */
|
||||
|
||||
/*
|
||||
** If possible, return a pointer to a mapping of file fd starting at offset
|
||||
@@ -4804,6 +4833,7 @@ static int unixUnfetch(sqlite3_file *fd, i64 iOff, void *p){
|
||||
unixFile *pFd = (unixFile *)fd; /* The underlying database file */
|
||||
UNUSED_PARAMETER(iOff);
|
||||
|
||||
#if SQLITE_MAX_MMAP_SIZE>0
|
||||
/* If p==0 (unmap the entire file) then there must be no outstanding
|
||||
** xFetch references. Or, if p!=0 (meaning it is an xFetch reference),
|
||||
** then there must be at least one outstanding. */
|
||||
@@ -4819,6 +4849,7 @@ static int unixUnfetch(sqlite3_file *fd, i64 iOff, void *p){
|
||||
}
|
||||
|
||||
assert( pFd->nFetchOut>=0 );
|
||||
#endif
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
@@ -5150,7 +5181,9 @@ static int fillInUnixFile(
|
||||
pNew->pVfs = pVfs;
|
||||
pNew->zPath = zFilename;
|
||||
pNew->ctrlFlags = (u8)ctrlFlags;
|
||||
#if SQLITE_MAX_MMAP_SIZE>0
|
||||
pNew->mmapSizeMax = sqlite3GlobalConfig.szMmap;
|
||||
#endif
|
||||
if( sqlite3_uri_boolean(((ctrlFlags & UNIXFILE_URI) ? zFilename : 0),
|
||||
"psow", SQLITE_POWERSAFE_OVERWRITE) ){
|
||||
pNew->ctrlFlags |= UNIXFILE_PSOW;
|
||||
@@ -5305,6 +5338,7 @@ static int fillInUnixFile(
|
||||
*/
|
||||
static const char *unixTempFileDir(void){
|
||||
static const char *azDirs[] = {
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
"/var/tmp",
|
||||
@@ -5317,7 +5351,8 @@ static const char *unixTempFileDir(void){
|
||||
const char *zDir = 0;
|
||||
|
||||
azDirs[0] = sqlite3_temp_directory;
|
||||
if( !azDirs[1] ) azDirs[1] = getenv("TMPDIR");
|
||||
if( !azDirs[1] ) azDirs[1] = getenv("SQLITE_TMPDIR");
|
||||
if( !azDirs[2] ) azDirs[2] = getenv("TMPDIR");
|
||||
for(i=0; i<sizeof(azDirs)/sizeof(azDirs[0]); zDir=azDirs[i++]){
|
||||
if( zDir==0 ) continue;
|
||||
if( osStat(zDir, &buf) ) continue;
|
||||
|
||||
+473
-225
File diff suppressed because it is too large
Load Diff
+65
-46
@@ -453,6 +453,13 @@ struct PagerSavepoint {
|
||||
#endif
|
||||
};
|
||||
|
||||
/*
|
||||
** Bits of the Pager.doNotSpill flag. See further description below.
|
||||
*/
|
||||
#define SPILLFLAG_OFF 0x01 /* Never spill cache. Set via pragma */
|
||||
#define SPILLFLAG_ROLLBACK 0x02 /* Current rolling back, so do not spill */
|
||||
#define SPILLFLAG_NOSYNC 0x04 /* Spill is ok, but do not sync */
|
||||
|
||||
/*
|
||||
** A open page cache is an instance of struct Pager. A description of
|
||||
** some of the more important member variables follows:
|
||||
@@ -519,19 +526,21 @@ struct PagerSavepoint {
|
||||
** journal file from being successfully finalized, the setMaster flag
|
||||
** is cleared anyway (and the pager will move to ERROR state).
|
||||
**
|
||||
** doNotSpill, doNotSyncSpill
|
||||
** doNotSpill
|
||||
**
|
||||
** These two boolean variables control the behavior of cache-spills
|
||||
** (calls made by the pcache module to the pagerStress() routine to
|
||||
** write cached data to the file-system in order to free up memory).
|
||||
** This variables control the behavior of cache-spills (calls made by
|
||||
** the pcache module to the pagerStress() routine to write cached data
|
||||
** to the file-system in order to free up memory).
|
||||
**
|
||||
** When doNotSpill is non-zero, writing to the database from pagerStress()
|
||||
** is disabled altogether. This is done in a very obscure case that
|
||||
** When bits SPILLFLAG_OFF or SPILLFLAG_ROLLBACK of doNotSpill are set,
|
||||
** writing to the database from pagerStress() is disabled altogether.
|
||||
** The SPILLFLAG_ROLLBACK case is done in a very obscure case that
|
||||
** comes up during savepoint rollback that requires the pcache module
|
||||
** to allocate a new page to prevent the journal file from being written
|
||||
** while it is being traversed by code in pager_playback().
|
||||
** while it is being traversed by code in pager_playback(). The SPILLFLAG_OFF
|
||||
** case is a user preference.
|
||||
**
|
||||
** If doNotSyncSpill is non-zero, writing to the database from pagerStress()
|
||||
** If the SPILLFLAG_NOSYNC bit is set, writing to the database from pagerStress()
|
||||
** is permitted, but syncing the journal file is not. This flag is set
|
||||
** by sqlite3PagerWrite() when the file-system sector-size is larger than
|
||||
** the database page-size in order to prevent a journal sync from happening
|
||||
@@ -635,7 +644,6 @@ struct Pager {
|
||||
u8 changeCountDone; /* Set after incrementing the change-counter */
|
||||
u8 setMaster; /* True if a m-j name has been written to jrnl */
|
||||
u8 doNotSpill; /* Do not spill the cache when non-zero */
|
||||
u8 doNotSyncSpill; /* Do not do a spill that requires jrnl sync */
|
||||
u8 subjInMemory; /* True to use in-memory sub-journals */
|
||||
Pgno dbSize; /* Number of pages in the database */
|
||||
Pgno dbOrigSize; /* dbSize before the current transaction */
|
||||
@@ -1014,13 +1022,17 @@ static char *print_pager_state(Pager *p){
|
||||
** PagerSavepoint.pInSavepoint.
|
||||
*/
|
||||
static int subjRequiresPage(PgHdr *pPg){
|
||||
Pgno pgno = pPg->pgno;
|
||||
Pager *pPager = pPg->pPager;
|
||||
PagerSavepoint *p;
|
||||
Pgno pgno;
|
||||
int i;
|
||||
for(i=0; i<pPager->nSavepoint; i++){
|
||||
PagerSavepoint *p = &pPager->aSavepoint[i];
|
||||
if( p->nOrig>=pgno && 0==sqlite3BitvecTest(p->pInSavepoint, pgno) ){
|
||||
return 1;
|
||||
if( pPager->nSavepoint ){
|
||||
pgno = pPg->pgno;
|
||||
for(i=0; i<pPager->nSavepoint; i++){
|
||||
p = &pPager->aSavepoint[i];
|
||||
if( p->nOrig>=pgno && 0==sqlite3BitvecTest(p->pInSavepoint, pgno) ){
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
@@ -2295,11 +2307,11 @@ static int pager_playback_one_page(
|
||||
** requiring a journal-sync before it is written.
|
||||
*/
|
||||
assert( isSavepnt );
|
||||
assert( pPager->doNotSpill==0 );
|
||||
pPager->doNotSpill++;
|
||||
assert( (pPager->doNotSpill & SPILLFLAG_ROLLBACK)==0 );
|
||||
pPager->doNotSpill |= SPILLFLAG_ROLLBACK;
|
||||
rc = sqlite3PagerAcquire(pPager, pgno, &pPg, 1);
|
||||
assert( pPager->doNotSpill==1 );
|
||||
pPager->doNotSpill--;
|
||||
assert( (pPager->doNotSpill & SPILLFLAG_ROLLBACK)!=0 );
|
||||
pPager->doNotSpill &= ~SPILLFLAG_ROLLBACK;
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
pPg->flags &= ~PGHDR_NEED_READ;
|
||||
sqlite3PcacheMakeDirty(pPg);
|
||||
@@ -2866,12 +2878,6 @@ static int readDbPage(PgHdr *pPg, u32 iFrame){
|
||||
assert( pPager->eState>=PAGER_READER && !MEMDB );
|
||||
assert( isOpen(pPager->fd) );
|
||||
|
||||
if( NEVER(!isOpen(pPager->fd)) ){
|
||||
assert( pPager->tempFile );
|
||||
memset(pPg->pData, 0, pPager->pageSize);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_WAL
|
||||
if( iFrame ){
|
||||
/* Try to pull the page from the write-ahead log. */
|
||||
@@ -3404,9 +3410,12 @@ void sqlite3PagerShrink(Pager *pPager){
|
||||
}
|
||||
|
||||
/*
|
||||
** Adjust the robustness of the database to damage due to OS crashes
|
||||
** or power failures by changing the number of syncs()s when writing
|
||||
** the rollback journal. There are three levels:
|
||||
** Adjust settings of the pager to those specified in the pgFlags parameter.
|
||||
**
|
||||
** The "level" in pgFlags & PAGER_SYNCHRONOUS_MASK sets the robustness
|
||||
** of the database to damage due to OS crashes or power failures by
|
||||
** changing the number of syncs()s when writing the journals.
|
||||
** There are three levels:
|
||||
**
|
||||
** OFF sqlite3OsSync() is never called. This is the default
|
||||
** for temporary and transient files.
|
||||
@@ -3447,22 +3456,21 @@ void sqlite3PagerShrink(Pager *pPager){
|
||||
** and FULL=3.
|
||||
*/
|
||||
#ifndef SQLITE_OMIT_PAGER_PRAGMAS
|
||||
void sqlite3PagerSetSafetyLevel(
|
||||
void sqlite3PagerSetFlags(
|
||||
Pager *pPager, /* The pager to set safety level for */
|
||||
int level, /* PRAGMA synchronous. 1=OFF, 2=NORMAL, 3=FULL */
|
||||
int bFullFsync, /* PRAGMA fullfsync */
|
||||
int bCkptFullFsync /* PRAGMA checkpoint_fullfsync */
|
||||
unsigned pgFlags /* Various flags */
|
||||
){
|
||||
unsigned level = pgFlags & PAGER_SYNCHRONOUS_MASK;
|
||||
assert( level>=1 && level<=3 );
|
||||
pPager->noSync = (level==1 || pPager->tempFile) ?1:0;
|
||||
pPager->fullSync = (level==3 && !pPager->tempFile) ?1:0;
|
||||
if( pPager->noSync ){
|
||||
pPager->syncFlags = 0;
|
||||
pPager->ckptSyncFlags = 0;
|
||||
}else if( bFullFsync ){
|
||||
}else if( pgFlags & PAGER_FULLFSYNC ){
|
||||
pPager->syncFlags = SQLITE_SYNC_FULL;
|
||||
pPager->ckptSyncFlags = SQLITE_SYNC_FULL;
|
||||
}else if( bCkptFullFsync ){
|
||||
}else if( pgFlags & PAGER_CKPT_FULLFSYNC ){
|
||||
pPager->syncFlags = SQLITE_SYNC_NORMAL;
|
||||
pPager->ckptSyncFlags = SQLITE_SYNC_FULL;
|
||||
}else{
|
||||
@@ -3473,6 +3481,11 @@ void sqlite3PagerSetSafetyLevel(
|
||||
if( pPager->fullSync ){
|
||||
pPager->walSyncFlags |= WAL_SYNC_TRANSACTIONS;
|
||||
}
|
||||
if( pgFlags & PAGER_CACHESPILL ){
|
||||
pPager->doNotSpill &= ~SPILLFLAG_OFF;
|
||||
}else{
|
||||
pPager->doNotSpill |= SPILLFLAG_OFF;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -4373,13 +4386,14 @@ static int pagerStress(void *p, PgHdr *pPg){
|
||||
assert( pPg->pPager==pPager );
|
||||
assert( pPg->flags&PGHDR_DIRTY );
|
||||
|
||||
/* The doNotSyncSpill flag is set during times when doing a sync of
|
||||
/* The doNotSpill NOSYNC bit is set during times when doing a sync of
|
||||
** journal (and adding a new header) is not allowed. This occurs
|
||||
** during calls to sqlite3PagerWrite() while trying to journal multiple
|
||||
** pages belonging to the same sector.
|
||||
**
|
||||
** The doNotSpill flag inhibits all cache spilling regardless of whether
|
||||
** or not a sync is required. This is set during a rollback.
|
||||
** The doNotSpill ROLLBACK and OFF bits inhibits all cache spilling
|
||||
** regardless of whether or not a sync is required. This is set during
|
||||
** a rollback or by user request, respectively.
|
||||
**
|
||||
** Spilling is also prohibited when in an error state since that could
|
||||
** lead to database corruption. In the current implementaton it
|
||||
@@ -4389,8 +4403,13 @@ static int pagerStress(void *p, PgHdr *pPg){
|
||||
** test for the error state as a safeguard against future changes.
|
||||
*/
|
||||
if( NEVER(pPager->errCode) ) return SQLITE_OK;
|
||||
if( pPager->doNotSpill ) return SQLITE_OK;
|
||||
if( pPager->doNotSyncSpill && (pPg->flags & PGHDR_NEED_SYNC)!=0 ){
|
||||
testcase( pPager->doNotSpill & SPILLFLAG_ROLLBACK );
|
||||
testcase( pPager->doNotSpill & SPILLFLAG_OFF );
|
||||
testcase( pPager->doNotSpill & SPILLFLAG_NOSYNC );
|
||||
if( pPager->doNotSpill
|
||||
&& ((pPager->doNotSpill & (SPILLFLAG_ROLLBACK|SPILLFLAG_OFF))!=0
|
||||
|| (pPg->flags & PGHDR_NEED_SYNC)!=0)
|
||||
){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
@@ -5212,19 +5231,19 @@ int sqlite3PagerAcquire(
|
||||
Pager *pPager, /* The pager open on the database file */
|
||||
Pgno pgno, /* Page number to fetch */
|
||||
DbPage **ppPage, /* Write a pointer to the page here */
|
||||
int flags /* PAGER_ACQUIRE_XXX flags */
|
||||
int flags /* PAGER_GET_XXX flags */
|
||||
){
|
||||
int rc = SQLITE_OK;
|
||||
PgHdr *pPg = 0;
|
||||
u32 iFrame = 0; /* Frame to read from WAL file */
|
||||
const int noContent = (flags & PAGER_ACQUIRE_NOCONTENT);
|
||||
const int noContent = (flags & PAGER_GET_NOCONTENT);
|
||||
|
||||
/* It is acceptable to use a read-only (mmap) page for any page except
|
||||
** page 1 if there is no write-transaction open or the ACQUIRE_READONLY
|
||||
** flag was specified by the caller. And so long as the db is not a
|
||||
** temporary or in-memory database. */
|
||||
const int bMmapOk = (pgno!=1 && USEFETCH(pPager)
|
||||
&& (pPager->eState==PAGER_READER || (flags & PAGER_ACQUIRE_READONLY))
|
||||
&& (pPager->eState==PAGER_READER || (flags & PAGER_GET_READONLY))
|
||||
#ifdef SQLITE_HAS_CODEC
|
||||
&& pPager->xCodec==0
|
||||
#endif
|
||||
@@ -5744,13 +5763,13 @@ int sqlite3PagerWrite(DbPage *pDbPage){
|
||||
int ii; /* Loop counter */
|
||||
int needSync = 0; /* True if any page has PGHDR_NEED_SYNC */
|
||||
|
||||
/* Set the doNotSyncSpill flag to 1. This is because we cannot allow
|
||||
/* Set the doNotSpill NOSYNC bit to 1. This is because we cannot allow
|
||||
** a journal header to be written between the pages journaled by
|
||||
** this function.
|
||||
*/
|
||||
assert( !MEMDB );
|
||||
assert( pPager->doNotSyncSpill==0 );
|
||||
pPager->doNotSyncSpill++;
|
||||
assert( (pPager->doNotSpill & SPILLFLAG_NOSYNC)==0 );
|
||||
pPager->doNotSpill |= SPILLFLAG_NOSYNC;
|
||||
|
||||
/* This trick assumes that both the page-size and sector-size are
|
||||
** an integer power of 2. It sets variable pg1 to the identifier
|
||||
@@ -5809,8 +5828,8 @@ int sqlite3PagerWrite(DbPage *pDbPage){
|
||||
}
|
||||
}
|
||||
|
||||
assert( pPager->doNotSyncSpill==1 );
|
||||
pPager->doNotSyncSpill--;
|
||||
assert( (pPager->doNotSpill & SPILLFLAG_NOSYNC)!=0 );
|
||||
pPager->doNotSpill &= ~SPILLFLAG_NOSYNC;
|
||||
}else{
|
||||
rc = pager_write(pDbPage);
|
||||
}
|
||||
|
||||
+15
-3
@@ -81,8 +81,20 @@ typedef struct PgHdr DbPage;
|
||||
/*
|
||||
** Flags that make up the mask passed to sqlite3PagerAcquire().
|
||||
*/
|
||||
#define PAGER_ACQUIRE_NOCONTENT 0x01 /* Do not load data from disk */
|
||||
#define PAGER_ACQUIRE_READONLY 0x02 /* Read-only page is acceptable */
|
||||
#define PAGER_GET_NOCONTENT 0x01 /* Do not load data from disk */
|
||||
#define PAGER_GET_READONLY 0x02 /* Read-only page is acceptable */
|
||||
|
||||
/*
|
||||
** Flags for sqlite3PagerSetFlags()
|
||||
*/
|
||||
#define PAGER_SYNCHRONOUS_OFF 0x01 /* PRAGMA synchronous=OFF */
|
||||
#define PAGER_SYNCHRONOUS_NORMAL 0x02 /* PRAGMA synchronous=NORMAL */
|
||||
#define PAGER_SYNCHRONOUS_FULL 0x03 /* PRAGMA synchronous=FULL */
|
||||
#define PAGER_SYNCHRONOUS_MASK 0x03 /* Mask for three values above */
|
||||
#define PAGER_FULLFSYNC 0x04 /* PRAGMA fullfsync=ON */
|
||||
#define PAGER_CKPT_FULLFSYNC 0x08 /* PRAGMA checkpoint_fullfsync=ON */
|
||||
#define PAGER_CACHESPILL 0x10 /* PRAGMA cache_spill=ON */
|
||||
#define PAGER_FLAGS_MASK 0x1c /* All above except SYNCHRONOUS */
|
||||
|
||||
/*
|
||||
** The remainder of this file contains the declarations of the functions
|
||||
@@ -110,7 +122,7 @@ int sqlite3PagerMaxPageCount(Pager*, int);
|
||||
void sqlite3PagerSetCachesize(Pager*, int);
|
||||
void sqlite3PagerSetMmapLimit(Pager *, sqlite3_int64);
|
||||
void sqlite3PagerShrink(Pager*);
|
||||
void sqlite3PagerSetSafetyLevel(Pager*,int,int,int);
|
||||
void sqlite3PagerSetFlags(Pager*,unsigned);
|
||||
int sqlite3PagerLockingMode(Pager *, int);
|
||||
int sqlite3PagerSetJournalMode(Pager *, int);
|
||||
int sqlite3PagerGetJournalMode(Pager*);
|
||||
|
||||
+3
-2
@@ -1081,12 +1081,13 @@ expr(A) ::= expr(W) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
|
||||
|
||||
/* CASE expressions */
|
||||
expr(A) ::= CASE(C) case_operand(X) case_exprlist(Y) case_else(Z) END(E). {
|
||||
A.pExpr = sqlite3PExpr(pParse, TK_CASE, X, Z, 0);
|
||||
A.pExpr = sqlite3PExpr(pParse, TK_CASE, X, 0, 0);
|
||||
if( A.pExpr ){
|
||||
A.pExpr->x.pList = Y;
|
||||
A.pExpr->x.pList = Z ? sqlite3ExprListAppend(pParse,Y,Z) : Y;
|
||||
sqlite3ExprSetHeight(pParse, A.pExpr);
|
||||
}else{
|
||||
sqlite3ExprListDelete(pParse->db, Y);
|
||||
sqlite3ExprDelete(pParse->db, Z);
|
||||
}
|
||||
A.zStart = C.z;
|
||||
A.zEnd = &E.z[E.n];
|
||||
|
||||
@@ -765,6 +765,7 @@ static sqlite3_pcache_page *pcache1Fetch(
|
||||
if( pCache->nPage>=pCache->nHash && pcache1ResizeHash(pCache) ){
|
||||
goto fetch_out;
|
||||
}
|
||||
assert( pCache->nHash>0 && pCache->apHash );
|
||||
|
||||
/* Step 4. Try to recycle a page. */
|
||||
if( pCache->bPurgeable && pGroup->pLruTail && (
|
||||
|
||||
+38
-16
@@ -158,6 +158,36 @@ static void returnSingleInt(Parse *pParse, const char *zLabel, i64 value){
|
||||
sqlite3VdbeAddOp2(v, OP_ResultRow, mem, 1);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Set the safety_level and pager flags for pager iDb. Or if iDb<0
|
||||
** set these values for all pagers.
|
||||
*/
|
||||
#ifndef SQLITE_OMIT_PAGER_PRAGMAS
|
||||
static void setAllPagerFlags(sqlite3 *db){
|
||||
if( db->autoCommit ){
|
||||
Db *pDb = db->aDb;
|
||||
int n = db->nDb;
|
||||
assert( SQLITE_FullFSync==PAGER_FULLFSYNC );
|
||||
assert( SQLITE_CkptFullFSync==PAGER_CKPT_FULLFSYNC );
|
||||
assert( SQLITE_CacheSpill==PAGER_CACHESPILL );
|
||||
assert( (PAGER_FULLFSYNC | PAGER_CKPT_FULLFSYNC | PAGER_CACHESPILL)
|
||||
== PAGER_FLAGS_MASK );
|
||||
assert( (pDb->safety_level & PAGER_SYNCHRONOUS_MASK)==pDb->safety_level );
|
||||
while( (n--) > 0 ){
|
||||
if( pDb->pBt ){
|
||||
sqlite3BtreeSetPagerFlags(pDb->pBt,
|
||||
pDb->safety_level | (db->flags & PAGER_FLAGS_MASK) );
|
||||
}
|
||||
pDb++;
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
# define setAllPagerFlags(X) /* no-op */
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef SQLITE_OMIT_FLAG_PRAGMAS
|
||||
/*
|
||||
** Check to see if zRight and zLeft refer to a pragma that queries
|
||||
@@ -176,6 +206,7 @@ static int flagPragma(Parse *pParse, const char *zLeft, const char *zRight){
|
||||
{ "legacy_file_format", SQLITE_LegacyFileFmt },
|
||||
{ "fullfsync", SQLITE_FullFSync },
|
||||
{ "checkpoint_fullfsync", SQLITE_CkptFullFSync },
|
||||
{ "cache_spill", SQLITE_CacheSpill },
|
||||
{ "reverse_unordered_selects", SQLITE_ReverseOrder },
|
||||
{ "query_only", SQLITE_QueryOnly },
|
||||
#ifndef SQLITE_OMIT_AUTOMATIC_INDEX
|
||||
@@ -630,7 +661,7 @@ void sqlite3Pragma(
|
||||
Pager *pPager = sqlite3BtreePager(pDb->pBt);
|
||||
i64 iLimit = -2;
|
||||
if( zRight ){
|
||||
sqlite3Atoi64(zRight, &iLimit, 1000000, SQLITE_UTF8);
|
||||
sqlite3Atoi64(zRight, &iLimit, sqlite3Strlen30(zRight), SQLITE_UTF8);
|
||||
if( iLimit<-1 ) iLimit = -1;
|
||||
}
|
||||
iLimit = sqlite3PagerJournalSizeLimit(pPager, iLimit);
|
||||
@@ -764,10 +795,11 @@ void sqlite3Pragma(
|
||||
*/
|
||||
if( sqlite3StrICmp(zLeft,"mmap_size")==0 ){
|
||||
sqlite3_int64 sz;
|
||||
#if SQLITE_MAX_MMAP_SIZE>0
|
||||
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
|
||||
if( zRight ){
|
||||
int ii;
|
||||
sqlite3Atoi64(zRight, &sz, 1000, SQLITE_UTF8);
|
||||
sqlite3Atoi64(zRight, &sz, sqlite3Strlen30(zRight), SQLITE_UTF8);
|
||||
if( sz<0 ) sz = sqlite3GlobalConfig.szMmap;
|
||||
if( pId2->n==0 ) db->szMmap = sz;
|
||||
for(ii=db->nDb-1; ii>=0; ii--){
|
||||
@@ -778,8 +810,9 @@ void sqlite3Pragma(
|
||||
}
|
||||
sz = -1;
|
||||
rc = sqlite3_file_control(db, zDb, SQLITE_FCNTL_MMAP_SIZE, &sz);
|
||||
#if SQLITE_MAX_MMAP_SIZE==0
|
||||
#else
|
||||
sz = 0;
|
||||
rc = SQLITE_OK;
|
||||
#endif
|
||||
if( rc==SQLITE_OK ){
|
||||
returnSingleInt(pParse, "mmap_size", sz);
|
||||
@@ -966,6 +999,7 @@ void sqlite3Pragma(
|
||||
"Safety level may not be changed inside a transaction");
|
||||
}else{
|
||||
pDb->safety_level = getSafetyLevel(zRight,0,1)+1;
|
||||
setAllPagerFlags(db);
|
||||
}
|
||||
}
|
||||
}else
|
||||
@@ -973,8 +1007,7 @@ void sqlite3Pragma(
|
||||
|
||||
#ifndef SQLITE_OMIT_FLAG_PRAGMAS
|
||||
if( flagPragma(pParse, zLeft, zRight) ){
|
||||
/* The flagPragma() subroutine also generates any necessary code
|
||||
** there is nothing more to do here */
|
||||
setAllPagerFlags(db);
|
||||
}else
|
||||
#endif /* SQLITE_OMIT_FLAG_PRAGMAS */
|
||||
|
||||
@@ -1805,17 +1838,6 @@ void sqlite3Pragma(
|
||||
|
||||
{/* Empty ELSE clause */}
|
||||
|
||||
/*
|
||||
** Reset the safety level, in case the fullfsync flag or synchronous
|
||||
** setting changed.
|
||||
*/
|
||||
#ifndef SQLITE_OMIT_PAGER_PRAGMAS
|
||||
if( db->autoCommit ){
|
||||
sqlite3BtreeSetSafetyLevel(pDb->pBt, pDb->safety_level,
|
||||
(db->flags&SQLITE_FullFSync)!=0,
|
||||
(db->flags&SQLITE_CkptFullFSync)!=0);
|
||||
}
|
||||
#endif
|
||||
pragma_out:
|
||||
sqlite3DbFree(db, zLeft);
|
||||
sqlite3DbFree(db, zRight);
|
||||
|
||||
+14
-17
@@ -359,7 +359,7 @@ void sqlite3VXPrintf(
|
||||
nOut = precision + 10;
|
||||
zOut = zExtra = sqlite3Malloc( nOut );
|
||||
if( zOut==0 ){
|
||||
pAccum->mallocFailed = 1;
|
||||
pAccum->accError = STRACCUM_NOMEM;
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -471,7 +471,7 @@ void sqlite3VXPrintf(
|
||||
if( MAX(e2,0)+precision+width > etBUFSIZE - 15 ){
|
||||
bufpt = zExtra = sqlite3Malloc( MAX(e2,0)+precision+width+15 );
|
||||
if( bufpt==0 ){
|
||||
pAccum->mallocFailed = 1;
|
||||
pAccum->accError = STRACCUM_NOMEM;
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -606,7 +606,7 @@ void sqlite3VXPrintf(
|
||||
if( n>etBUFSIZE ){
|
||||
bufpt = zExtra = sqlite3Malloc( n );
|
||||
if( bufpt==0 ){
|
||||
pAccum->mallocFailed = 1;
|
||||
pAccum->accError = STRACCUM_NOMEM;
|
||||
return;
|
||||
}
|
||||
}else{
|
||||
@@ -684,22 +684,20 @@ void sqlite3VXPrintf(
|
||||
*/
|
||||
void sqlite3StrAccumAppend(StrAccum *p, const char *z, int N){
|
||||
assert( z!=0 || N==0 );
|
||||
if( p->tooBig | p->mallocFailed ){
|
||||
testcase(p->tooBig);
|
||||
testcase(p->mallocFailed);
|
||||
if( p->accError ){
|
||||
testcase(p->accError==STRACCUM_TOOBIG);
|
||||
testcase(p->accError==STRACCUM_NOMEM);
|
||||
return;
|
||||
}
|
||||
assert( p->zText!=0 || p->nChar==0 );
|
||||
if( N<0 ){
|
||||
if( N<=0 ){
|
||||
if( N==0 || z[0]==0 ) return;
|
||||
N = sqlite3Strlen30(z);
|
||||
}
|
||||
if( N==0 || NEVER(z==0) ){
|
||||
return;
|
||||
}
|
||||
if( p->nChar+N >= p->nAlloc ){
|
||||
char *zNew;
|
||||
if( !p->useMalloc ){
|
||||
p->tooBig = 1;
|
||||
p->accError = STRACCUM_TOOBIG;
|
||||
N = p->nAlloc - p->nChar - 1;
|
||||
if( N<=0 ){
|
||||
return;
|
||||
@@ -710,7 +708,7 @@ void sqlite3StrAccumAppend(StrAccum *p, const char *z, int N){
|
||||
szNew += N + 1;
|
||||
if( szNew > p->mxAlloc ){
|
||||
sqlite3StrAccumReset(p);
|
||||
p->tooBig = 1;
|
||||
p->accError = STRACCUM_TOOBIG;
|
||||
return;
|
||||
}else{
|
||||
p->nAlloc = (int)szNew;
|
||||
@@ -724,7 +722,7 @@ void sqlite3StrAccumAppend(StrAccum *p, const char *z, int N){
|
||||
if( zOld==0 && p->nChar>0 ) memcpy(zNew, p->zText, p->nChar);
|
||||
p->zText = zNew;
|
||||
}else{
|
||||
p->mallocFailed = 1;
|
||||
p->accError = STRACCUM_NOMEM;
|
||||
sqlite3StrAccumReset(p);
|
||||
return;
|
||||
}
|
||||
@@ -752,7 +750,7 @@ char *sqlite3StrAccumFinish(StrAccum *p){
|
||||
if( p->zText ){
|
||||
memcpy(p->zText, p->zBase, p->nChar+1);
|
||||
}else{
|
||||
p->mallocFailed = 1;
|
||||
p->accError = STRACCUM_NOMEM;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -783,8 +781,7 @@ void sqlite3StrAccumInit(StrAccum *p, char *zBase, int n, int mx){
|
||||
p->nAlloc = n;
|
||||
p->mxAlloc = mx;
|
||||
p->useMalloc = 1;
|
||||
p->tooBig = 0;
|
||||
p->mallocFailed = 0;
|
||||
p->accError = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -801,7 +798,7 @@ char *sqlite3VMPrintf(sqlite3 *db, const char *zFormat, va_list ap){
|
||||
acc.db = db;
|
||||
sqlite3VXPrintf(&acc, 1, zFormat, ap);
|
||||
z = sqlite3StrAccumFinish(&acc);
|
||||
if( acc.mallocFailed ){
|
||||
if( acc.accError==STRACCUM_NOMEM ){
|
||||
db->mallocFailed = 1;
|
||||
}
|
||||
return z;
|
||||
|
||||
+14
-37
@@ -28,24 +28,11 @@ static SQLITE_WSD struct sqlite3PrngType {
|
||||
} sqlite3Prng;
|
||||
|
||||
/*
|
||||
** Get a single 8-bit random value from the RC4 PRNG. The Mutex
|
||||
** must be held while executing this routine.
|
||||
**
|
||||
** Why not just use a library random generator like lrand48() for this?
|
||||
** Because the OP_NewRowid opcode in the VDBE depends on having a very
|
||||
** good source of random numbers. The lrand48() library function may
|
||||
** well be good enough. But maybe not. Or maybe lrand48() has some
|
||||
** subtle problems on some systems that could cause problems. It is hard
|
||||
** to know. To minimize the risk of problems due to bad lrand48()
|
||||
** implementations, SQLite uses this random number generator based
|
||||
** on RC4, which we know works very well.
|
||||
**
|
||||
** (Later): Actually, OP_NewRowid does not depend on a good source of
|
||||
** randomness any more. But we will leave this code in all the same.
|
||||
** Return N random bytes.
|
||||
*/
|
||||
static u8 randomByte(void){
|
||||
void sqlite3_randomness(int N, void *pBuf){
|
||||
unsigned char t;
|
||||
|
||||
unsigned char *zBuf = pBuf;
|
||||
|
||||
/* The "wsdPrng" macro will resolve to the pseudo-random number generator
|
||||
** state vector. If writable static data is unsupported on the target,
|
||||
@@ -60,6 +47,10 @@ static u8 randomByte(void){
|
||||
# define wsdPrng sqlite3Prng
|
||||
#endif
|
||||
|
||||
#if SQLITE_THREADSAFE
|
||||
sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_PRNG);
|
||||
sqlite3_mutex_enter(mutex);
|
||||
#endif
|
||||
|
||||
/* Initialize the state of the random number generator once,
|
||||
** the first time this routine is called. The seed value does
|
||||
@@ -88,28 +79,14 @@ static u8 randomByte(void){
|
||||
wsdPrng.isInit = 1;
|
||||
}
|
||||
|
||||
/* Generate and return single random byte
|
||||
*/
|
||||
wsdPrng.i++;
|
||||
t = wsdPrng.s[wsdPrng.i];
|
||||
wsdPrng.j += t;
|
||||
wsdPrng.s[wsdPrng.i] = wsdPrng.s[wsdPrng.j];
|
||||
wsdPrng.s[wsdPrng.j] = t;
|
||||
t += wsdPrng.s[wsdPrng.i];
|
||||
return wsdPrng.s[t];
|
||||
}
|
||||
|
||||
/*
|
||||
** Return N random bytes.
|
||||
*/
|
||||
void sqlite3_randomness(int N, void *pBuf){
|
||||
unsigned char *zBuf = pBuf;
|
||||
#if SQLITE_THREADSAFE
|
||||
sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_PRNG);
|
||||
#endif
|
||||
sqlite3_mutex_enter(mutex);
|
||||
while( N-- ){
|
||||
*(zBuf++) = randomByte();
|
||||
wsdPrng.i++;
|
||||
t = wsdPrng.s[wsdPrng.i];
|
||||
wsdPrng.j += t;
|
||||
wsdPrng.s[wsdPrng.i] = wsdPrng.s[wsdPrng.j];
|
||||
wsdPrng.s[wsdPrng.j] = t;
|
||||
t += wsdPrng.s[wsdPrng.i];
|
||||
*(zBuf++) = wsdPrng.s[t];
|
||||
}
|
||||
sqlite3_mutex_leave(mutex);
|
||||
}
|
||||
|
||||
+29
-21
@@ -55,7 +55,7 @@ static void incrAggFunctionDepth(Expr *pExpr, int N){
|
||||
** column reference is so that the column reference will be recognized as
|
||||
** usable by indices within the WHERE clause processing logic.
|
||||
**
|
||||
** Hack: The TK_AS operator is inhibited if zType[0]=='G'. This means
|
||||
** The TK_AS operator is inhibited if zType[0]=='G'. This means
|
||||
** that in a GROUP BY clause, the expression is evaluated twice. Hence:
|
||||
**
|
||||
** SELECT random()%5 AS x, count(*) FROM tab GROUP BY x
|
||||
@@ -65,8 +65,9 @@ static void incrAggFunctionDepth(Expr *pExpr, int N){
|
||||
** SELECT random()%5 AS x, count(*) FROM tab GROUP BY random()%5
|
||||
**
|
||||
** The result of random()%5 in the GROUP BY clause is probably different
|
||||
** from the result in the result-set. We might fix this someday. Or
|
||||
** then again, we might not...
|
||||
** from the result in the result-set. On the other hand Standard SQL does
|
||||
** not allow the GROUP BY clause to contain references to result-set columns.
|
||||
** So this should never come up in well-formed queries.
|
||||
**
|
||||
** If the reference is followed by a COLLATE operator, then make sure
|
||||
** the COLLATE operator is preserved. For example:
|
||||
@@ -128,7 +129,7 @@ static void resolveAlias(
|
||||
if( !ExprHasProperty(pExpr, EP_IntValue) && pExpr->u.zToken!=0 ){
|
||||
assert( (pExpr->flags & (EP_Reduced|EP_TokenOnly))==0 );
|
||||
pExpr->u.zToken = sqlite3DbStrDup(db, pExpr->u.zToken);
|
||||
pExpr->flags2 |= EP2_MallocedToken;
|
||||
pExpr->flags |= EP_MemToken;
|
||||
}
|
||||
sqlite3DbFree(db, pDup);
|
||||
}
|
||||
@@ -228,7 +229,7 @@ static int lookupName(
|
||||
|
||||
assert( pNC ); /* the name context cannot be NULL. */
|
||||
assert( zCol ); /* The Z in X.Y.Z cannot be NULL */
|
||||
assert( !ExprHasAnyProperty(pExpr, EP_TokenOnly|EP_Reduced) );
|
||||
assert( !ExprHasProperty(pExpr, EP_TokenOnly|EP_Reduced) );
|
||||
|
||||
/* Initialize the node to no-match */
|
||||
pExpr->iTable = -1;
|
||||
@@ -396,10 +397,16 @@ static int lookupName(
|
||||
** forms the result set entry ("a+b" in the example) and return immediately.
|
||||
** Note that the expression in the result set should have already been
|
||||
** resolved by the time the WHERE clause is resolved.
|
||||
**
|
||||
** The ability to use an output result-set column in the WHERE, GROUP BY,
|
||||
** or HAVING clauses, or as part of a larger expression in the ORDRE BY
|
||||
** clause is not standard SQL. This is a (goofy) SQLite extension, that
|
||||
** is supported for backwards compatibility only. TO DO: Issue a warning
|
||||
** on sqlite3_log() whenever the capability is used.
|
||||
*/
|
||||
if( (pEList = pNC->pEList)!=0
|
||||
&& zTab==0
|
||||
&& ((pNC->ncFlags & NC_AsMaybe)==0 || cnt==0)
|
||||
&& cnt==0
|
||||
){
|
||||
for(j=0; j<pEList->nExpr; j++){
|
||||
char *zAs = pEList->a[j].zName;
|
||||
@@ -584,7 +591,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
|
||||
pParse = pNC->pParse;
|
||||
assert( pParse==pWalker->pParse );
|
||||
|
||||
if( ExprHasAnyProperty(pExpr, EP_Resolved) ) return WRC_Prune;
|
||||
if( ExprHasProperty(pExpr, EP_Resolved) ) return WRC_Prune;
|
||||
ExprSetProperty(pExpr, EP_Resolved);
|
||||
#ifndef NDEBUG
|
||||
if( pNC->pSrcList && pNC->pSrcList->nAlloc>0 ){
|
||||
@@ -961,7 +968,7 @@ static int resolveCompoundOrderBy(
|
||||
/*
|
||||
** Check every term in the ORDER BY or GROUP BY clause pOrderBy of
|
||||
** the SELECT statement pSelect. If any term is reference to a
|
||||
** result set expression (as determined by the ExprList.a.iCol field)
|
||||
** result set expression (as determined by the ExprList.a.iOrderByCol field)
|
||||
** then convert that term into a copy of the corresponding result set
|
||||
** column.
|
||||
**
|
||||
@@ -1009,7 +1016,7 @@ int sqlite3ResolveOrderGroupBy(
|
||||
** If the order-by term is an integer I between 1 and N (where N is the
|
||||
** number of columns in the result set of the SELECT) then the expression
|
||||
** in the resolution is a copy of the I-th result-set expression. If
|
||||
** the order-by term is an identify that corresponds to the AS-name of
|
||||
** the order-by term is an identifier that corresponds to the AS-name of
|
||||
** a result-set expression, then the term resolves to a copy of the
|
||||
** result-set expression. Otherwise, the expression is resolved in
|
||||
** the usual way - using sqlite3ResolveExprNames().
|
||||
@@ -1035,16 +1042,19 @@ static int resolveOrderGroupBy(
|
||||
pParse = pNC->pParse;
|
||||
for(i=0, pItem=pOrderBy->a; i<pOrderBy->nExpr; i++, pItem++){
|
||||
Expr *pE = pItem->pExpr;
|
||||
iCol = resolveAsName(pParse, pSelect->pEList, pE);
|
||||
if( iCol>0 ){
|
||||
/* If an AS-name match is found, mark this ORDER BY column as being
|
||||
** a copy of the iCol-th result-set column. The subsequent call to
|
||||
** sqlite3ResolveOrderGroupBy() will convert the expression to a
|
||||
** copy of the iCol-th result-set expression. */
|
||||
pItem->iOrderByCol = (u16)iCol;
|
||||
continue;
|
||||
Expr *pE2 = sqlite3ExprSkipCollate(pE);
|
||||
if( zType[0]!='G' ){
|
||||
iCol = resolveAsName(pParse, pSelect->pEList, pE2);
|
||||
if( iCol>0 ){
|
||||
/* If an AS-name match is found, mark this ORDER BY column as being
|
||||
** a copy of the iCol-th result-set column. The subsequent call to
|
||||
** sqlite3ResolveOrderGroupBy() will convert the expression to a
|
||||
** copy of the iCol-th result-set expression. */
|
||||
pItem->iOrderByCol = (u16)iCol;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if( sqlite3ExprIsInteger(sqlite3ExprSkipCollate(pE), &iCol) ){
|
||||
if( sqlite3ExprIsInteger(pE2, &iCol) ){
|
||||
/* The ORDER BY term is an integer constant. Again, set the column
|
||||
** number so that sqlite3ResolveOrderGroupBy() will convert the
|
||||
** order-by term to a copy of the result-set expression */
|
||||
@@ -1187,7 +1197,7 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
|
||||
return WRC_Abort;
|
||||
}
|
||||
|
||||
/* Add the expression list to the name-context before parsing the
|
||||
/* Add the output column list to the name-context before parsing the
|
||||
** other expressions in the SELECT statement. This is so that
|
||||
** expressions in the WHERE clause (etc.) can refer to expressions by
|
||||
** aliases in the result set.
|
||||
@@ -1196,10 +1206,8 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
|
||||
** re-evaluated for each reference to it.
|
||||
*/
|
||||
sNC.pEList = p->pEList;
|
||||
sNC.ncFlags |= NC_AsMaybe;
|
||||
if( sqlite3ResolveExprNames(&sNC, p->pHaving) ) return WRC_Abort;
|
||||
if( sqlite3ResolveExprNames(&sNC, p->pWhere) ) return WRC_Abort;
|
||||
sNC.ncFlags &= ~NC_AsMaybe;
|
||||
|
||||
/* The ORDER BY and GROUP BY clauses may not refer to terms in
|
||||
** outer queries
|
||||
|
||||
+4
-4
@@ -264,7 +264,7 @@ static void addWhereTerm(
|
||||
pEq = sqlite3PExpr(pParse, TK_EQ, pE1, pE2, 0);
|
||||
if( pEq && isOuterJoin ){
|
||||
ExprSetProperty(pEq, EP_FromJoin);
|
||||
assert( !ExprHasAnyProperty(pEq, EP_TokenOnly|EP_Reduced) );
|
||||
assert( !ExprHasProperty(pEq, EP_TokenOnly|EP_Reduced) );
|
||||
ExprSetIrreducible(pEq);
|
||||
pEq->iRightJoinTable = (i16)pE2->iTable;
|
||||
}
|
||||
@@ -300,7 +300,7 @@ static void addWhereTerm(
|
||||
static void setJoinExpr(Expr *p, int iTable){
|
||||
while( p ){
|
||||
ExprSetProperty(p, EP_FromJoin);
|
||||
assert( !ExprHasAnyProperty(p, EP_TokenOnly|EP_Reduced) );
|
||||
assert( !ExprHasProperty(p, EP_TokenOnly|EP_Reduced) );
|
||||
ExprSetIrreducible(p);
|
||||
p->iRightJoinTable = (i16)iTable;
|
||||
setJoinExpr(p->pLeft, iTable);
|
||||
@@ -3228,7 +3228,7 @@ static Table *isSimpleCount(Select *p, AggInfo *pAggInfo){
|
||||
if( IsVirtual(pTab) ) return 0;
|
||||
if( pExpr->op!=TK_AGG_FUNCTION ) return 0;
|
||||
if( NEVER(pAggInfo->nFunc==0) ) return 0;
|
||||
if( (pAggInfo->aFunc[0].pFunc->flags&SQLITE_FUNC_COUNT)==0 ) return 0;
|
||||
if( (pAggInfo->aFunc[0].pFunc->funcFlags&SQLITE_FUNC_COUNT)==0 ) return 0;
|
||||
if( pExpr->flags&EP_Distinct ) return 0;
|
||||
|
||||
return pTab;
|
||||
@@ -3825,7 +3825,7 @@ static void updateAccumulator(Parse *pParse, AggInfo *pAggInfo){
|
||||
assert( nArg==1 );
|
||||
codeDistinct(pParse, pF->iDistinct, addrNext, 1, regAgg);
|
||||
}
|
||||
if( pF->pFunc->flags & SQLITE_FUNC_NEEDCOLL ){
|
||||
if( pF->pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL ){
|
||||
CollSeq *pColl = 0;
|
||||
struct ExprList_item *pItem;
|
||||
int j;
|
||||
|
||||
+14
-10
@@ -71,12 +71,12 @@
|
||||
/* Make sure isatty() has a prototype.
|
||||
*/
|
||||
extern int isatty(int);
|
||||
#endif
|
||||
|
||||
/* popen and pclose are not C89 functions and so are sometimes omitted from
|
||||
** the <stdio.h> header */
|
||||
FILE *popen(const char*,const char*);
|
||||
int pclose(FILE*);
|
||||
extern FILE *popen(const char*,const char*);
|
||||
extern int pclose(FILE*);
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32_WCE)
|
||||
/* Windows CE (arm-wince-mingw32ce-gcc) does not provide isatty()
|
||||
@@ -554,7 +554,7 @@ static void output_c_string(FILE *out, const char *z){
|
||||
}else if( c=='\r' ){
|
||||
fputc('\\', out);
|
||||
fputc('r', out);
|
||||
}else if( !isprint(c) ){
|
||||
}else if( !isprint(c&0xff) ){
|
||||
fprintf(out, "\\%03o", c&0xff);
|
||||
}else{
|
||||
fputc(c, out);
|
||||
@@ -1194,7 +1194,7 @@ static int shell_exec(
|
||||
char **azCols = (char **)pData; /* Names of result columns */
|
||||
char **azVals = &azCols[nCol]; /* Results */
|
||||
int *aiTypes = (int *)&azVals[nCol]; /* Result types */
|
||||
int i;
|
||||
int i, x;
|
||||
assert(sizeof(int) <= sizeof(char *));
|
||||
/* save off ptrs to column names */
|
||||
for(i=0; i<nCol; i++){
|
||||
@@ -1203,8 +1203,12 @@ static int shell_exec(
|
||||
do{
|
||||
/* extract the data and data types */
|
||||
for(i=0; i<nCol; i++){
|
||||
azVals[i] = (char *)sqlite3_column_text(pStmt, i);
|
||||
aiTypes[i] = sqlite3_column_type(pStmt, i);
|
||||
aiTypes[i] = x = sqlite3_column_type(pStmt, i);
|
||||
if( x==SQLITE_BLOB && pArg->mode==MODE_Insert ){
|
||||
azVals[i] = "";
|
||||
}else{
|
||||
azVals[i] = (char*)sqlite3_column_text(pStmt, i);
|
||||
}
|
||||
if( !azVals[i] && (aiTypes[i]!=SQLITE_NULL) ){
|
||||
rc = SQLITE_NOMEM;
|
||||
break; /* from for */
|
||||
@@ -1280,7 +1284,7 @@ static int dump_callback(void *pArg, int nArg, char **azArg, char **azCol){
|
||||
|
||||
if( strcmp(zTable, "sqlite_sequence")==0 ){
|
||||
zPrepStmt = "DELETE FROM sqlite_sequence;\n";
|
||||
}else if( strcmp(zTable, "sqlite_stat1")==0 ){
|
||||
}else if( sqlite3_strglob("sqlite_stat?", zTable)==0 ){
|
||||
fprintf(p->out, "ANALYZE sqlite_master;\n");
|
||||
}else if( strncmp(zTable, "sqlite_", 7)==0 ){
|
||||
return 0;
|
||||
@@ -1717,7 +1721,7 @@ static char *csv_read_one_field(CSVReader *p){
|
||||
}
|
||||
if( (c==cSep && pc==cQuote)
|
||||
|| (c=='\n' && pc==cQuote)
|
||||
|| (c=='\n' && pc=='\r' && p->n>2 && p->z[p->n-2]==cQuote)
|
||||
|| (c=='\n' && pc=='\r' && p->n>=2 && p->z[p->n-2]==cQuote)
|
||||
|| (c==EOF && pc==cQuote)
|
||||
){
|
||||
do{ p->n--; }while( p->z[p->n]!=cQuote );
|
||||
@@ -2902,6 +2906,7 @@ static int process_input(struct callback_data *p, FILE *in){
|
||||
if( nSql==0 ){
|
||||
int i;
|
||||
for(i=0; zLine[i] && IsSpace(zLine[i]); i++){}
|
||||
assert( nAlloc>0 && zSql!=0 );
|
||||
memcpy(zSql, zLine+i, nLine+1-i);
|
||||
startline = lineno;
|
||||
nSql = nLine-i;
|
||||
@@ -3187,7 +3192,6 @@ int main(int argc, char **argv){
|
||||
stdin_is_interactive = 0;
|
||||
}else if( strcmp(z,"-heap")==0 ){
|
||||
#if defined(SQLITE_ENABLE_MEMSYS3) || defined(SQLITE_ENABLE_MEMSYS5)
|
||||
int j, c;
|
||||
const char *zSize;
|
||||
sqlite3_int64 szHeap;
|
||||
|
||||
|
||||
@@ -474,12 +474,14 @@ int sqlite3_exec(
|
||||
#define SQLITE_IOERR_DELETE_NOENT (SQLITE_IOERR | (23<<8))
|
||||
#define SQLITE_IOERR_MMAP (SQLITE_IOERR | (24<<8))
|
||||
#define SQLITE_IOERR_GETTEMPPATH (SQLITE_IOERR | (25<<8))
|
||||
#define SQLITE_IOERR_CONVPATH (SQLITE_IOERR | (26<<8))
|
||||
#define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8))
|
||||
#define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8))
|
||||
#define SQLITE_BUSY_SNAPSHOT (SQLITE_BUSY | (2<<8))
|
||||
#define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1<<8))
|
||||
#define SQLITE_CANTOPEN_ISDIR (SQLITE_CANTOPEN | (2<<8))
|
||||
#define SQLITE_CANTOPEN_FULLPATH (SQLITE_CANTOPEN | (3<<8))
|
||||
#define SQLITE_CANTOPEN_CONVPATH (SQLITE_CANTOPEN | (4<<8))
|
||||
#define SQLITE_CORRUPT_VTAB (SQLITE_CORRUPT | (1<<8))
|
||||
#define SQLITE_READONLY_RECOVERY (SQLITE_READONLY | (1<<8))
|
||||
#define SQLITE_READONLY_CANTLOCK (SQLITE_READONLY | (2<<8))
|
||||
|
||||
+104
-96
@@ -568,6 +568,20 @@ extern const int sqlite3one;
|
||||
# define SQLITE_DEFAULT_MMAP_SIZE SQLITE_MAX_MMAP_SIZE
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Only one of SQLITE_ENABLE_STAT3 or SQLITE_ENABLE_STAT4 can be defined.
|
||||
** Priority is given to SQLITE_ENABLE_STAT4. If either are defined, also
|
||||
** define SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
*/
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
# undef SQLITE_ENABLE_STAT3
|
||||
# define SQLITE_ENABLE_STAT3_OR_STAT4 1
|
||||
#elif SQLITE_ENABLE_STAT3
|
||||
# define SQLITE_ENABLE_STAT3_OR_STAT4 1
|
||||
#elif SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
# undef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
#endif
|
||||
|
||||
/*
|
||||
** An instance of the following structure is used to store the busy-handler
|
||||
** callback for a given sqlite handle.
|
||||
@@ -907,8 +921,6 @@ struct sqlite3 {
|
||||
void(*xCollNeeded16)(void*,sqlite3*,int eTextRep,const void*);
|
||||
void *pCollNeededArg;
|
||||
sqlite3_value *pErr; /* Most recent error message */
|
||||
char *zErrMsg; /* Most recent error message (UTF-8 encoded) */
|
||||
char *zErrMsg16; /* Most recent error message (UTF-16 encoded) */
|
||||
union {
|
||||
volatile int isInterrupted; /* True if sqlite3_interrupt has been called */
|
||||
double notUsed1; /* Spacer */
|
||||
@@ -972,32 +984,33 @@ struct sqlite3 {
|
||||
*/
|
||||
#define SQLITE_VdbeTrace 0x00000001 /* True to trace VDBE execution */
|
||||
#define SQLITE_InternChanges 0x00000002 /* Uncommitted Hash table changes */
|
||||
#define SQLITE_FullColNames 0x00000004 /* Show full column names on SELECT */
|
||||
#define SQLITE_ShortColNames 0x00000008 /* Show short columns names */
|
||||
#define SQLITE_CountRows 0x00000010 /* Count rows changed by INSERT, */
|
||||
#define SQLITE_FullFSync 0x00000004 /* Use full fsync on the backend */
|
||||
#define SQLITE_CkptFullFSync 0x00000008 /* Use full fsync for checkpoint */
|
||||
#define SQLITE_CacheSpill 0x00000010 /* OK to spill pager cache */
|
||||
#define SQLITE_FullColNames 0x00000020 /* Show full column names on SELECT */
|
||||
#define SQLITE_ShortColNames 0x00000040 /* Show short columns names */
|
||||
#define SQLITE_CountRows 0x00000080 /* Count rows changed by INSERT, */
|
||||
/* DELETE, or UPDATE and return */
|
||||
/* the count using a callback. */
|
||||
#define SQLITE_NullCallback 0x00000020 /* Invoke the callback once if the */
|
||||
#define SQLITE_NullCallback 0x00000100 /* Invoke the callback once if the */
|
||||
/* result set is empty */
|
||||
#define SQLITE_SqlTrace 0x00000040 /* Debug print SQL as it executes */
|
||||
#define SQLITE_VdbeListing 0x00000080 /* Debug listings of VDBE programs */
|
||||
#define SQLITE_WriteSchema 0x00000100 /* OK to update SQLITE_MASTER */
|
||||
#define SQLITE_VdbeAddopTrace 0x00000200 /* Trace sqlite3VdbeAddOp() calls */
|
||||
#define SQLITE_IgnoreChecks 0x00000400 /* Do not enforce check constraints */
|
||||
#define SQLITE_ReadUncommitted 0x0000800 /* For shared-cache mode */
|
||||
#define SQLITE_LegacyFileFmt 0x00001000 /* Create new databases in format 1 */
|
||||
#define SQLITE_FullFSync 0x00002000 /* Use full fsync on the backend */
|
||||
#define SQLITE_CkptFullFSync 0x00004000 /* Use full fsync for checkpoint */
|
||||
#define SQLITE_RecoveryMode 0x00008000 /* Ignore schema errors */
|
||||
#define SQLITE_ReverseOrder 0x00010000 /* Reverse unordered SELECTs */
|
||||
#define SQLITE_RecTriggers 0x00020000 /* Enable recursive triggers */
|
||||
#define SQLITE_ForeignKeys 0x00040000 /* Enforce foreign key constraints */
|
||||
#define SQLITE_AutoIndex 0x00080000 /* Enable automatic indexes */
|
||||
#define SQLITE_PreferBuiltin 0x00100000 /* Preference to built-in funcs */
|
||||
#define SQLITE_LoadExtension 0x00200000 /* Enable load_extension */
|
||||
#define SQLITE_EnableTrigger 0x00400000 /* True to enable triggers */
|
||||
#define SQLITE_DeferFKs 0x00800000 /* Defer all FK constraints */
|
||||
#define SQLITE_QueryOnly 0x01000000 /* Disable database changes */
|
||||
#define SQLITE_SqlTrace 0x00000200 /* Debug print SQL as it executes */
|
||||
#define SQLITE_VdbeListing 0x00000400 /* Debug listings of VDBE programs */
|
||||
#define SQLITE_WriteSchema 0x00000800 /* OK to update SQLITE_MASTER */
|
||||
#define SQLITE_VdbeAddopTrace 0x00001000 /* Trace sqlite3VdbeAddOp() calls */
|
||||
#define SQLITE_IgnoreChecks 0x00002000 /* Do not enforce check constraints */
|
||||
#define SQLITE_ReadUncommitted 0x0004000 /* For shared-cache mode */
|
||||
#define SQLITE_LegacyFileFmt 0x00008000 /* Create new databases in format 1 */
|
||||
#define SQLITE_RecoveryMode 0x00010000 /* Ignore schema errors */
|
||||
#define SQLITE_ReverseOrder 0x00020000 /* Reverse unordered SELECTs */
|
||||
#define SQLITE_RecTriggers 0x00040000 /* Enable recursive triggers */
|
||||
#define SQLITE_ForeignKeys 0x00080000 /* Enforce foreign key constraints */
|
||||
#define SQLITE_AutoIndex 0x00100000 /* Enable automatic indexes */
|
||||
#define SQLITE_PreferBuiltin 0x00200000 /* Preference to built-in funcs */
|
||||
#define SQLITE_LoadExtension 0x00400000 /* Enable load_extension */
|
||||
#define SQLITE_EnableTrigger 0x00800000 /* True to enable triggers */
|
||||
#define SQLITE_DeferFKs 0x01000000 /* Defer all FK constraints */
|
||||
#define SQLITE_QueryOnly 0x02000000 /* Disable database changes */
|
||||
|
||||
|
||||
/*
|
||||
@@ -1050,8 +1063,7 @@ struct sqlite3 {
|
||||
*/
|
||||
struct FuncDef {
|
||||
i16 nArg; /* Number of arguments. -1 means unlimited */
|
||||
u8 iPrefEnc; /* Preferred text encoding (SQLITE_UTF8, 16LE, 16BE) */
|
||||
u8 flags; /* Some combination of SQLITE_FUNC_* */
|
||||
u16 funcFlags; /* Some combination of SQLITE_FUNC_* */
|
||||
void *pUserData; /* User data parameter */
|
||||
FuncDef *pNext; /* Next function with same name */
|
||||
void (*xFunc)(sqlite3_context*,int,sqlite3_value**); /* Regular function */
|
||||
@@ -1087,14 +1099,16 @@ struct FuncDestructor {
|
||||
** values must correspond to OPFLAG_LENGTHARG and OPFLAG_TYPEOFARG. There
|
||||
** are assert() statements in the code to verify this.
|
||||
*/
|
||||
#define SQLITE_FUNC_LIKE 0x01 /* Candidate for the LIKE optimization */
|
||||
#define SQLITE_FUNC_CASE 0x02 /* Case-sensitive LIKE-type function */
|
||||
#define SQLITE_FUNC_EPHEM 0x04 /* Ephemeral. Delete with VDBE */
|
||||
#define SQLITE_FUNC_NEEDCOLL 0x08 /* sqlite3GetFuncCollSeq() might be called */
|
||||
#define SQLITE_FUNC_COUNT 0x10 /* Built-in count(*) aggregate */
|
||||
#define SQLITE_FUNC_COALESCE 0x20 /* Built-in coalesce() or ifnull() function */
|
||||
#define SQLITE_FUNC_LENGTH 0x40 /* Built-in length() function */
|
||||
#define SQLITE_FUNC_TYPEOF 0x80 /* Built-in typeof() function */
|
||||
#define SQLITE_FUNC_ENCMASK 0x003 /* SQLITE_UTF8, SQLITE_UTF16BE or UTF16LE */
|
||||
#define SQLITE_FUNC_LIKE 0x004 /* Candidate for the LIKE optimization */
|
||||
#define SQLITE_FUNC_CASE 0x008 /* Case-sensitive LIKE-type function */
|
||||
#define SQLITE_FUNC_EPHEM 0x010 /* Ephemeral. Delete with VDBE */
|
||||
#define SQLITE_FUNC_NEEDCOLL 0x020 /* sqlite3GetFuncCollSeq() might be called */
|
||||
#define SQLITE_FUNC_LENGTH 0x040 /* Built-in length() function */
|
||||
#define SQLITE_FUNC_TYPEOF 0x080 /* Built-in typeof() function */
|
||||
#define SQLITE_FUNC_COUNT 0x100 /* Built-in count(*) aggregate */
|
||||
#define SQLITE_FUNC_COALESCE 0x200 /* Built-in coalesce() or ifnull() */
|
||||
#define SQLITE_FUNC_UNLIKELY 0x400 /* Built-in unlikely() function */
|
||||
|
||||
/*
|
||||
** The following three macros, FUNCTION(), LIKEFUNC() and AGGREGATE() are
|
||||
@@ -1122,18 +1136,18 @@ struct FuncDestructor {
|
||||
** parameter.
|
||||
*/
|
||||
#define FUNCTION(zName, nArg, iArg, bNC, xFunc) \
|
||||
{nArg, SQLITE_UTF8, (bNC*SQLITE_FUNC_NEEDCOLL), \
|
||||
{nArg, SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \
|
||||
SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, #zName, 0, 0}
|
||||
#define FUNCTION2(zName, nArg, iArg, bNC, xFunc, extraFlags) \
|
||||
{nArg, SQLITE_UTF8, (bNC*SQLITE_FUNC_NEEDCOLL)|extraFlags, \
|
||||
{nArg, SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL)|extraFlags, \
|
||||
SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, #zName, 0, 0}
|
||||
#define STR_FUNCTION(zName, nArg, pArg, bNC, xFunc) \
|
||||
{nArg, SQLITE_UTF8, bNC*SQLITE_FUNC_NEEDCOLL, \
|
||||
{nArg, SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \
|
||||
pArg, 0, xFunc, 0, 0, #zName, 0, 0}
|
||||
#define LIKEFUNC(zName, nArg, arg, flags) \
|
||||
{nArg, SQLITE_UTF8, flags, (void *)arg, 0, likeFunc, 0, 0, #zName, 0, 0}
|
||||
{nArg, SQLITE_UTF8|flags, (void *)arg, 0, likeFunc, 0, 0, #zName, 0, 0}
|
||||
#define AGGREGATE(zName, nArg, arg, nc, xStep, xFinal) \
|
||||
{nArg, SQLITE_UTF8, nc*SQLITE_FUNC_NEEDCOLL, \
|
||||
{nArg, SQLITE_UTF8|(nc*SQLITE_FUNC_NEEDCOLL), \
|
||||
SQLITE_INT_TO_PTR(arg), 0, 0, xStep,xFinal,#zName,0,0}
|
||||
|
||||
/*
|
||||
@@ -1549,9 +1563,10 @@ struct Index {
|
||||
unsigned autoIndex:2; /* 1==UNIQUE, 2==PRIMARY KEY, 0==CREATE INDEX */
|
||||
unsigned bUnordered:1; /* Use this index for == or IN queries only */
|
||||
unsigned uniqNotNull:1; /* True if UNIQUE and NOT NULL for all columns */
|
||||
#ifdef SQLITE_ENABLE_STAT3
|
||||
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
int nSample; /* Number of elements in aSample[] */
|
||||
tRowcnt avgEq; /* Average nEq value for key values not in aSample */
|
||||
int nSampleCol; /* Size of IndexSample.anEq[] and so on */
|
||||
tRowcnt *aAvgEq; /* Average nEq values for keys not in aSample */
|
||||
IndexSample *aSample; /* Samples of the left-most key */
|
||||
#endif
|
||||
};
|
||||
@@ -1562,16 +1577,11 @@ struct Index {
|
||||
** analyze.c source file for additional information.
|
||||
*/
|
||||
struct IndexSample {
|
||||
union {
|
||||
char *z; /* Value if eType is SQLITE_TEXT or SQLITE_BLOB */
|
||||
double r; /* Value if eType is SQLITE_FLOAT */
|
||||
i64 i; /* Value if eType is SQLITE_INTEGER */
|
||||
} u;
|
||||
u8 eType; /* SQLITE_NULL, SQLITE_INTEGER ... etc. */
|
||||
int nByte; /* Size in byte of text or blob. */
|
||||
tRowcnt nEq; /* Est. number of rows where the key equals this sample */
|
||||
tRowcnt nLt; /* Est. number of rows where key is less than this sample */
|
||||
tRowcnt nDLt; /* Est. number of distinct keys less than this sample */
|
||||
void *p; /* Pointer to sampled record */
|
||||
int n; /* Size of record in bytes */
|
||||
tRowcnt *anEq; /* Est. number of rows where the key equals this sample */
|
||||
tRowcnt *anLt; /* Est. number of rows where key is less than this sample */
|
||||
tRowcnt *anDLt; /* Est. number of distinct keys less than this sample */
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -1712,7 +1722,7 @@ typedef int ynVar;
|
||||
struct Expr {
|
||||
u8 op; /* Operation performed by this node */
|
||||
char affinity; /* The affinity of the column or 0 if not a column */
|
||||
u16 flags; /* Various flags. EP_* See below */
|
||||
u32 flags; /* Various flags. EP_* See below */
|
||||
union {
|
||||
char *zToken; /* Token value. Zero terminated and dequoted */
|
||||
int iValue; /* Non-negative integer value if EP_IntValue */
|
||||
@@ -1726,8 +1736,8 @@ struct Expr {
|
||||
Expr *pLeft; /* Left subnode */
|
||||
Expr *pRight; /* Right subnode */
|
||||
union {
|
||||
ExprList *pList; /* Function arguments or in "<expr> IN (<expr-list)" */
|
||||
Select *pSelect; /* Used for sub-selects and "<expr> IN (<select>)" */
|
||||
ExprList *pList; /* op = IN, EXISTS, SELECT, CASE, FUNCTION, BETWEEN */
|
||||
Select *pSelect; /* EP_xIsSelect and op = IN, EXISTS, SELECT */
|
||||
} x;
|
||||
|
||||
/* If the EP_Reduced flag is set in the Expr.flags mask, then no
|
||||
@@ -1745,7 +1755,6 @@ struct Expr {
|
||||
** TK_VARIABLE: variable number (always >= 1). */
|
||||
i16 iAgg; /* Which entry in pAggInfo->aCol[] or ->aFunc[] */
|
||||
i16 iRightJoinTable; /* If EP_FromJoin, the right table of the join */
|
||||
u8 flags2; /* Second set of flags. EP2_... */
|
||||
u8 op2; /* TK_REGISTER: original value of Expr.op
|
||||
** TK_COLUMN: the value of p5 for OP_Column
|
||||
** TK_AGG_FUNCTION: nesting depth */
|
||||
@@ -1756,28 +1765,24 @@ struct Expr {
|
||||
/*
|
||||
** The following are the meanings of bits in the Expr.flags field.
|
||||
*/
|
||||
#define EP_FromJoin 0x0001 /* Originated in ON or USING clause of a join */
|
||||
#define EP_Agg 0x0002 /* Contains one or more aggregate functions */
|
||||
#define EP_Resolved 0x0004 /* IDs have been resolved to COLUMNs */
|
||||
#define EP_Error 0x0008 /* Expression contains one or more errors */
|
||||
#define EP_Distinct 0x0010 /* Aggregate function with DISTINCT keyword */
|
||||
#define EP_VarSelect 0x0020 /* pSelect is correlated, not constant */
|
||||
#define EP_DblQuoted 0x0040 /* token.z was originally in "..." */
|
||||
#define EP_InfixFunc 0x0080 /* True for an infix function: LIKE, GLOB, etc */
|
||||
#define EP_Collate 0x0100 /* Tree contains a TK_COLLATE opeartor */
|
||||
#define EP_FixedDest 0x0200 /* Result needed in a specific register */
|
||||
#define EP_IntValue 0x0400 /* Integer value contained in u.iValue */
|
||||
#define EP_xIsSelect 0x0800 /* x.pSelect is valid (otherwise x.pList is) */
|
||||
#define EP_Hint 0x1000 /* Not used */
|
||||
#define EP_Reduced 0x2000 /* Expr struct is EXPR_REDUCEDSIZE bytes only */
|
||||
#define EP_TokenOnly 0x4000 /* Expr struct is EXPR_TOKENONLYSIZE bytes only */
|
||||
#define EP_Static 0x8000 /* Held in memory not obtained from malloc() */
|
||||
|
||||
/*
|
||||
** The following are the meanings of bits in the Expr.flags2 field.
|
||||
*/
|
||||
#define EP2_MallocedToken 0x0001 /* Need to sqlite3DbFree() Expr.zToken */
|
||||
#define EP2_Irreducible 0x0002 /* Cannot EXPRDUP_REDUCE this Expr */
|
||||
#define EP_FromJoin 0x000001 /* Originated in ON or USING clause of a join */
|
||||
#define EP_Agg 0x000002 /* Contains one or more aggregate functions */
|
||||
#define EP_Resolved 0x000004 /* IDs have been resolved to COLUMNs */
|
||||
#define EP_Error 0x000008 /* Expression contains one or more errors */
|
||||
#define EP_Distinct 0x000010 /* Aggregate function with DISTINCT keyword */
|
||||
#define EP_VarSelect 0x000020 /* pSelect is correlated, not constant */
|
||||
#define EP_DblQuoted 0x000040 /* token.z was originally in "..." */
|
||||
#define EP_InfixFunc 0x000080 /* True for an infix function: LIKE, GLOB, etc */
|
||||
#define EP_Collate 0x000100 /* Tree contains a TK_COLLATE opeartor */
|
||||
#define EP_FixedDest 0x000200 /* Result needed in a specific register */
|
||||
#define EP_IntValue 0x000400 /* Integer value contained in u.iValue */
|
||||
#define EP_xIsSelect 0x000800 /* x.pSelect is valid (otherwise x.pList is) */
|
||||
#define EP_Hint 0x001000 /* Not used */
|
||||
#define EP_Reduced 0x002000 /* Expr struct EXPR_REDUCEDSIZE bytes only */
|
||||
#define EP_TokenOnly 0x004000 /* Expr struct EXPR_TOKENONLYSIZE bytes only */
|
||||
#define EP_Static 0x008000 /* Held in memory not obtained from malloc() */
|
||||
#define EP_MemToken 0x010000 /* Need to sqlite3DbFree() Expr.zToken */
|
||||
#define EP_Irreduce 0x020000 /* Cannot EXPRDUP_REDUCE this Expr */
|
||||
|
||||
/*
|
||||
** The pseudo-routine sqlite3ExprSetIrreducible sets the EP2_Irreducible
|
||||
@@ -1786,7 +1791,7 @@ struct Expr {
|
||||
** so as not to burden production code.
|
||||
*/
|
||||
#ifdef SQLITE_DEBUG
|
||||
# define ExprSetIrreducible(X) (X)->flags2 |= EP2_Irreducible
|
||||
# define ExprSetIrreducible(X) (X)->flags |= EP_Irreduce
|
||||
#else
|
||||
# define ExprSetIrreducible(X)
|
||||
#endif
|
||||
@@ -1795,8 +1800,8 @@ struct Expr {
|
||||
** These macros can be used to test, set, or clear bits in the
|
||||
** Expr.flags field.
|
||||
*/
|
||||
#define ExprHasProperty(E,P) (((E)->flags&(P))==(P))
|
||||
#define ExprHasAnyProperty(E,P) (((E)->flags&(P))!=0)
|
||||
#define ExprHasProperty(E,P) (((E)->flags&(P))!=0)
|
||||
#define ExprHasAllProperty(E,P) (((E)->flags&(P))==(P))
|
||||
#define ExprSetProperty(E,P) (E)->flags|=(P)
|
||||
#define ExprClearProperty(E,P) (E)->flags&=~(P)
|
||||
|
||||
@@ -2006,7 +2011,7 @@ struct SrcList {
|
||||
struct NameContext {
|
||||
Parse *pParse; /* The parser */
|
||||
SrcList *pSrcList; /* One or more tables used to resolve names */
|
||||
ExprList *pEList; /* Optional list of named expressions */
|
||||
ExprList *pEList; /* Optional list of result-set columns */
|
||||
AggInfo *pAggInfo; /* Information about aggregates at this level */
|
||||
NameContext *pNext; /* Next outer name context. NULL for outermost */
|
||||
int nRef; /* Number of names resolved by this context */
|
||||
@@ -2021,9 +2026,7 @@ struct NameContext {
|
||||
#define NC_HasAgg 0x02 /* One or more aggregate functions seen */
|
||||
#define NC_IsCheck 0x04 /* True if resolving names in a CHECK constraint */
|
||||
#define NC_InAggFunc 0x08 /* True if analyzing arguments to an agg func */
|
||||
#define NC_AsMaybe 0x10 /* Resolve to AS terms of the result set only
|
||||
** if no other resolution is available */
|
||||
#define NC_PartIdx 0x20 /* True if resolving a partial index WHERE */
|
||||
#define NC_PartIdx 0x10 /* True if resolving a partial index WHERE */
|
||||
|
||||
/*
|
||||
** An instance of the following structure contains all information
|
||||
@@ -2426,10 +2429,11 @@ struct StrAccum {
|
||||
int nChar; /* Length of the string so far */
|
||||
int nAlloc; /* Amount of space allocated in zText */
|
||||
int mxAlloc; /* Maximum allowed string length */
|
||||
u8 mallocFailed; /* Becomes true if any memory allocation fails */
|
||||
u8 useMalloc; /* 0: none, 1: sqlite3DbMalloc, 2: sqlite3_malloc */
|
||||
u8 tooBig; /* Becomes true if string size exceeds limits */
|
||||
u8 accError; /* STRACCUM_NOMEM or STRACCUM_TOOBIG */
|
||||
};
|
||||
#define STRACCUM_NOMEM 1
|
||||
#define STRACCUM_TOOBIG 2
|
||||
|
||||
/*
|
||||
** A pointer to this structure is used to communicate information
|
||||
@@ -3044,9 +3048,6 @@ void sqlite3ValueSetStr(sqlite3_value*, int, const void *,u8,
|
||||
void sqlite3ValueFree(sqlite3_value*);
|
||||
sqlite3_value *sqlite3ValueNew(sqlite3 *);
|
||||
char *sqlite3Utf16to8(sqlite3 *, const void*, int, u8);
|
||||
#ifdef SQLITE_ENABLE_STAT3
|
||||
char *sqlite3Utf8to16(sqlite3 *, u8, char *, int, int *);
|
||||
#endif
|
||||
int sqlite3ValueFromExpr(sqlite3 *, Expr *, u8, u8, sqlite3_value **);
|
||||
void sqlite3ValueApplyAffinity(sqlite3_value *, u8, u8);
|
||||
#ifndef SQLITE_AMALGAMATION
|
||||
@@ -3113,6 +3114,12 @@ Expr *sqlite3CreateColumnExpr(sqlite3 *, SrcList *, int, int);
|
||||
void sqlite3BackupRestart(sqlite3_backup *);
|
||||
void sqlite3BackupUpdate(sqlite3_backup *, Pgno, const u8 *);
|
||||
|
||||
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
void sqlite3AnalyzeFunctions(void);
|
||||
int sqlite3Stat4ProbeSetValue(Parse*,Index*,UnpackedRecord**,Expr*,u8,int,int*);
|
||||
void sqlite3Stat4ProbeFree(UnpackedRecord*);
|
||||
#endif
|
||||
|
||||
/*
|
||||
** The interface to the LEMON-generated parser
|
||||
*/
|
||||
@@ -3154,13 +3161,14 @@ void sqlite3AutoLoadExtensions(sqlite3*);
|
||||
#else
|
||||
void sqlite3VtabClear(sqlite3 *db, Table*);
|
||||
void sqlite3VtabDisconnect(sqlite3 *db, Table *p);
|
||||
int sqlite3VtabSync(sqlite3 *db, char **);
|
||||
int sqlite3VtabSync(sqlite3 *db, Vdbe*);
|
||||
int sqlite3VtabRollback(sqlite3 *db);
|
||||
int sqlite3VtabCommit(sqlite3 *db);
|
||||
void sqlite3VtabLock(VTable *);
|
||||
void sqlite3VtabUnlock(VTable *);
|
||||
void sqlite3VtabUnlockList(sqlite3*);
|
||||
int sqlite3VtabSavepoint(sqlite3 *, int, int);
|
||||
void sqlite3VtabImportErrmsg(Vdbe*, sqlite3_vtab*);
|
||||
VTable *sqlite3GetVTable(sqlite3*, Table*);
|
||||
# define sqlite3VtabInSync(db) ((db)->nVTrans>0 && (db)->aVTrans==0)
|
||||
#endif
|
||||
@@ -3195,18 +3203,18 @@ const char *sqlite3JournalModename(int);
|
||||
** provided (enforcement of FK constraints requires the triggers sub-system).
|
||||
*/
|
||||
#if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER)
|
||||
void sqlite3FkCheck(Parse*, Table*, int, int);
|
||||
void sqlite3FkCheck(Parse*, Table*, int, int, int*, int);
|
||||
void sqlite3FkDropTable(Parse*, SrcList *, Table*);
|
||||
void sqlite3FkActions(Parse*, Table*, ExprList*, int);
|
||||
void sqlite3FkActions(Parse*, Table*, ExprList*, int, int*, int);
|
||||
int sqlite3FkRequired(Parse*, Table*, int*, int);
|
||||
u32 sqlite3FkOldmask(Parse*, Table*);
|
||||
FKey *sqlite3FkReferences(Table *);
|
||||
#else
|
||||
#define sqlite3FkActions(a,b,c,d)
|
||||
#define sqlite3FkActions(a,b,c,d,e,f)
|
||||
#define sqlite3FkCheck(a,b,c,d)
|
||||
#define sqlite3FkDropTable(a,b,c)
|
||||
#define sqlite3FkOldmask(a,b) 0
|
||||
#define sqlite3FkRequired(a,b,c,d) 0
|
||||
#define sqlite3FkOldmask(a,b) 0
|
||||
#define sqlite3FkRequired(a,b,c,d,e,f) 0
|
||||
#endif
|
||||
#ifndef SQLITE_OMIT_FOREIGN_KEY
|
||||
void sqlite3FkDelete(sqlite3 *, Table*);
|
||||
|
||||
+144
@@ -5934,6 +5934,145 @@ static int win32_file_lock(
|
||||
CloseHandle(ev);
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** exists_win32_path PATH
|
||||
**
|
||||
** Returns non-zero if the specified path exists, whose fully qualified name
|
||||
** may exceed 260 characters if it is prefixed with "\\?\".
|
||||
*/
|
||||
static int win32_exists_path(
|
||||
void *clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
if( objc!=2 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "PATH");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
Tcl_SetObjResult(interp, Tcl_NewBooleanObj(
|
||||
GetFileAttributesW( Tcl_GetUnicode(objv[1]))!=INVALID_FILE_ATTRIBUTES ));
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** find_win32_file PATTERN
|
||||
**
|
||||
** Returns a list of entries in a directory that match the specified pattern,
|
||||
** whose fully qualified name may exceed 248 characters if it is prefixed with
|
||||
** "\\?\".
|
||||
*/
|
||||
static int win32_find_file(
|
||||
void *clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
HANDLE hFindFile = INVALID_HANDLE_VALUE;
|
||||
WIN32_FIND_DATAW findData;
|
||||
Tcl_Obj *listObj;
|
||||
DWORD lastErrno;
|
||||
if( objc!=2 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "PATTERN");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
hFindFile = FindFirstFileW(Tcl_GetUnicode(objv[1]), &findData);
|
||||
if( hFindFile==INVALID_HANDLE_VALUE ){
|
||||
Tcl_SetObjResult(interp, Tcl_NewWideIntObj(GetLastError()));
|
||||
return TCL_ERROR;
|
||||
}
|
||||
listObj = Tcl_NewObj();
|
||||
Tcl_IncrRefCount(listObj);
|
||||
do {
|
||||
Tcl_ListObjAppendElement(interp, listObj, Tcl_NewUnicodeObj(
|
||||
findData.cFileName, -1));
|
||||
Tcl_ListObjAppendElement(interp, listObj, Tcl_NewWideIntObj(
|
||||
findData.dwFileAttributes));
|
||||
} while( FindNextFileW(hFindFile, &findData) );
|
||||
lastErrno = GetLastError();
|
||||
if( lastErrno!=NO_ERROR && lastErrno!=ERROR_NO_MORE_FILES ){
|
||||
FindClose(hFindFile);
|
||||
Tcl_DecrRefCount(listObj);
|
||||
Tcl_SetObjResult(interp, Tcl_NewWideIntObj(GetLastError()));
|
||||
return TCL_ERROR;
|
||||
}
|
||||
FindClose(hFindFile);
|
||||
Tcl_SetObjResult(interp, listObj);
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** delete_win32_file FILENAME
|
||||
**
|
||||
** Deletes the specified file, whose fully qualified name may exceed 260
|
||||
** characters if it is prefixed with "\\?\".
|
||||
*/
|
||||
static int win32_delete_file(
|
||||
void *clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
if( objc!=2 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "FILENAME");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( !DeleteFileW(Tcl_GetUnicode(objv[1])) ){
|
||||
Tcl_SetObjResult(interp, Tcl_NewWideIntObj(GetLastError()));
|
||||
return TCL_ERROR;
|
||||
}
|
||||
Tcl_ResetResult(interp);
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** make_win32_dir DIRECTORY
|
||||
**
|
||||
** Creates the specified directory, whose fully qualified name may exceed 248
|
||||
** characters if it is prefixed with "\\?\".
|
||||
*/
|
||||
static int win32_mkdir(
|
||||
void *clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
if( objc!=2 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "DIRECTORY");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( !CreateDirectoryW(Tcl_GetUnicode(objv[1]), NULL) ){
|
||||
Tcl_SetObjResult(interp, Tcl_NewWideIntObj(GetLastError()));
|
||||
return TCL_ERROR;
|
||||
}
|
||||
Tcl_ResetResult(interp);
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** remove_win32_dir DIRECTORY
|
||||
**
|
||||
** Removes the specified directory, whose fully qualified name may exceed 248
|
||||
** characters if it is prefixed with "\\?\".
|
||||
*/
|
||||
static int win32_rmdir(
|
||||
void *clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
if( objc!=2 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "DIRECTORY");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( !RemoveDirectoryW(Tcl_GetUnicode(objv[1])) ){
|
||||
Tcl_SetObjResult(interp, Tcl_NewWideIntObj(GetLastError()));
|
||||
return TCL_ERROR;
|
||||
}
|
||||
Tcl_ResetResult(interp);
|
||||
return TCL_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -6193,6 +6332,11 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
||||
{ "optimization_control", optimization_control,0},
|
||||
#if SQLITE_OS_WIN
|
||||
{ "lock_win32_file", win32_file_lock, 0 },
|
||||
{ "exists_win32_path", win32_exists_path, 0 },
|
||||
{ "find_win32_file", win32_find_file, 0 },
|
||||
{ "delete_win32_file", win32_delete_file, 0 },
|
||||
{ "make_win32_dir", win32_mkdir, 0 },
|
||||
{ "remove_win32_dir", win32_rmdir, 0 },
|
||||
#endif
|
||||
{ "tcl_objproc", runAsObjProc, 0 },
|
||||
|
||||
|
||||
+6
-1
@@ -458,7 +458,12 @@ Tcl_SetVar2(interp, "sqlite_options", "mergesort", "1", TCL_GLOBAL_ONLY);
|
||||
Tcl_SetVar2(interp, "sqlite_options", "schema_version", "1", TCL_GLOBAL_ONLY);
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_ENABLE_STAT3
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
Tcl_SetVar2(interp, "sqlite_options", "stat4", "1", TCL_GLOBAL_ONLY);
|
||||
#else
|
||||
Tcl_SetVar2(interp, "sqlite_options", "stat4", "0", TCL_GLOBAL_ONLY);
|
||||
#endif
|
||||
#if defined(SQLITE_ENABLE_STAT3) && !defined(SQLITE_ENABLE_STAT4)
|
||||
Tcl_SetVar2(interp, "sqlite_options", "stat3", "1", TCL_GLOBAL_ONLY);
|
||||
#else
|
||||
Tcl_SetVar2(interp, "sqlite_options", "stat3", "0", TCL_GLOBAL_ONLY);
|
||||
|
||||
+146
@@ -18,6 +18,9 @@
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "sqliteInt.h"
|
||||
#include "vdbeInt.h"
|
||||
|
||||
|
||||
/*
|
||||
** Allocate nByte bytes of space using sqlite3_malloc(). If the
|
||||
@@ -458,6 +461,147 @@ static void real2hex(
|
||||
sqlite3_result_text(context, zOut, -1, SQLITE_TRANSIENT);
|
||||
}
|
||||
|
||||
/*
|
||||
** tclcmd: test_extract(record, field)
|
||||
**
|
||||
** This function implements an SQL user-function that accepts a blob
|
||||
** containing a formatted database record as the first argument. The
|
||||
** second argument is the index of the field within that record to
|
||||
** extract and return.
|
||||
*/
|
||||
static void test_extract(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
sqlite3 *db = sqlite3_context_db_handle(context);
|
||||
u8 *pRec;
|
||||
u8 *pEndHdr; /* Points to one byte past record header */
|
||||
u8 *pHdr; /* Current point in record header */
|
||||
u8 *pBody; /* Current point in record data */
|
||||
u64 nHdr; /* Bytes in record header */
|
||||
int iIdx; /* Required field */
|
||||
int iCurrent = 0; /* Current field */
|
||||
|
||||
assert( argc==2 );
|
||||
pRec = (u8*)sqlite3_value_blob(argv[0]);
|
||||
iIdx = sqlite3_value_int(argv[1]);
|
||||
|
||||
pHdr = pRec + sqlite3GetVarint(pRec, &nHdr);
|
||||
pBody = pEndHdr = &pRec[nHdr];
|
||||
|
||||
for(iCurrent=0; pHdr<pEndHdr && iCurrent<=iIdx; iCurrent++){
|
||||
u64 iSerialType;
|
||||
Mem mem;
|
||||
|
||||
memset(&mem, 0, sizeof(mem));
|
||||
mem.db = db;
|
||||
mem.enc = ENC(db);
|
||||
pHdr += sqlite3GetVarint(pHdr, &iSerialType);
|
||||
pBody += sqlite3VdbeSerialGet(pBody, (u32)iSerialType, &mem);
|
||||
sqlite3VdbeMemStoreType(&mem);
|
||||
|
||||
if( iCurrent==iIdx ){
|
||||
sqlite3_result_value(context, &mem);
|
||||
}
|
||||
|
||||
sqlite3DbFree(db, mem.zMalloc);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** tclcmd: test_decode(record)
|
||||
**
|
||||
** This function implements an SQL user-function that accepts a blob
|
||||
** containing a formatted database record as its only argument. It returns
|
||||
** a tcl list (type SQLITE_TEXT) containing each of the values stored
|
||||
** in the record.
|
||||
*/
|
||||
static void test_decode(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
sqlite3 *db = sqlite3_context_db_handle(context);
|
||||
u8 *pRec;
|
||||
u8 *pEndHdr; /* Points to one byte past record header */
|
||||
u8 *pHdr; /* Current point in record header */
|
||||
u8 *pBody; /* Current point in record data */
|
||||
u64 nHdr; /* Bytes in record header */
|
||||
Tcl_Obj *pRet; /* Return value */
|
||||
|
||||
pRet = Tcl_NewObj();
|
||||
Tcl_IncrRefCount(pRet);
|
||||
|
||||
assert( argc==1 );
|
||||
pRec = (u8*)sqlite3_value_blob(argv[0]);
|
||||
|
||||
pHdr = pRec + sqlite3GetVarint(pRec, &nHdr);
|
||||
pBody = pEndHdr = &pRec[nHdr];
|
||||
while( pHdr<pEndHdr ){
|
||||
Tcl_Obj *pVal = 0;
|
||||
u64 iSerialType;
|
||||
Mem mem;
|
||||
|
||||
memset(&mem, 0, sizeof(mem));
|
||||
mem.db = db;
|
||||
mem.enc = ENC(db);
|
||||
pHdr += sqlite3GetVarint(pHdr, &iSerialType);
|
||||
pBody += sqlite3VdbeSerialGet(pBody, (u32)iSerialType, &mem);
|
||||
|
||||
sqlite3VdbeMemStoreType(&mem);
|
||||
switch( sqlite3_value_type(&mem) ){
|
||||
case SQLITE_TEXT:
|
||||
pVal = Tcl_NewStringObj((const char*)sqlite3_value_text(&mem), -1);
|
||||
break;
|
||||
|
||||
case SQLITE_BLOB: {
|
||||
char hexdigit[] = {
|
||||
'0', '1', '2', '3', '4', '5', '6', '7',
|
||||
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
|
||||
};
|
||||
int n = sqlite3_value_bytes(&mem);
|
||||
u8 *z = (u8*)sqlite3_value_blob(&mem);
|
||||
int i;
|
||||
pVal = Tcl_NewStringObj("x'", -1);
|
||||
for(i=0; i<n; i++){
|
||||
char hex[3];
|
||||
hex[0] = hexdigit[((z[i] >> 4) & 0x0F)];
|
||||
hex[1] = hexdigit[(z[i] & 0x0F)];
|
||||
hex[2] = '\0';
|
||||
Tcl_AppendStringsToObj(pVal, hex, 0);
|
||||
}
|
||||
Tcl_AppendStringsToObj(pVal, "'", 0);
|
||||
break;
|
||||
}
|
||||
|
||||
case SQLITE_FLOAT:
|
||||
pVal = Tcl_NewDoubleObj(sqlite3_value_double(&mem));
|
||||
break;
|
||||
|
||||
case SQLITE_INTEGER:
|
||||
pVal = Tcl_NewWideIntObj(sqlite3_value_int64(&mem));
|
||||
break;
|
||||
|
||||
case SQLITE_NULL:
|
||||
pVal = Tcl_NewStringObj("NULL", -1);
|
||||
break;
|
||||
|
||||
default:
|
||||
assert( 0 );
|
||||
}
|
||||
|
||||
Tcl_ListObjAppendElement(0, pRet, pVal);
|
||||
|
||||
if( mem.zMalloc ){
|
||||
sqlite3DbFree(db, mem.zMalloc);
|
||||
}
|
||||
}
|
||||
|
||||
sqlite3_result_text(context, Tcl_GetString(pRet), -1, SQLITE_TRANSIENT);
|
||||
Tcl_DecrRefCount(pRet);
|
||||
}
|
||||
|
||||
|
||||
static int registerTestFunctions(sqlite3 *db){
|
||||
static const struct {
|
||||
@@ -482,6 +626,8 @@ static int registerTestFunctions(sqlite3 *db){
|
||||
{ "test_isolation", 2, SQLITE_UTF8, test_isolation},
|
||||
{ "test_counter", 1, SQLITE_UTF8, counterFunc},
|
||||
{ "real2hex", 1, SQLITE_UTF8, real2hex},
|
||||
{ "test_decode", 1, SQLITE_UTF8, test_decode},
|
||||
{ "test_extract", 2, SQLITE_UTF8, test_extract},
|
||||
};
|
||||
int i;
|
||||
|
||||
|
||||
+1
-1
@@ -749,7 +749,7 @@ static void test_memdebug_callback(int nByte, int nFrame, void **aFrame){
|
||||
int isNew;
|
||||
|
||||
int aKey[MALLOC_LOG_KEYINTS];
|
||||
int nKey = sizeof(int)*MALLOC_LOG_KEYINTS;
|
||||
unsigned int nKey = sizeof(int)*MALLOC_LOG_KEYINTS;
|
||||
|
||||
memset(aKey, 0, nKey);
|
||||
if( (sizeof(void*)*nFrame)<nKey ){
|
||||
|
||||
+4
-4
@@ -61,7 +61,7 @@ static void updateVirtualTable(
|
||||
void sqlite3ColumnDefault(Vdbe *v, Table *pTab, int i, int iReg){
|
||||
assert( pTab!=0 );
|
||||
if( !pTab->pSelect ){
|
||||
sqlite3_value *pValue;
|
||||
sqlite3_value *pValue = 0;
|
||||
u8 enc = ENC(sqlite3VdbeDb(v));
|
||||
Column *pCol = &pTab->aCol[i];
|
||||
VdbeComment((v, "%s.%s", pTab->zName, pCol->zName));
|
||||
@@ -488,7 +488,7 @@ void sqlite3Update(
|
||||
|
||||
/* Do FK constraint checks. */
|
||||
if( hasFK ){
|
||||
sqlite3FkCheck(pParse, pTab, regOldRowid, 0);
|
||||
sqlite3FkCheck(pParse, pTab, regOldRowid, 0, aXRef, chngRowid);
|
||||
}
|
||||
|
||||
/* Delete the index entries associated with the current record. */
|
||||
@@ -502,7 +502,7 @@ void sqlite3Update(
|
||||
sqlite3VdbeJumpHere(v, j1);
|
||||
|
||||
if( hasFK ){
|
||||
sqlite3FkCheck(pParse, pTab, 0, regNewRowid);
|
||||
sqlite3FkCheck(pParse, pTab, 0, regNewRowid, aXRef, chngRowid);
|
||||
}
|
||||
|
||||
/* Insert the new index entries and the new record. */
|
||||
@@ -512,7 +512,7 @@ void sqlite3Update(
|
||||
** handle rows (possibly in other tables) that refer via a foreign key
|
||||
** to the row just updated. */
|
||||
if( hasFK ){
|
||||
sqlite3FkActions(pParse, pTab, pChanges, regOldRowid);
|
||||
sqlite3FkActions(pParse, pTab, pChanges, regOldRowid, aXRef, chngRowid);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -450,32 +450,6 @@ char *sqlite3Utf16to8(sqlite3 *db, const void *z, int nByte, u8 enc){
|
||||
return m.z;
|
||||
}
|
||||
|
||||
/*
|
||||
** Convert a UTF-8 string to the UTF-16 encoding specified by parameter
|
||||
** enc. A pointer to the new string is returned, and the value of *pnOut
|
||||
** is set to the length of the returned string in bytes. The call should
|
||||
** arrange to call sqlite3DbFree() on the returned pointer when it is
|
||||
** no longer required.
|
||||
**
|
||||
** If a malloc failure occurs, NULL is returned and the db.mallocFailed
|
||||
** flag set.
|
||||
*/
|
||||
#ifdef SQLITE_ENABLE_STAT3
|
||||
char *sqlite3Utf8to16(sqlite3 *db, u8 enc, char *z, int n, int *pnOut){
|
||||
Mem m;
|
||||
memset(&m, 0, sizeof(m));
|
||||
m.db = db;
|
||||
sqlite3VdbeMemSetStr(&m, z, n, SQLITE_UTF8, SQLITE_STATIC);
|
||||
if( sqlite3VdbeMemTranslate(&m, enc) ){
|
||||
assert( db->mallocFailed );
|
||||
return 0;
|
||||
}
|
||||
assert( m.z==m.zMalloc );
|
||||
*pnOut = m.n;
|
||||
return m.z;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** zIn is a UTF-16 encoded unicode string at least nChar characters long.
|
||||
** Return the number of bytes in the first nChar unicode characters
|
||||
|
||||
+57
-70
@@ -497,19 +497,6 @@ static int checkSavepointCount(sqlite3 *db){
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Transfer error message text from an sqlite3_vtab.zErrMsg (text stored
|
||||
** in memory obtained from sqlite3_malloc) into a Vdbe.zErrMsg (text stored
|
||||
** in memory obtained from sqlite3DbMalloc).
|
||||
*/
|
||||
static void importVtabErrMsg(Vdbe *p, sqlite3_vtab *pVtab){
|
||||
sqlite3 *db = p->db;
|
||||
sqlite3DbFree(db, p->zErrMsg);
|
||||
p->zErrMsg = sqlite3DbStrDup(db, pVtab->zErrMsg);
|
||||
sqlite3_free(pVtab->zErrMsg);
|
||||
pVtab->zErrMsg = 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Execute as much of a VDBE program as we can then return.
|
||||
@@ -588,7 +575,7 @@ int sqlite3VdbeExec(
|
||||
#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
|
||||
if( db->xProgress ){
|
||||
assert( 0 < db->nProgressOps );
|
||||
nProgressLimit = (unsigned)p->aCounter[SQLITE_STMTSTATUS_VM_STEP-1];
|
||||
nProgressLimit = (unsigned)p->aCounter[SQLITE_STMTSTATUS_VM_STEP];
|
||||
if( nProgressLimit==0 ){
|
||||
nProgressLimit = db->nProgressOps;
|
||||
}else{
|
||||
@@ -651,7 +638,7 @@ int sqlite3VdbeExec(
|
||||
assert( pOp->opflags==sqlite3OpcodeProperty[pOp->opcode] );
|
||||
if( pOp->opflags & OPFLG_OUT2_PRERELEASE ){
|
||||
assert( pOp->p2>0 );
|
||||
assert( pOp->p2<=p->nMem );
|
||||
assert( pOp->p2<=(p->nMem-p->nCursor) );
|
||||
pOut = &aMem[pOp->p2];
|
||||
memAboutToChange(p, pOut);
|
||||
VdbeMemRelease(pOut);
|
||||
@@ -662,30 +649,30 @@ int sqlite3VdbeExec(
|
||||
#ifdef SQLITE_DEBUG
|
||||
if( (pOp->opflags & OPFLG_IN1)!=0 ){
|
||||
assert( pOp->p1>0 );
|
||||
assert( pOp->p1<=p->nMem );
|
||||
assert( pOp->p1<=(p->nMem-p->nCursor) );
|
||||
assert( memIsValid(&aMem[pOp->p1]) );
|
||||
REGISTER_TRACE(pOp->p1, &aMem[pOp->p1]);
|
||||
}
|
||||
if( (pOp->opflags & OPFLG_IN2)!=0 ){
|
||||
assert( pOp->p2>0 );
|
||||
assert( pOp->p2<=p->nMem );
|
||||
assert( pOp->p2<=(p->nMem-p->nCursor) );
|
||||
assert( memIsValid(&aMem[pOp->p2]) );
|
||||
REGISTER_TRACE(pOp->p2, &aMem[pOp->p2]);
|
||||
}
|
||||
if( (pOp->opflags & OPFLG_IN3)!=0 ){
|
||||
assert( pOp->p3>0 );
|
||||
assert( pOp->p3<=p->nMem );
|
||||
assert( pOp->p3<=(p->nMem-p->nCursor) );
|
||||
assert( memIsValid(&aMem[pOp->p3]) );
|
||||
REGISTER_TRACE(pOp->p3, &aMem[pOp->p3]);
|
||||
}
|
||||
if( (pOp->opflags & OPFLG_OUT2)!=0 ){
|
||||
assert( pOp->p2>0 );
|
||||
assert( pOp->p2<=p->nMem );
|
||||
assert( pOp->p2<=(p->nMem-p->nCursor) );
|
||||
memAboutToChange(p, &aMem[pOp->p2]);
|
||||
}
|
||||
if( (pOp->opflags & OPFLG_OUT3)!=0 ){
|
||||
assert( pOp->p3>0 );
|
||||
assert( pOp->p3<=p->nMem );
|
||||
assert( pOp->p3<=(p->nMem-p->nCursor) );
|
||||
memAboutToChange(p, &aMem[pOp->p3]);
|
||||
}
|
||||
#endif
|
||||
@@ -778,7 +765,7 @@ check_for_interrupt:
|
||||
** and then jump to address P2.
|
||||
*/
|
||||
case OP_Gosub: { /* jump */
|
||||
assert( pOp->p1>0 && pOp->p1<=p->nMem );
|
||||
assert( pOp->p1>0 && pOp->p1<=(p->nMem-p->nCursor) );
|
||||
pIn1 = &aMem[pOp->p1];
|
||||
assert( (pIn1->flags & MEM_Dyn)==0 );
|
||||
memAboutToChange(p, pIn1);
|
||||
@@ -990,7 +977,7 @@ case OP_Null: { /* out2-prerelease */
|
||||
int cnt;
|
||||
u16 nullFlag;
|
||||
cnt = pOp->p3-pOp->p2;
|
||||
assert( pOp->p3<=p->nMem );
|
||||
assert( pOp->p3<=(p->nMem-p->nCursor) );
|
||||
pOut->flags = nullFlag = pOp->p1 ? (MEM_Null|MEM_Cleared) : MEM_Null;
|
||||
while( cnt>0 ){
|
||||
pOut++;
|
||||
@@ -1059,8 +1046,8 @@ case OP_Move: {
|
||||
pIn1 = &aMem[p1];
|
||||
pOut = &aMem[p2];
|
||||
while( n-- ){
|
||||
assert( pOut<=&aMem[p->nMem] );
|
||||
assert( pIn1<=&aMem[p->nMem] );
|
||||
assert( pOut<=&aMem[(p->nMem-p->nCursor)] );
|
||||
assert( pIn1<=&aMem[(p->nMem-p->nCursor)] );
|
||||
assert( memIsValid(pIn1) );
|
||||
memAboutToChange(p, pOut);
|
||||
zMalloc = pOut->zMalloc;
|
||||
@@ -1144,7 +1131,7 @@ case OP_ResultRow: {
|
||||
int i;
|
||||
assert( p->nResColumn==pOp->p2 );
|
||||
assert( pOp->p1>0 );
|
||||
assert( pOp->p1+pOp->p2<=p->nMem+1 );
|
||||
assert( pOp->p1+pOp->p2<=(p->nMem-p->nCursor)+1 );
|
||||
|
||||
/* If this statement has violated immediate foreign key constraints, do
|
||||
** not return the number of rows modified. And do not RELEASE the statement
|
||||
@@ -1418,11 +1405,11 @@ case OP_Function: {
|
||||
n = pOp->p5;
|
||||
apVal = p->apArg;
|
||||
assert( apVal || n==0 );
|
||||
assert( pOp->p3>0 && pOp->p3<=p->nMem );
|
||||
assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) );
|
||||
pOut = &aMem[pOp->p3];
|
||||
memAboutToChange(p, pOut);
|
||||
|
||||
assert( n==0 || (pOp->p2>0 && pOp->p2+n<=p->nMem+1) );
|
||||
assert( n==0 || (pOp->p2>0 && pOp->p2+n<=(p->nMem-p->nCursor)+1) );
|
||||
assert( pOp->p3<pOp->p2 || pOp->p3>=pOp->p2+n );
|
||||
pArg = &aMem[pOp->p2];
|
||||
for(i=0; i<n; i++, pArg++){
|
||||
@@ -1449,8 +1436,8 @@ case OP_Function: {
|
||||
sqlite3VdbeMemMove(&ctx.s, pOut);
|
||||
MemSetTypeFlag(&ctx.s, MEM_Null);
|
||||
|
||||
ctx.isError = 0;
|
||||
if( ctx.pFunc->flags & SQLITE_FUNC_NEEDCOLL ){
|
||||
ctx.fErrorOrAux = 0;
|
||||
if( ctx.pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL ){
|
||||
assert( pOp>aOp );
|
||||
assert( pOp[-1].p4type==P4_COLLSEQ );
|
||||
assert( pOp[-1].opcode==OP_CollSeq );
|
||||
@@ -1460,11 +1447,6 @@ case OP_Function: {
|
||||
(*ctx.pFunc->xFunc)(&ctx, n, apVal); /* IMP: R-24505-23230 */
|
||||
lastRowid = db->lastRowid;
|
||||
|
||||
/* If any auxiliary data functions have been called by this user function,
|
||||
** immediately call the destructor for any non-static values.
|
||||
*/
|
||||
sqlite3VdbeDeleteAuxData(p, pc, pOp->p1);
|
||||
|
||||
if( db->mallocFailed ){
|
||||
/* Even though a malloc() has failed, the implementation of the
|
||||
** user function may have called an sqlite3_result_XXX() function
|
||||
@@ -1476,9 +1458,12 @@ case OP_Function: {
|
||||
}
|
||||
|
||||
/* If the function returned an error, throw an exception */
|
||||
if( ctx.isError ){
|
||||
sqlite3SetString(&p->zErrMsg, db, "%s", sqlite3_value_text(&ctx.s));
|
||||
rc = ctx.isError;
|
||||
if( ctx.fErrorOrAux ){
|
||||
if( ctx.isError ){
|
||||
sqlite3SetString(&p->zErrMsg, db, "%s", sqlite3_value_text(&ctx.s));
|
||||
rc = ctx.isError;
|
||||
}
|
||||
sqlite3VdbeDeleteAuxData(p, pc, pOp->p1);
|
||||
}
|
||||
|
||||
/* Copy the result of the function into register P3 */
|
||||
@@ -1850,12 +1835,12 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
|
||||
** then the result is always NULL.
|
||||
** The jump is taken if the SQLITE_JUMPIFNULL bit is set.
|
||||
*/
|
||||
if( pOp->p5 & SQLITE_STOREP2 ){
|
||||
if( pOp->p5 & SQLITE_JUMPIFNULL ){
|
||||
pc = pOp->p2-1;
|
||||
}else if( pOp->p5 & SQLITE_STOREP2 ){
|
||||
pOut = &aMem[pOp->p2];
|
||||
MemSetTypeFlag(pOut, MEM_Null);
|
||||
REGISTER_TRACE(pOp->p2, pOut);
|
||||
}else if( pOp->p5 & SQLITE_JUMPIFNULL ){
|
||||
pc = pOp->p2-1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -1954,11 +1939,11 @@ case OP_Compare: {
|
||||
if( aPermute ){
|
||||
int k, mx = 0;
|
||||
for(k=0; k<n; k++) if( aPermute[k]>mx ) mx = aPermute[k];
|
||||
assert( p1>0 && p1+mx<=p->nMem+1 );
|
||||
assert( p2>0 && p2+mx<=p->nMem+1 );
|
||||
assert( p1>0 && p1+mx<=(p->nMem-p->nCursor)+1 );
|
||||
assert( p2>0 && p2+mx<=(p->nMem-p->nCursor)+1 );
|
||||
}else{
|
||||
assert( p1>0 && p1+n<=p->nMem+1 );
|
||||
assert( p2>0 && p2+n<=p->nMem+1 );
|
||||
assert( p1>0 && p1+n<=(p->nMem-p->nCursor)+1 );
|
||||
assert( p2>0 && p2+n<=(p->nMem-p->nCursor)+1 );
|
||||
}
|
||||
#endif /* SQLITE_DEBUG */
|
||||
for(i=0; i<n; i++){
|
||||
@@ -2209,7 +2194,7 @@ case OP_Column: {
|
||||
pC = 0;
|
||||
memset(&sMem, 0, sizeof(sMem));
|
||||
assert( p1<p->nCursor );
|
||||
assert( pOp->p3>0 && pOp->p3<=p->nMem );
|
||||
assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) );
|
||||
pDest = &aMem[pOp->p3];
|
||||
memAboutToChange(p, pDest);
|
||||
zRec = 0;
|
||||
@@ -2507,7 +2492,7 @@ case OP_Affinity: {
|
||||
assert( zAffinity[pOp->p2]==0 );
|
||||
pIn1 = &aMem[pOp->p1];
|
||||
while( (cAff = *(zAffinity++))!=0 ){
|
||||
assert( pIn1 <= &p->aMem[p->nMem] );
|
||||
assert( pIn1 <= &p->aMem[(p->nMem-p->nCursor)] );
|
||||
assert( memIsValid(pIn1) );
|
||||
ExpandBlob(pIn1);
|
||||
applyAffinity(pIn1, cAff, encoding);
|
||||
@@ -2568,7 +2553,7 @@ case OP_MakeRecord: {
|
||||
nZero = 0; /* Number of zero bytes at the end of the record */
|
||||
nField = pOp->p1;
|
||||
zAffinity = pOp->p4.z;
|
||||
assert( nField>0 && pOp->p2>0 && pOp->p2+nField<=p->nMem+1 );
|
||||
assert( nField>0 && pOp->p2>0 && pOp->p2+nField<=(p->nMem-p->nCursor)+1 );
|
||||
pData0 = &aMem[nField];
|
||||
nField = pOp->p2;
|
||||
pLast = &pData0[nField-1];
|
||||
@@ -2634,7 +2619,7 @@ case OP_MakeRecord: {
|
||||
}
|
||||
assert( i==nByte );
|
||||
|
||||
assert( pOp->p3>0 && pOp->p3<=p->nMem );
|
||||
assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) );
|
||||
pOut->n = (int)nByte;
|
||||
pOut->flags = MEM_Blob | MEM_Dyn;
|
||||
pOut->xDel = 0;
|
||||
@@ -3214,7 +3199,7 @@ case OP_OpenWrite: {
|
||||
}
|
||||
if( pOp->p5 & OPFLAG_P2ISREG ){
|
||||
assert( p2>0 );
|
||||
assert( p2<=p->nMem );
|
||||
assert( p2<=(p->nMem-p->nCursor) );
|
||||
pIn2 = &aMem[p2];
|
||||
assert( memIsValid(pIn2) );
|
||||
assert( (pIn2->flags & MEM_Int)!=0 );
|
||||
@@ -3751,7 +3736,7 @@ case OP_IsUnique: { /* jump, in3 */
|
||||
aMx = &aMem[pOp->p4.i];
|
||||
/* Assert that the values of parameters P1 and P4 are in range. */
|
||||
assert( pOp->p4type==P4_INT32 );
|
||||
assert( pOp->p4.i>0 && pOp->p4.i<=p->nMem );
|
||||
assert( pOp->p4.i>0 && pOp->p4.i<=(p->nMem-p->nCursor) );
|
||||
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
|
||||
|
||||
/* Find the index cursor. */
|
||||
@@ -3954,7 +3939,7 @@ case OP_NewRowid: { /* out2-prerelease */
|
||||
pMem = &pFrame->aMem[pOp->p3];
|
||||
}else{
|
||||
/* Assert that P3 is a valid memory cell. */
|
||||
assert( pOp->p3<=p->nMem );
|
||||
assert( pOp->p3<=(p->nMem-p->nCursor) );
|
||||
pMem = &aMem[pOp->p3];
|
||||
memAboutToChange(p, pMem);
|
||||
}
|
||||
@@ -4352,7 +4337,7 @@ case OP_Rowid: { /* out2-prerelease */
|
||||
pModule = pVtab->pModule;
|
||||
assert( pModule->xRowid );
|
||||
rc = pModule->xRowid(pC->pVtabCursor, &v);
|
||||
importVtabErrMsg(p, pVtab);
|
||||
sqlite3VtabImportErrmsg(p, pVtab);
|
||||
#endif /* SQLITE_OMIT_VIRTUALTABLE */
|
||||
}else{
|
||||
assert( pC->pCursor!=0 );
|
||||
@@ -4440,7 +4425,7 @@ case OP_Sort: { /* jump */
|
||||
sqlite3_sort_count++;
|
||||
sqlite3_search_count--;
|
||||
#endif
|
||||
p->aCounter[SQLITE_STMTSTATUS_SORT-1]++;
|
||||
p->aCounter[SQLITE_STMTSTATUS_SORT]++;
|
||||
/* Fall through into OP_Rewind */
|
||||
}
|
||||
/* Opcode: Rewind P1 P2 * * *
|
||||
@@ -4519,7 +4504,7 @@ case OP_Next: { /* jump */
|
||||
int res;
|
||||
|
||||
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
|
||||
assert( pOp->p5<=ArraySize(p->aCounter) );
|
||||
assert( pOp->p5<ArraySize(p->aCounter) );
|
||||
pC = p->apCsr[pOp->p1];
|
||||
if( pC==0 ){
|
||||
break; /* See ticket #2273 */
|
||||
@@ -4529,7 +4514,7 @@ case OP_Next: { /* jump */
|
||||
assert( pOp->opcode==OP_SorterNext );
|
||||
rc = sqlite3VdbeSorterNext(db, pC, &res);
|
||||
}else{
|
||||
res = 1;
|
||||
/* res = 1; // Always initialized by the xAdvance() call */
|
||||
assert( pC->deferredMoveto==0 );
|
||||
assert( pC->pCursor );
|
||||
assert( pOp->opcode!=OP_Next || pOp->p4.xAdvance==sqlite3BtreeNext );
|
||||
@@ -4540,7 +4525,7 @@ case OP_Next: { /* jump */
|
||||
pC->cacheStatus = CACHE_STALE;
|
||||
if( res==0 ){
|
||||
pc = pOp->p2 - 1;
|
||||
if( pOp->p5 ) p->aCounter[pOp->p5-1]++;
|
||||
p->aCounter[pOp->p5]++;
|
||||
#ifdef SQLITE_TEST
|
||||
sqlite3_search_count++;
|
||||
#endif
|
||||
@@ -4608,7 +4593,7 @@ case OP_IdxDelete: {
|
||||
UnpackedRecord r;
|
||||
|
||||
assert( pOp->p3>0 );
|
||||
assert( pOp->p2>0 && pOp->p2+pOp->p3<=p->nMem+1 );
|
||||
assert( pOp->p2>0 && pOp->p2+pOp->p3<=(p->nMem-p->nCursor)+1 );
|
||||
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
|
||||
pC = p->apCsr[pOp->p1];
|
||||
assert( pC!=0 );
|
||||
@@ -4816,6 +4801,7 @@ case OP_Clear: {
|
||||
|
||||
nChange = 0;
|
||||
assert( p->readOnly==0 );
|
||||
assert( pOp->p1!=1 );
|
||||
assert( (p->btreeMask & (((yDbMask)1)<<pOp->p2))!=0 );
|
||||
rc = sqlite3BtreeClearTable(
|
||||
db->aDb[pOp->p2].pBt, pOp->p1, (pOp->p3 ? &nChange : 0)
|
||||
@@ -5016,7 +5002,7 @@ case OP_IntegrityCk: {
|
||||
assert( nRoot>0 );
|
||||
aRoot = sqlite3DbMallocRaw(db, sizeof(int)*(nRoot+1) );
|
||||
if( aRoot==0 ) goto no_mem;
|
||||
assert( pOp->p3>0 && pOp->p3<=p->nMem );
|
||||
assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) );
|
||||
pnErr = &aMem[pOp->p3];
|
||||
assert( (pnErr->flags & MEM_Int)!=0 );
|
||||
assert( (pnErr->flags & (MEM_Str|MEM_Blob))==0 );
|
||||
@@ -5440,7 +5426,7 @@ case OP_AggStep: {
|
||||
sqlite3VdbeMemStoreType(pRec);
|
||||
}
|
||||
ctx.pFunc = pOp->p4.pFunc;
|
||||
assert( pOp->p3>0 && pOp->p3<=p->nMem );
|
||||
assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) );
|
||||
ctx.pMem = pMem = &aMem[pOp->p3];
|
||||
pMem->n++;
|
||||
ctx.s.flags = MEM_Null;
|
||||
@@ -5451,7 +5437,7 @@ case OP_AggStep: {
|
||||
ctx.isError = 0;
|
||||
ctx.pColl = 0;
|
||||
ctx.skipFlag = 0;
|
||||
if( ctx.pFunc->flags & SQLITE_FUNC_NEEDCOLL ){
|
||||
if( ctx.pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL ){
|
||||
assert( pOp>p->aOp );
|
||||
assert( pOp[-1].p4type==P4_COLLSEQ );
|
||||
assert( pOp[-1].opcode==OP_CollSeq );
|
||||
@@ -5487,7 +5473,7 @@ case OP_AggStep: {
|
||||
*/
|
||||
case OP_AggFinal: {
|
||||
Mem *pMem;
|
||||
assert( pOp->p1>0 && pOp->p1<=p->nMem );
|
||||
assert( pOp->p1>0 && pOp->p1<=(p->nMem-p->nCursor) );
|
||||
pMem = &aMem[pOp->p1];
|
||||
assert( (pMem->flags & ~(MEM_Null|MEM_Agg))==0 );
|
||||
rc = sqlite3VdbeMemFinalize(pMem, pOp->p4.pFunc);
|
||||
@@ -5745,7 +5731,7 @@ case OP_VBegin: {
|
||||
VTable *pVTab;
|
||||
pVTab = pOp->p4.pVtab;
|
||||
rc = sqlite3VtabBegin(db, pVTab);
|
||||
if( pVTab ) importVtabErrMsg(p, pVTab->pVtab);
|
||||
if( pVTab ) sqlite3VtabImportErrmsg(p, pVTab->pVtab);
|
||||
break;
|
||||
}
|
||||
#endif /* SQLITE_OMIT_VIRTUALTABLE */
|
||||
@@ -5796,7 +5782,7 @@ case OP_VOpen: {
|
||||
pModule = (sqlite3_module *)pVtab->pModule;
|
||||
assert(pVtab && pModule);
|
||||
rc = pModule->xOpen(pVtab, &pVtabCursor);
|
||||
importVtabErrMsg(p, pVtab);
|
||||
sqlite3VtabImportErrmsg(p, pVtab);
|
||||
if( SQLITE_OK==rc ){
|
||||
/* Initialize sqlite3_vtab_cursor base class */
|
||||
pVtabCursor->pVtab = pVtab;
|
||||
@@ -5874,7 +5860,7 @@ case OP_VFilter: { /* jump */
|
||||
p->inVtabMethod = 1;
|
||||
rc = pModule->xFilter(pVtabCursor, iQuery, pOp->p4.z, nArg, apArg);
|
||||
p->inVtabMethod = 0;
|
||||
importVtabErrMsg(p, pVtab);
|
||||
sqlite3VtabImportErrmsg(p, pVtab);
|
||||
if( rc==SQLITE_OK ){
|
||||
res = pModule->xEof(pVtabCursor);
|
||||
}
|
||||
@@ -5904,7 +5890,7 @@ case OP_VColumn: {
|
||||
|
||||
VdbeCursor *pCur = p->apCsr[pOp->p1];
|
||||
assert( pCur->pVtabCursor );
|
||||
assert( pOp->p3>0 && pOp->p3<=p->nMem );
|
||||
assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) );
|
||||
pDest = &aMem[pOp->p3];
|
||||
memAboutToChange(p, pDest);
|
||||
if( pCur->nullRow ){
|
||||
@@ -5925,7 +5911,7 @@ case OP_VColumn: {
|
||||
MemSetTypeFlag(&sContext.s, MEM_Null);
|
||||
|
||||
rc = pModule->xColumn(pCur->pVtabCursor, &sContext, pOp->p2);
|
||||
importVtabErrMsg(p, pVtab);
|
||||
sqlite3VtabImportErrmsg(p, pVtab);
|
||||
if( sContext.isError ){
|
||||
rc = sContext.isError;
|
||||
}
|
||||
@@ -5978,7 +5964,7 @@ case OP_VNext: { /* jump */
|
||||
p->inVtabMethod = 1;
|
||||
rc = pModule->xNext(pCur->pVtabCursor);
|
||||
p->inVtabMethod = 0;
|
||||
importVtabErrMsg(p, pVtab);
|
||||
sqlite3VtabImportErrmsg(p, pVtab);
|
||||
if( rc==SQLITE_OK ){
|
||||
res = pModule->xEof(pCur->pVtabCursor);
|
||||
}
|
||||
@@ -6015,7 +6001,7 @@ case OP_VRename: {
|
||||
rc = sqlite3VdbeChangeEncoding(pName, SQLITE_UTF8);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = pVtab->pModule->xRename(pVtab, pName->z);
|
||||
importVtabErrMsg(p, pVtab);
|
||||
sqlite3VtabImportErrmsg(p, pVtab);
|
||||
p->expired = 0;
|
||||
}
|
||||
break;
|
||||
@@ -6077,7 +6063,7 @@ case OP_VUpdate: {
|
||||
db->vtabOnConflict = pOp->p5;
|
||||
rc = pModule->xUpdate(pVtab, nArg, apArg, &rowid);
|
||||
db->vtabOnConflict = vtabOnConflict;
|
||||
importVtabErrMsg(p, pVtab);
|
||||
sqlite3VtabImportErrmsg(p, pVtab);
|
||||
if( rc==SQLITE_OK && pOp->p1 ){
|
||||
assert( nArg>1 && apArg[0] && (apArg[0]->flags&MEM_Null) );
|
||||
db->lastRowid = lastRowid = rowid;
|
||||
@@ -6242,7 +6228,8 @@ vdbe_error_halt:
|
||||
** top. */
|
||||
vdbe_return:
|
||||
db->lastRowid = lastRowid;
|
||||
p->aCounter[SQLITE_STMTSTATUS_VM_STEP-1] += (int)nVmStep;
|
||||
testcase( nVmStep>0 );
|
||||
p->aCounter[SQLITE_STMTSTATUS_VM_STEP] += (int)nVmStep;
|
||||
sqlite3VdbeLeave(p);
|
||||
return rc;
|
||||
|
||||
|
||||
+5
-4
@@ -266,10 +266,11 @@ struct sqlite3_context {
|
||||
Mem s; /* The return value is stored here */
|
||||
Mem *pMem; /* Memory cell used to store aggregate context */
|
||||
CollSeq *pColl; /* Collating sequence */
|
||||
int isError; /* Error code returned by the function. */
|
||||
int skipFlag; /* Skip skip accumulator loading if true */
|
||||
int iOp; /* Instruction number of OP_Function */
|
||||
Vdbe *pVdbe; /* The VM that owns this context */
|
||||
int iOp; /* Instruction number of OP_Function */
|
||||
int isError; /* Error code returned by the function. */
|
||||
u8 skipFlag; /* Skip skip accumulator loading if true */
|
||||
u8 fErrorOrAux; /* isError!=0 or pVdbe->pAuxData modified */
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -345,7 +346,7 @@ struct Vdbe {
|
||||
yDbMask btreeMask; /* Bitmask of db->aDb[] entries referenced */
|
||||
yDbMask lockMask; /* Subset of btreeMask that requires a lock */
|
||||
int iStatement; /* Statement number (or 0 if has not opened stmt) */
|
||||
int aCounter[4]; /* Counters used by sqlite3_stmt_status() */
|
||||
u32 aCounter[5]; /* Counters used by sqlite3_stmt_status() */
|
||||
#ifndef SQLITE_OMIT_TRACE
|
||||
i64 startTime; /* Time when query started - used for profiling */
|
||||
#endif
|
||||
|
||||
+12
-3
@@ -211,12 +211,14 @@ void sqlite3_result_double(sqlite3_context *pCtx, double rVal){
|
||||
void sqlite3_result_error(sqlite3_context *pCtx, const char *z, int n){
|
||||
assert( sqlite3_mutex_held(pCtx->s.db->mutex) );
|
||||
pCtx->isError = SQLITE_ERROR;
|
||||
pCtx->fErrorOrAux = 1;
|
||||
sqlite3VdbeMemSetStr(&pCtx->s, z, n, SQLITE_UTF8, SQLITE_TRANSIENT);
|
||||
}
|
||||
#ifndef SQLITE_OMIT_UTF16
|
||||
void sqlite3_result_error16(sqlite3_context *pCtx, const void *z, int n){
|
||||
assert( sqlite3_mutex_held(pCtx->s.db->mutex) );
|
||||
pCtx->isError = SQLITE_ERROR;
|
||||
pCtx->fErrorOrAux = 1;
|
||||
sqlite3VdbeMemSetStr(&pCtx->s, z, n, SQLITE_UTF16NATIVE, SQLITE_TRANSIENT);
|
||||
}
|
||||
#endif
|
||||
@@ -280,6 +282,7 @@ void sqlite3_result_zeroblob(sqlite3_context *pCtx, int n){
|
||||
}
|
||||
void sqlite3_result_error_code(sqlite3_context *pCtx, int errCode){
|
||||
pCtx->isError = errCode;
|
||||
pCtx->fErrorOrAux = 1;
|
||||
if( pCtx->s.flags & MEM_Null ){
|
||||
sqlite3VdbeMemSetStr(&pCtx->s, sqlite3ErrStr(errCode), -1,
|
||||
SQLITE_UTF8, SQLITE_STATIC);
|
||||
@@ -290,6 +293,7 @@ void sqlite3_result_error_code(sqlite3_context *pCtx, int errCode){
|
||||
void sqlite3_result_error_toobig(sqlite3_context *pCtx){
|
||||
assert( sqlite3_mutex_held(pCtx->s.db->mutex) );
|
||||
pCtx->isError = SQLITE_TOOBIG;
|
||||
pCtx->fErrorOrAux = 1;
|
||||
sqlite3VdbeMemSetStr(&pCtx->s, "string or blob too big", -1,
|
||||
SQLITE_UTF8, SQLITE_STATIC);
|
||||
}
|
||||
@@ -299,6 +303,7 @@ void sqlite3_result_error_nomem(sqlite3_context *pCtx){
|
||||
assert( sqlite3_mutex_held(pCtx->s.db->mutex) );
|
||||
sqlite3VdbeMemSetNull(&pCtx->s);
|
||||
pCtx->isError = SQLITE_NOMEM;
|
||||
pCtx->fErrorOrAux = 1;
|
||||
pCtx->s.db->mallocFailed = 1;
|
||||
}
|
||||
|
||||
@@ -621,6 +626,10 @@ void sqlite3_set_auxdata(
|
||||
pAuxData->iArg = iArg;
|
||||
pAuxData->pNext = pVdbe->pAuxData;
|
||||
pVdbe->pAuxData = pAuxData;
|
||||
if( pCtx->fErrorOrAux==0 ){
|
||||
pCtx->isError = 0;
|
||||
pCtx->fErrorOrAux = 1;
|
||||
}
|
||||
}else if( pAuxData->xDelete ){
|
||||
pAuxData->xDelete(pAuxData->pAux);
|
||||
}
|
||||
@@ -1289,7 +1298,7 @@ sqlite3_stmt *sqlite3_next_stmt(sqlite3 *pDb, sqlite3_stmt *pStmt){
|
||||
*/
|
||||
int sqlite3_stmt_status(sqlite3_stmt *pStmt, int op, int resetFlag){
|
||||
Vdbe *pVdbe = (Vdbe*)pStmt;
|
||||
int v = pVdbe->aCounter[op-1];
|
||||
if( resetFlag ) pVdbe->aCounter[op-1] = 0;
|
||||
return v;
|
||||
u32 v = pVdbe->aCounter[op];
|
||||
if( resetFlag ) pVdbe->aCounter[op] = 0;
|
||||
return (int)v;
|
||||
}
|
||||
|
||||
+17
-2
@@ -604,7 +604,7 @@ void sqlite3VdbeJumpHere(Vdbe *p, int addr){
|
||||
** the FuncDef is not ephermal, then do nothing.
|
||||
*/
|
||||
static void freeEphemeralFunction(sqlite3 *db, FuncDef *pDef){
|
||||
if( ALWAYS(pDef) && (pDef->flags & SQLITE_FUNC_EPHEM)!=0 ){
|
||||
if( ALWAYS(pDef) && (pDef->funcFlags & SQLITE_FUNC_EPHEM)!=0 ){
|
||||
sqlite3DbFree(db, pDef);
|
||||
}
|
||||
}
|
||||
@@ -1765,7 +1765,7 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
|
||||
** required, as an xSync() callback may add an attached database
|
||||
** to the transaction.
|
||||
*/
|
||||
rc = sqlite3VtabSync(db, &p->zErrMsg);
|
||||
rc = sqlite3VtabSync(db, p);
|
||||
|
||||
/* This loop determines (a) if the commit hook should be invoked and
|
||||
** (b) how many database files have open write transactions, not
|
||||
@@ -3304,3 +3304,18 @@ void sqlite3VdbeSetVarmask(Vdbe *v, int iVar){
|
||||
v->expmask |= ((u32)1 << (iVar-1));
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
/*
|
||||
** Transfer error message text from an sqlite3_vtab.zErrMsg (text stored
|
||||
** in memory obtained from sqlite3_malloc) into a Vdbe.zErrMsg (text stored
|
||||
** in memory obtained from sqlite3DbMalloc).
|
||||
*/
|
||||
void sqlite3VtabImportErrmsg(Vdbe *p, sqlite3_vtab *pVtab){
|
||||
sqlite3 *db = p->db;
|
||||
sqlite3DbFree(db, p->zErrMsg);
|
||||
p->zErrMsg = sqlite3DbStrDup(db, pVtab->zErrMsg);
|
||||
sqlite3_free(pVtab->zErrMsg);
|
||||
pVtab->zErrMsg = 0;
|
||||
}
|
||||
#endif /* SQLITE_OMIT_VIRTUALTABLE */
|
||||
|
||||
+298
-49
@@ -799,34 +799,29 @@ int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const CollSeq *pColl){
|
||||
** if both values are integers.
|
||||
*/
|
||||
if( combined_flags&(MEM_Int|MEM_Real) ){
|
||||
if( !(f1&(MEM_Int|MEM_Real)) ){
|
||||
return 1;
|
||||
}
|
||||
if( !(f2&(MEM_Int|MEM_Real)) ){
|
||||
return -1;
|
||||
}
|
||||
if( (f1 & f2 & MEM_Int)==0 ){
|
||||
double r1, r2;
|
||||
if( (f1&MEM_Real)==0 ){
|
||||
r1 = (double)pMem1->u.i;
|
||||
}else{
|
||||
r1 = pMem1->r;
|
||||
}
|
||||
if( (f2&MEM_Real)==0 ){
|
||||
r2 = (double)pMem2->u.i;
|
||||
}else{
|
||||
r2 = pMem2->r;
|
||||
}
|
||||
if( r1<r2 ) return -1;
|
||||
if( r1>r2 ) return 1;
|
||||
return 0;
|
||||
}else{
|
||||
assert( f1&MEM_Int );
|
||||
assert( f2&MEM_Int );
|
||||
double r1, r2;
|
||||
if( (f1 & f2 & MEM_Int)!=0 ){
|
||||
if( pMem1->u.i < pMem2->u.i ) return -1;
|
||||
if( pMem1->u.i > pMem2->u.i ) return 1;
|
||||
return 0;
|
||||
}
|
||||
if( (f1&MEM_Real)!=0 ){
|
||||
r1 = pMem1->r;
|
||||
}else if( (f1&MEM_Int)!=0 ){
|
||||
r1 = (double)pMem1->u.i;
|
||||
}else{
|
||||
return 1;
|
||||
}
|
||||
if( (f2&MEM_Real)!=0 ){
|
||||
r2 = pMem2->r;
|
||||
}else if( (f2&MEM_Int)!=0 ){
|
||||
r2 = (double)pMem2->u.i;
|
||||
}else{
|
||||
return -1;
|
||||
}
|
||||
if( r1<r2 ) return -1;
|
||||
if( r1>r2 ) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If one value is a string and the other is a blob, the string is less.
|
||||
@@ -1006,27 +1001,92 @@ sqlite3_value *sqlite3ValueNew(sqlite3 *db){
|
||||
}
|
||||
|
||||
/*
|
||||
** Create a new sqlite3_value object, containing the value of pExpr.
|
||||
**
|
||||
** This only works for very simple expressions that consist of one constant
|
||||
** token (i.e. "5", "5.1", "'a string'"). If the expression can
|
||||
** be converted directly into a value, then the value is allocated and
|
||||
** a pointer written to *ppVal. The caller is responsible for deallocating
|
||||
** the value by passing it to sqlite3ValueFree() later on. If the expression
|
||||
** cannot be converted to a value, then *ppVal is set to NULL.
|
||||
** Context object passed by sqlite3Stat4ProbeSetValue() through to
|
||||
** valueNew(). See comments above valueNew() for details.
|
||||
*/
|
||||
int sqlite3ValueFromExpr(
|
||||
sqlite3 *db, /* The database connection */
|
||||
Expr *pExpr, /* The expression to evaluate */
|
||||
u8 enc, /* Encoding to use */
|
||||
u8 affinity, /* Affinity to use */
|
||||
sqlite3_value **ppVal /* Write the new value here */
|
||||
struct ValueNewStat4Ctx {
|
||||
Parse *pParse;
|
||||
Index *pIdx;
|
||||
UnpackedRecord **ppRec;
|
||||
int iVal;
|
||||
};
|
||||
|
||||
/*
|
||||
** Allocate and return a pointer to a new sqlite3_value object. If
|
||||
** the second argument to this function is NULL, the object is allocated
|
||||
** by calling sqlite3ValueNew().
|
||||
**
|
||||
** Otherwise, if the second argument is non-zero, then this function is
|
||||
** being called indirectly by sqlite3Stat4ProbeSetValue(). If it has not
|
||||
** already been allocated, allocate the UnpackedRecord structure that
|
||||
** that function will return to its caller here. Then return a pointer
|
||||
** an sqlite3_value within the UnpackedRecord.a[] array.
|
||||
*/
|
||||
static sqlite3_value *valueNew(sqlite3 *db, struct ValueNewStat4Ctx *p){
|
||||
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
if( p ){
|
||||
UnpackedRecord *pRec = p->ppRec[0];
|
||||
|
||||
if( pRec==0 ){
|
||||
Index *pIdx = p->pIdx; /* Index being probed */
|
||||
int nByte; /* Bytes of space to allocate */
|
||||
int i; /* Counter variable */
|
||||
int nCol = pIdx->nColumn+1; /* Number of index columns including rowid */
|
||||
|
||||
nByte = sizeof(Mem) * nCol + sizeof(UnpackedRecord);
|
||||
pRec = (UnpackedRecord*)sqlite3DbMallocZero(db, nByte);
|
||||
if( pRec ){
|
||||
pRec->pKeyInfo = sqlite3IndexKeyinfo(p->pParse, pIdx);
|
||||
if( pRec->pKeyInfo ){
|
||||
assert( pRec->pKeyInfo->nField+1==nCol );
|
||||
pRec->pKeyInfo->enc = ENC(db);
|
||||
pRec->flags = UNPACKED_PREFIX_MATCH;
|
||||
pRec->aMem = (Mem *)&pRec[1];
|
||||
for(i=0; i<nCol; i++){
|
||||
pRec->aMem[i].flags = MEM_Null;
|
||||
pRec->aMem[i].type = SQLITE_NULL;
|
||||
pRec->aMem[i].db = db;
|
||||
}
|
||||
}else{
|
||||
sqlite3DbFree(db, pRec);
|
||||
pRec = 0;
|
||||
}
|
||||
}
|
||||
if( pRec==0 ) return 0;
|
||||
p->ppRec[0] = pRec;
|
||||
}
|
||||
|
||||
pRec->nField = p->iVal+1;
|
||||
return &pRec->aMem[p->iVal];
|
||||
}
|
||||
#endif
|
||||
return sqlite3ValueNew(db);
|
||||
}
|
||||
|
||||
/*
|
||||
** Extract a value from the supplied expression in the manner described
|
||||
** above sqlite3ValueFromExpr(). Allocate the sqlite3_value object
|
||||
** using valueNew().
|
||||
**
|
||||
** If pCtx is NULL and an error occurs after the sqlite3_value object
|
||||
** has been allocated, it is freed before returning. Or, if pCtx is not
|
||||
** NULL, it is assumed that the caller will free any allocated object
|
||||
** in all cases.
|
||||
*/
|
||||
int valueFromExpr(
|
||||
sqlite3 *db, /* The database connection */
|
||||
Expr *pExpr, /* The expression to evaluate */
|
||||
u8 enc, /* Encoding to use */
|
||||
u8 affinity, /* Affinity to use */
|
||||
sqlite3_value **ppVal, /* Write the new value here */
|
||||
struct ValueNewStat4Ctx *pCtx /* Second argument for valueNew() */
|
||||
){
|
||||
int op;
|
||||
char *zVal = 0;
|
||||
sqlite3_value *pVal = 0;
|
||||
int negInt = 1;
|
||||
const char *zNeg = "";
|
||||
int rc = SQLITE_OK;
|
||||
|
||||
if( !pExpr ){
|
||||
*ppVal = 0;
|
||||
@@ -1034,11 +1094,11 @@ int sqlite3ValueFromExpr(
|
||||
}
|
||||
op = pExpr->op;
|
||||
|
||||
/* op can only be TK_REGISTER if we have compiled with SQLITE_ENABLE_STAT3.
|
||||
/* op can only be TK_REGISTER if we have compiled with SQLITE_ENABLE_STAT4.
|
||||
** The ifdef here is to enable us to achieve 100% branch test coverage even
|
||||
** when SQLITE_ENABLE_STAT3 is omitted.
|
||||
** when SQLITE_ENABLE_STAT4 is omitted.
|
||||
*/
|
||||
#ifdef SQLITE_ENABLE_STAT3
|
||||
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
if( op==TK_REGISTER ) op = pExpr->op2;
|
||||
#else
|
||||
if( NEVER(op==TK_REGISTER) ) op = pExpr->op2;
|
||||
@@ -1056,7 +1116,7 @@ int sqlite3ValueFromExpr(
|
||||
}
|
||||
|
||||
if( op==TK_STRING || op==TK_FLOAT || op==TK_INTEGER ){
|
||||
pVal = sqlite3ValueNew(db);
|
||||
pVal = valueNew(db, pCtx);
|
||||
if( pVal==0 ) goto no_mem;
|
||||
if( ExprHasProperty(pExpr, EP_IntValue) ){
|
||||
sqlite3VdbeMemSetInt64(pVal, (i64)pExpr->u.iValue*negInt);
|
||||
@@ -1073,11 +1133,13 @@ int sqlite3ValueFromExpr(
|
||||
}
|
||||
if( pVal->flags & (MEM_Int|MEM_Real) ) pVal->flags &= ~MEM_Str;
|
||||
if( enc!=SQLITE_UTF8 ){
|
||||
sqlite3VdbeChangeEncoding(pVal, enc);
|
||||
rc = sqlite3VdbeChangeEncoding(pVal, enc);
|
||||
}
|
||||
}else if( op==TK_UMINUS ) {
|
||||
/* This branch happens for multiple negative signs. Ex: -(-5) */
|
||||
if( SQLITE_OK==sqlite3ValueFromExpr(db,pExpr->pLeft,enc,affinity,&pVal) ){
|
||||
if( SQLITE_OK==sqlite3ValueFromExpr(db,pExpr->pLeft,enc,affinity,&pVal)
|
||||
&& pVal!=0
|
||||
){
|
||||
sqlite3VdbeMemNumerify(pVal);
|
||||
if( pVal->u.i==SMALLEST_INT64 ){
|
||||
pVal->flags &= MEM_Int;
|
||||
@@ -1090,7 +1152,7 @@ int sqlite3ValueFromExpr(
|
||||
sqlite3ValueApplyAffinity(pVal, affinity, enc);
|
||||
}
|
||||
}else if( op==TK_NULL ){
|
||||
pVal = sqlite3ValueNew(db);
|
||||
pVal = valueNew(db, pCtx);
|
||||
if( pVal==0 ) goto no_mem;
|
||||
}
|
||||
#ifndef SQLITE_OMIT_BLOB_LITERAL
|
||||
@@ -1098,7 +1160,7 @@ int sqlite3ValueFromExpr(
|
||||
int nVal;
|
||||
assert( pExpr->u.zToken[0]=='x' || pExpr->u.zToken[0]=='X' );
|
||||
assert( pExpr->u.zToken[1]=='\'' );
|
||||
pVal = sqlite3ValueNew(db);
|
||||
pVal = valueNew(db, pCtx);
|
||||
if( !pVal ) goto no_mem;
|
||||
zVal = &pExpr->u.zToken[2];
|
||||
nVal = sqlite3Strlen30(zVal)-1;
|
||||
@@ -1112,16 +1174,203 @@ int sqlite3ValueFromExpr(
|
||||
sqlite3VdbeMemStoreType(pVal);
|
||||
}
|
||||
*ppVal = pVal;
|
||||
return SQLITE_OK;
|
||||
return rc;
|
||||
|
||||
no_mem:
|
||||
db->mallocFailed = 1;
|
||||
sqlite3DbFree(db, zVal);
|
||||
sqlite3ValueFree(pVal);
|
||||
*ppVal = 0;
|
||||
assert( *ppVal==0 );
|
||||
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
if( pCtx==0 ) sqlite3ValueFree(pVal);
|
||||
#else
|
||||
assert( pCtx==0 ); sqlite3ValueFree(pVal);
|
||||
#endif
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
|
||||
/*
|
||||
** Create a new sqlite3_value object, containing the value of pExpr.
|
||||
**
|
||||
** This only works for very simple expressions that consist of one constant
|
||||
** token (i.e. "5", "5.1", "'a string'"). If the expression can
|
||||
** be converted directly into a value, then the value is allocated and
|
||||
** a pointer written to *ppVal. The caller is responsible for deallocating
|
||||
** the value by passing it to sqlite3ValueFree() later on. If the expression
|
||||
** cannot be converted to a value, then *ppVal is set to NULL.
|
||||
*/
|
||||
int sqlite3ValueFromExpr(
|
||||
sqlite3 *db, /* The database connection */
|
||||
Expr *pExpr, /* The expression to evaluate */
|
||||
u8 enc, /* Encoding to use */
|
||||
u8 affinity, /* Affinity to use */
|
||||
sqlite3_value **ppVal /* Write the new value here */
|
||||
){
|
||||
return valueFromExpr(db, pExpr, enc, affinity, ppVal, 0);
|
||||
}
|
||||
|
||||
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
/*
|
||||
** The implementation of the sqlite_record() function. This function accepts
|
||||
** a single argument of any type. The return value is a formatted database
|
||||
** record (a blob) containing the argument value.
|
||||
**
|
||||
** This is used to convert the value stored in the 'sample' column of the
|
||||
** sqlite_stat3 table to the record format SQLite uses internally.
|
||||
*/
|
||||
static void recordFunc(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
const int file_format = 1;
|
||||
int iSerial; /* Serial type */
|
||||
int nSerial; /* Bytes of space for iSerial as varint */
|
||||
int nVal; /* Bytes of space required for argv[0] */
|
||||
int nRet;
|
||||
sqlite3 *db;
|
||||
u8 *aRet;
|
||||
|
||||
iSerial = sqlite3VdbeSerialType(argv[0], file_format);
|
||||
nSerial = sqlite3VarintLen(iSerial);
|
||||
nVal = sqlite3VdbeSerialTypeLen(iSerial);
|
||||
db = sqlite3_context_db_handle(context);
|
||||
|
||||
nRet = 1 + nSerial + nVal;
|
||||
aRet = sqlite3DbMallocRaw(db, nRet);
|
||||
if( aRet==0 ){
|
||||
sqlite3_result_error_nomem(context);
|
||||
}else{
|
||||
aRet[0] = nSerial+1;
|
||||
sqlite3PutVarint(&aRet[1], iSerial);
|
||||
sqlite3VdbeSerialPut(&aRet[1+nSerial], nVal, argv[0], file_format);
|
||||
sqlite3_result_blob(context, aRet, nRet, SQLITE_TRANSIENT);
|
||||
sqlite3DbFree(db, aRet);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Register built-in functions used to help read ANALYZE data.
|
||||
*/
|
||||
void sqlite3AnalyzeFunctions(void){
|
||||
static SQLITE_WSD FuncDef aAnalyzeTableFuncs[] = {
|
||||
FUNCTION(sqlite_record, 1, 0, 0, recordFunc),
|
||||
};
|
||||
int i;
|
||||
FuncDefHash *pHash = &GLOBAL(FuncDefHash, sqlite3GlobalFunctions);
|
||||
FuncDef *aFunc = (FuncDef*)&GLOBAL(FuncDef, aAnalyzeTableFuncs);
|
||||
for(i=0; i<ArraySize(aAnalyzeTableFuncs); i++){
|
||||
sqlite3FuncDefInsert(pHash, &aFunc[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** This function is used to allocate and populate UnpackedRecord
|
||||
** structures intended to be compared against sample index keys stored
|
||||
** in the sqlite_stat4 table.
|
||||
**
|
||||
** A single call to this function attempts to populates field iVal (leftmost
|
||||
** is 0 etc.) of the unpacked record with a value extracted from expression
|
||||
** pExpr. Extraction of values is possible if:
|
||||
**
|
||||
** * (pExpr==0). In this case the value is assumed to be an SQL NULL,
|
||||
**
|
||||
** * The expression is a bound variable, and this is a reprepare, or
|
||||
**
|
||||
** * The sqlite3ValueFromExpr() function is able to extract a value
|
||||
** from the expression (i.e. the expression is a literal value).
|
||||
**
|
||||
** If a value can be extracted, the affinity passed as the 5th argument
|
||||
** is applied to it before it is copied into the UnpackedRecord. Output
|
||||
** parameter *pbOk is set to true if a value is extracted, or false
|
||||
** otherwise.
|
||||
**
|
||||
** When this function is called, *ppRec must either point to an object
|
||||
** allocated by an earlier call to this function, or must be NULL. If it
|
||||
** is NULL and a value can be successfully extracted, a new UnpackedRecord
|
||||
** is allocated (and *ppRec set to point to it) before returning.
|
||||
**
|
||||
** Unless an error is encountered, SQLITE_OK is returned. It is not an
|
||||
** error if a value cannot be extracted from pExpr. If an error does
|
||||
** occur, an SQLite error code is returned.
|
||||
*/
|
||||
int sqlite3Stat4ProbeSetValue(
|
||||
Parse *pParse, /* Parse context */
|
||||
Index *pIdx, /* Index being probed */
|
||||
UnpackedRecord **ppRec, /* IN/OUT: Probe record */
|
||||
Expr *pExpr, /* The expression to extract a value from */
|
||||
u8 affinity, /* Affinity to use */
|
||||
int iVal, /* Array element to populate */
|
||||
int *pbOk /* OUT: True if value was extracted */
|
||||
){
|
||||
int rc = SQLITE_OK;
|
||||
sqlite3_value *pVal = 0;
|
||||
sqlite3 *db = pParse->db;
|
||||
|
||||
|
||||
struct ValueNewStat4Ctx alloc;
|
||||
alloc.pParse = pParse;
|
||||
alloc.pIdx = pIdx;
|
||||
alloc.ppRec = ppRec;
|
||||
alloc.iVal = iVal;
|
||||
|
||||
/* Skip over any TK_COLLATE nodes */
|
||||
pExpr = sqlite3ExprSkipCollate(pExpr);
|
||||
|
||||
if( !pExpr ){
|
||||
pVal = valueNew(db, &alloc);
|
||||
if( pVal ){
|
||||
sqlite3VdbeMemSetNull((Mem*)pVal);
|
||||
*pbOk = 1;
|
||||
}
|
||||
}else if( pExpr->op==TK_VARIABLE
|
||||
|| (pExpr->op==TK_REGISTER && pExpr->op2==TK_VARIABLE)
|
||||
){
|
||||
Vdbe *v;
|
||||
int iBindVar = pExpr->iColumn;
|
||||
sqlite3VdbeSetVarmask(pParse->pVdbe, iBindVar);
|
||||
if( (v = pParse->pReprepare)!=0 ){
|
||||
pVal = valueNew(db, &alloc);
|
||||
if( pVal ){
|
||||
rc = sqlite3VdbeMemCopy((Mem*)pVal, &v->aVar[iBindVar-1]);
|
||||
if( rc==SQLITE_OK ){
|
||||
sqlite3ValueApplyAffinity(pVal, affinity, ENC(db));
|
||||
}
|
||||
pVal->db = pParse->db;
|
||||
*pbOk = 1;
|
||||
sqlite3VdbeMemStoreType((Mem*)pVal);
|
||||
}
|
||||
}else{
|
||||
*pbOk = 0;
|
||||
}
|
||||
}else{
|
||||
rc = valueFromExpr(db, pExpr, ENC(db), affinity, &pVal, &alloc);
|
||||
*pbOk = (pVal!=0);
|
||||
}
|
||||
|
||||
assert( pVal==0 || pVal->db==db );
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Unless it is NULL, the argument must be an UnpackedRecord object returned
|
||||
** by an earlier call to sqlite3Stat4ProbeSetValue(). This call deletes
|
||||
** the object.
|
||||
*/
|
||||
void sqlite3Stat4ProbeFree(UnpackedRecord *pRec){
|
||||
if( pRec ){
|
||||
int i;
|
||||
int nCol = pRec->pKeyInfo->nField+1;
|
||||
Mem *aMem = pRec->aMem;
|
||||
sqlite3 *db = aMem[0].db;
|
||||
for(i=0; i<nCol; i++){
|
||||
sqlite3DbFree(db, aMem[i].zMalloc);
|
||||
}
|
||||
sqlite3DbFree(db, pRec->pKeyInfo);
|
||||
sqlite3DbFree(db, pRec);
|
||||
}
|
||||
}
|
||||
#endif /* ifdef SQLITE_ENABLE_STAT4 */
|
||||
|
||||
/*
|
||||
** Change the string value of an sqlite3_value object
|
||||
*/
|
||||
|
||||
+4
-7
@@ -810,10 +810,9 @@ static void callFinaliser(sqlite3 *db, int offset){
|
||||
** array. Return the error code for the first error that occurs, or
|
||||
** SQLITE_OK if all xSync operations are successful.
|
||||
**
|
||||
** Set *pzErrmsg to point to a buffer that should be released using
|
||||
** sqlite3DbFree() containing an error message, if one is available.
|
||||
** If an error message is available, leave it in p->zErrMsg.
|
||||
*/
|
||||
int sqlite3VtabSync(sqlite3 *db, char **pzErrmsg){
|
||||
int sqlite3VtabSync(sqlite3 *db, Vdbe *p){
|
||||
int i;
|
||||
int rc = SQLITE_OK;
|
||||
VTable **aVTrans = db->aVTrans;
|
||||
@@ -824,9 +823,7 @@ int sqlite3VtabSync(sqlite3 *db, char **pzErrmsg){
|
||||
sqlite3_vtab *pVtab = aVTrans[i]->pVtab;
|
||||
if( pVtab && (x = pVtab->pModule->xSync)!=0 ){
|
||||
rc = x(pVtab);
|
||||
sqlite3DbFree(db, *pzErrmsg);
|
||||
*pzErrmsg = pVtab->zErrMsg;
|
||||
pVtab->zErrMsg = 0;
|
||||
sqlite3VtabImportErrmsg(p, pVtab);
|
||||
}
|
||||
}
|
||||
db->aVTrans = aVTrans;
|
||||
@@ -1016,7 +1013,7 @@ FuncDef *sqlite3VtabOverloadFunction(
|
||||
memcpy(pNew->zName, pDef->zName, sqlite3Strlen30(pDef->zName)+1);
|
||||
pNew->xFunc = xFunc;
|
||||
pNew->pUserData = pArg;
|
||||
pNew->flags |= SQLITE_FUNC_EPHEM;
|
||||
pNew->funcFlags |= SQLITE_FUNC_EPHEM;
|
||||
return pNew;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -43,7 +43,7 @@ int sqlite3WalkExpr(Walker *pWalker, Expr *pExpr){
|
||||
testcase( ExprHasProperty(pExpr, EP_Reduced) );
|
||||
rc = pWalker->xExprCallback(pWalker, pExpr);
|
||||
if( rc==WRC_Continue
|
||||
&& !ExprHasAnyProperty(pExpr,EP_TokenOnly) ){
|
||||
&& !ExprHasProperty(pExpr,EP_TokenOnly) ){
|
||||
if( sqlite3WalkExpr(pWalker, pExpr->pLeft) ) return WRC_Abort;
|
||||
if( sqlite3WalkExpr(pWalker, pExpr->pRight) ) return WRC_Abort;
|
||||
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
|
||||
|
||||
+292
-271
@@ -90,6 +90,7 @@ struct WhereLevel {
|
||||
int addrNxt; /* Jump here to start the next IN combination */
|
||||
int addrCont; /* Jump here to continue with the next loop cycle */
|
||||
int addrFirst; /* First instruction of interior of the loop */
|
||||
int addrBody; /* Beginning of the body of this loop */
|
||||
u8 iFrom; /* Which entry in the FROM clause */
|
||||
u8 op, p5; /* Opcode and P5 of the opcode that ends the loop */
|
||||
int p1, p2; /* Operands of the opcode used to ends the loop */
|
||||
@@ -105,6 +106,7 @@ struct WhereLevel {
|
||||
Index *pCovidx; /* Possible covering index for WHERE_MULTI_OR */
|
||||
} u;
|
||||
struct WhereLoop *pWLoop; /* The selected WhereLoop object */
|
||||
Bitmask notReady; /* FROM entries not usable at this level */
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -184,9 +186,9 @@ static int whereLoopResize(sqlite3*, WhereLoop*, int);
|
||||
** that implement some or all of a query plan.
|
||||
**
|
||||
** Think of each WhereLoop object as a node in a graph with arcs
|
||||
** showing dependences and costs for travelling between nodes. (That is
|
||||
** showing dependencies and costs for travelling between nodes. (That is
|
||||
** not a completely accurate description because WhereLoop costs are a
|
||||
** vector, not a scalar, and because dependences are many-to-one, not
|
||||
** vector, not a scalar, and because dependencies are many-to-one, not
|
||||
** one-to-one as are graph nodes. But it is a useful visualization aid.)
|
||||
** Then a WherePath object is a path through the graph that visits some
|
||||
** or all of the WhereLoop objects once.
|
||||
@@ -285,7 +287,7 @@ struct WhereTerm {
|
||||
#define TERM_ORINFO 0x10 /* Need to free the WhereTerm.u.pOrInfo object */
|
||||
#define TERM_ANDINFO 0x20 /* Need to free the WhereTerm.u.pAndInfo obj */
|
||||
#define TERM_OR_OK 0x40 /* Used during OR-clause processing */
|
||||
#ifdef SQLITE_ENABLE_STAT3
|
||||
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
# define TERM_VNULL 0x80 /* Manufactured x>NULL or x<=NULL term */
|
||||
#else
|
||||
# define TERM_VNULL 0x00 /* Disabled if not using stat3 */
|
||||
@@ -391,6 +393,10 @@ struct WhereLoopBuilder {
|
||||
ExprList *pOrderBy; /* ORDER BY clause */
|
||||
WhereLoop *pNew; /* Template WhereLoop */
|
||||
WhereOrSet *pOrSet; /* Record best loops here, if not NULL */
|
||||
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
UnpackedRecord *pRec; /* Probe for stat4 (if required) */
|
||||
int nRecValid; /* Number of valid fields currently in pRec */
|
||||
#endif
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -1204,8 +1210,10 @@ static int isMatchOfColumn(
|
||||
** a join, then transfer the appropriate markings over to derived.
|
||||
*/
|
||||
static void transferJoinMarkings(Expr *pDerived, Expr *pBase){
|
||||
pDerived->flags |= pBase->flags & EP_FromJoin;
|
||||
pDerived->iRightJoinTable = pBase->iRightJoinTable;
|
||||
if( pDerived ){
|
||||
pDerived->flags |= pBase->flags & EP_FromJoin;
|
||||
pDerived->iRightJoinTable = pBase->iRightJoinTable;
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined(SQLITE_OMIT_OR_OPTIMIZATION) && !defined(SQLITE_OMIT_SUBQUERY)
|
||||
@@ -1662,6 +1670,7 @@ static void exprAnalyze(
|
||||
pNewExpr = sqlite3PExpr(pParse, ops[i],
|
||||
sqlite3ExprDup(db, pExpr->pLeft, 0),
|
||||
sqlite3ExprDup(db, pList->a[i].pExpr, 0), 0);
|
||||
transferJoinMarkings(pNewExpr, pExpr);
|
||||
idxNew = whereClauseInsert(pWC, pNewExpr, TERM_VIRTUAL|TERM_DYNAMIC);
|
||||
testcase( idxNew==0 );
|
||||
exprAnalyze(pSrc, pWC, idxNew);
|
||||
@@ -1729,6 +1738,7 @@ static void exprAnalyze(
|
||||
pNewExpr1 = sqlite3PExpr(pParse, TK_GE,
|
||||
sqlite3ExprAddCollateToken(pParse,pNewExpr1,&sCollSeqName),
|
||||
pStr1, 0);
|
||||
transferJoinMarkings(pNewExpr1, pExpr);
|
||||
idxNew1 = whereClauseInsert(pWC, pNewExpr1, TERM_VIRTUAL|TERM_DYNAMIC);
|
||||
testcase( idxNew1==0 );
|
||||
exprAnalyze(pSrc, pWC, idxNew1);
|
||||
@@ -1736,6 +1746,7 @@ static void exprAnalyze(
|
||||
pNewExpr2 = sqlite3PExpr(pParse, TK_LT,
|
||||
sqlite3ExprAddCollateToken(pParse,pNewExpr2,&sCollSeqName),
|
||||
pStr2, 0);
|
||||
transferJoinMarkings(pNewExpr2, pExpr);
|
||||
idxNew2 = whereClauseInsert(pWC, pNewExpr2, TERM_VIRTUAL|TERM_DYNAMIC);
|
||||
testcase( idxNew2==0 );
|
||||
exprAnalyze(pSrc, pWC, idxNew2);
|
||||
@@ -1785,7 +1796,7 @@ static void exprAnalyze(
|
||||
}
|
||||
#endif /* SQLITE_OMIT_VIRTUALTABLE */
|
||||
|
||||
#ifdef SQLITE_ENABLE_STAT3
|
||||
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
/* When sqlite_stat3 histogram data is available an operator of the
|
||||
** form "x IS NOT NULL" can sometimes be evaluated more efficiently
|
||||
** as "x>NULL" if x is not an INTEGER PRIMARY KEY. So construct a
|
||||
@@ -1825,7 +1836,7 @@ static void exprAnalyze(
|
||||
pNewTerm->prereqAll = pTerm->prereqAll;
|
||||
}
|
||||
}
|
||||
#endif /* SQLITE_ENABLE_STAT */
|
||||
#endif /* SQLITE_ENABLE_STAT3_OR_STAT4 */
|
||||
|
||||
/* Prevent ON clause terms of a LEFT JOIN from being used to drive
|
||||
** an index for tables to the left of the join.
|
||||
@@ -2393,7 +2404,7 @@ static int vtabBestIndex(Parse *pParse, Table *pTab, sqlite3_index_info *p){
|
||||
#endif /* !defined(SQLITE_OMIT_VIRTUALTABLE) */
|
||||
|
||||
|
||||
#ifdef SQLITE_ENABLE_STAT3
|
||||
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
/*
|
||||
** Estimate the location of a particular key among all keys in an
|
||||
** index. Store the results in aStat as follows:
|
||||
@@ -2403,141 +2414,73 @@ static int vtabBestIndex(Parse *pParse, Table *pTab, sqlite3_index_info *p){
|
||||
**
|
||||
** Return SQLITE_OK on success.
|
||||
*/
|
||||
static int whereKeyStats(
|
||||
static void whereKeyStats(
|
||||
Parse *pParse, /* Database connection */
|
||||
Index *pIdx, /* Index to consider domain of */
|
||||
sqlite3_value *pVal, /* Value to consider */
|
||||
UnpackedRecord *pRec, /* Vector of values to consider */
|
||||
int roundUp, /* Round up if true. Round down if false */
|
||||
tRowcnt *aStat /* OUT: stats written here */
|
||||
){
|
||||
tRowcnt n;
|
||||
IndexSample *aSample;
|
||||
int i, eType;
|
||||
int isEq = 0;
|
||||
i64 v;
|
||||
double r, rS;
|
||||
IndexSample *aSample = pIdx->aSample;
|
||||
int iCol; /* Index of required stats in anEq[] etc. */
|
||||
int iMin = 0; /* Smallest sample not yet tested */
|
||||
int i = pIdx->nSample; /* Smallest sample larger than or equal to pRec */
|
||||
int iTest; /* Next sample to test */
|
||||
int res; /* Result of comparison operation */
|
||||
|
||||
assert( roundUp==0 || roundUp==1 );
|
||||
assert( pRec!=0 || pParse->db->mallocFailed );
|
||||
if( pRec==0 ) return;
|
||||
iCol = pRec->nField - 1;
|
||||
assert( pIdx->nSample>0 );
|
||||
if( pVal==0 ) return SQLITE_ERROR;
|
||||
n = pIdx->aiRowEst[0];
|
||||
aSample = pIdx->aSample;
|
||||
eType = sqlite3_value_type(pVal);
|
||||
assert( pRec->nField>0 && iCol<pIdx->nSampleCol );
|
||||
do{
|
||||
iTest = (iMin+i)/2;
|
||||
res = sqlite3VdbeRecordCompare(aSample[iTest].n, aSample[iTest].p, pRec);
|
||||
if( res<0 ){
|
||||
iMin = iTest+1;
|
||||
}else{
|
||||
i = iTest;
|
||||
}
|
||||
}while( res && iMin<i );
|
||||
|
||||
if( eType==SQLITE_INTEGER ){
|
||||
v = sqlite3_value_int64(pVal);
|
||||
r = (i64)v;
|
||||
for(i=0; i<pIdx->nSample; i++){
|
||||
if( aSample[i].eType==SQLITE_NULL ) continue;
|
||||
if( aSample[i].eType>=SQLITE_TEXT ) break;
|
||||
if( aSample[i].eType==SQLITE_INTEGER ){
|
||||
if( aSample[i].u.i>=v ){
|
||||
isEq = aSample[i].u.i==v;
|
||||
break;
|
||||
}
|
||||
}else{
|
||||
assert( aSample[i].eType==SQLITE_FLOAT );
|
||||
if( aSample[i].u.r>=r ){
|
||||
isEq = aSample[i].u.r==r;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}else if( eType==SQLITE_FLOAT ){
|
||||
r = sqlite3_value_double(pVal);
|
||||
for(i=0; i<pIdx->nSample; i++){
|
||||
if( aSample[i].eType==SQLITE_NULL ) continue;
|
||||
if( aSample[i].eType>=SQLITE_TEXT ) break;
|
||||
if( aSample[i].eType==SQLITE_FLOAT ){
|
||||
rS = aSample[i].u.r;
|
||||
}else{
|
||||
rS = aSample[i].u.i;
|
||||
}
|
||||
if( rS>=r ){
|
||||
isEq = rS==r;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}else if( eType==SQLITE_NULL ){
|
||||
i = 0;
|
||||
if( aSample[0].eType==SQLITE_NULL ) isEq = 1;
|
||||
#ifdef SQLITE_DEBUG
|
||||
/* The following assert statements check that the binary search code
|
||||
** above found the right answer. This block serves no purpose other
|
||||
** than to invoke the asserts. */
|
||||
if( res==0 ){
|
||||
/* If (res==0) is true, then sample $i must be equal to pRec */
|
||||
assert( i<pIdx->nSample );
|
||||
assert( 0==sqlite3VdbeRecordCompare(aSample[i].n, aSample[i].p, pRec)
|
||||
|| pParse->db->mallocFailed );
|
||||
}else{
|
||||
assert( eType==SQLITE_TEXT || eType==SQLITE_BLOB );
|
||||
for(i=0; i<pIdx->nSample; i++){
|
||||
if( aSample[i].eType==SQLITE_TEXT || aSample[i].eType==SQLITE_BLOB ){
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( i<pIdx->nSample ){
|
||||
sqlite3 *db = pParse->db;
|
||||
CollSeq *pColl;
|
||||
const u8 *z;
|
||||
if( eType==SQLITE_BLOB ){
|
||||
z = (const u8 *)sqlite3_value_blob(pVal);
|
||||
pColl = db->pDfltColl;
|
||||
assert( pColl->enc==SQLITE_UTF8 );
|
||||
}else{
|
||||
pColl = sqlite3GetCollSeq(pParse, SQLITE_UTF8, 0, *pIdx->azColl);
|
||||
/* If the collating sequence was unavailable, we should have failed
|
||||
** long ago and never reached this point. But we'll check just to
|
||||
** be doubly sure. */
|
||||
if( NEVER(pColl==0) ) return SQLITE_ERROR;
|
||||
z = (const u8 *)sqlite3ValueText(pVal, pColl->enc);
|
||||
if( !z ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
assert( z && pColl && pColl->xCmp );
|
||||
}
|
||||
n = sqlite3ValueBytes(pVal, pColl->enc);
|
||||
|
||||
for(; i<pIdx->nSample; i++){
|
||||
int c;
|
||||
int eSampletype = aSample[i].eType;
|
||||
if( eSampletype<eType ) continue;
|
||||
if( eSampletype!=eType ) break;
|
||||
#ifndef SQLITE_OMIT_UTF16
|
||||
if( pColl->enc!=SQLITE_UTF8 ){
|
||||
int nSample;
|
||||
char *zSample = sqlite3Utf8to16(
|
||||
db, pColl->enc, aSample[i].u.z, aSample[i].nByte, &nSample
|
||||
);
|
||||
if( !zSample ){
|
||||
assert( db->mallocFailed );
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
c = pColl->xCmp(pColl->pUser, nSample, zSample, n, z);
|
||||
sqlite3DbFree(db, zSample);
|
||||
}else
|
||||
#endif
|
||||
{
|
||||
c = pColl->xCmp(pColl->pUser, aSample[i].nByte, aSample[i].u.z, n, z);
|
||||
}
|
||||
if( c>=0 ){
|
||||
if( c==0 ) isEq = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Otherwise, pRec must be smaller than sample $i and larger than
|
||||
** sample ($i-1). */
|
||||
assert( i==pIdx->nSample
|
||||
|| sqlite3VdbeRecordCompare(aSample[i].n, aSample[i].p, pRec)>0
|
||||
|| pParse->db->mallocFailed );
|
||||
assert( i==0
|
||||
|| sqlite3VdbeRecordCompare(aSample[i-1].n, aSample[i-1].p, pRec)<0
|
||||
|| pParse->db->mallocFailed );
|
||||
}
|
||||
#endif /* ifdef SQLITE_DEBUG */
|
||||
|
||||
/* At this point, aSample[i] is the first sample that is greater than
|
||||
** or equal to pVal. Or if i==pIdx->nSample, then all samples are less
|
||||
** than pVal. If aSample[i]==pVal, then isEq==1.
|
||||
** than pVal. If aSample[i]==pVal, then res==0.
|
||||
*/
|
||||
if( isEq ){
|
||||
assert( i<pIdx->nSample );
|
||||
aStat[0] = aSample[i].nLt;
|
||||
aStat[1] = aSample[i].nEq;
|
||||
if( res==0 ){
|
||||
aStat[0] = aSample[i].anLt[iCol];
|
||||
aStat[1] = aSample[i].anEq[iCol];
|
||||
}else{
|
||||
tRowcnt iLower, iUpper, iGap;
|
||||
if( i==0 ){
|
||||
iLower = 0;
|
||||
iUpper = aSample[0].nLt;
|
||||
iUpper = aSample[0].anLt[iCol];
|
||||
}else{
|
||||
iUpper = i>=pIdx->nSample ? n : aSample[i].nLt;
|
||||
iLower = aSample[i-1].nEq + aSample[i-1].nLt;
|
||||
iUpper = i>=pIdx->nSample ? pIdx->aiRowEst[0] : aSample[i].anLt[iCol];
|
||||
iLower = aSample[i-1].anEq[iCol] + aSample[i-1].anLt[iCol];
|
||||
}
|
||||
aStat[1] = pIdx->avgEq;
|
||||
aStat[1] = (pIdx->nColumn>iCol ? pIdx->aAvgEq[iCol] : 1);
|
||||
if( iLower>=iUpper ){
|
||||
iGap = 0;
|
||||
}else{
|
||||
@@ -2550,44 +2493,8 @@ static int whereKeyStats(
|
||||
}
|
||||
aStat[0] = iLower + iGap;
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
#endif /* SQLITE_ENABLE_STAT3 */
|
||||
|
||||
/*
|
||||
** If expression pExpr represents a literal value, set *pp to point to
|
||||
** an sqlite3_value structure containing the same value, with affinity
|
||||
** aff applied to it, before returning. It is the responsibility of the
|
||||
** caller to eventually release this structure by passing it to
|
||||
** sqlite3ValueFree().
|
||||
**
|
||||
** If the current parse is a recompile (sqlite3Reprepare()) and pExpr
|
||||
** is an SQL variable that currently has a non-NULL value bound to it,
|
||||
** create an sqlite3_value structure containing this value, again with
|
||||
** affinity aff applied to it, instead.
|
||||
**
|
||||
** If neither of the above apply, set *pp to NULL.
|
||||
**
|
||||
** If an error occurs, return an error code. Otherwise, SQLITE_OK.
|
||||
*/
|
||||
#ifdef SQLITE_ENABLE_STAT3
|
||||
static int valueFromExpr(
|
||||
Parse *pParse,
|
||||
Expr *pExpr,
|
||||
u8 aff,
|
||||
sqlite3_value **pp
|
||||
){
|
||||
if( pExpr->op==TK_VARIABLE
|
||||
|| (pExpr->op==TK_REGISTER && pExpr->op2==TK_VARIABLE)
|
||||
){
|
||||
int iVar = pExpr->iColumn;
|
||||
sqlite3VdbeSetVarmask(pParse->pVdbe, iVar);
|
||||
*pp = sqlite3VdbeGetBoundValue(pParse->pReprepare, iVar, aff);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
return sqlite3ValueFromExpr(pParse->db, pExpr, SQLITE_UTF8, aff, pp);
|
||||
}
|
||||
#endif
|
||||
#endif /* SQLITE_ENABLE_STAT3_OR_STAT4 */
|
||||
|
||||
/*
|
||||
** This function is used to estimate the number of rows that will be visited
|
||||
@@ -2604,103 +2511,155 @@ static int valueFromExpr(
|
||||
** If either of the upper or lower bound is not present, then NULL is passed in
|
||||
** place of the corresponding WhereTerm.
|
||||
**
|
||||
** The nEq parameter is passed the index of the index column subject to the
|
||||
** range constraint. Or, equivalently, the number of equality constraints
|
||||
** optimized by the proposed index scan. For example, assuming index p is
|
||||
** on t1(a, b), and the SQL query is:
|
||||
** The value in (pBuilder->pNew->u.btree.nEq) is the index of the index
|
||||
** column subject to the range constraint. Or, equivalently, the number of
|
||||
** equality constraints optimized by the proposed index scan. For example,
|
||||
** assuming index p is on t1(a, b), and the SQL query is:
|
||||
**
|
||||
** ... FROM t1 WHERE a = ? AND b > ? AND b < ? ...
|
||||
**
|
||||
** then nEq should be passed the value 1 (as the range restricted column,
|
||||
** b, is the second left-most column of the index). Or, if the query is:
|
||||
** then nEq is set to 1 (as the range restricted column, b, is the second
|
||||
** left-most column of the index). Or, if the query is:
|
||||
**
|
||||
** ... FROM t1 WHERE a > ? AND a < ? ...
|
||||
**
|
||||
** then nEq should be passed 0.
|
||||
** then nEq is set to 0.
|
||||
**
|
||||
** The returned value is an integer divisor to reduce the estimated
|
||||
** search space. A return value of 1 means that range constraints are
|
||||
** no help at all. A return value of 2 means range constraints are
|
||||
** expected to reduce the search space by half. And so forth...
|
||||
**
|
||||
** In the absence of sqlite_stat3 ANALYZE data, each range inequality
|
||||
** reduces the search space by a factor of 4. Hence a single constraint (x>?)
|
||||
** results in a return of 4 and a range constraint (x>? AND x<?) results
|
||||
** in a return of 16.
|
||||
** When this function is called, *pnOut is set to the whereCost() of the
|
||||
** number of rows that the index scan is expected to visit without
|
||||
** considering the range constraints. If nEq is 0, this is the number of
|
||||
** rows in the index. Assuming no error occurs, *pnOut is adjusted (reduced)
|
||||
** to account for the range contraints pLower and pUpper.
|
||||
**
|
||||
** In the absence of sqlite_stat4 ANALYZE data, or if such data cannot be
|
||||
** used, each range inequality reduces the search space by a factor of 4.
|
||||
** Hence a pair of constraints (x>? AND x<?) reduces the expected number of
|
||||
** rows visited by a factor of 16.
|
||||
*/
|
||||
static int whereRangeScanEst(
|
||||
Parse *pParse, /* Parsing & code generating context */
|
||||
Index *p, /* The index containing the range-compared column; "x" */
|
||||
int nEq, /* index into p->aCol[] of the range-compared column */
|
||||
WhereLoopBuilder *pBuilder,
|
||||
WhereTerm *pLower, /* Lower bound on the range. ex: "x>123" Might be NULL */
|
||||
WhereTerm *pUpper, /* Upper bound on the range. ex: "x<455" Might be NULL */
|
||||
WhereCost *pRangeDiv /* OUT: Reduce search space by this divisor */
|
||||
WhereCost *pnOut /* IN/OUT: Number of rows visited */
|
||||
){
|
||||
int rc = SQLITE_OK;
|
||||
int nOut = (int)*pnOut;
|
||||
|
||||
#ifdef SQLITE_ENABLE_STAT3
|
||||
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
Index *p = pBuilder->pNew->u.btree.pIndex;
|
||||
int nEq = pBuilder->pNew->u.btree.nEq;
|
||||
|
||||
if( nEq==0 && p->nSample && OptimizationEnabled(pParse->db, SQLITE_Stat3) ){
|
||||
sqlite3_value *pRangeVal;
|
||||
tRowcnt iLower = 0;
|
||||
tRowcnt iUpper = p->aiRowEst[0];
|
||||
if( p->nSample>0
|
||||
&& nEq==pBuilder->nRecValid
|
||||
&& nEq<p->nSampleCol
|
||||
&& OptimizationEnabled(pParse->db, SQLITE_Stat3)
|
||||
){
|
||||
UnpackedRecord *pRec = pBuilder->pRec;
|
||||
tRowcnt a[2];
|
||||
u8 aff = p->pTable->aCol[p->aiColumn[0]].affinity;
|
||||
u8 aff;
|
||||
|
||||
/* Variable iLower will be set to the estimate of the number of rows in
|
||||
** the index that are less than the lower bound of the range query. The
|
||||
** lower bound being the concatenation of $P and $L, where $P is the
|
||||
** key-prefix formed by the nEq values matched against the nEq left-most
|
||||
** columns of the index, and $L is the value in pLower.
|
||||
**
|
||||
** Or, if pLower is NULL or $L cannot be extracted from it (because it
|
||||
** is not a simple variable or literal value), the lower bound of the
|
||||
** range is $P. Due to a quirk in the way whereKeyStats() works, even
|
||||
** if $L is available, whereKeyStats() is called for both ($P) and
|
||||
** ($P:$L) and the larger of the two returned values used.
|
||||
**
|
||||
** Similarly, iUpper is to be set to the estimate of the number of rows
|
||||
** less than the upper bound of the range query. Where the upper bound
|
||||
** is either ($P) or ($P:$U). Again, even if $U is available, both values
|
||||
** of iUpper are requested of whereKeyStats() and the smaller used.
|
||||
*/
|
||||
tRowcnt iLower;
|
||||
tRowcnt iUpper;
|
||||
|
||||
if( nEq==p->nColumn ){
|
||||
aff = SQLITE_AFF_INTEGER;
|
||||
}else{
|
||||
aff = p->pTable->aCol[p->aiColumn[nEq]].affinity;
|
||||
}
|
||||
/* Determine iLower and iUpper using ($P) only. */
|
||||
if( nEq==0 ){
|
||||
iLower = 0;
|
||||
iUpper = p->aiRowEst[0];
|
||||
}else{
|
||||
/* Note: this call could be optimized away - since the same values must
|
||||
** have been requested when testing key $P in whereEqualScanEst(). */
|
||||
whereKeyStats(pParse, p, pRec, 0, a);
|
||||
iLower = a[0];
|
||||
iUpper = a[0] + a[1];
|
||||
}
|
||||
|
||||
/* If possible, improve on the iLower estimate using ($P:$L). */
|
||||
if( pLower ){
|
||||
int bOk; /* True if value is extracted from pExpr */
|
||||
Expr *pExpr = pLower->pExpr->pRight;
|
||||
rc = valueFromExpr(pParse, pExpr, aff, &pRangeVal);
|
||||
assert( (pLower->eOperator & (WO_GT|WO_GE))!=0 );
|
||||
if( rc==SQLITE_OK
|
||||
&& whereKeyStats(pParse, p, pRangeVal, 0, a)==SQLITE_OK
|
||||
){
|
||||
iLower = a[0];
|
||||
if( (pLower->eOperator & WO_GT)!=0 ) iLower += a[1];
|
||||
rc = sqlite3Stat4ProbeSetValue(pParse, p, &pRec, pExpr, aff, nEq, &bOk);
|
||||
if( rc==SQLITE_OK && bOk ){
|
||||
tRowcnt iNew;
|
||||
whereKeyStats(pParse, p, pRec, 0, a);
|
||||
iNew = a[0] + ((pLower->eOperator & WO_GT) ? a[1] : 0);
|
||||
if( iNew>iLower ) iLower = iNew;
|
||||
}
|
||||
sqlite3ValueFree(pRangeVal);
|
||||
}
|
||||
if( rc==SQLITE_OK && pUpper ){
|
||||
|
||||
/* If possible, improve on the iUpper estimate using ($P:$U). */
|
||||
if( pUpper ){
|
||||
int bOk; /* True if value is extracted from pExpr */
|
||||
Expr *pExpr = pUpper->pExpr->pRight;
|
||||
rc = valueFromExpr(pParse, pExpr, aff, &pRangeVal);
|
||||
assert( (pUpper->eOperator & (WO_LT|WO_LE))!=0 );
|
||||
if( rc==SQLITE_OK
|
||||
&& whereKeyStats(pParse, p, pRangeVal, 1, a)==SQLITE_OK
|
||||
){
|
||||
iUpper = a[0];
|
||||
if( (pUpper->eOperator & WO_LE)!=0 ) iUpper += a[1];
|
||||
rc = sqlite3Stat4ProbeSetValue(pParse, p, &pRec, pExpr, aff, nEq, &bOk);
|
||||
if( rc==SQLITE_OK && bOk ){
|
||||
tRowcnt iNew;
|
||||
whereKeyStats(pParse, p, pRec, 1, a);
|
||||
iNew = a[0] + ((pUpper->eOperator & WO_LE) ? a[1] : 0);
|
||||
if( iNew<iUpper ) iUpper = iNew;
|
||||
}
|
||||
sqlite3ValueFree(pRangeVal);
|
||||
}
|
||||
|
||||
pBuilder->pRec = pRec;
|
||||
if( rc==SQLITE_OK ){
|
||||
WhereCost iBase = whereCost(p->aiRowEst[0]);
|
||||
WhereCost nNew;
|
||||
if( iUpper>iLower ){
|
||||
iBase -= whereCost(iUpper - iLower);
|
||||
nNew = whereCost(iUpper - iLower);
|
||||
}else{
|
||||
nNew = 10; assert( 10==whereCost(2) );
|
||||
}
|
||||
*pRangeDiv = iBase;
|
||||
WHERETRACE(0x100, ("range scan regions: %u..%u div=%d\n",
|
||||
(u32)iLower, (u32)iUpper, *pRangeDiv));
|
||||
if( nNew<nOut ){
|
||||
nOut = nNew;
|
||||
}
|
||||
*pnOut = (WhereCost)nOut;
|
||||
WHERETRACE(0x100, ("range scan regions: %u..%u est=%d\n",
|
||||
(u32)iLower, (u32)iUpper, nOut));
|
||||
return SQLITE_OK;
|
||||
}
|
||||
}
|
||||
#else
|
||||
UNUSED_PARAMETER(pParse);
|
||||
UNUSED_PARAMETER(p);
|
||||
UNUSED_PARAMETER(nEq);
|
||||
UNUSED_PARAMETER(pBuilder);
|
||||
#endif
|
||||
assert( pLower || pUpper );
|
||||
*pRangeDiv = 0;
|
||||
/* TUNING: Each inequality constraint reduces the search space 4-fold.
|
||||
** A BETWEEN operator, therefore, reduces the search space 16-fold */
|
||||
if( pLower && (pLower->wtFlags & TERM_VNULL)==0 ){
|
||||
*pRangeDiv += 20; assert( 20==whereCost(4) );
|
||||
nOut -= 20; assert( 20==whereCost(4) );
|
||||
}
|
||||
if( pUpper ){
|
||||
*pRangeDiv += 20; assert( 20==whereCost(4) );
|
||||
nOut -= 20; assert( 20==whereCost(4) );
|
||||
}
|
||||
if( nOut<10 ) nOut = 10;
|
||||
*pnOut = (WhereCost)nOut;
|
||||
return rc;
|
||||
}
|
||||
|
||||
#ifdef SQLITE_ENABLE_STAT3
|
||||
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
/*
|
||||
** Estimate the number of rows that will be returned based on
|
||||
** an equality constraint x=VALUE and where that VALUE occurs in
|
||||
@@ -2720,37 +2679,53 @@ static int whereRangeScanEst(
|
||||
*/
|
||||
static int whereEqualScanEst(
|
||||
Parse *pParse, /* Parsing & code generating context */
|
||||
Index *p, /* The index whose left-most column is pTerm */
|
||||
WhereLoopBuilder *pBuilder,
|
||||
Expr *pExpr, /* Expression for VALUE in the x=VALUE constraint */
|
||||
tRowcnt *pnRow /* Write the revised row estimate here */
|
||||
){
|
||||
sqlite3_value *pRhs = 0; /* VALUE on right-hand side of pTerm */
|
||||
Index *p = pBuilder->pNew->u.btree.pIndex;
|
||||
int nEq = pBuilder->pNew->u.btree.nEq;
|
||||
UnpackedRecord *pRec = pBuilder->pRec;
|
||||
u8 aff; /* Column affinity */
|
||||
int rc; /* Subfunction return code */
|
||||
tRowcnt a[2]; /* Statistics */
|
||||
int bOk;
|
||||
|
||||
assert( nEq>=1 );
|
||||
assert( nEq<=(p->nColumn+1) );
|
||||
assert( p->aSample!=0 );
|
||||
assert( p->nSample>0 );
|
||||
aff = p->pTable->aCol[p->aiColumn[0]].affinity;
|
||||
if( pExpr ){
|
||||
rc = valueFromExpr(pParse, pExpr, aff, &pRhs);
|
||||
if( rc ) goto whereEqualScanEst_cancel;
|
||||
}else{
|
||||
pRhs = sqlite3ValueNew(pParse->db);
|
||||
assert( pBuilder->nRecValid<nEq );
|
||||
|
||||
/* If values are not available for all fields of the index to the left
|
||||
** of this one, no estimate can be made. Return SQLITE_NOTFOUND. */
|
||||
if( pBuilder->nRecValid<(nEq-1) ){
|
||||
return SQLITE_NOTFOUND;
|
||||
}
|
||||
if( pRhs==0 ) return SQLITE_NOTFOUND;
|
||||
rc = whereKeyStats(pParse, p, pRhs, 0, a);
|
||||
if( rc==SQLITE_OK ){
|
||||
WHERETRACE(0x100,("equality scan regions: %d\n", (int)a[1]));
|
||||
*pnRow = a[1];
|
||||
|
||||
/* This is an optimization only. The call to sqlite3Stat4ProbeSetValue()
|
||||
** below would return the same value. */
|
||||
if( nEq>p->nColumn ){
|
||||
*pnRow = 1;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
whereEqualScanEst_cancel:
|
||||
sqlite3ValueFree(pRhs);
|
||||
|
||||
aff = p->pTable->aCol[p->aiColumn[nEq-1]].affinity;
|
||||
rc = sqlite3Stat4ProbeSetValue(pParse, p, &pRec, pExpr, aff, nEq-1, &bOk);
|
||||
pBuilder->pRec = pRec;
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
if( bOk==0 ) return SQLITE_NOTFOUND;
|
||||
pBuilder->nRecValid = nEq;
|
||||
|
||||
whereKeyStats(pParse, p, pRec, 0, a);
|
||||
WHERETRACE(0x100,("equality scan regions: %d\n", (int)a[1]));
|
||||
*pnRow = a[1];
|
||||
|
||||
return rc;
|
||||
}
|
||||
#endif /* defined(SQLITE_ENABLE_STAT3) */
|
||||
#endif /* SQLITE_ENABLE_STAT3_OR_STAT4 */
|
||||
|
||||
#ifdef SQLITE_ENABLE_STAT3
|
||||
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
/*
|
||||
** Estimate the number of rows that will be returned based on
|
||||
** an IN constraint where the right-hand side of the IN operator
|
||||
@@ -2769,10 +2744,12 @@ whereEqualScanEst_cancel:
|
||||
*/
|
||||
static int whereInScanEst(
|
||||
Parse *pParse, /* Parsing & code generating context */
|
||||
Index *p, /* The index whose left-most column is pTerm */
|
||||
WhereLoopBuilder *pBuilder,
|
||||
ExprList *pList, /* The value list on the RHS of "x IN (v1,v2,v3,...)" */
|
||||
tRowcnt *pnRow /* Write the revised row estimate here */
|
||||
){
|
||||
Index *p = pBuilder->pNew->u.btree.pIndex;
|
||||
int nRecValid = pBuilder->nRecValid;
|
||||
int rc = SQLITE_OK; /* Subfunction return code */
|
||||
tRowcnt nEst; /* Number of rows for a single term */
|
||||
tRowcnt nRowEst = 0; /* New estimate of the number of rows */
|
||||
@@ -2781,17 +2758,20 @@ static int whereInScanEst(
|
||||
assert( p->aSample!=0 );
|
||||
for(i=0; rc==SQLITE_OK && i<pList->nExpr; i++){
|
||||
nEst = p->aiRowEst[0];
|
||||
rc = whereEqualScanEst(pParse, p, pList->a[i].pExpr, &nEst);
|
||||
rc = whereEqualScanEst(pParse, pBuilder, pList->a[i].pExpr, &nEst);
|
||||
nRowEst += nEst;
|
||||
pBuilder->nRecValid = nRecValid;
|
||||
}
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
if( nRowEst > p->aiRowEst[0] ) nRowEst = p->aiRowEst[0];
|
||||
*pnRow = nRowEst;
|
||||
WHERETRACE(0x100,("IN row estimate: est=%g\n", nRowEst));
|
||||
}
|
||||
assert( pBuilder->nRecValid==nRecValid );
|
||||
return rc;
|
||||
}
|
||||
#endif /* defined(SQLITE_ENABLE_STAT3) */
|
||||
#endif /* SQLITE_ENABLE_STAT3_OR_STAT4 */
|
||||
|
||||
/*
|
||||
** Disable a term in the WHERE clause. Except, do not disable the term
|
||||
@@ -2820,6 +2800,7 @@ static void disableTerm(WhereLevel *pLevel, WhereTerm *pTerm){
|
||||
if( pTerm
|
||||
&& (pTerm->wtFlags & TERM_CODED)==0
|
||||
&& (pLevel->iLeftJoin==0 || ExprHasProperty(pTerm->pExpr, EP_FromJoin))
|
||||
&& (pLevel->notReady & pTerm->prereqAll)==0
|
||||
){
|
||||
pTerm->wtFlags |= TERM_CODED;
|
||||
if( pTerm->iParent>=0 ){
|
||||
@@ -3029,7 +3010,7 @@ static int codeAllEqualityTerms(
|
||||
|
||||
/* Evaluate the equality constraints
|
||||
*/
|
||||
assert( pIdx->nColumn>=nEq );
|
||||
assert( zAff==0 || (int)strlen(zAff)>=nEq );
|
||||
for(j=0; j<nEq; j++){
|
||||
int r1;
|
||||
pTerm = pLoop->aLTerm[j];
|
||||
@@ -3121,7 +3102,8 @@ static char *explainIndexRange(sqlite3 *db, WhereLoop *pLoop, Table *pTab){
|
||||
txt.db = db;
|
||||
sqlite3StrAccumAppend(&txt, " (", 2);
|
||||
for(i=0; i<nEq; i++){
|
||||
explainAppendTerm(&txt, i, aCol[aiColumn[i]].zName, "=");
|
||||
char *z = (i==pIndex->nColumn ) ? "rowid" : aCol[aiColumn[i]].zName;
|
||||
explainAppendTerm(&txt, i, z, "=");
|
||||
}
|
||||
|
||||
j = i;
|
||||
@@ -3244,7 +3226,6 @@ static Bitmask codeOneLoopStart(
|
||||
int addrCont; /* Jump here to continue with next cycle */
|
||||
int iRowidReg = 0; /* Rowid is stored in this register, if not zero */
|
||||
int iReleaseReg = 0; /* Temp register to free before returning */
|
||||
Bitmask newNotReady; /* Return value */
|
||||
|
||||
pParse = pWInfo->pParse;
|
||||
v = pParse->pVdbe;
|
||||
@@ -3254,6 +3235,7 @@ static Bitmask codeOneLoopStart(
|
||||
pLoop = pLevel->pWLoop;
|
||||
pTabItem = &pWInfo->pTabList->a[pLevel->iFrom];
|
||||
iCur = pTabItem->iCursor;
|
||||
pLevel->notReady = notReady & ~getMask(&pWInfo->sMaskSet, iCur);
|
||||
bRev = (pWInfo->revMask>>iLevel)&1;
|
||||
omitTable = (pLoop->wsFlags & WHERE_IDX_ONLY)!=0
|
||||
&& (pWInfo->wctrlFlags & WHERE_FORCE_TABLE)==0;
|
||||
@@ -3906,7 +3888,6 @@ static Bitmask codeOneLoopStart(
|
||||
pLevel->p2 = 1 + sqlite3VdbeAddOp2(v, aStart[bRev], iCur, addrBrk);
|
||||
pLevel->p5 = SQLITE_STMTSTATUS_FULLSCAN_STEP;
|
||||
}
|
||||
newNotReady = notReady & ~getMask(&pWInfo->sMaskSet, iCur);
|
||||
|
||||
/* Insert code to test every subexpression that can be completely
|
||||
** computed using the current set of tables.
|
||||
@@ -3916,7 +3897,7 @@ static Bitmask codeOneLoopStart(
|
||||
testcase( pTerm->wtFlags & TERM_VIRTUAL );
|
||||
testcase( pTerm->wtFlags & TERM_CODED );
|
||||
if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue;
|
||||
if( (pTerm->prereqAll & newNotReady)!=0 ){
|
||||
if( (pTerm->prereqAll & pLevel->notReady)!=0 ){
|
||||
testcase( pWInfo->untestedTerms==0
|
||||
&& (pWInfo->wctrlFlags & WHERE_ONETABLE_ONLY)!=0 );
|
||||
pWInfo->untestedTerms = 1;
|
||||
@@ -3948,7 +3929,7 @@ static Bitmask codeOneLoopStart(
|
||||
if( pLevel->iLeftJoin ) continue;
|
||||
pE = pTerm->pExpr;
|
||||
assert( !ExprHasProperty(pE, EP_FromJoin) );
|
||||
assert( (pTerm->prereqRight & newNotReady)!=0 );
|
||||
assert( (pTerm->prereqRight & pLevel->notReady)!=0 );
|
||||
pAlt = findTerm(pWC, iCur, pTerm->u.leftColumn, notReady, WO_EQ|WO_IN, 0);
|
||||
if( pAlt==0 ) continue;
|
||||
if( pAlt->wtFlags & (TERM_CODED) ) continue;
|
||||
@@ -3976,7 +3957,7 @@ static Bitmask codeOneLoopStart(
|
||||
testcase( pTerm->wtFlags & TERM_VIRTUAL );
|
||||
testcase( pTerm->wtFlags & TERM_CODED );
|
||||
if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue;
|
||||
if( (pTerm->prereqAll & newNotReady)!=0 ){
|
||||
if( (pTerm->prereqAll & pLevel->notReady)!=0 ){
|
||||
assert( pWInfo->untestedTerms );
|
||||
continue;
|
||||
}
|
||||
@@ -3987,7 +3968,7 @@ static Bitmask codeOneLoopStart(
|
||||
}
|
||||
sqlite3ReleaseTempReg(pParse, iReleaseReg);
|
||||
|
||||
return newNotReady;
|
||||
return pLevel->notReady;
|
||||
}
|
||||
|
||||
#ifdef WHERETRACE_ENABLED
|
||||
@@ -4088,8 +4069,11 @@ static int whereLoopResize(sqlite3 *db, WhereLoop *p, int n){
|
||||
** Transfer content from the second pLoop into the first.
|
||||
*/
|
||||
static int whereLoopXfer(sqlite3 *db, WhereLoop *pTo, WhereLoop *pFrom){
|
||||
if( whereLoopResize(db, pTo, pFrom->nLTerm) ) return SQLITE_NOMEM;
|
||||
whereLoopClearUnion(db, pTo);
|
||||
if( whereLoopResize(db, pTo, pFrom->nLTerm) ){
|
||||
memset(&pTo->u, 0, sizeof(pTo->u));
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
memcpy(pTo, pFrom, WHERE_LOOP_XFER_SZ);
|
||||
memcpy(pTo->aLTerm, pFrom->aLTerm, pTo->nLTerm*sizeof(pTo->aLTerm[0]));
|
||||
if( pFrom->wsFlags & WHERE_VIRTUALTABLE ){
|
||||
@@ -4197,15 +4181,17 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){
|
||||
if( (p->prereq & pTemplate->prereq)==p->prereq
|
||||
&& p->rSetup<=pTemplate->rSetup
|
||||
&& p->rRun<=pTemplate->rRun
|
||||
&& p->nOut<=pTemplate->nOut
|
||||
){
|
||||
/* This branch taken when p is equal or better than pTemplate in
|
||||
** all of (1) dependences (2) setup-cost, and (3) run-cost. */
|
||||
** all of (1) dependencies (2) setup-cost, (3) run-cost, and
|
||||
** (4) number of output rows. */
|
||||
assert( p->rSetup==pTemplate->rSetup );
|
||||
if( p->nLTerm<pTemplate->nLTerm
|
||||
if( p->prereq==pTemplate->prereq
|
||||
&& p->nLTerm<pTemplate->nLTerm
|
||||
&& (p->wsFlags & WHERE_INDEXED)!=0
|
||||
&& (pTemplate->wsFlags & WHERE_INDEXED)!=0
|
||||
&& p->u.btree.pIndex==pTemplate->u.btree.pIndex
|
||||
&& p->prereq==pTemplate->prereq
|
||||
){
|
||||
/* Overwrite an existing WhereLoop with an similar one that uses
|
||||
** more terms of the index */
|
||||
@@ -4219,11 +4205,13 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){
|
||||
}
|
||||
if( (p->prereq & pTemplate->prereq)==pTemplate->prereq
|
||||
&& p->rRun>=pTemplate->rRun
|
||||
&& p->nOut>=pTemplate->nOut
|
||||
&& ALWAYS(p->rSetup>=pTemplate->rSetup) /* See SETUP-INVARIANT above */
|
||||
){
|
||||
/* Overwrite an existing WhereLoop with a better one: one that is
|
||||
** better at one of (1) dependences, (2) setup-cost, or (3) run-cost
|
||||
** and is no worse in any of those categories. */
|
||||
** better at one of (1) dependencies, (2) setup-cost, (3) run-cost
|
||||
** or (4) number of output rows, and is no worse in any of those
|
||||
** categories. */
|
||||
pNext = p->pNextLoop;
|
||||
break;
|
||||
}
|
||||
@@ -4335,12 +4323,18 @@ static int whereLoopAddBtreeIndex(
|
||||
rLogSize = estLog(whereCost(pProbe->aiRowEst[0]));
|
||||
for(; rc==SQLITE_OK && pTerm!=0; pTerm = whereScanNext(&scan)){
|
||||
int nIn = 0;
|
||||
if( pTerm->prereqRight & pNew->maskSelf ) continue;
|
||||
#ifdef SQLITE_ENABLE_STAT3
|
||||
if( (pTerm->wtFlags & TERM_VNULL)!=0 && pSrc->pTab->aCol[iCol].notNull ){
|
||||
continue; /* skip IS NOT NULL constraints on a NOT NULL column */
|
||||
}
|
||||
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
int nRecValid = pBuilder->nRecValid;
|
||||
#endif
|
||||
if( (pTerm->eOperator==WO_ISNULL || (pTerm->wtFlags&TERM_VNULL)!=0)
|
||||
&& (iCol<0 || pSrc->pTab->aCol[iCol].notNull)
|
||||
){
|
||||
continue; /* ignore IS [NOT] NULL constraints on NOT NULL columns */
|
||||
}
|
||||
if( pTerm->prereqRight & pNew->maskSelf ) continue;
|
||||
|
||||
assert( pNew->nOut==saved_nOut );
|
||||
|
||||
pNew->wsFlags = saved_wsFlags;
|
||||
pNew->u.btree.nEq = saved_nEq;
|
||||
pNew->nLTerm = saved_nLTerm;
|
||||
@@ -4397,25 +4391,30 @@ static int whereLoopAddBtreeIndex(
|
||||
}
|
||||
if( pNew->wsFlags & WHERE_COLUMN_RANGE ){
|
||||
/* Adjust nOut and rRun for STAT3 range values */
|
||||
WhereCost rDiv;
|
||||
whereRangeScanEst(pParse, pProbe, pNew->u.btree.nEq,
|
||||
pBtm, pTop, &rDiv);
|
||||
pNew->nOut = saved_nOut>rDiv+10 ? saved_nOut - rDiv : 10;
|
||||
assert( pNew->nOut==saved_nOut );
|
||||
whereRangeScanEst(pParse, pBuilder, pBtm, pTop, &pNew->nOut);
|
||||
}
|
||||
#ifdef SQLITE_ENABLE_STAT3
|
||||
if( pNew->u.btree.nEq==1 && pProbe->nSample
|
||||
&& OptimizationEnabled(db, SQLITE_Stat3) ){
|
||||
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
if( nInMul==0
|
||||
&& pProbe->nSample
|
||||
&& pNew->u.btree.nEq<=pProbe->nSampleCol
|
||||
&& OptimizationEnabled(db, SQLITE_Stat3)
|
||||
){
|
||||
Expr *pExpr = pTerm->pExpr;
|
||||
tRowcnt nOut = 0;
|
||||
if( (pTerm->eOperator & (WO_EQ|WO_ISNULL))!=0 ){
|
||||
testcase( pTerm->eOperator & WO_EQ );
|
||||
testcase( pTerm->eOperator & WO_ISNULL );
|
||||
rc = whereEqualScanEst(pParse, pProbe, pTerm->pExpr->pRight, &nOut);
|
||||
rc = whereEqualScanEst(pParse, pBuilder, pExpr->pRight, &nOut);
|
||||
}else if( (pTerm->eOperator & WO_IN)
|
||||
&& !ExprHasProperty(pTerm->pExpr, EP_xIsSelect) ){
|
||||
rc = whereInScanEst(pParse, pProbe, pTerm->pExpr->x.pList, &nOut);
|
||||
&& !ExprHasProperty(pExpr, EP_xIsSelect) ){
|
||||
rc = whereInScanEst(pParse, pBuilder, pExpr->x.pList, &nOut);
|
||||
}
|
||||
assert( nOut==0 || rc==SQLITE_OK );
|
||||
if( nOut ) pNew->nOut = whereCost(nOut);
|
||||
if( nOut ){
|
||||
nOut = whereCost(nOut);
|
||||
pNew->nOut = MIN(nOut, saved_nOut);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if( (pNew->wsFlags & (WHERE_IDX_ONLY|WHERE_IPK))==0 ){
|
||||
@@ -4432,6 +4431,10 @@ static int whereLoopAddBtreeIndex(
|
||||
){
|
||||
whereLoopAddBtreeIndex(pBuilder, pSrc, pProbe, nInMul+nIn);
|
||||
}
|
||||
pNew->nOut = saved_nOut;
|
||||
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
pBuilder->nRecValid = nRecValid;
|
||||
#endif
|
||||
}
|
||||
pNew->prereq = saved_prereq;
|
||||
pNew->u.btree.nEq = saved_nEq;
|
||||
@@ -4480,6 +4483,7 @@ static Bitmask columnsInIndex(Index *pIdx){
|
||||
int j;
|
||||
for(j=pIdx->nColumn-1; j>=0; j--){
|
||||
int x = pIdx->aiColumn[j];
|
||||
assert( x>=0 );
|
||||
testcase( x==BMS-1 );
|
||||
testcase( x==BMS-2 );
|
||||
if( x<BMS-1 ) m |= MASKBIT(x);
|
||||
@@ -4558,6 +4562,7 @@ static int whereLoopAddBtree(
|
||||
rSize = whereCost(pSrc->pTab->nRowEst);
|
||||
rLogSize = estLog(rSize);
|
||||
|
||||
#ifndef SQLITE_OMIT_AUTOMATIC_INDEX
|
||||
/* Automatic indexes */
|
||||
if( !pBuilder->pOrSet
|
||||
&& (pWInfo->pParse->db->flags & SQLITE_AutoIndex)!=0
|
||||
@@ -4592,6 +4597,7 @@ static int whereLoopAddBtree(
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* SQLITE_OMIT_AUTOMATIC_INDEX */
|
||||
|
||||
/* Loop over all indices
|
||||
*/
|
||||
@@ -4658,7 +4664,13 @@ static int whereLoopAddBtree(
|
||||
if( rc ) break;
|
||||
}
|
||||
}
|
||||
|
||||
rc = whereLoopAddBtreeIndex(pBuilder, pSrc, pProbe, 0);
|
||||
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
sqlite3Stat4ProbeFree(pBuilder->pRec);
|
||||
pBuilder->nRecValid = 0;
|
||||
pBuilder->pRec = 0;
|
||||
#endif
|
||||
|
||||
/* If there was an INDEXED BY clause, then only that one index is
|
||||
** considered. */
|
||||
@@ -4855,6 +4867,7 @@ static int whereLoopAddOr(WhereLoopBuilder *pBuilder, Bitmask mExtra){
|
||||
if( pWInfo->wctrlFlags & WHERE_AND_ONLY ) return SQLITE_OK;
|
||||
pWCEnd = pWC->a + pWC->nTerm;
|
||||
pNew = pBuilder->pNew;
|
||||
memset(&sSum, 0, sizeof(sSum));
|
||||
|
||||
for(pTerm=pWC->a; pTerm<pWCEnd && rc==SQLITE_OK; pTerm++){
|
||||
if( (pTerm->eOperator & WO_OR)!=0
|
||||
@@ -5540,11 +5553,15 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){
|
||||
pLoop->rRun = 33; /* 33==whereCost(10) */
|
||||
}else{
|
||||
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
||||
if( pIdx->onError==OE_None || pIdx->pPartIdxWhere!=0 ) continue;
|
||||
assert( pLoop->aLTermSpace==pLoop->aLTerm );
|
||||
assert( ArraySize(pLoop->aLTermSpace)==4 );
|
||||
if( pIdx->onError==OE_None
|
||||
|| pIdx->pPartIdxWhere!=0
|
||||
|| pIdx->nColumn>ArraySize(pLoop->aLTermSpace)
|
||||
) continue;
|
||||
for(j=0; j<pIdx->nColumn; j++){
|
||||
pTerm = findTerm(pWC, iCur, pIdx->aiColumn[j], 0, WO_EQ, pIdx);
|
||||
if( pTerm==0 ) break;
|
||||
whereLoopResize(pWInfo->pParse->db, pLoop, j);
|
||||
pLoop->aLTerm[j] = pTerm;
|
||||
}
|
||||
if( j!=pIdx->nColumn ) continue;
|
||||
@@ -5899,7 +5916,7 @@ WhereInfo *sqlite3WhereBegin(
|
||||
&& OptimizationEnabled(db, SQLITE_OmitNoopJoin)
|
||||
){
|
||||
Bitmask tabUsed = exprListTableUsage(pMaskSet, pResultSet);
|
||||
if( pOrderBy ) tabUsed |= exprListTableUsage(pMaskSet, pOrderBy);
|
||||
if( sWLB.pOrderBy ) tabUsed |= exprListTableUsage(pMaskSet, sWLB.pOrderBy);
|
||||
while( pWInfo->nLevel>=2 ){
|
||||
WhereTerm *pTerm, *pEnd;
|
||||
pLoop = pWInfo->a[pWInfo->nLevel-1].pWLoop;
|
||||
@@ -5981,11 +5998,6 @@ WhereInfo *sqlite3WhereBegin(
|
||||
}else{
|
||||
sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName);
|
||||
}
|
||||
#ifndef SQLITE_OMIT_AUTOMATIC_INDEX
|
||||
if( (pLoop->wsFlags & WHERE_AUTO_INDEX)!=0 ){
|
||||
constructAutomaticIndex(pParse, &pWInfo->sWC, pTabItem, notReady, pLevel);
|
||||
}else
|
||||
#endif
|
||||
if( pLoop->wsFlags & WHERE_INDEXED ){
|
||||
Index *pIx = pLoop->u.btree.pIndex;
|
||||
KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIx);
|
||||
@@ -6010,7 +6022,15 @@ WhereInfo *sqlite3WhereBegin(
|
||||
notReady = ~(Bitmask)0;
|
||||
for(ii=0; ii<nTabList; ii++){
|
||||
pLevel = &pWInfo->a[ii];
|
||||
#ifndef SQLITE_OMIT_AUTOMATIC_INDEX
|
||||
if( (pLevel->pWLoop->wsFlags & WHERE_AUTO_INDEX)!=0 ){
|
||||
constructAutomaticIndex(pParse, &pWInfo->sWC,
|
||||
&pTabList->a[pLevel->iFrom], notReady, pLevel);
|
||||
if( db->mallocFailed ) goto whereBeginError;
|
||||
}
|
||||
#endif
|
||||
explainOneScan(pParse, pTabList, pLevel, ii, pLevel->iFrom, wctrlFlags);
|
||||
pLevel->addrBody = sqlite3VdbeCurrentAddr(v);
|
||||
notReady = codeOneLoopStart(pWInfo, ii, notReady);
|
||||
pWInfo->iContinue = pLevel->addrCont;
|
||||
}
|
||||
@@ -6130,9 +6150,10 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
|
||||
int k, j, last;
|
||||
VdbeOp *pOp;
|
||||
|
||||
pOp = sqlite3VdbeGetOp(v, pWInfo->iTop);
|
||||
last = sqlite3VdbeCurrentAddr(v);
|
||||
for(k=pWInfo->iTop; k<last; k++, pOp++){
|
||||
k = pLevel->addrBody;
|
||||
pOp = sqlite3VdbeGetOp(v, k);
|
||||
for(; k<last; k++, pOp++){
|
||||
if( pOp->p1!=pLevel->iTabCur ) continue;
|
||||
if( pOp->opcode==OP_Column ){
|
||||
for(j=0; j<pIdx->nColumn; j++){
|
||||
|
||||
+2
-1
@@ -847,7 +847,8 @@ do_test alter-14.2 {
|
||||
set system_table_list {1 sqlite_master}
|
||||
catchsql ANALYZE
|
||||
ifcapable analyze { lappend system_table_list 2 sqlite_stat1 }
|
||||
ifcapable stat3 { lappend system_table_list 4 sqlite_stat3 }
|
||||
ifcapable stat3 { lappend system_table_list 3 sqlite_stat3 }
|
||||
ifcapable stat4 { lappend system_table_list 4 sqlite_stat4 }
|
||||
|
||||
foreach {tn tbl} $system_table_list {
|
||||
do_test alter-15.$tn.1 {
|
||||
|
||||
@@ -143,6 +143,11 @@ do_test alter4-2.6 {
|
||||
alter table t1 add column d DEFAULT CURRENT_TIME;
|
||||
}
|
||||
} {1 {Cannot add a column with non-constant default}}
|
||||
do_test alter4-2.7 {
|
||||
catchsql {
|
||||
alter table t1 add column d default (-+1);
|
||||
}
|
||||
} {1 {Cannot add a column with non-constant default}}
|
||||
do_test alter4-2.99 {
|
||||
execsql {
|
||||
DROP TABLE t1;
|
||||
|
||||
+17
-17
@@ -288,7 +288,7 @@ do_test analyze-4.3 {
|
||||
} {}
|
||||
|
||||
# Verify that DROP TABLE and DROP INDEX remove entries from the
|
||||
# sqlite_stat1 and sqlite_stat3 tables.
|
||||
# sqlite_stat1, sqlite_stat3 and sqlite_stat4 tables.
|
||||
#
|
||||
do_test analyze-5.0 {
|
||||
execsql {
|
||||
@@ -306,12 +306,13 @@ do_test analyze-5.0 {
|
||||
SELECT DISTINCT tbl FROM sqlite_stat1 ORDER BY 1;
|
||||
}
|
||||
} {t3i1 t3i2 t3i3 t4i1 t4i2 t3 t4}
|
||||
ifcapable stat3 {
|
||||
ifcapable stat4||stat3 {
|
||||
ifcapable stat4 {set stat sqlite_stat4} else {set stat sqlite_stat3}
|
||||
do_test analyze-5.1 {
|
||||
execsql {
|
||||
SELECT DISTINCT idx FROM sqlite_stat3 ORDER BY 1;
|
||||
SELECT DISTINCT tbl FROM sqlite_stat3 ORDER BY 1;
|
||||
}
|
||||
execsql "
|
||||
SELECT DISTINCT idx FROM $stat ORDER BY 1;
|
||||
SELECT DISTINCT tbl FROM $stat ORDER BY 1;
|
||||
"
|
||||
} {t3i1 t3i2 t3i3 t4i1 t4i2 t3 t4}
|
||||
}
|
||||
do_test analyze-5.2 {
|
||||
@@ -321,12 +322,12 @@ do_test analyze-5.2 {
|
||||
SELECT DISTINCT tbl FROM sqlite_stat1 ORDER BY 1;
|
||||
}
|
||||
} {t3i1 t3i3 t4i1 t4i2 t3 t4}
|
||||
ifcapable stat3 {
|
||||
ifcapable stat4||stat3 {
|
||||
do_test analyze-5.3 {
|
||||
execsql {
|
||||
SELECT DISTINCT idx FROM sqlite_stat3 ORDER BY 1;
|
||||
SELECT DISTINCT tbl FROM sqlite_stat3 ORDER BY 1;
|
||||
}
|
||||
execsql "
|
||||
SELECT DISTINCT idx FROM $stat ORDER BY 1;
|
||||
SELECT DISTINCT tbl FROM $stat ORDER BY 1;
|
||||
"
|
||||
} {t3i1 t3i3 t4i1 t4i2 t3 t4}
|
||||
}
|
||||
do_test analyze-5.4 {
|
||||
@@ -336,12 +337,12 @@ do_test analyze-5.4 {
|
||||
SELECT DISTINCT tbl FROM sqlite_stat1 ORDER BY 1;
|
||||
}
|
||||
} {t4i1 t4i2 t4}
|
||||
ifcapable stat3 {
|
||||
ifcapable stat4||stat3 {
|
||||
do_test analyze-5.5 {
|
||||
execsql {
|
||||
SELECT DISTINCT idx FROM sqlite_stat3 ORDER BY 1;
|
||||
SELECT DISTINCT tbl FROM sqlite_stat3 ORDER BY 1;
|
||||
}
|
||||
execsql "
|
||||
SELECT DISTINCT idx FROM $stat ORDER BY 1;
|
||||
SELECT DISTINCT tbl FROM $stat ORDER BY 1;
|
||||
"
|
||||
} {t4i1 t4i2 t4}
|
||||
}
|
||||
|
||||
@@ -360,5 +361,4 @@ do_test analyze-99.1 {
|
||||
}
|
||||
} {1 {malformed database schema (sqlite_stat1) - near "nonsense": syntax error}}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
+8
-3
@@ -17,7 +17,7 @@
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
ifcapable !stat3 {
|
||||
ifcapable !stat4&&!stat3 {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
@@ -95,7 +95,13 @@ do_test analyze3-1.1.1 {
|
||||
COMMIT;
|
||||
ANALYZE;
|
||||
}
|
||||
} {}
|
||||
|
||||
ifcapable stat4 {
|
||||
execsql { SELECT count(*)>0 FROM sqlite_stat4; }
|
||||
} else {
|
||||
execsql { SELECT count(*)>0 FROM sqlite_stat3; }
|
||||
}
|
||||
} {1}
|
||||
|
||||
do_eqp_test analyze3-1.1.2 {
|
||||
SELECT sum(y) FROM t1 WHERE x>200 AND x<300
|
||||
@@ -312,7 +318,6 @@ do_test analyze3-3.1 {
|
||||
execsql COMMIT
|
||||
execsql ANALYZE
|
||||
} {}
|
||||
|
||||
do_test analyze3-3.2.1 {
|
||||
set S [sqlite3_prepare_v2 db "SELECT * FROM t1 WHERE b>?" -1 dummy]
|
||||
sqlite3_expired $S
|
||||
|
||||
+42
-8
@@ -10,14 +10,14 @@
|
||||
#***********************************************************************
|
||||
#
|
||||
# This file implements tests for SQLite library. The focus of the tests
|
||||
# in this file is the use of the sqlite_stat3 histogram data on tables
|
||||
# in this file is the use of the sqlite_stat4 histogram data on tables
|
||||
# with many repeated values and only a few distinct values.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
ifcapable !stat3 {
|
||||
ifcapable !stat4&&!stat3 {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
@@ -28,6 +28,17 @@ proc eqp {sql {db db}} {
|
||||
uplevel execsql [list "EXPLAIN QUERY PLAN $sql"] $db
|
||||
}
|
||||
|
||||
proc alpha {blob} {
|
||||
set ret ""
|
||||
foreach c [split $blob {}] {
|
||||
if {[string is alpha $c]} {append ret $c}
|
||||
}
|
||||
return $ret
|
||||
}
|
||||
db func alpha alpha
|
||||
|
||||
db func lindex lindex
|
||||
|
||||
unset -nocomplain i t u v w x y z
|
||||
do_test analyze5-1.0 {
|
||||
db eval {CREATE TABLE t1(t,u,v TEXT COLLATE nocase,w,x,y,z)}
|
||||
@@ -55,17 +66,40 @@ do_test analyze5-1.0 {
|
||||
CREATE INDEX t1y ON t1(y); -- integers 0 and very few 1s
|
||||
CREATE INDEX t1z ON t1(z); -- integers 0, 1, 2, and 3
|
||||
ANALYZE;
|
||||
SELECT sample FROM sqlite_stat3 WHERE idx='t1u' ORDER BY nlt;
|
||||
}
|
||||
ifcapable stat4 {
|
||||
db eval {
|
||||
SELECT DISTINCT lindex(test_decode(sample),0)
|
||||
FROM sqlite_stat4 WHERE idx='t1u' ORDER BY nlt;
|
||||
}
|
||||
} else {
|
||||
db eval {
|
||||
SELECT sample FROM sqlite_stat3 WHERE idx='t1u' ORDER BY nlt;
|
||||
}
|
||||
}
|
||||
} {alpha bravo charlie delta}
|
||||
|
||||
do_test analyze5-1.1 {
|
||||
db eval {SELECT DISTINCT lower(sample) FROM sqlite_stat3 WHERE idx='t1v'
|
||||
ORDER BY 1}
|
||||
ifcapable stat4 {
|
||||
db eval {
|
||||
SELECT DISTINCT lower(lindex(test_decode(sample), 0))
|
||||
FROM sqlite_stat4 WHERE idx='t1v' ORDER BY 1
|
||||
}
|
||||
} else {
|
||||
db eval {
|
||||
SELECT lower(sample) FROM sqlite_stat3 WHERE idx='t1v' ORDER BY 1
|
||||
}
|
||||
}
|
||||
} {alpha bravo charlie delta}
|
||||
do_test analyze5-1.2 {
|
||||
db eval {SELECT idx, count(*) FROM sqlite_stat3 GROUP BY 1 ORDER BY 1}
|
||||
} {t1t 4 t1u 4 t1v 4 t1w 4 t1x 4 t1y 2 t1z 4}
|
||||
ifcapable stat4 {
|
||||
do_test analyze5-1.2 {
|
||||
db eval {SELECT idx, count(*) FROM sqlite_stat4 GROUP BY 1 ORDER BY 1}
|
||||
} {t1t 8 t1u 8 t1v 8 t1w 8 t1x 8 t1y 9 t1z 8}
|
||||
} else {
|
||||
do_test analyze5-1.2 {
|
||||
db eval {SELECT idx, count(*) FROM sqlite_stat3 GROUP BY 1 ORDER BY 1}
|
||||
} {t1t 4 t1u 4 t1v 4 t1w 4 t1x 4 t1y 2 t1z 4}
|
||||
}
|
||||
|
||||
# Verify that range queries generate the correct row count estimates
|
||||
#
|
||||
|
||||
+1
-1
@@ -17,7 +17,7 @@
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
ifcapable !stat3 {
|
||||
ifcapable !stat4&&!stat3 {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
+5
-4
@@ -82,14 +82,14 @@ do_test analyze7-3.1 {
|
||||
do_test analyze7-3.2.1 {
|
||||
execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE c=?;}
|
||||
} {0 0 0 {SEARCH TABLE t1 USING INDEX t1cd (c=?)}}
|
||||
ifcapable stat3 {
|
||||
# If ENABLE_STAT3 is defined, SQLite comes up with a different estimated
|
||||
ifcapable stat4||stat3 {
|
||||
# If ENABLE_STAT4 is defined, SQLite comes up with a different estimated
|
||||
# row count for (c=2) than it does for (c=?).
|
||||
do_test analyze7-3.2.2 {
|
||||
execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE c=2;}
|
||||
} {0 0 0 {SEARCH TABLE t1 USING INDEX t1cd (c=?)}}
|
||||
} else {
|
||||
# If ENABLE_STAT3 is not defined, the expected row count for (c=2) is the
|
||||
# If ENABLE_STAT4 is not defined, the expected row count for (c=2) is the
|
||||
# same as that for (c=?).
|
||||
do_test analyze7-3.2.3 {
|
||||
execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE c=2;}
|
||||
@@ -98,7 +98,8 @@ ifcapable stat3 {
|
||||
do_test analyze7-3.3 {
|
||||
execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a=123 AND b=123}
|
||||
} {0 0 0 {SEARCH TABLE t1 USING INDEX t1a (a=?)}}
|
||||
ifcapable {!stat3} {
|
||||
|
||||
ifcapable {!stat4 && !stat3} {
|
||||
do_test analyze7-3.4 {
|
||||
execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE c=123 AND b=123}
|
||||
} {0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b=?)}}
|
||||
|
||||
+13
-1
@@ -16,7 +16,7 @@
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
ifcapable !stat3 {
|
||||
ifcapable !stat4&&!stat3 {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
@@ -84,7 +84,19 @@ do_test 2.1 {
|
||||
# There are many more values of c between 0 and 100000 than there are
|
||||
# between 800000 and 900000. So t1c is more selective for the latter
|
||||
# range.
|
||||
#
|
||||
# Test 3.2 is a little unstable. It depends on the planner estimating
|
||||
# that (b BETWEEN 50 AND 54) will match more rows than (c BETWEEN
|
||||
# 800000 AND 900000). Which is a pretty close call (50 vs. 32), so
|
||||
# the planner could get it wrong with an unlucky set of samples. This
|
||||
# case happens to work, but others ("b BETWEEN 40 AND 44" for example)
|
||||
# will fail.
|
||||
#
|
||||
do_execsql_test 3.0 {
|
||||
SELECT count(*) FROM t1 WHERE b BETWEEN 50 AND 54;
|
||||
SELECT count(*) FROM t1 WHERE c BETWEEN 0 AND 100000;
|
||||
SELECT count(*) FROM t1 WHERE c BETWEEN 800000 AND 900000;
|
||||
} {50 376 32}
|
||||
do_test 3.1 {
|
||||
eqp {SELECT * FROM t1 WHERE b BETWEEN 50 AND 54 AND c BETWEEN 0 AND 100000}
|
||||
} {0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b>? AND b<?)}}
|
||||
|
||||
@@ -0,0 +1,952 @@
|
||||
# 2013 August 3
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
# This file contains automated tests used to verify that the sqlite_stat4
|
||||
# functionality is working.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix analyze9
|
||||
|
||||
ifcapable !stat4 {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
proc s {blob} {
|
||||
set ret ""
|
||||
binary scan $blob c* bytes
|
||||
foreach b $bytes {
|
||||
set t [binary format c $b]
|
||||
if {[string is print $t]} {
|
||||
append ret $t
|
||||
} else {
|
||||
append ret .
|
||||
}
|
||||
}
|
||||
return $ret
|
||||
}
|
||||
db function s s
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE TABLE t1(a TEXT, b TEXT);
|
||||
INSERT INTO t1 VALUES('(0)', '(0)');
|
||||
INSERT INTO t1 VALUES('(1)', '(1)');
|
||||
INSERT INTO t1 VALUES('(2)', '(2)');
|
||||
INSERT INTO t1 VALUES('(3)', '(3)');
|
||||
INSERT INTO t1 VALUES('(4)', '(4)');
|
||||
CREATE INDEX i1 ON t1(a, b);
|
||||
} {}
|
||||
|
||||
|
||||
do_execsql_test 1.1 {
|
||||
ANALYZE;
|
||||
} {}
|
||||
|
||||
do_execsql_test 1.2 {
|
||||
SELECT tbl,idx,nEq,nLt,nDLt,test_decode(sample) FROM sqlite_stat4;
|
||||
} {
|
||||
t1 i1 {1 1 1} {0 0 0} {0 0 0} {(0) (0) 1}
|
||||
t1 i1 {1 1 1} {1 1 1} {1 1 1} {(1) (1) 2}
|
||||
t1 i1 {1 1 1} {2 2 2} {2 2 2} {(2) (2) 3}
|
||||
t1 i1 {1 1 1} {3 3 3} {3 3 3} {(3) (3) 4}
|
||||
t1 i1 {1 1 1} {4 4 4} {4 4 4} {(4) (4) 5}
|
||||
}
|
||||
|
||||
if {[permutation] != "utf16"} {
|
||||
do_execsql_test 1.3 {
|
||||
SELECT tbl,idx,nEq,nLt,nDLt,s(sample) FROM sqlite_stat4;
|
||||
} {
|
||||
t1 i1 {1 1 1} {0 0 0} {0 0 0} ....(0)(0)
|
||||
t1 i1 {1 1 1} {1 1 1} {1 1 1} ....(1)(1).
|
||||
t1 i1 {1 1 1} {2 2 2} {2 2 2} ....(2)(2).
|
||||
t1 i1 {1 1 1} {3 3 3} {3 3 3} ....(3)(3).
|
||||
t1 i1 {1 1 1} {4 4 4} {4 4 4} ....(4)(4).
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# This is really just to test SQL user function "test_decode".
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 2.1 {
|
||||
CREATE TABLE t1(a, b, c);
|
||||
INSERT INTO t1 VALUES('some text', 14, NULL);
|
||||
INSERT INTO t1 VALUES(22.0, NULL, x'656667');
|
||||
CREATE INDEX i1 ON t1(a, b, c);
|
||||
ANALYZE;
|
||||
SELECT test_decode(sample) FROM sqlite_stat4;
|
||||
} {
|
||||
{22.0 NULL x'656667' 2}
|
||||
{{some text} 14 NULL 1}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 3.1 {
|
||||
CREATE TABLE t2(a, b);
|
||||
CREATE INDEX i2 ON t2(a, b);
|
||||
BEGIN;
|
||||
}
|
||||
|
||||
do_test 3.2 {
|
||||
for {set i 0} {$i < 1000} {incr i} {
|
||||
set a [expr $i / 10]
|
||||
set b [expr int(rand() * 15.0)]
|
||||
execsql { INSERT INTO t2 VALUES($a, $b) }
|
||||
}
|
||||
execsql COMMIT
|
||||
} {}
|
||||
|
||||
db func lindex lindex
|
||||
|
||||
# Each value of "a" occurs exactly 10 times in the table.
|
||||
#
|
||||
do_execsql_test 3.3.1 {
|
||||
SELECT count(*) FROM t2 GROUP BY a;
|
||||
} [lrange [string repeat "10 " 100] 0 99]
|
||||
|
||||
# The first element in the "nEq" list of all samples should therefore be 10.
|
||||
#
|
||||
do_execsql_test 3.3.2 {
|
||||
ANALYZE;
|
||||
SELECT lindex(nEq, 0) FROM sqlite_stat4;
|
||||
} [lrange [string repeat "10 " 100] 0 23]
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
do_execsql_test 3.4 {
|
||||
DROP TABLE IF EXISTS t1;
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
|
||||
INSERT INTO t1 VALUES(1, 1, 'one-a');
|
||||
INSERT INTO t1 VALUES(11, 1, 'one-b');
|
||||
INSERT INTO t1 VALUES(21, 1, 'one-c');
|
||||
INSERT INTO t1 VALUES(31, 1, 'one-d');
|
||||
INSERT INTO t1 VALUES(41, 1, 'one-e');
|
||||
INSERT INTO t1 VALUES(51, 1, 'one-f');
|
||||
INSERT INTO t1 VALUES(61, 1, 'one-g');
|
||||
INSERT INTO t1 VALUES(71, 1, 'one-h');
|
||||
INSERT INTO t1 VALUES(81, 1, 'one-i');
|
||||
INSERT INTO t1 VALUES(91, 1, 'one-j');
|
||||
INSERT INTO t1 SELECT a+1,2,'two' || substr(c,4) FROM t1;
|
||||
INSERT INTO t1 SELECT a+2,3,'three'||substr(c,4) FROM t1 WHERE c GLOB 'one-*';
|
||||
INSERT INTO t1 SELECT a+3,4,'four'||substr(c,4) FROM t1 WHERE c GLOB 'one-*';
|
||||
INSERT INTO t1 SELECT a+4,5,'five'||substr(c,4) FROM t1 WHERE c GLOB 'one-*';
|
||||
INSERT INTO t1 SELECT a+5,6,'six'||substr(c,4) FROM t1 WHERE c GLOB 'one-*';
|
||||
CREATE INDEX t1b ON t1(b);
|
||||
ANALYZE;
|
||||
SELECT c FROM t1 WHERE b=3 AND a BETWEEN 30 AND 60;
|
||||
} {three-d three-e three-f}
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# These tests verify that the sample selection for stat4 appears to be
|
||||
# working as designed.
|
||||
#
|
||||
|
||||
reset_db
|
||||
db func lindex lindex
|
||||
db func lrange lrange
|
||||
|
||||
do_execsql_test 4.0 {
|
||||
DROP TABLE IF EXISTS t1;
|
||||
CREATE TABLE t1(a, b, c);
|
||||
CREATE INDEX i1 ON t1(c, b, a);
|
||||
}
|
||||
|
||||
|
||||
proc insert_filler_rows_n {iStart args} {
|
||||
set A(-ncopy) 1
|
||||
set A(-nval) 1
|
||||
|
||||
foreach {k v} $args {
|
||||
if {[info exists A($k)]==0} { error "no such option: $k" }
|
||||
set A($k) $v
|
||||
}
|
||||
if {[llength $args] % 2} {
|
||||
error "option requires an argument: [lindex $args end]"
|
||||
}
|
||||
|
||||
for {set i 0} {$i < $A(-nval)} {incr i} {
|
||||
set iVal [expr $iStart+$i]
|
||||
for {set j 0} {$j < $A(-ncopy)} {incr j} {
|
||||
execsql { INSERT INTO t1 VALUES($iVal, $iVal, $iVal) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
do_test 4.1 {
|
||||
execsql { BEGIN }
|
||||
insert_filler_rows_n 0 -ncopy 10 -nval 19
|
||||
insert_filler_rows_n 20 -ncopy 1 -nval 100
|
||||
|
||||
execsql {
|
||||
INSERT INTO t1(c, b, a) VALUES(200, 1, 'a');
|
||||
INSERT INTO t1(c, b, a) VALUES(200, 1, 'b');
|
||||
INSERT INTO t1(c, b, a) VALUES(200, 1, 'c');
|
||||
|
||||
INSERT INTO t1(c, b, a) VALUES(200, 2, 'e');
|
||||
INSERT INTO t1(c, b, a) VALUES(200, 2, 'f');
|
||||
|
||||
INSERT INTO t1(c, b, a) VALUES(201, 3, 'g');
|
||||
INSERT INTO t1(c, b, a) VALUES(201, 4, 'h');
|
||||
|
||||
ANALYZE;
|
||||
SELECT count(*) FROM sqlite_stat4;
|
||||
SELECT count(*) FROM t1;
|
||||
}
|
||||
} {24 297}
|
||||
|
||||
do_execsql_test 4.2 {
|
||||
SELECT
|
||||
neq,
|
||||
lrange(nlt, 0, 2),
|
||||
lrange(ndlt, 0, 2),
|
||||
lrange(test_decode(sample), 0, 2)
|
||||
FROM sqlite_stat4
|
||||
ORDER BY rowid LIMIT 16;
|
||||
} {
|
||||
{10 10 10 1} {0 0 0} {0 0 0} {0 0 0}
|
||||
{10 10 10 1} {10 10 10} {1 1 1} {1 1 1}
|
||||
{10 10 10 1} {20 20 20} {2 2 2} {2 2 2}
|
||||
{10 10 10 1} {30 30 30} {3 3 3} {3 3 3}
|
||||
{10 10 10 1} {40 40 40} {4 4 4} {4 4 4}
|
||||
{10 10 10 1} {50 50 50} {5 5 5} {5 5 5}
|
||||
{10 10 10 1} {60 60 60} {6 6 6} {6 6 6}
|
||||
{10 10 10 1} {70 70 70} {7 7 7} {7 7 7}
|
||||
{10 10 10 1} {80 80 80} {8 8 8} {8 8 8}
|
||||
{10 10 10 1} {90 90 90} {9 9 9} {9 9 9}
|
||||
{10 10 10 1} {100 100 100} {10 10 10} {10 10 10}
|
||||
{10 10 10 1} {110 110 110} {11 11 11} {11 11 11}
|
||||
{10 10 10 1} {120 120 120} {12 12 12} {12 12 12}
|
||||
{10 10 10 1} {130 130 130} {13 13 13} {13 13 13}
|
||||
{10 10 10 1} {140 140 140} {14 14 14} {14 14 14}
|
||||
{10 10 10 1} {150 150 150} {15 15 15} {15 15 15}
|
||||
}
|
||||
|
||||
do_execsql_test 4.3 {
|
||||
SELECT
|
||||
neq,
|
||||
lrange(nlt, 0, 2),
|
||||
lrange(ndlt, 0, 2),
|
||||
lrange(test_decode(sample), 0, 1)
|
||||
FROM sqlite_stat4
|
||||
ORDER BY rowid DESC LIMIT 2;
|
||||
} {
|
||||
{2 1 1 1} {295 296 296} {120 122 125} {201 4}
|
||||
{5 3 1 1} {290 290 290} {119 119 119} {200 1}
|
||||
}
|
||||
|
||||
do_execsql_test 4.4 { SELECT count(DISTINCT c) FROM t1 WHERE c<201 } 120
|
||||
do_execsql_test 4.5 { SELECT count(DISTINCT c) FROM t1 WHERE c<200 } 119
|
||||
|
||||
# Check that the perioidic samples are present.
|
||||
do_execsql_test 4.6 {
|
||||
SELECT count(*) FROM sqlite_stat4
|
||||
WHERE lindex(test_decode(sample), 3) IN
|
||||
('34', '68', '102', '136', '170', '204', '238', '272')
|
||||
} {8}
|
||||
|
||||
reset_db
|
||||
do_test 4.7 {
|
||||
execsql {
|
||||
BEGIN;
|
||||
CREATE TABLE t1(o,t INTEGER PRIMARY KEY);
|
||||
CREATE INDEX i1 ON t1(o);
|
||||
}
|
||||
for {set i 0} {$i<10000} {incr i [expr (($i<1000)?1:10)]} {
|
||||
execsql { INSERT INTO t1 VALUES('x', $i) }
|
||||
}
|
||||
execsql {
|
||||
COMMIT;
|
||||
ANALYZE;
|
||||
SELECT count(*) FROM sqlite_stat4;
|
||||
}
|
||||
} {8}
|
||||
do_execsql_test 4.8 {
|
||||
SELECT test_decode(sample) FROM sqlite_stat4;
|
||||
} {
|
||||
{x 211} {x 423} {x 635} {x 847}
|
||||
{x 1590} {x 3710} {x 5830} {x 7950}
|
||||
}
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# The following would cause a crash at one point.
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 5.1 {
|
||||
PRAGMA encoding = 'utf-16';
|
||||
CREATE TABLE t0(v);
|
||||
ANALYZE;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# This was also crashing (corrupt sqlite_stat4 table).
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 6.1 {
|
||||
CREATE TABLE t1(a, b);
|
||||
CREATE INDEX i1 ON t1(a);
|
||||
CREATE INDEX i2 ON t1(b);
|
||||
INSERT INTO t1 VALUES(1, 1);
|
||||
INSERT INTO t1 VALUES(2, 2);
|
||||
INSERT INTO t1 VALUES(3, 3);
|
||||
INSERT INTO t1 VALUES(4, 4);
|
||||
INSERT INTO t1 VALUES(5, 5);
|
||||
ANALYZE;
|
||||
PRAGMA writable_schema = 1;
|
||||
CREATE TEMP TABLE x1 AS
|
||||
SELECT tbl,idx,neq,nlt,ndlt,sample FROM sqlite_stat4
|
||||
ORDER BY (rowid%5), rowid;
|
||||
DELETE FROM sqlite_stat4;
|
||||
INSERT INTO sqlite_stat4 SELECT * FROM x1;
|
||||
PRAGMA writable_schema = 0;
|
||||
ANALYZE sqlite_master;
|
||||
}
|
||||
do_execsql_test 6.2 {
|
||||
SELECT * FROM t1 WHERE a = 'abc';
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# The following tests experiment with adding corrupted records to the
|
||||
# 'sample' column of the sqlite_stat4 table.
|
||||
#
|
||||
reset_db
|
||||
sqlite3_db_config_lookaside db 0 0 0
|
||||
|
||||
do_execsql_test 7.1 {
|
||||
CREATE TABLE t1(a, b);
|
||||
CREATE INDEX i1 ON t1(a, b);
|
||||
INSERT INTO t1 VALUES(1, 1);
|
||||
INSERT INTO t1 VALUES(2, 2);
|
||||
INSERT INTO t1 VALUES(3, 3);
|
||||
INSERT INTO t1 VALUES(4, 4);
|
||||
INSERT INTO t1 VALUES(5, 5);
|
||||
ANALYZE;
|
||||
UPDATE sqlite_stat4 SET sample = X'' WHERE rowid = 1;
|
||||
ANALYZE sqlite_master;
|
||||
}
|
||||
|
||||
do_execsql_test 7.2 {
|
||||
UPDATE sqlite_stat4 SET sample = X'FFFF';
|
||||
ANALYZE sqlite_master;
|
||||
SELECT * FROM t1 WHERE a = 1;
|
||||
} {1 1}
|
||||
|
||||
do_execsql_test 7.3 {
|
||||
ANALYZE;
|
||||
UPDATE sqlite_stat4 SET neq = '0 0 0';
|
||||
ANALYZE sqlite_master;
|
||||
SELECT * FROM t1 WHERE a = 1;
|
||||
} {1 1}
|
||||
|
||||
do_execsql_test 7.4 {
|
||||
ANALYZE;
|
||||
UPDATE sqlite_stat4 SET ndlt = '0 0 0';
|
||||
ANALYZE sqlite_master;
|
||||
SELECT * FROM t1 WHERE a = 3;
|
||||
} {3 3}
|
||||
|
||||
do_execsql_test 7.5 {
|
||||
ANALYZE;
|
||||
UPDATE sqlite_stat4 SET nlt = '0 0 0';
|
||||
ANALYZE sqlite_master;
|
||||
SELECT * FROM t1 WHERE a = 5;
|
||||
} {5 5}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 8.1 {
|
||||
CREATE TABLE t1(x TEXT);
|
||||
CREATE INDEX i1 ON t1(x);
|
||||
INSERT INTO t1 VALUES('1');
|
||||
INSERT INTO t1 VALUES('2');
|
||||
INSERT INTO t1 VALUES('3');
|
||||
INSERT INTO t1 VALUES('4');
|
||||
ANALYZE;
|
||||
}
|
||||
do_execsql_test 8.2 {
|
||||
SELECT * FROM t1 WHERE x = 3;
|
||||
} {3}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Check that the bug fixed by [91733bc485] really is fixed.
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 9.1 {
|
||||
CREATE TABLE t1(a, b, c, d, e);
|
||||
CREATE INDEX i1 ON t1(a, b, c, d);
|
||||
CREATE INDEX i2 ON t1(e);
|
||||
}
|
||||
do_test 9.2 {
|
||||
execsql BEGIN;
|
||||
for {set i 0} {$i < 100} {incr i} {
|
||||
execsql "INSERT INTO t1 VALUES('x', 'y', 'z', $i, [expr $i/2])"
|
||||
}
|
||||
for {set i 0} {$i < 20} {incr i} {
|
||||
execsql "INSERT INTO t1 VALUES('x', 'y', 'z', 101, $i)"
|
||||
}
|
||||
for {set i 102} {$i < 200} {incr i} {
|
||||
execsql "INSERT INTO t1 VALUES('x', 'y', 'z', $i, [expr $i/2])"
|
||||
}
|
||||
execsql COMMIT
|
||||
execsql ANALYZE
|
||||
} {}
|
||||
|
||||
do_eqp_test 9.3.1 {
|
||||
SELECT * FROM t1 WHERE a='x' AND b='y' AND c='z' AND d=101 AND e=5;
|
||||
} {/t1 USING INDEX i2/}
|
||||
do_eqp_test 9.3.2 {
|
||||
SELECT * FROM t1 WHERE a='x' AND b='y' AND c='z' AND d=99 AND e=5;
|
||||
} {/t1 USING INDEX i1/}
|
||||
|
||||
set value_d [expr 101]
|
||||
do_eqp_test 9.4.1 {
|
||||
SELECT * FROM t1 WHERE a='x' AND b='y' AND c='z' AND d=$value_d AND e=5
|
||||
} {/t1 USING INDEX i2/}
|
||||
set value_d [expr 99]
|
||||
do_eqp_test 9.4.2 {
|
||||
SELECT * FROM t1 WHERE a='x' AND b='y' AND c='z' AND d=$value_d AND e=5
|
||||
} {/t1 USING INDEX i1/}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Check that the planner takes stat4 data into account when considering
|
||||
# "IS NULL" and "IS NOT NULL" constraints.
|
||||
#
|
||||
do_execsql_test 10.1.1 {
|
||||
DROP TABLE IF EXISTS t3;
|
||||
CREATE TABLE t3(a, b);
|
||||
CREATE INDEX t3a ON t3(a);
|
||||
CREATE INDEX t3b ON t3(b);
|
||||
}
|
||||
do_test 10.1.2 {
|
||||
for {set i 1} {$i < 100} {incr i} {
|
||||
if {$i>90} { set a $i } else { set a NULL }
|
||||
set b [expr $i % 5]
|
||||
execsql "INSERT INTO t3 VALUES($a, $b)"
|
||||
}
|
||||
execsql ANALYZE
|
||||
} {}
|
||||
do_eqp_test 10.1.3 {
|
||||
SELECT * FROM t3 WHERE a IS NULL AND b = 2
|
||||
} {/t3 USING INDEX t3b/}
|
||||
do_eqp_test 10.1.4 {
|
||||
SELECT * FROM t3 WHERE a IS NOT NULL AND b = 2
|
||||
} {/t3 USING INDEX t3a/}
|
||||
|
||||
do_execsql_test 10.2.1 {
|
||||
DROP TABLE IF EXISTS t3;
|
||||
CREATE TABLE t3(x, a, b);
|
||||
CREATE INDEX t3a ON t3(x, a);
|
||||
CREATE INDEX t3b ON t3(x, b);
|
||||
}
|
||||
do_test 10.2.2 {
|
||||
for {set i 1} {$i < 100} {incr i} {
|
||||
if {$i>90} { set a $i } else { set a NULL }
|
||||
set b [expr $i % 5]
|
||||
execsql "INSERT INTO t3 VALUES('xyz', $a, $b)"
|
||||
}
|
||||
execsql ANALYZE
|
||||
} {}
|
||||
do_eqp_test 10.2.3 {
|
||||
SELECT * FROM t3 WHERE x = 'xyz' AND a IS NULL AND b = 2
|
||||
} {/t3 USING INDEX t3b/}
|
||||
do_eqp_test 10.2.4 {
|
||||
SELECT * FROM t3 WHERE x = 'xyz' AND a IS NOT NULL AND b = 2
|
||||
} {/t3 USING INDEX t3a/}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Check that stat4 data is used correctly with non-default collation
|
||||
# sequences.
|
||||
#
|
||||
foreach {tn schema} {
|
||||
1 {
|
||||
CREATE TABLE t4(a COLLATE nocase, b);
|
||||
CREATE INDEX t4a ON t4(a);
|
||||
CREATE INDEX t4b ON t4(b);
|
||||
}
|
||||
2 {
|
||||
CREATE TABLE t4(a, b);
|
||||
CREATE INDEX t4a ON t4(a COLLATE nocase);
|
||||
CREATE INDEX t4b ON t4(b);
|
||||
}
|
||||
} {
|
||||
drop_all_tables
|
||||
do_test 11.$tn.1 { execsql $schema } {}
|
||||
|
||||
do_test 11.$tn.2 {
|
||||
for {set i 0} {$i < 100} {incr i} {
|
||||
if { ($i % 10)==0 } { set a ABC } else { set a DEF }
|
||||
set b [expr $i % 5]
|
||||
execsql { INSERT INTO t4 VALUES($a, $b) }
|
||||
}
|
||||
execsql ANALYZE
|
||||
} {}
|
||||
|
||||
do_eqp_test 11.$tn.3 {
|
||||
SELECT * FROM t4 WHERE a = 'def' AND b = 3;
|
||||
} {/t4 USING INDEX t4b/}
|
||||
|
||||
if {$tn==1} {
|
||||
set sql "SELECT * FROM t4 WHERE a = 'abc' AND b = 3;"
|
||||
do_eqp_test 11.$tn.4 $sql {/t4 USING INDEX t4a/}
|
||||
} else {
|
||||
|
||||
set sql "SELECT * FROM t4 WHERE a = 'abc' COLLATE nocase AND b = 3;"
|
||||
do_eqp_test 11.$tn.5 $sql {/t4 USING INDEX t4a/}
|
||||
|
||||
set sql "SELECT * FROM t4 WHERE a COLLATE nocase = 'abc' AND b = 3;"
|
||||
do_eqp_test 11.$tn.6 $sql {/t4 USING INDEX t4a/}
|
||||
}
|
||||
}
|
||||
|
||||
foreach {tn schema} {
|
||||
1 {
|
||||
CREATE TABLE t4(x, a COLLATE nocase, b);
|
||||
CREATE INDEX t4a ON t4(x, a);
|
||||
CREATE INDEX t4b ON t4(x, b);
|
||||
}
|
||||
2 {
|
||||
CREATE TABLE t4(x, a, b);
|
||||
CREATE INDEX t4a ON t4(x, a COLLATE nocase);
|
||||
CREATE INDEX t4b ON t4(x, b);
|
||||
}
|
||||
} {
|
||||
drop_all_tables
|
||||
do_test 12.$tn.1 { execsql $schema } {}
|
||||
|
||||
do_test 12.$tn.2 {
|
||||
for {set i 0} {$i < 100} {incr i} {
|
||||
if { ($i % 10)==0 } { set a ABC } else { set a DEF }
|
||||
set b [expr $i % 5]
|
||||
execsql { INSERT INTO t4 VALUES(X'abcdef', $a, $b) }
|
||||
}
|
||||
execsql ANALYZE
|
||||
} {}
|
||||
|
||||
do_eqp_test 12.$tn.3 {
|
||||
SELECT * FROM t4 WHERE x=X'abcdef' AND a = 'def' AND b = 3;
|
||||
} {/t4 USING INDEX t4b/}
|
||||
|
||||
if {$tn==1} {
|
||||
set sql "SELECT * FROM t4 WHERE x=X'abcdef' AND a = 'abc' AND b = 3;"
|
||||
do_eqp_test 12.$tn.4 $sql {/t4 USING INDEX t4a/}
|
||||
} else {
|
||||
set sql {
|
||||
SELECT * FROM t4 WHERE x=X'abcdef' AND a = 'abc' COLLATE nocase AND b = 3
|
||||
}
|
||||
do_eqp_test 12.$tn.5 $sql {/t4 USING INDEX t4a/}
|
||||
set sql {
|
||||
SELECT * FROM t4 WHERE x=X'abcdef' AND a COLLATE nocase = 'abc' AND b = 3
|
||||
}
|
||||
do_eqp_test 12.$tn.6 $sql {/t4 USING INDEX t4a/}
|
||||
}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Check that affinities are taken into account when using stat4 data to
|
||||
# estimate the number of rows scanned by a rowid constraint.
|
||||
#
|
||||
drop_all_tables
|
||||
do_test 13.1 {
|
||||
execsql {
|
||||
CREATE TABLE t1(a, b, c);
|
||||
CREATE INDEX i1 ON t1(a);
|
||||
CREATE INDEX i2 ON t1(b, c);
|
||||
}
|
||||
for {set i 0} {$i<100} {incr i} {
|
||||
if {$i %2} {set a abc} else {set a def}
|
||||
execsql { INSERT INTO t1(rowid, a, b, c) VALUES($i, $a, $i, $i) }
|
||||
}
|
||||
execsql ANALYZE
|
||||
} {}
|
||||
do_eqp_test 13.2.1 {
|
||||
SELECT * FROM t1 WHERE a='abc' AND rowid<15 AND b<20
|
||||
} {/SEARCH TABLE t1 USING INDEX i1/}
|
||||
do_eqp_test 13.2.2 {
|
||||
SELECT * FROM t1 WHERE a='abc' AND rowid<'15' AND b<20
|
||||
} {/SEARCH TABLE t1 USING INDEX i1/}
|
||||
do_eqp_test 13.3.1 {
|
||||
SELECT * FROM t1 WHERE a='abc' AND rowid<100 AND b<20
|
||||
} {/SEARCH TABLE t1 USING INDEX i2/}
|
||||
do_eqp_test 13.3.2 {
|
||||
SELECT * FROM t1 WHERE a='abc' AND rowid<'100' AND b<20
|
||||
} {/SEARCH TABLE t1 USING INDEX i2/}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Check also that affinities are taken into account when using stat4 data
|
||||
# to estimate the number of rows scanned by any other constraint on a
|
||||
# column other than the leftmost.
|
||||
#
|
||||
drop_all_tables
|
||||
do_test 14.1 {
|
||||
execsql { CREATE TABLE t1(a, b INTEGER, c) }
|
||||
for {set i 0} {$i<100} {incr i} {
|
||||
set c [expr $i % 3]
|
||||
execsql { INSERT INTO t1 VALUES('ott', $i, $c) }
|
||||
}
|
||||
execsql {
|
||||
CREATE INDEX i1 ON t1(a, b);
|
||||
CREATE INDEX i2 ON t1(c);
|
||||
ANALYZE;
|
||||
}
|
||||
} {}
|
||||
do_eqp_test 13.2.1 {
|
||||
SELECT * FROM t1 WHERE a='ott' AND b<10 AND c=1
|
||||
} {/SEARCH TABLE t1 USING INDEX i1/}
|
||||
do_eqp_test 13.2.2 {
|
||||
SELECT * FROM t1 WHERE a='ott' AND b<'10' AND c=1
|
||||
} {/SEARCH TABLE t1 USING INDEX i1/}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# By default, 16 non-periodic samples are collected for the stat4 table.
|
||||
# The following tests attempt to verify that the most common keys are
|
||||
# being collected.
|
||||
#
|
||||
proc check_stat4 {tn} {
|
||||
db eval ANALYZE
|
||||
db eval {SELECT a, b, c, d FROM t1} {
|
||||
incr k($a)
|
||||
incr k([list $a $b])
|
||||
incr k([list $a $b $c])
|
||||
if { [info exists k([list $a $b $c $d])]==0 } { incr nRow }
|
||||
incr k([list $a $b $c $d])
|
||||
}
|
||||
|
||||
set L [list]
|
||||
foreach key [array names k] {
|
||||
lappend L [list $k($key) $key]
|
||||
}
|
||||
|
||||
set nSample $nRow
|
||||
if {$nSample>16} {set nSample 16}
|
||||
|
||||
set nThreshold [lindex [lsort -decr -integer -index 0 $L] [expr $nSample-1] 0]
|
||||
foreach key [array names k] {
|
||||
if {$k($key)>$nThreshold} {
|
||||
set expect($key) 1
|
||||
}
|
||||
if {$k($key)==$nThreshold} {
|
||||
set possible($key) 1
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
set nPossible [expr $nSample - [llength [array names expect]]]
|
||||
|
||||
#puts "EXPECT: [array names expect]"
|
||||
#puts "POSSIBLE($nPossible/[array size possible]): [array names possible]"
|
||||
#puts "HAVE: [db eval {SELECT test_decode(sample) FROM sqlite_stat4 WHERE idx='i1'}]"
|
||||
|
||||
db eval {SELECT test_decode(sample) AS s FROM sqlite_stat4 WHERE idx='i1'} {
|
||||
set seen 0
|
||||
for {set i 0} {$i<4} {incr i} {
|
||||
unset -nocomplain expect([lrange $s 0 $i])
|
||||
if {[info exists possible([lrange $s 0 $i])]} {
|
||||
set seen 1
|
||||
unset -nocomplain possible([lrange $s 0 $i])
|
||||
}
|
||||
}
|
||||
if {$seen} {incr nPossible -1}
|
||||
}
|
||||
if {$nPossible<0} {set nPossible 0}
|
||||
|
||||
set res [list [llength [array names expect]] $nPossible]
|
||||
uplevel [list do_test $tn [list set {} $res] {0 0}]
|
||||
}
|
||||
|
||||
drop_all_tables
|
||||
do_test 14.1.1 {
|
||||
execsql {
|
||||
CREATE TABLE t1(a,b,c,d);
|
||||
CREATE INDEX i1 ON t1(a,b,c,d);
|
||||
}
|
||||
for {set i 0} {$i < 160} {incr i} {
|
||||
execsql { INSERT INTO t1 VALUES($i,$i,$i,$i) }
|
||||
if {($i % 10)==0} { execsql { INSERT INTO t1 VALUES($i,$i,$i,$i) } }
|
||||
}
|
||||
} {}
|
||||
check_stat4 14.1.2
|
||||
|
||||
do_test 14.2.1 {
|
||||
execsql { DELETE FROM t1 }
|
||||
for {set i 0} {$i < 1600} {incr i} {
|
||||
execsql { INSERT INTO t1 VALUES($i/10,$i/17,$i/27,$i/37) }
|
||||
}
|
||||
} {}
|
||||
check_stat4 14.2.2
|
||||
|
||||
do_test 14.3.1 {
|
||||
for {set i 0} {$i < 10} {incr i} {
|
||||
execsql { INSERT INTO t1 VALUES($i*50,$i*50,$i*50,$i*50) }
|
||||
execsql { INSERT INTO t1 VALUES($i*50,$i*50,$i*50,$i*50) }
|
||||
execsql { INSERT INTO t1 VALUES($i*50,$i*50,$i*50,$i*50) }
|
||||
execsql { INSERT INTO t1 VALUES($i*50,$i*50,$i*50,$i*50) }
|
||||
execsql { INSERT INTO t1 VALUES($i*50,$i*50,$i*50,$i*50) }
|
||||
execsql { INSERT INTO t1 VALUES($i*50,$i*50,$i*50,$i*50) }
|
||||
execsql { INSERT INTO t1 VALUES($i*50,$i*50,$i*50,$i*50) }
|
||||
execsql { INSERT INTO t1 VALUES($i*50,$i*50,$i*50,$i*50) }
|
||||
execsql { INSERT INTO t1 VALUES($i*50,$i*50,$i*50,$i*50) }
|
||||
execsql { INSERT INTO t1 VALUES($i*50,$i*50,$i*50,$i*50) }
|
||||
}
|
||||
} {}
|
||||
check_stat4 14.3.2
|
||||
|
||||
do_test 14.4.1 {
|
||||
execsql {DELETE FROM t1}
|
||||
for {set i 1} {$i < 160} {incr i} {
|
||||
set b [expr $i % 10]
|
||||
if {$b==0 || $b==2} {set b 1}
|
||||
execsql { INSERT INTO t1 VALUES($i/10,$b,$i,$i) }
|
||||
}
|
||||
} {}
|
||||
check_stat4 14.4.2
|
||||
db func lrange lrange
|
||||
db func lindex lindex
|
||||
do_execsql_test 14.4.3 {
|
||||
SELECT lrange(test_decode(sample), 0, 1) AS s FROM sqlite_stat4
|
||||
WHERE lindex(s, 1)=='1' ORDER BY rowid
|
||||
} {
|
||||
{0 1} {1 1} {2 1} {3 1}
|
||||
{4 1} {5 1} {6 1} {7 1}
|
||||
{8 1} {9 1} {10 1} {11 1}
|
||||
{12 1} {13 1} {14 1} {15 1}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test that nothing untoward happens if the stat4 table contains entries
|
||||
# for indexes that do not exist. Or NULL values in the idx column.
|
||||
# Or NULL values in any of the other columns.
|
||||
#
|
||||
drop_all_tables
|
||||
do_execsql_test 15.1 {
|
||||
CREATE TABLE x1(a, b, UNIQUE(a, b));
|
||||
INSERT INTO x1 VALUES(1, 2);
|
||||
INSERT INTO x1 VALUES(3, 4);
|
||||
INSERT INTO x1 VALUES(5, 6);
|
||||
ANALYZE;
|
||||
INSERT INTO sqlite_stat4 VALUES(NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
}
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
do_execsql_test 15.2 { SELECT * FROM x1 } {1 2 3 4 5 6}
|
||||
|
||||
do_execsql_test 15.3 {
|
||||
INSERT INTO sqlite_stat4 VALUES(42, 42, 42, 42, 42, 42);
|
||||
}
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
do_execsql_test 15.4 { SELECT * FROM x1 } {1 2 3 4 5 6}
|
||||
|
||||
do_execsql_test 15.5 {
|
||||
UPDATE sqlite_stat1 SET stat = NULL;
|
||||
}
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
do_execsql_test 15.6 { SELECT * FROM x1 } {1 2 3 4 5 6}
|
||||
|
||||
do_execsql_test 15.7 {
|
||||
ANALYZE;
|
||||
UPDATE sqlite_stat1 SET tbl = 'no such tbl';
|
||||
}
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
do_execsql_test 15.8 { SELECT * FROM x1 } {1 2 3 4 5 6}
|
||||
|
||||
do_execsql_test 15.9 {
|
||||
ANALYZE;
|
||||
UPDATE sqlite_stat4 SET neq = NULL, nlt=NULL, ndlt=NULL;
|
||||
}
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
do_execsql_test 15.10 { SELECT * FROM x1 } {1 2 3 4 5 6}
|
||||
|
||||
# This is just for coverage....
|
||||
do_execsql_test 15.11 {
|
||||
ANALYZE;
|
||||
UPDATE sqlite_stat1 SET stat = stat || ' unordered';
|
||||
}
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
do_execsql_test 15.12 { SELECT * FROM x1 } {1 2 3 4 5 6}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test that allocations used for sqlite_stat4 samples are included in
|
||||
# the quantity returned by SQLITE_DBSTATUS_SCHEMA_USED.
|
||||
#
|
||||
set one [string repeat x 1000]
|
||||
set two [string repeat x 2000]
|
||||
do_test 16.1 {
|
||||
reset_db
|
||||
execsql {
|
||||
CREATE TABLE t1(a, UNIQUE(a));
|
||||
INSERT INTO t1 VALUES($one);
|
||||
ANALYZE;
|
||||
}
|
||||
set nByte [lindex [sqlite3_db_status db SCHEMA_USED 0] 1]
|
||||
|
||||
reset_db
|
||||
execsql {
|
||||
CREATE TABLE t1(a, UNIQUE(a));
|
||||
INSERT INTO t1 VALUES($two);
|
||||
ANALYZE;
|
||||
}
|
||||
set nByte2 [lindex [sqlite3_db_status db SCHEMA_USED 0] 1]
|
||||
|
||||
expr {$nByte2 > $nByte+900 && $nByte2 < $nByte+1050}
|
||||
} {1}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test that stat4 data may be used with partial indexes.
|
||||
#
|
||||
do_test 17.1 {
|
||||
reset_db
|
||||
execsql {
|
||||
CREATE TABLE t1(a, b, c, d);
|
||||
CREATE INDEX i1 ON t1(a, b) WHERE d IS NOT NULL;
|
||||
INSERT INTO t1 VALUES(-1, -1, -1, NULL);
|
||||
INSERT INTO t1 SELECT 2*a,2*b,2*c,d FROM t1;
|
||||
INSERT INTO t1 SELECT 2*a,2*b,2*c,d FROM t1;
|
||||
INSERT INTO t1 SELECT 2*a,2*b,2*c,d FROM t1;
|
||||
INSERT INTO t1 SELECT 2*a,2*b,2*c,d FROM t1;
|
||||
INSERT INTO t1 SELECT 2*a,2*b,2*c,d FROM t1;
|
||||
INSERT INTO t1 SELECT 2*a,2*b,2*c,d FROM t1;
|
||||
}
|
||||
|
||||
for {set i 0} {$i < 32} {incr i} {
|
||||
if {$i<8} {set b 0} else { set b $i }
|
||||
execsql { INSERT INTO t1 VALUES($i%2, $b, $i/2, 'abc') }
|
||||
}
|
||||
execsql {ANALYZE main.t1}
|
||||
} {}
|
||||
|
||||
do_catchsql_test 17.1.2 {
|
||||
ANALYZE temp.t1;
|
||||
} {1 {no such table: temp.t1}}
|
||||
|
||||
do_eqp_test 17.2 {
|
||||
SELECT * FROM t1 WHERE d IS NOT NULL AND a=0 AND b=10 AND c=10;
|
||||
} {/USING INDEX i1/}
|
||||
do_eqp_test 17.3 {
|
||||
SELECT * FROM t1 WHERE d IS NOT NULL AND a=0 AND b=0 AND c=10;
|
||||
} {/USING INDEX i1/}
|
||||
|
||||
do_execsql_test 17.4 {
|
||||
CREATE INDEX i2 ON t1(c);
|
||||
ANALYZE main.i2;
|
||||
}
|
||||
do_eqp_test 17.5 {
|
||||
SELECT * FROM t1 WHERE d IS NOT NULL AND a=0 AND b=10 AND c=10;
|
||||
} {/USING INDEX i1/}
|
||||
do_eqp_test 17.6 {
|
||||
SELECT * FROM t1 WHERE d IS NOT NULL AND a=0 AND b=0 AND c=10;
|
||||
} {/USING INDEX i2/}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
do_test 18.1 {
|
||||
reset_db
|
||||
execsql {
|
||||
CREATE TABLE t1(a, b);
|
||||
CREATE INDEX i1 ON t1(a, b);
|
||||
}
|
||||
for {set i 0} {$i < 9} {incr i} {
|
||||
execsql {
|
||||
INSERT INTO t1 VALUES($i, 0);
|
||||
INSERT INTO t1 VALUES($i, 0);
|
||||
INSERT INTO t1 VALUES($i, 0);
|
||||
INSERT INTO t1 VALUES($i, 0);
|
||||
INSERT INTO t1 VALUES($i, 0);
|
||||
INSERT INTO t1 VALUES($i, 0);
|
||||
INSERT INTO t1 VALUES($i, 0);
|
||||
INSERT INTO t1 VALUES($i, 0);
|
||||
INSERT INTO t1 VALUES($i, 0);
|
||||
INSERT INTO t1 VALUES($i, 0);
|
||||
INSERT INTO t1 VALUES($i, 0);
|
||||
INSERT INTO t1 VALUES($i, 0);
|
||||
INSERT INTO t1 VALUES($i, 0);
|
||||
INSERT INTO t1 VALUES($i, 0);
|
||||
INSERT INTO t1 VALUES($i, 0);
|
||||
}
|
||||
}
|
||||
execsql ANALYZE
|
||||
execsql { SELECT count(*) FROM sqlite_stat4 }
|
||||
} {9}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# For coverage.
|
||||
#
|
||||
ifcapable view {
|
||||
do_test 19.1 {
|
||||
reset_db
|
||||
execsql {
|
||||
CREATE TABLE t1(x, y);
|
||||
CREATE INDEX i1 ON t1(x, y);
|
||||
CREATE VIEW v1 AS SELECT * FROM t1;
|
||||
ANALYZE;
|
||||
}
|
||||
} {}
|
||||
}
|
||||
ifcapable auth {
|
||||
proc authproc {op args} {
|
||||
if {$op == "SQLITE_ANALYZE"} { return "SQLITE_DENY" }
|
||||
return "SQLITE_OK"
|
||||
}
|
||||
do_test 19.2 {
|
||||
reset_db
|
||||
db auth authproc
|
||||
execsql {
|
||||
CREATE TABLE t1(x, y);
|
||||
CREATE VIEW v1 AS SELECT * FROM t1;
|
||||
}
|
||||
catchsql ANALYZE
|
||||
} {1 {not authorized}}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
reset_db
|
||||
proc r {args} { expr rand() }
|
||||
db func r r
|
||||
db func lrange lrange
|
||||
do_test 20.1 {
|
||||
execsql {
|
||||
CREATE TABLE t1(a,b,c,d);
|
||||
CREATE INDEX i1 ON t1(a,b,c,d);
|
||||
}
|
||||
for {set i 0} {$i < 16} {incr i} {
|
||||
execsql {
|
||||
INSERT INTO t1 VALUES($i, r(), r(), r());
|
||||
INSERT INTO t1 VALUES($i, $i, r(), r());
|
||||
INSERT INTO t1 VALUES($i, $i, $i, r());
|
||||
INSERT INTO t1 VALUES($i, $i, $i, $i);
|
||||
INSERT INTO t1 VALUES($i, $i, $i, $i);
|
||||
INSERT INTO t1 VALUES($i, $i, $i, r());
|
||||
INSERT INTO t1 VALUES($i, $i, r(), r());
|
||||
INSERT INTO t1 VALUES($i, r(), r(), r());
|
||||
}
|
||||
}
|
||||
} {}
|
||||
do_execsql_test 20.2 { ANALYZE }
|
||||
for {set i 0} {$i<16} {incr i} {
|
||||
set val "$i $i $i $i"
|
||||
do_execsql_test 20.3.$i {
|
||||
SELECT count(*) FROM sqlite_stat4
|
||||
WHERE lrange(test_decode(sample), 0, 3)=$val
|
||||
} {1}
|
||||
}
|
||||
|
||||
finish_test
|
||||
@@ -0,0 +1,167 @@
|
||||
# 2013 August 3
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
# This file contains automated tests used to verify that the current build
|
||||
# (which must be either ENABLE_STAT3 or ENABLE_STAT4) works with both stat3
|
||||
# and stat4 data.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix analyzeA
|
||||
|
||||
ifcapable !stat4&&!stat3 {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
# Populate the stat3 table according to the current contents of the db
|
||||
#
|
||||
proc populate_stat3 {{bDropTable 1}} {
|
||||
# Open a second connection on database "test.db" and run ANALYZE. If this
|
||||
# is an ENABLE_STAT3 build, this is all that is required to create and
|
||||
# populate the sqlite_stat3 table.
|
||||
#
|
||||
sqlite3 db2 test.db
|
||||
execsql { ANALYZE }
|
||||
|
||||
# Now, if this is an ENABLE_STAT4 build, create and populate the
|
||||
# sqlite_stat3 table based on the stat4 data gathered by the ANALYZE
|
||||
# above. Then drop the sqlite_stat4 table.
|
||||
#
|
||||
ifcapable stat4 {
|
||||
db2 func lindex lindex
|
||||
execsql {
|
||||
PRAGMA writable_schema = on;
|
||||
CREATE TABLE sqlite_stat3(tbl,idx,neq,nlt,ndlt,sample);
|
||||
INSERT INTO sqlite_stat3
|
||||
SELECT DISTINCT tbl, idx,
|
||||
lindex(neq,0), lindex(nlt,0), lindex(ndlt,0), test_extract(sample, 0)
|
||||
FROM sqlite_stat4;
|
||||
} db2
|
||||
if {$bDropTable} { execsql {DROP TABLE sqlite_stat4} db2 }
|
||||
execsql { PRAGMA writable_schema = off }
|
||||
}
|
||||
|
||||
# Modify the database schema cookie to ensure that the other connection
|
||||
# reloads the schema.
|
||||
#
|
||||
execsql {
|
||||
CREATE TABLE obscure_tbl_nm(x);
|
||||
DROP TABLE obscure_tbl_nm;
|
||||
} db2
|
||||
db2 close
|
||||
}
|
||||
|
||||
# Populate the stat4 table according to the current contents of the db
|
||||
#
|
||||
proc populate_stat4 {{bDropTable 1}} {
|
||||
sqlite3 db2 test.db
|
||||
execsql { ANALYZE }
|
||||
|
||||
ifcapable stat3 {
|
||||
execsql {
|
||||
PRAGMA writable_schema = on;
|
||||
CREATE TABLE sqlite_stat4(tbl,idx,neq,nlt,ndlt,sample);
|
||||
INSERT INTO sqlite_stat4
|
||||
SELECT tbl, idx, neq, nlt, ndlt, sqlite_record(sample)
|
||||
FROM sqlite_stat3;
|
||||
} db2
|
||||
if {$bDropTable} { execsql {DROP TABLE sqlite_stat3} db2 }
|
||||
execsql { PRAGMA writable_schema = off }
|
||||
}
|
||||
|
||||
# Modify the database schema cookie to ensure that the other connection
|
||||
# reloads the schema.
|
||||
#
|
||||
execsql {
|
||||
CREATE TABLE obscure_tbl_nm(x);
|
||||
DROP TABLE obscure_tbl_nm;
|
||||
} db2
|
||||
db2 close
|
||||
}
|
||||
|
||||
# Populate the stat4 table according to the current contents of the db.
|
||||
# Leave deceptive data in the stat3 table. This data should be ignored
|
||||
# in favour of that from the stat4 table.
|
||||
#
|
||||
proc populate_both {} {
|
||||
ifcapable stat4 { populate_stat3 0 }
|
||||
ifcapable stat3 { populate_stat4 0 }
|
||||
|
||||
sqlite3 db2 test.db
|
||||
execsql {
|
||||
PRAGMA writable_schema = on;
|
||||
UPDATE sqlite_stat3 SET idx =
|
||||
CASE idx WHEN 't1b' THEN 't1c' ELSE 't1b'
|
||||
END;
|
||||
PRAGMA writable_schema = off;
|
||||
CREATE TABLE obscure_tbl_nm(x);
|
||||
DROP TABLE obscure_tbl_nm;
|
||||
} db2
|
||||
db2 close
|
||||
}
|
||||
|
||||
foreach {tn analyze_cmd} {
|
||||
1 populate_stat4
|
||||
2 populate_stat3
|
||||
3 populate_both
|
||||
} {
|
||||
reset_db
|
||||
do_test 1.$tn.1 {
|
||||
execsql { CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c) }
|
||||
for {set i 0} {$i < 100} {incr i} {
|
||||
set c [expr int(pow(1.1,$i)/100)]
|
||||
set b [expr 125 - int(pow(1.1,99-$i))/100]
|
||||
execsql {INSERT INTO t1 VALUES($i, $b, $c)}
|
||||
}
|
||||
} {}
|
||||
|
||||
execsql { CREATE INDEX t1b ON t1(b) }
|
||||
execsql { CREATE INDEX t1c ON t1(c) }
|
||||
$analyze_cmd
|
||||
|
||||
do_execsql_test 1.$tn.2.1 { SELECT count(*) FROM t1 WHERE b=31 } 1
|
||||
do_execsql_test 1.$tn.2.2 { SELECT count(*) FROM t1 WHERE c=0 } 49
|
||||
do_execsql_test 1.$tn.2.3 { SELECT count(*) FROM t1 WHERE b=125 } 49
|
||||
do_execsql_test 1.$tn.2.4 { SELECT count(*) FROM t1 WHERE c=16 } 1
|
||||
|
||||
do_eqp_test 1.$tn.2.5 {
|
||||
SELECT * FROM t1 WHERE b = 31 AND c = 0;
|
||||
} {0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b=?)}}
|
||||
do_eqp_test 1.$tn.2.6 {
|
||||
SELECT * FROM t1 WHERE b = 125 AND c = 16;
|
||||
} {0 0 0 {SEARCH TABLE t1 USING INDEX t1c (c=?)}}
|
||||
|
||||
do_execsql_test 1.$tn.3.1 {
|
||||
SELECT count(*) FROM t1 WHERE b BETWEEN 0 AND 50
|
||||
} {6}
|
||||
do_execsql_test 1.$tn.3.2 {
|
||||
SELECT count(*) FROM t1 WHERE c BETWEEN 0 AND 50
|
||||
} {90}
|
||||
do_execsql_test 1.$tn.3.3 {
|
||||
SELECT count(*) FROM t1 WHERE b BETWEEN 75 AND 125
|
||||
} {90}
|
||||
do_execsql_test 1.$tn.3.4 {
|
||||
SELECT count(*) FROM t1 WHERE c BETWEEN 75 AND 125
|
||||
} {6}
|
||||
|
||||
do_eqp_test 1.$tn.3.5 {
|
||||
SELECT * FROM t1 WHERE b BETWEEN 0 AND 50 AND c BETWEEN 0 AND 50
|
||||
} {0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b>? AND b<?)}}
|
||||
|
||||
do_eqp_test 1.$tn.3.6 {
|
||||
SELECT * FROM t1 WHERE b BETWEEN 75 AND 125 AND c BETWEEN 75 AND 125
|
||||
} {0 0 0 {SEARCH TABLE t1 USING INDEX t1c (c>? AND c<?)}}
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -0,0 +1,683 @@
|
||||
# 2013 August 3
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
# This file contains automated tests used to verify that the sqlite_stat3
|
||||
# functionality is working. The tests in this file are based on a subset
|
||||
# of the sqlite_stat4 tests in analyze9.test.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix analyzeB
|
||||
|
||||
ifcapable !stat3 {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE TABLE t1(a TEXT, b TEXT);
|
||||
INSERT INTO t1 VALUES('(0)', '(0)');
|
||||
INSERT INTO t1 VALUES('(1)', '(1)');
|
||||
INSERT INTO t1 VALUES('(2)', '(2)');
|
||||
INSERT INTO t1 VALUES('(3)', '(3)');
|
||||
INSERT INTO t1 VALUES('(4)', '(4)');
|
||||
CREATE INDEX i1 ON t1(a, b);
|
||||
} {}
|
||||
|
||||
|
||||
do_execsql_test 1.1 {
|
||||
ANALYZE;
|
||||
} {}
|
||||
|
||||
do_execsql_test 1.2 {
|
||||
SELECT tbl,idx,nEq,nLt,nDLt,quote(sample) FROM sqlite_stat3;
|
||||
} {
|
||||
t1 i1 1 0 0 '(0)'
|
||||
t1 i1 1 1 1 '(1)'
|
||||
t1 i1 1 2 2 '(2)'
|
||||
t1 i1 1 3 3 '(3)'
|
||||
t1 i1 1 4 4 '(4)'
|
||||
}
|
||||
|
||||
if {[permutation] != "utf16"} {
|
||||
do_execsql_test 1.3 {
|
||||
SELECT tbl,idx,nEq,nLt,nDLt,quote(sample) FROM sqlite_stat3;
|
||||
} {
|
||||
t1 i1 1 0 0 '(0)'
|
||||
t1 i1 1 1 1 '(1)'
|
||||
t1 i1 1 2 2 '(2)'
|
||||
t1 i1 1 3 3 '(3)'
|
||||
t1 i1 1 4 4 '(4)'
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# This is really just to test SQL user function "test_decode".
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 2.1 {
|
||||
CREATE TABLE t1(a, b, c);
|
||||
INSERT INTO t1(a) VALUES('some text');
|
||||
INSERT INTO t1(a) VALUES(14);
|
||||
INSERT INTO t1(a) VALUES(NULL);
|
||||
INSERT INTO t1(a) VALUES(22.0);
|
||||
INSERT INTO t1(a) VALUES(x'656667');
|
||||
CREATE INDEX i1 ON t1(a, b, c);
|
||||
ANALYZE;
|
||||
SELECT quote(sample) FROM sqlite_stat3;
|
||||
} {
|
||||
NULL 14 22.0 {'some text'} X'656667'
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 3.1 {
|
||||
CREATE TABLE t2(a, b);
|
||||
CREATE INDEX i2 ON t2(a, b);
|
||||
BEGIN;
|
||||
}
|
||||
|
||||
do_test 3.2 {
|
||||
for {set i 0} {$i < 1000} {incr i} {
|
||||
set a [expr $i / 10]
|
||||
set b [expr int(rand() * 15.0)]
|
||||
execsql { INSERT INTO t2 VALUES($a, $b) }
|
||||
}
|
||||
execsql COMMIT
|
||||
} {}
|
||||
|
||||
db func lindex lindex
|
||||
|
||||
# Each value of "a" occurs exactly 10 times in the table.
|
||||
#
|
||||
do_execsql_test 3.3.1 {
|
||||
SELECT count(*) FROM t2 GROUP BY a;
|
||||
} [lrange [string repeat "10 " 100] 0 99]
|
||||
|
||||
# The first element in the "nEq" list of all samples should therefore be 10.
|
||||
#
|
||||
do_execsql_test 3.3.2 {
|
||||
ANALYZE;
|
||||
SELECT nEq FROM sqlite_stat3;
|
||||
} [lrange [string repeat "10 " 100] 0 23]
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
do_execsql_test 3.4 {
|
||||
DROP TABLE IF EXISTS t1;
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
|
||||
INSERT INTO t1 VALUES(1, 1, 'one-a');
|
||||
INSERT INTO t1 VALUES(11, 1, 'one-b');
|
||||
INSERT INTO t1 VALUES(21, 1, 'one-c');
|
||||
INSERT INTO t1 VALUES(31, 1, 'one-d');
|
||||
INSERT INTO t1 VALUES(41, 1, 'one-e');
|
||||
INSERT INTO t1 VALUES(51, 1, 'one-f');
|
||||
INSERT INTO t1 VALUES(61, 1, 'one-g');
|
||||
INSERT INTO t1 VALUES(71, 1, 'one-h');
|
||||
INSERT INTO t1 VALUES(81, 1, 'one-i');
|
||||
INSERT INTO t1 VALUES(91, 1, 'one-j');
|
||||
INSERT INTO t1 SELECT a+1,2,'two' || substr(c,4) FROM t1;
|
||||
INSERT INTO t1 SELECT a+2,3,'three'||substr(c,4) FROM t1 WHERE c GLOB 'one-*';
|
||||
INSERT INTO t1 SELECT a+3,4,'four'||substr(c,4) FROM t1 WHERE c GLOB 'one-*';
|
||||
INSERT INTO t1 SELECT a+4,5,'five'||substr(c,4) FROM t1 WHERE c GLOB 'one-*';
|
||||
INSERT INTO t1 SELECT a+5,6,'six'||substr(c,4) FROM t1 WHERE c GLOB 'one-*';
|
||||
CREATE INDEX t1b ON t1(b);
|
||||
ANALYZE;
|
||||
SELECT c FROM t1 WHERE b=3 AND a BETWEEN 30 AND 60;
|
||||
} {three-d three-e three-f}
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# These tests verify that the sample selection for stat3 appears to be
|
||||
# working as designed.
|
||||
#
|
||||
|
||||
reset_db
|
||||
db func lindex lindex
|
||||
db func lrange lrange
|
||||
|
||||
do_execsql_test 4.0 {
|
||||
DROP TABLE IF EXISTS t1;
|
||||
CREATE TABLE t1(a, b, c);
|
||||
CREATE INDEX i1 ON t1(c, b, a);
|
||||
}
|
||||
|
||||
|
||||
proc insert_filler_rows_n {iStart args} {
|
||||
set A(-ncopy) 1
|
||||
set A(-nval) 1
|
||||
|
||||
foreach {k v} $args {
|
||||
if {[info exists A($k)]==0} { error "no such option: $k" }
|
||||
set A($k) $v
|
||||
}
|
||||
if {[llength $args] % 2} {
|
||||
error "option requires an argument: [lindex $args end]"
|
||||
}
|
||||
|
||||
for {set i 0} {$i < $A(-nval)} {incr i} {
|
||||
set iVal [expr $iStart+$i]
|
||||
for {set j 0} {$j < $A(-ncopy)} {incr j} {
|
||||
execsql { INSERT INTO t1 VALUES($iVal, $iVal, $iVal) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
do_test 4.1 {
|
||||
execsql { BEGIN }
|
||||
insert_filler_rows_n 0 -ncopy 10 -nval 19
|
||||
insert_filler_rows_n 20 -ncopy 1 -nval 100
|
||||
|
||||
execsql {
|
||||
INSERT INTO t1(c, b, a) VALUES(200, 1, 'a');
|
||||
INSERT INTO t1(c, b, a) VALUES(200, 1, 'b');
|
||||
INSERT INTO t1(c, b, a) VALUES(200, 1, 'c');
|
||||
|
||||
INSERT INTO t1(c, b, a) VALUES(200, 2, 'e');
|
||||
INSERT INTO t1(c, b, a) VALUES(200, 2, 'f');
|
||||
|
||||
INSERT INTO t1(c, b, a) VALUES(201, 3, 'g');
|
||||
INSERT INTO t1(c, b, a) VALUES(201, 4, 'h');
|
||||
|
||||
ANALYZE;
|
||||
SELECT count(*) FROM sqlite_stat3;
|
||||
SELECT count(*) FROM t1;
|
||||
}
|
||||
} {24 297}
|
||||
|
||||
do_execsql_test 4.2 {
|
||||
SELECT neq, nlt, ndlt, sample FROM sqlite_stat3 ORDER BY rowid LIMIT 16;
|
||||
} {
|
||||
10 0 0 0
|
||||
10 10 1 1
|
||||
10 20 2 2
|
||||
10 30 3 3
|
||||
10 40 4 4
|
||||
10 50 5 5
|
||||
10 60 6 6
|
||||
10 70 7 7
|
||||
10 80 8 8
|
||||
10 90 9 9
|
||||
10 100 10 10
|
||||
10 110 11 11
|
||||
10 120 12 12
|
||||
10 130 13 13
|
||||
10 140 14 14
|
||||
10 150 15 15
|
||||
}
|
||||
|
||||
do_execsql_test 4.3 {
|
||||
SELECT neq, nlt, ndlt, sample FROM sqlite_stat3
|
||||
ORDER BY rowid DESC LIMIT 2;
|
||||
} {
|
||||
2 295 120 201
|
||||
5 290 119 200
|
||||
}
|
||||
|
||||
do_execsql_test 4.4 { SELECT count(DISTINCT c) FROM t1 WHERE c<201 } 120
|
||||
do_execsql_test 4.5 { SELECT count(DISTINCT c) FROM t1 WHERE c<200 } 119
|
||||
|
||||
reset_db
|
||||
do_test 4.7 {
|
||||
execsql {
|
||||
BEGIN;
|
||||
CREATE TABLE t1(o,t INTEGER PRIMARY KEY);
|
||||
CREATE INDEX i1 ON t1(o);
|
||||
}
|
||||
for {set i 0} {$i<10000} {incr i [expr (($i<1000)?1:10)]} {
|
||||
execsql { INSERT INTO t1 VALUES('x', $i) }
|
||||
}
|
||||
execsql {
|
||||
COMMIT;
|
||||
ANALYZE;
|
||||
SELECT count(*) FROM sqlite_stat3;
|
||||
}
|
||||
} {1}
|
||||
do_execsql_test 4.8 {
|
||||
SELECT sample FROM sqlite_stat3;
|
||||
} {x}
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# The following would cause a crash at one point.
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 5.1 {
|
||||
PRAGMA encoding = 'utf-16';
|
||||
CREATE TABLE t0(v);
|
||||
ANALYZE;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# This was also crashing (corrupt sqlite_stat3 table).
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 6.1 {
|
||||
CREATE TABLE t1(a, b);
|
||||
CREATE INDEX i1 ON t1(a);
|
||||
CREATE INDEX i2 ON t1(b);
|
||||
INSERT INTO t1 VALUES(1, 1);
|
||||
INSERT INTO t1 VALUES(2, 2);
|
||||
INSERT INTO t1 VALUES(3, 3);
|
||||
INSERT INTO t1 VALUES(4, 4);
|
||||
INSERT INTO t1 VALUES(5, 5);
|
||||
ANALYZE;
|
||||
PRAGMA writable_schema = 1;
|
||||
CREATE TEMP TABLE x1 AS
|
||||
SELECT tbl,idx,neq,nlt,ndlt,sample FROM sqlite_stat3
|
||||
ORDER BY (rowid%5), rowid;
|
||||
DELETE FROM sqlite_stat3;
|
||||
INSERT INTO sqlite_stat3 SELECT * FROM x1;
|
||||
PRAGMA writable_schema = 0;
|
||||
ANALYZE sqlite_master;
|
||||
}
|
||||
do_execsql_test 6.2 {
|
||||
SELECT * FROM t1 WHERE a = 'abc';
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# The following tests experiment with adding corrupted records to the
|
||||
# 'sample' column of the sqlite_stat3 table.
|
||||
#
|
||||
reset_db
|
||||
sqlite3_db_config_lookaside db 0 0 0
|
||||
|
||||
do_execsql_test 7.1 {
|
||||
CREATE TABLE t1(a, b);
|
||||
CREATE INDEX i1 ON t1(a, b);
|
||||
INSERT INTO t1 VALUES(1, 1);
|
||||
INSERT INTO t1 VALUES(2, 2);
|
||||
INSERT INTO t1 VALUES(3, 3);
|
||||
INSERT INTO t1 VALUES(4, 4);
|
||||
INSERT INTO t1 VALUES(5, 5);
|
||||
ANALYZE;
|
||||
UPDATE sqlite_stat3 SET sample = X'' WHERE rowid = 1;
|
||||
ANALYZE sqlite_master;
|
||||
}
|
||||
|
||||
do_execsql_test 7.2 {
|
||||
UPDATE sqlite_stat3 SET sample = X'FFFF';
|
||||
ANALYZE sqlite_master;
|
||||
SELECT * FROM t1 WHERE a = 1;
|
||||
} {1 1}
|
||||
|
||||
do_execsql_test 7.3 {
|
||||
ANALYZE;
|
||||
UPDATE sqlite_stat3 SET neq = '0 0 0';
|
||||
ANALYZE sqlite_master;
|
||||
SELECT * FROM t1 WHERE a = 1;
|
||||
} {1 1}
|
||||
|
||||
do_execsql_test 7.4 {
|
||||
ANALYZE;
|
||||
UPDATE sqlite_stat3 SET ndlt = '0 0 0';
|
||||
ANALYZE sqlite_master;
|
||||
SELECT * FROM t1 WHERE a = 3;
|
||||
} {3 3}
|
||||
|
||||
do_execsql_test 7.5 {
|
||||
ANALYZE;
|
||||
UPDATE sqlite_stat3 SET nlt = '0 0 0';
|
||||
ANALYZE sqlite_master;
|
||||
SELECT * FROM t1 WHERE a = 5;
|
||||
} {5 5}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 8.1 {
|
||||
CREATE TABLE t1(x TEXT);
|
||||
CREATE INDEX i1 ON t1(x);
|
||||
INSERT INTO t1 VALUES('1');
|
||||
INSERT INTO t1 VALUES('2');
|
||||
INSERT INTO t1 VALUES('3');
|
||||
INSERT INTO t1 VALUES('4');
|
||||
ANALYZE;
|
||||
}
|
||||
do_execsql_test 8.2 {
|
||||
SELECT * FROM t1 WHERE x = 3;
|
||||
} {3}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 9.1 {
|
||||
CREATE TABLE t1(a, b, c, d, e);
|
||||
CREATE INDEX i1 ON t1(a, b, c, d);
|
||||
CREATE INDEX i2 ON t1(e);
|
||||
}
|
||||
do_test 9.2 {
|
||||
execsql BEGIN;
|
||||
for {set i 0} {$i < 100} {incr i} {
|
||||
execsql "INSERT INTO t1 VALUES('x', 'y', 'z', $i, [expr $i/2])"
|
||||
}
|
||||
for {set i 0} {$i < 20} {incr i} {
|
||||
execsql "INSERT INTO t1 VALUES('x', 'y', 'z', 101, $i)"
|
||||
}
|
||||
for {set i 102} {$i < 200} {incr i} {
|
||||
execsql "INSERT INTO t1 VALUES('x', 'y', 'z', $i, [expr $i/2])"
|
||||
}
|
||||
execsql COMMIT
|
||||
execsql ANALYZE
|
||||
} {}
|
||||
|
||||
do_eqp_test 9.3.1 {
|
||||
SELECT * FROM t1 WHERE a='x' AND b='y' AND c='z' AND d=101 AND e=5;
|
||||
} {/t1 USING INDEX i1/}
|
||||
do_eqp_test 9.3.2 {
|
||||
SELECT * FROM t1 WHERE a='x' AND b='y' AND c='z' AND d=99 AND e=5;
|
||||
} {/t1 USING INDEX i1/}
|
||||
|
||||
set value_d [expr 101]
|
||||
do_eqp_test 9.4.1 {
|
||||
SELECT * FROM t1 WHERE a='x' AND b='y' AND c='z' AND d=$value_d AND e=5
|
||||
} {/t1 USING INDEX i1/}
|
||||
set value_d [expr 99]
|
||||
do_eqp_test 9.4.2 {
|
||||
SELECT * FROM t1 WHERE a='x' AND b='y' AND c='z' AND d=$value_d AND e=5
|
||||
} {/t1 USING INDEX i1/}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Check that the planner takes stat3 data into account when considering
|
||||
# "IS NULL" and "IS NOT NULL" constraints.
|
||||
#
|
||||
do_execsql_test 10.1.1 {
|
||||
DROP TABLE IF EXISTS t3;
|
||||
CREATE TABLE t3(a, b);
|
||||
CREATE INDEX t3a ON t3(a);
|
||||
CREATE INDEX t3b ON t3(b);
|
||||
}
|
||||
do_test 10.1.2 {
|
||||
for {set i 1} {$i < 100} {incr i} {
|
||||
if {$i>90} { set a $i } else { set a NULL }
|
||||
set b [expr $i % 5]
|
||||
execsql "INSERT INTO t3 VALUES($a, $b)"
|
||||
}
|
||||
execsql ANALYZE
|
||||
} {}
|
||||
do_eqp_test 10.1.3 {
|
||||
SELECT * FROM t3 WHERE a IS NULL AND b = 2
|
||||
} {/t3 USING INDEX t3b/}
|
||||
do_eqp_test 10.1.4 {
|
||||
SELECT * FROM t3 WHERE a IS NOT NULL AND b = 2
|
||||
} {/t3 USING INDEX t3a/}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Check that stat3 data is used correctly with non-default collation
|
||||
# sequences.
|
||||
#
|
||||
foreach {tn schema} {
|
||||
1 {
|
||||
CREATE TABLE t4(a COLLATE nocase, b);
|
||||
CREATE INDEX t4a ON t4(a);
|
||||
CREATE INDEX t4b ON t4(b);
|
||||
}
|
||||
2 {
|
||||
CREATE TABLE t4(a, b);
|
||||
CREATE INDEX t4a ON t4(a COLLATE nocase);
|
||||
CREATE INDEX t4b ON t4(b);
|
||||
}
|
||||
} {
|
||||
drop_all_tables
|
||||
do_test 11.$tn.1 { execsql $schema } {}
|
||||
|
||||
do_test 11.$tn.2 {
|
||||
for {set i 0} {$i < 100} {incr i} {
|
||||
if { ($i % 10)==0 } { set a ABC } else { set a DEF }
|
||||
set b [expr $i % 5]
|
||||
execsql { INSERT INTO t4 VALUES($a, $b) }
|
||||
}
|
||||
execsql ANALYZE
|
||||
} {}
|
||||
|
||||
do_eqp_test 11.$tn.3 {
|
||||
SELECT * FROM t4 WHERE a = 'def' AND b = 3;
|
||||
} {/t4 USING INDEX t4b/}
|
||||
|
||||
if {$tn==1} {
|
||||
set sql "SELECT * FROM t4 WHERE a = 'abc' AND b = 3;"
|
||||
do_eqp_test 11.$tn.4 $sql {/t4 USING INDEX t4a/}
|
||||
} else {
|
||||
|
||||
set sql "SELECT * FROM t4 WHERE a = 'abc' COLLATE nocase AND b = 3;"
|
||||
do_eqp_test 11.$tn.5 $sql {/t4 USING INDEX t4a/}
|
||||
|
||||
set sql "SELECT * FROM t4 WHERE a COLLATE nocase = 'abc' AND b = 3;"
|
||||
do_eqp_test 11.$tn.6 $sql {/t4 USING INDEX t4a/}
|
||||
}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test that nothing untoward happens if the stat3 table contains entries
|
||||
# for indexes that do not exist. Or NULL values in the idx column.
|
||||
# Or NULL values in any of the other columns.
|
||||
#
|
||||
drop_all_tables
|
||||
do_execsql_test 15.1 {
|
||||
CREATE TABLE x1(a, b, UNIQUE(a, b));
|
||||
INSERT INTO x1 VALUES(1, 2);
|
||||
INSERT INTO x1 VALUES(3, 4);
|
||||
INSERT INTO x1 VALUES(5, 6);
|
||||
ANALYZE;
|
||||
INSERT INTO sqlite_stat3 VALUES(NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
}
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
do_execsql_test 15.2 { SELECT * FROM x1 } {1 2 3 4 5 6}
|
||||
|
||||
do_execsql_test 15.3 {
|
||||
INSERT INTO sqlite_stat3 VALUES(42, 42, 42, 42, 42, 42);
|
||||
}
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
do_execsql_test 15.4 { SELECT * FROM x1 } {1 2 3 4 5 6}
|
||||
|
||||
do_execsql_test 15.5 {
|
||||
UPDATE sqlite_stat1 SET stat = NULL;
|
||||
}
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
do_execsql_test 15.6 { SELECT * FROM x1 } {1 2 3 4 5 6}
|
||||
|
||||
do_execsql_test 15.7 {
|
||||
ANALYZE;
|
||||
UPDATE sqlite_stat1 SET tbl = 'no such tbl';
|
||||
}
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
do_execsql_test 15.8 { SELECT * FROM x1 } {1 2 3 4 5 6}
|
||||
|
||||
do_execsql_test 15.9 {
|
||||
ANALYZE;
|
||||
UPDATE sqlite_stat3 SET neq = NULL, nlt=NULL, ndlt=NULL;
|
||||
}
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
do_execsql_test 15.10 { SELECT * FROM x1 } {1 2 3 4 5 6}
|
||||
|
||||
# This is just for coverage....
|
||||
do_execsql_test 15.11 {
|
||||
ANALYZE;
|
||||
UPDATE sqlite_stat1 SET stat = stat || ' unordered';
|
||||
}
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
do_execsql_test 15.12 { SELECT * FROM x1 } {1 2 3 4 5 6}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test that allocations used for sqlite_stat3 samples are included in
|
||||
# the quantity returned by SQLITE_DBSTATUS_SCHEMA_USED.
|
||||
#
|
||||
set one [string repeat x 1000]
|
||||
set two [string repeat x 2000]
|
||||
do_test 16.1 {
|
||||
reset_db
|
||||
execsql {
|
||||
CREATE TABLE t1(a, UNIQUE(a));
|
||||
INSERT INTO t1 VALUES($one);
|
||||
ANALYZE;
|
||||
}
|
||||
set nByte [lindex [sqlite3_db_status db SCHEMA_USED 0] 1]
|
||||
|
||||
reset_db
|
||||
execsql {
|
||||
CREATE TABLE t1(a, UNIQUE(a));
|
||||
INSERT INTO t1 VALUES($two);
|
||||
ANALYZE;
|
||||
}
|
||||
set nByte2 [lindex [sqlite3_db_status db SCHEMA_USED 0] 1]
|
||||
|
||||
expr {$nByte2 > $nByte+950 && $nByte2 < $nByte+1050}
|
||||
} {1}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test that stat3 data may be used with partial indexes.
|
||||
#
|
||||
do_test 17.1 {
|
||||
reset_db
|
||||
execsql {
|
||||
CREATE TABLE t1(a, b, c, d);
|
||||
CREATE INDEX i1 ON t1(a, b) WHERE d IS NOT NULL;
|
||||
INSERT INTO t1 VALUES(-1, -1, -1, NULL);
|
||||
INSERT INTO t1 SELECT 2*a,2*b,2*c,d FROM t1;
|
||||
INSERT INTO t1 SELECT 2*a,2*b,2*c,d FROM t1;
|
||||
INSERT INTO t1 SELECT 2*a,2*b,2*c,d FROM t1;
|
||||
INSERT INTO t1 SELECT 2*a,2*b,2*c,d FROM t1;
|
||||
INSERT INTO t1 SELECT 2*a,2*b,2*c,d FROM t1;
|
||||
INSERT INTO t1 SELECT 2*a,2*b,2*c,d FROM t1;
|
||||
}
|
||||
|
||||
for {set i 0} {$i < 32} {incr i} {
|
||||
execsql { INSERT INTO t1 VALUES($i%2, $b, $i/2, 'abc') }
|
||||
}
|
||||
execsql {ANALYZE main.t1}
|
||||
} {}
|
||||
|
||||
do_catchsql_test 17.1.2 {
|
||||
ANALYZE temp.t1;
|
||||
} {1 {no such table: temp.t1}}
|
||||
|
||||
do_eqp_test 17.2 {
|
||||
SELECT * FROM t1 WHERE d IS NOT NULL AND a=0;
|
||||
} {/USING INDEX i1/}
|
||||
do_eqp_test 17.3 {
|
||||
SELECT * FROM t1 WHERE d IS NOT NULL AND a=0;
|
||||
} {/USING INDEX i1/}
|
||||
|
||||
do_execsql_test 17.4 {
|
||||
CREATE INDEX i2 ON t1(c) WHERE d IS NOT NULL;
|
||||
ANALYZE main.i2;
|
||||
}
|
||||
do_eqp_test 17.5 {
|
||||
SELECT * FROM t1 WHERE d IS NOT NULL AND a=0;
|
||||
} {/USING INDEX i1/}
|
||||
do_eqp_test 17.6 {
|
||||
SELECT * FROM t1 WHERE d IS NOT NULL AND a=0 AND b=0 AND c=10;
|
||||
} {/USING INDEX i2/}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
do_test 18.1 {
|
||||
reset_db
|
||||
execsql {
|
||||
CREATE TABLE t1(a, b);
|
||||
CREATE INDEX i1 ON t1(a, b);
|
||||
}
|
||||
for {set i 0} {$i < 9} {incr i} {
|
||||
execsql {
|
||||
INSERT INTO t1 VALUES($i, 0);
|
||||
INSERT INTO t1 VALUES($i, 0);
|
||||
INSERT INTO t1 VALUES($i, 0);
|
||||
INSERT INTO t1 VALUES($i, 0);
|
||||
INSERT INTO t1 VALUES($i, 0);
|
||||
INSERT INTO t1 VALUES($i, 0);
|
||||
INSERT INTO t1 VALUES($i, 0);
|
||||
INSERT INTO t1 VALUES($i, 0);
|
||||
INSERT INTO t1 VALUES($i, 0);
|
||||
INSERT INTO t1 VALUES($i, 0);
|
||||
INSERT INTO t1 VALUES($i, 0);
|
||||
INSERT INTO t1 VALUES($i, 0);
|
||||
INSERT INTO t1 VALUES($i, 0);
|
||||
INSERT INTO t1 VALUES($i, 0);
|
||||
INSERT INTO t1 VALUES($i, 0);
|
||||
}
|
||||
}
|
||||
execsql ANALYZE
|
||||
execsql { SELECT count(*) FROM sqlite_stat3 }
|
||||
} {9}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# For coverage.
|
||||
#
|
||||
ifcapable view {
|
||||
do_test 19.1 {
|
||||
reset_db
|
||||
execsql {
|
||||
CREATE TABLE t1(x, y);
|
||||
CREATE INDEX i1 ON t1(x, y);
|
||||
CREATE VIEW v1 AS SELECT * FROM t1;
|
||||
ANALYZE;
|
||||
}
|
||||
} {}
|
||||
}
|
||||
ifcapable auth {
|
||||
proc authproc {op args} {
|
||||
if {$op == "SQLITE_ANALYZE"} { return "SQLITE_DENY" }
|
||||
return "SQLITE_OK"
|
||||
}
|
||||
do_test 19.2 {
|
||||
reset_db
|
||||
db auth authproc
|
||||
execsql {
|
||||
CREATE TABLE t1(x, y);
|
||||
CREATE VIEW v1 AS SELECT * FROM t1;
|
||||
}
|
||||
catchsql ANALYZE
|
||||
} {1 {not authorized}}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
reset_db
|
||||
proc r {args} { expr rand() }
|
||||
db func r r
|
||||
db func lrange lrange
|
||||
do_test 20.1 {
|
||||
execsql {
|
||||
CREATE TABLE t1(a,b,c,d);
|
||||
CREATE INDEX i1 ON t1(a,b,c,d);
|
||||
}
|
||||
for {set i 0} {$i < 16} {incr i} {
|
||||
execsql {
|
||||
INSERT INTO t1 VALUES($i, r(), r(), r());
|
||||
INSERT INTO t1 VALUES($i, $i, r(), r());
|
||||
INSERT INTO t1 VALUES($i, $i, $i, r());
|
||||
INSERT INTO t1 VALUES($i, $i, $i, $i);
|
||||
INSERT INTO t1 VALUES($i, $i, $i, $i);
|
||||
INSERT INTO t1 VALUES($i, $i, $i, r());
|
||||
INSERT INTO t1 VALUES($i, $i, r(), r());
|
||||
INSERT INTO t1 VALUES($i, r(), r(), r());
|
||||
}
|
||||
}
|
||||
} {}
|
||||
do_execsql_test 20.2 { ANALYZE }
|
||||
for {set i 0} {$i<16} {incr i} {
|
||||
set val $i
|
||||
do_execsql_test 20.3.$i {
|
||||
SELECT count(*) FROM sqlite_stat3 WHERE sample=$val
|
||||
} {1}
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
+8
-4
@@ -2325,10 +2325,14 @@ ifcapable compound&&subquery {
|
||||
}
|
||||
}
|
||||
}
|
||||
ifcapable stat3 {
|
||||
set stat3 "sqlite_stat3 "
|
||||
ifcapable stat4 {
|
||||
set stat4 "sqlite_stat4 "
|
||||
} else {
|
||||
set stat3 ""
|
||||
ifcapable stat3 {
|
||||
set stat4 "sqlite_stat3 "
|
||||
} else {
|
||||
set stat4 ""
|
||||
}
|
||||
}
|
||||
do_test auth-5.2 {
|
||||
execsql {
|
||||
@@ -2337,7 +2341,7 @@ ifcapable compound&&subquery {
|
||||
WHERE type='table'
|
||||
ORDER BY name
|
||||
}
|
||||
} "sqlite_stat1 ${stat3}t1 t2 t3 t4"
|
||||
} "sqlite_stat1 ${stat4}t1 t2 t3 t4"
|
||||
}
|
||||
|
||||
# Ticket #3944
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
set ::testprefix collate2
|
||||
|
||||
#
|
||||
# Tests are organised as follows:
|
||||
#
|
||||
@@ -693,4 +695,30 @@ do_test collate2-5.5 {
|
||||
}
|
||||
} {aa aa}
|
||||
|
||||
do_execsql_test 6.1 {
|
||||
CREATE TABLE t1(x);
|
||||
INSERT INTO t1 VALUES('b');
|
||||
INSERT INTO t1 VALUES('B');
|
||||
}
|
||||
do_execsql_test 6.2 {
|
||||
SELECT * FROM t1 WHERE x COLLATE nocase BETWEEN 'a' AND 'c';
|
||||
} {b B}
|
||||
do_execsql_test 6.3 {
|
||||
SELECT * FROM t1 WHERE x BETWEEN 'a' COLLATE nocase AND 'c' COLLATE nocase;
|
||||
} {b B}
|
||||
do_execsql_test 6.4 {
|
||||
SELECT * FROM t1
|
||||
WHERE x COLLATE nocase BETWEEN 'a' COLLATE nocase AND 'c' COLLATE nocase;
|
||||
} {b B}
|
||||
do_execsql_test 6.5 {
|
||||
SELECT * FROM t1 WHERE +x COLLATE nocase BETWEEN 'a' AND 'c';
|
||||
} {b B}
|
||||
do_execsql_test 6.6 {
|
||||
SELECT * FROM t1 WHERE +x BETWEEN 'a' COLLATE nocase AND 'c' COLLATE nocase;
|
||||
} {b B}
|
||||
do_execsql_test 6.7 {
|
||||
SELECT * FROM t1
|
||||
WHERE +x COLLATE nocase BETWEEN 'a' COLLATE nocase AND 'c' COLLATE nocase;
|
||||
} {b B}
|
||||
|
||||
finish_test
|
||||
|
||||
+4
-2
@@ -31,9 +31,11 @@ do_execsql_test 1.1 {
|
||||
CREATE INDEX t1abc ON t1(a,b,c);
|
||||
}
|
||||
|
||||
set idxroot [db one {SELECT rootpage FROM sqlite_master WHERE name = 't1abc'}]
|
||||
|
||||
# Corrupt the file
|
||||
db close
|
||||
hexio_write test.db [expr {3*512 - 15}] 888080807f
|
||||
hexio_write test.db [expr {$idxroot*512 - 15}] 888080807f
|
||||
sqlite3 db test.db
|
||||
|
||||
# Try to use the file.
|
||||
@@ -58,7 +60,7 @@ do_test 1.4 {
|
||||
# such that the payload begins in allocated space but overflows the buffer.
|
||||
#
|
||||
db close
|
||||
hexio_write test.db [expr {3*512-15}] 0513ff7f01
|
||||
hexio_write test.db [expr {$idxroot*512-15}] 0513ff7f01
|
||||
sqlite3 db test.db
|
||||
|
||||
do_test 2.1 {
|
||||
|
||||
+2
-2
@@ -61,7 +61,7 @@ proc lookaside {db} {
|
||||
}
|
||||
}
|
||||
|
||||
ifcapable stat3 {
|
||||
ifcapable stat4||stat3 {
|
||||
set STAT3 1
|
||||
} else {
|
||||
set STAT3 0
|
||||
@@ -214,7 +214,7 @@ foreach ::lookaside_buffer_size {0 64 120} {
|
||||
# much greater than just that reported by DBSTATUS_SCHEMA_USED in this
|
||||
# case.
|
||||
#
|
||||
# Some of the memory used for sqlite_stat3 is unaccounted for by
|
||||
# Some of the memory used for sqlite_stat4 is unaccounted for by
|
||||
# dbstatus.
|
||||
#
|
||||
# Finally, on osx the estimate of memory used by the schema may be
|
||||
|
||||
+2
-2
@@ -191,8 +191,8 @@ do_insert_tests e_insert-1.3 {
|
||||
3b "SELECT * FROM a2 WHERE oid=last_insert_rowid()" {2 x y}
|
||||
}
|
||||
|
||||
# EVIDENCE-OF: R-44710-64652 If a column-list is specified, then the
|
||||
# number of values in each term of the VALUS list must match the number
|
||||
# EVIDENCE-OF: R-09234-17933 If a column-list is specified, then the
|
||||
# number of values in each term of the VALUE list must match the number
|
||||
# of specified columns.
|
||||
#
|
||||
do_insert_tests e_insert-1.4 -error {
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
# 2001 September 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.
|
||||
#
|
||||
# This file implements tests for foreign keys.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix fkey7
|
||||
|
||||
ifcapable {!foreignkey} {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
do_execsql_test 1.1 {
|
||||
PRAGMA foreign_keys = 1;
|
||||
|
||||
CREATE TABLE s1(a PRIMARY KEY, b);
|
||||
CREATE TABLE par(a, b REFERENCES s1, c UNIQUE, PRIMARY KEY(a));
|
||||
|
||||
CREATE TABLE c1(a, b REFERENCES par);
|
||||
CREATE TABLE c2(a, b REFERENCES par);
|
||||
CREATE TABLE c3(a, b REFERENCES par(c));
|
||||
}
|
||||
|
||||
proc auth {op tbl args} {
|
||||
if {$op == "SQLITE_READ"} { set ::tbls($tbl) 1 }
|
||||
return "SQLITE_OK"
|
||||
}
|
||||
db auth auth
|
||||
db cache size 0
|
||||
proc do_tblsread_test {tn sql tbllist} {
|
||||
array unset ::tbls
|
||||
uplevel [list execsql $sql]
|
||||
uplevel [list do_test $tn {lsort [array names ::tbls]} $tbllist]
|
||||
}
|
||||
|
||||
do_tblsread_test 1.2 { UPDATE par SET b=? WHERE a=? } {par s1}
|
||||
do_tblsread_test 1.3 { UPDATE par SET a=? WHERE b=? } {c1 c2 par}
|
||||
do_tblsread_test 1.4 { UPDATE par SET c=? WHERE b=? } {c3 par}
|
||||
do_tblsread_test 1.5 { UPDATE par SET a=?,b=?,c=? WHERE b=? } {c1 c2 c3 par s1}
|
||||
|
||||
|
||||
finish_test
|
||||
@@ -426,4 +426,11 @@ do_execsql_test 8.3 {
|
||||
{0 3 2 0 3 2 1 4 3} {1 3 2 1 3 2 1 4 3} {2 3 2 2 3 2 2 4 3}
|
||||
}
|
||||
|
||||
do_execsql_test 9.1 {
|
||||
CREATE VIRTUAL TABLE ft2 USING fts4;
|
||||
INSERT INTO ft2 VALUES('a b c d e');
|
||||
INSERT INTO ft2 VALUES('f a b c d');
|
||||
SELECT snippet(ft2, '[', ']', '', -1, 1) FROM ft2 WHERE ft2 MATCH 'c';
|
||||
} {{[c]} {[c]}}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -402,5 +402,40 @@ foreach {tn1 c} {
|
||||
}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Cursory test of remove_diacritics=0.
|
||||
#
|
||||
# 00C4;LATIN CAPITAL LETTER A WITH DIAERESIS
|
||||
# 00D6;LATIN CAPITAL LETTER O WITH DIAERESIS
|
||||
# 00E4;LATIN SMALL LETTER A WITH DIAERESIS
|
||||
# 00F6;LATIN SMALL LETTER O WITH DIAERESIS
|
||||
#
|
||||
do_execsql_test 8.1.1 "
|
||||
CREATE VIRTUAL TABLE t3 USING fts4(tokenize=unicode61 'remove_diacritics=1');
|
||||
INSERT INTO t3 VALUES('o');
|
||||
INSERT INTO t3 VALUES('a');
|
||||
INSERT INTO t3 VALUES('O');
|
||||
INSERT INTO t3 VALUES('A');
|
||||
INSERT INTO t3 VALUES('\xD6');
|
||||
INSERT INTO t3 VALUES('\xC4');
|
||||
INSERT INTO t3 VALUES('\xF6');
|
||||
INSERT INTO t3 VALUES('\xE4');
|
||||
"
|
||||
do_execsql_test 8.1.2 {
|
||||
SELECT rowid FROM t3 WHERE t3 MATCH 'o';
|
||||
} {1 3 5 7}
|
||||
do_execsql_test 8.1.3 {
|
||||
SELECT rowid FROM t3 WHERE t3 MATCH 'a';
|
||||
} {2 4 6 8}
|
||||
do_execsql_test 8.2.1 {
|
||||
CREATE VIRTUAL TABLE t4 USING fts4(tokenize=unicode61 "remove_diacritics=0");
|
||||
INSERT INTO t4 SELECT * FROM t3;
|
||||
}
|
||||
do_execsql_test 8.2.2 {
|
||||
SELECT rowid FROM t4 WHERE t4 MATCH 'o';
|
||||
} {1 3}
|
||||
do_execsql_test 8.2.3 {
|
||||
SELECT rowid FROM t4 WHERE t4 MATCH 'a';
|
||||
} {2 4}
|
||||
|
||||
finish_test
|
||||
|
||||
+8
-3
@@ -16,6 +16,11 @@
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
ifcapable !vtab {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
load_static_extension db wholenumber;
|
||||
do_test index6-1.1 {
|
||||
# Able to parse and manage partial indices
|
||||
@@ -144,15 +149,15 @@ do_test index6-2.2 {
|
||||
SELECT * FROM t2 WHERE a=5;
|
||||
}
|
||||
} {/.* TABLE t2 USING INDEX t2a1 .*/}
|
||||
ifcapable stat3 {
|
||||
do_test index6-2.3stat3 {
|
||||
ifcapable stat4||stat3 {
|
||||
do_test index6-2.3stat4 {
|
||||
execsql {
|
||||
EXPLAIN QUERY PLAN
|
||||
SELECT * FROM t2 WHERE a IS NOT NULL;
|
||||
}
|
||||
} {/.* TABLE t2 USING INDEX t2a1 .*/}
|
||||
} else {
|
||||
do_test index6-2.3stat3 {
|
||||
do_test index6-2.3stat4 {
|
||||
execsql {
|
||||
EXPLAIN QUERY PLAN
|
||||
SELECT * FROM t2 WHERE a IS NOT NULL AND a>0;
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set ::testprefix indexedby
|
||||
|
||||
# Create a schema with some indexes.
|
||||
#
|
||||
@@ -274,4 +275,50 @@ do_test indexedby-10.3 {
|
||||
}
|
||||
} {1}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Ensure that the rowid at the end of each index entry may be used
|
||||
# for equality constraints in the same way as other indexed fields.
|
||||
#
|
||||
do_execsql_test 11.1 {
|
||||
CREATE TABLE x1(a, b TEXT);
|
||||
CREATE INDEX x1i ON x1(a, b);
|
||||
INSERT INTO x1 VALUES(1, 1);
|
||||
INSERT INTO x1 VALUES(1, 1);
|
||||
INSERT INTO x1 VALUES(1, 1);
|
||||
INSERT INTO x1 VALUES(1, 1);
|
||||
}
|
||||
do_execsql_test 11.2 {
|
||||
SELECT a,b,rowid FROM x1 INDEXED BY x1i WHERE a=1 AND b=1 AND rowid=3;
|
||||
} {1 1 3}
|
||||
do_execsql_test 11.3 {
|
||||
SELECT a,b,rowid FROM x1 INDEXED BY x1i WHERE a=1 AND b=1 AND rowid='3';
|
||||
} {1 1 3}
|
||||
do_execsql_test 11.4 {
|
||||
SELECT a,b,rowid FROM x1 INDEXED BY x1i WHERE a=1 AND b=1 AND rowid='3.0';
|
||||
} {1 1 3}
|
||||
do_eqp_test 11.5 {
|
||||
SELECT a,b,rowid FROM x1 INDEXED BY x1i WHERE a=1 AND b=1 AND rowid='3.0';
|
||||
} {0 0 0 {SEARCH TABLE x1 USING COVERING INDEX x1i (a=? AND b=? AND rowid=?)}}
|
||||
|
||||
do_execsql_test 11.6 {
|
||||
CREATE TABLE x2(c INTEGER PRIMARY KEY, a, b TEXT);
|
||||
CREATE INDEX x2i ON x2(a, b);
|
||||
INSERT INTO x2 VALUES(1, 1, 1);
|
||||
INSERT INTO x2 VALUES(2, 1, 1);
|
||||
INSERT INTO x2 VALUES(3, 1, 1);
|
||||
INSERT INTO x2 VALUES(4, 1, 1);
|
||||
}
|
||||
do_execsql_test 11.7 {
|
||||
SELECT a,b,c FROM x2 INDEXED BY x2i WHERE a=1 AND b=1 AND c=3;
|
||||
} {1 1 3}
|
||||
do_execsql_test 11.8 {
|
||||
SELECT a,b,c FROM x2 INDEXED BY x2i WHERE a=1 AND b=1 AND c='3';
|
||||
} {1 1 3}
|
||||
do_execsql_test 11.9 {
|
||||
SELECT a,b,c FROM x2 INDEXED BY x2i WHERE a=1 AND b=1 AND c='3.0';
|
||||
} {1 1 3}
|
||||
do_eqp_test 11.10 {
|
||||
SELECT a,b,c FROM x2 INDEXED BY x2i WHERE a=1 AND b=1 AND c='3.0';
|
||||
} {0 0 0 {SEARCH TABLE x2 USING COVERING INDEX x2i (a=? AND b=? AND rowid=?)}}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -205,6 +205,7 @@ do_test malloc5-4.1 {
|
||||
execsql "INSERT INTO abc VALUES($i, $i, '[string repeat X 100]');"
|
||||
}
|
||||
execsql {COMMIT;}
|
||||
db cache flush
|
||||
sqlite3_release_memory
|
||||
sqlite3_memory_highwater 1
|
||||
execsql {SELECT * FROM abc}
|
||||
@@ -213,6 +214,7 @@ do_test malloc5-4.1 {
|
||||
expr $nMaxBytes > 1000000
|
||||
} {1}
|
||||
do_test malloc5-4.2 {
|
||||
db cache flush
|
||||
sqlite3_release_memory
|
||||
sqlite3_soft_heap_limit 100000
|
||||
sqlite3_memory_highwater 1
|
||||
|
||||
+49
-1
@@ -15,6 +15,7 @@
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
source $testdir/malloc_common.tcl
|
||||
set testprefix mallocA
|
||||
|
||||
# Only run these tests if memory debugging is turned on.
|
||||
#
|
||||
@@ -40,7 +41,6 @@ db eval {
|
||||
db close
|
||||
copy_file test.db test.db.bu
|
||||
|
||||
|
||||
do_malloc_test mallocA-1 -testdb test.db.bu -sqlbody {
|
||||
ANALYZE
|
||||
}
|
||||
@@ -53,6 +53,7 @@ do_malloc_test mallocA-1.2 -testdb test.db.bu -sqlbody {
|
||||
do_malloc_test mallocA-1.3 -testdb test.db.bu -sqlbody {
|
||||
ANALYZE main.t1
|
||||
}
|
||||
|
||||
ifcapable reindex {
|
||||
do_malloc_test mallocA-2 -testdb test.db.bu -sqlbody {
|
||||
REINDEX;
|
||||
@@ -68,6 +69,53 @@ ifcapable reindex {
|
||||
}
|
||||
}
|
||||
|
||||
reset_db
|
||||
sqlite3_db_config_lookaside db 0 0 0
|
||||
do_execsql_test 6-prep {
|
||||
CREATE TABLE t1(a, b);
|
||||
CREATE INDEX i1 ON t1(a, b);
|
||||
INSERT INTO t1 VALUES('abc', 'w'); -- rowid=1
|
||||
INSERT INTO t1 VALUES('abc', 'x'); -- rowid=2
|
||||
INSERT INTO t1 VALUES('abc', 'y'); -- rowid=3
|
||||
INSERT INTO t1 VALUES('abc', 'z'); -- rowid=4
|
||||
|
||||
INSERT INTO t1 VALUES('def', 'w'); -- rowid=5
|
||||
INSERT INTO t1 VALUES('def', 'x'); -- rowid=6
|
||||
INSERT INTO t1 VALUES('def', 'y'); -- rowid=7
|
||||
INSERT INTO t1 VALUES('def', 'z'); -- rowid=8
|
||||
|
||||
ANALYZE;
|
||||
}
|
||||
|
||||
do_faultsim_test 6.1 -faults oom* -body {
|
||||
execsql { SELECT rowid FROM t1 WHERE a='abc' AND b='x' }
|
||||
} -test {
|
||||
faultsim_test_result [list 0 2]
|
||||
}
|
||||
do_faultsim_test 6.2 -faults oom* -body {
|
||||
execsql { SELECT rowid FROM t1 WHERE a='abc' AND b<'y' }
|
||||
} -test {
|
||||
faultsim_test_result [list 0 {1 2}]
|
||||
}
|
||||
ifcapable stat3 {
|
||||
do_test 6.3-prep {
|
||||
execsql {
|
||||
PRAGMA writable_schema = 1;
|
||||
CREATE TABLE sqlite_stat4 AS
|
||||
SELECT tbl, idx, neq, nlt, ndlt, sqlite_record(sample) AS sample
|
||||
FROM sqlite_stat3;
|
||||
}
|
||||
} {}
|
||||
do_faultsim_test 6.3 -faults oom* -body {
|
||||
execsql {
|
||||
ANALYZE sqlite_master;
|
||||
SELECT rowid FROM t1 WHERE a='abc' AND b<'y';
|
||||
}
|
||||
} -test {
|
||||
faultsim_test_result [list 0 {1 2}]
|
||||
}
|
||||
}
|
||||
|
||||
# Ensure that no file descriptors were leaked.
|
||||
do_test malloc-99.X {
|
||||
catch {db close}
|
||||
|
||||
+27
-1
@@ -93,6 +93,14 @@ set FAULTSIM(cantopen-persistent) [list \
|
||||
-injectuninstall cantopen_injectuninstall \
|
||||
]
|
||||
|
||||
set FAULTSIM(interrupt) [list \
|
||||
-injectinstall interrupt_injectinstall \
|
||||
-injectstart interrupt_injectstart \
|
||||
-injectstop interrupt_injectstop \
|
||||
-injecterrlist {{1 interrupted} {1 interrupt}} \
|
||||
-injectuninstall interrupt_injectuninstall \
|
||||
]
|
||||
|
||||
|
||||
|
||||
#--------------------------------------------------------------------------
|
||||
@@ -113,7 +121,9 @@ set FAULTSIM(cantopen-persistent) [list \
|
||||
proc do_faultsim_test {name args} {
|
||||
global FAULTSIM
|
||||
|
||||
set DEFAULT(-faults) [array names FAULTSIM]
|
||||
foreach n [array names FAULTSIM] {
|
||||
if {$n != "interrupt"} {lappend DEFAULT(-faults) $n}
|
||||
}
|
||||
set DEFAULT(-prep) ""
|
||||
set DEFAULT(-body) ""
|
||||
set DEFAULT(-test) ""
|
||||
@@ -255,6 +265,22 @@ proc cantopen_injectstop {} {
|
||||
shmfault cantopen
|
||||
}
|
||||
|
||||
# The following procs are used as [do_one_faultsim_test] callbacks
|
||||
# when injecting SQLITE_INTERRUPT error faults into test cases.
|
||||
#
|
||||
proc interrupt_injectinstall {} {
|
||||
}
|
||||
proc interrupt_injectuninstall {} {
|
||||
}
|
||||
proc interrupt_injectstart {iFail} {
|
||||
set ::sqlite_interrupt_count $iFail
|
||||
}
|
||||
proc interrupt_injectstop {} {
|
||||
set res [expr $::sqlite_interrupt_count<=0]
|
||||
set ::sqlite_interrupt_count 0
|
||||
set res
|
||||
}
|
||||
|
||||
# This command is not called directly. It is used by the
|
||||
# [faultsim_test_result] command created by [do_faultsim_test] and used
|
||||
# by -test scripts.
|
||||
|
||||
@@ -311,6 +311,14 @@ test_suite "coverage-pager" -description {
|
||||
walfault.test walbak.test journal2.test tkt-9d68c883.test
|
||||
}
|
||||
|
||||
test_suite "coverage-analyze" -description {
|
||||
Coverage tests for file analyze.c.
|
||||
} -files {
|
||||
analyze3.test analyze4.test analyze5.test analyze6.test
|
||||
analyze7.test analyze8.test analyze9.test analyzeA.test
|
||||
analyze.test analyzeB.test mallocA.test
|
||||
}
|
||||
|
||||
|
||||
lappend ::testsuitelist xxx
|
||||
#-------------------------------------------------------------------------
|
||||
@@ -500,6 +508,8 @@ test_suite "utf16" -description {
|
||||
pragma encoding = 'UTF-16'
|
||||
} -files {
|
||||
alter.test alter3.test
|
||||
analyze.test analyze3.test analyze4.test analyze5.test analyze6.test
|
||||
analyze7.test analyze8.test analyze9.test analyzeA.test analyzeB.test
|
||||
auth.test bind.test blob.test capi2.test capi3.test collate1.test
|
||||
collate2.test collate3.test collate4.test collate5.test collate6.test
|
||||
conflict.test date.test delete.test expr.test fkey1.test func.test
|
||||
|
||||
@@ -22,6 +22,7 @@ source $testdir/tester.tcl
|
||||
# pragma2-1.*: Test freelist_count pragma on the main database.
|
||||
# pragma2-2.*: Test freelist_count pragma on an attached database.
|
||||
# pragma2-3.*: Test trying to write to the freelist_count is a no-op.
|
||||
# pragma2-4.*: Tests for PRAGMA cache_spill
|
||||
#
|
||||
|
||||
ifcapable !pragma||!schema_pragmas {
|
||||
@@ -116,4 +117,82 @@ ifcapable attach {
|
||||
} {9 9}
|
||||
}
|
||||
|
||||
# Default setting of PRAGMA cache_spill is always ON
|
||||
#
|
||||
db close
|
||||
delete_file test.db test.db-journal
|
||||
delete_file test2.db test2.db-journal
|
||||
sqlite3 db test.db
|
||||
do_execsql_test pragma2-4.1 {
|
||||
PRAGMA cache_spill;
|
||||
PRAGMA main.cache_spill;
|
||||
PRAGMA temp.cache_spill;
|
||||
} {1 1 1}
|
||||
do_execsql_test pragma2-4.2 {
|
||||
PRAGMA cache_spill=OFF;
|
||||
PRAGMA cache_spill;
|
||||
PRAGMA main.cache_spill;
|
||||
PRAGMA temp.cache_spill;
|
||||
} {0 0 0}
|
||||
do_execsql_test pragma2-4.3 {
|
||||
PRAGMA page_size=1024;
|
||||
PRAGMA cache_size=50;
|
||||
BEGIN;
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c, d);
|
||||
INSERT INTO t1 VALUES(1, randomblob(400), 1, randomblob(400));
|
||||
INSERT INTO t1 SELECT a+1, randomblob(400), a+1, randomblob(400) FROM t1;
|
||||
INSERT INTO t1 SELECT a+2, randomblob(400), a+2, randomblob(400) FROM t1;
|
||||
INSERT INTO t1 SELECT a+4, randomblob(400), a+4, randomblob(400) FROM t1;
|
||||
INSERT INTO t1 SELECT a+8, randomblob(400), a+8, randomblob(400) FROM t1;
|
||||
INSERT INTO t1 SELECT a+16, randomblob(400), a+16, randomblob(400) FROM t1;
|
||||
INSERT INTO t1 SELECT a+32, randomblob(400), a+32, randomblob(400) FROM t1;
|
||||
INSERT INTO t1 SELECT a+64, randomblob(400), a+64, randomblob(400) FROM t1;
|
||||
COMMIT;
|
||||
ATTACH 'test2.db' AS aux1;
|
||||
CREATE TABLE aux1.t2(a INTEGER PRIMARY KEY, b, c, d);
|
||||
INSERT INTO t2 SELECT * FROM t1;
|
||||
DETACH aux1;
|
||||
PRAGMA cache_spill=ON;
|
||||
} {}
|
||||
sqlite3_release_memory
|
||||
do_test pragma2-4.4 {
|
||||
db eval {
|
||||
BEGIN;
|
||||
UPDATE t1 SET c=c+1;
|
||||
PRAGMA lock_status;
|
||||
}
|
||||
} {main exclusive temp unknown} ;# EXCLUSIVE lock due to cache spill
|
||||
do_test pragma2-4.5 {
|
||||
db eval {
|
||||
COMMIT;
|
||||
PRAGMA cache_spill=OFF;
|
||||
BEGIN;
|
||||
UPDATE t1 SET c=c-1;
|
||||
PRAGMA lock_status;
|
||||
}
|
||||
} {main reserved temp unknown} ;# No cache spill, so no exclusive lock
|
||||
|
||||
# Verify that newly attached databases inherit the cache_spill=OFF
|
||||
# setting.
|
||||
#
|
||||
do_execsql_test pragma2-4.6 {
|
||||
COMMIT;
|
||||
ATTACH 'test2.db' AS aux1;
|
||||
PRAGMA aux1.cache_size=50;
|
||||
BEGIN;
|
||||
UPDATE t2 SET c=c+1;
|
||||
PRAGMA lock_status;
|
||||
} {main unlocked temp unknown aux1 reserved}
|
||||
do_execsql_test pragma2-4.7 {
|
||||
COMMIT;
|
||||
}
|
||||
sqlite3_release_memory
|
||||
do_execsql_test pragma2-4.8 {
|
||||
PRAGMA cache_spill=ON; -- Applies to all databases
|
||||
BEGIN;
|
||||
UPDATE t2 SET c=c-1;
|
||||
PRAGMA lock_status;
|
||||
} {main unlocked temp unknown aux1 exclusive}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -164,10 +164,12 @@ do_test progress-1.7 {
|
||||
}
|
||||
|
||||
set ::res [list]
|
||||
explain {SELECT a, b, c FROM abc}
|
||||
db eval {SELECT a, b, c FROM abc} {
|
||||
lappend ::res $a $b $c
|
||||
db progress 5 "expr 1"
|
||||
catch {db eval {SELECT a, b, c FROM abc} { }} msg
|
||||
db progress 5 "expr 0"
|
||||
lappend ::res $msg
|
||||
}
|
||||
|
||||
|
||||
+171
-2
@@ -13,10 +13,18 @@
|
||||
# figures out what identifiers in the SQL statement refer to) that
|
||||
# were fixed by ticket [2500cdb9be]
|
||||
#
|
||||
# See also tickets [1c69be2daf] and [f617ea3125] from 2013-08-14.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
# "ORDER BY y" binds to the output result-set column named "y"
|
||||
# if available. If no output column is named "y", then try to
|
||||
# bind against an input column named "y".
|
||||
#
|
||||
# This is classical SQL92 behavior.
|
||||
#
|
||||
do_test resolver01-1.1 {
|
||||
catchsql {
|
||||
CREATE TABLE t1(x, y); INSERT INTO t1 VALUES(11,22);
|
||||
@@ -25,15 +33,176 @@ do_test resolver01-1.1 {
|
||||
}
|
||||
} {0 1}
|
||||
do_test resolver01-1.2 {
|
||||
catchsql {
|
||||
SELECT 1 AS yy FROM t1, t2 ORDER BY y;
|
||||
}
|
||||
} {1 {ambiguous column name: y}}
|
||||
do_test resolver01-1.3 {
|
||||
catchsql {
|
||||
CREATE TABLE t3(x,y); INSERT INTO t3 VALUES(11,44),(33,22);
|
||||
SELECT x AS y FROM t3 ORDER BY y;
|
||||
}
|
||||
} {0 {11 33}}
|
||||
do_test resolver01-1.4 {
|
||||
catchsql {
|
||||
SELECT x AS yy FROM t3 ORDER BY y;
|
||||
}
|
||||
} {0 {33 11}}
|
||||
|
||||
# SQLite allows the WHERE clause to reference output columns if there is
|
||||
# no other way to resolve the name.
|
||||
#
|
||||
do_test resolver01-1.5 {
|
||||
catchsql {
|
||||
SELECT x AS yy FROM t3 ORDER BY yy;
|
||||
}
|
||||
} {0 {11 33}}
|
||||
do_test resolver01-1.6 {
|
||||
catchsql {
|
||||
SELECT x AS yy FROM t3 ORDER BY 1;
|
||||
}
|
||||
} {0 {11 33}}
|
||||
|
||||
# The "ORDER BY y COLLATE nocase" form works the same as "ORDER BY y".
|
||||
# The "y" binds more tightly to output columns than to input columns.
|
||||
#
|
||||
# This is for compatibility with SQL92 and with historical SQLite behavior.
|
||||
# Note that PostgreSQL considers "y COLLATE nocase" to be an expression
|
||||
# and thus PostgreSQL treats this case as if it where the 3.x case below.
|
||||
#
|
||||
do_test resolver01-2.1 {
|
||||
catchsql {
|
||||
SELECT 2 AS y FROM t1, t2 ORDER BY y COLLATE nocase;
|
||||
}
|
||||
} {0 2}
|
||||
do_test resolver01-1.3 {
|
||||
do_test resolver01-2.2 {
|
||||
catchsql {
|
||||
SELECT 2 AS yy FROM t1, t2 ORDER BY y COLLATE nocase;
|
||||
}
|
||||
} {1 {ambiguous column name: y}}
|
||||
do_test resolver01-2.3 {
|
||||
catchsql {
|
||||
SELECT x AS y FROM t3 ORDER BY y COLLATE nocase;
|
||||
}
|
||||
} {0 {11 33}}
|
||||
do_test resolver01-2.4 {
|
||||
catchsql {
|
||||
SELECT x AS yy FROM t3 ORDER BY y COLLATE nocase;
|
||||
}
|
||||
} {0 {33 11}}
|
||||
do_test resolver01-2.5 {
|
||||
catchsql {
|
||||
SELECT x AS yy FROM t3 ORDER BY yy COLLATE nocase;
|
||||
}
|
||||
} {0 {11 33}}
|
||||
do_test resolver01-2.6 {
|
||||
catchsql {
|
||||
SELECT x AS yy FROM t3 ORDER BY 1 COLLATE nocase;
|
||||
}
|
||||
} {0 {11 33}}
|
||||
|
||||
# But if the form is "ORDER BY expr" then bind more tightly to the
|
||||
# the input column names and only use the output column names if no
|
||||
# input column name matches.
|
||||
#
|
||||
# This is SQL99 behavior, as implemented by PostgreSQL and MS-SQL.
|
||||
# Note that Oracle works differently.
|
||||
#
|
||||
do_test resolver01-3.1 {
|
||||
catchsql {
|
||||
SELECT 3 AS y FROM t1, t2 ORDER BY +y;
|
||||
}
|
||||
} {0 3}
|
||||
} {1 {ambiguous column name: y}}
|
||||
do_test resolver01-3.2 {
|
||||
catchsql {
|
||||
SELECT 2 AS yy FROM t1, t2 ORDER BY +y;
|
||||
}
|
||||
} {1 {ambiguous column name: y}}
|
||||
do_test resolver01-3.3 {
|
||||
catchsql {
|
||||
SELECT x AS y FROM t3 ORDER BY +y;
|
||||
}
|
||||
} {0 {33 11}}
|
||||
do_test resolver01-3.4 {
|
||||
catchsql {
|
||||
SELECT x AS yy FROM t3 ORDER BY +y;
|
||||
}
|
||||
} {0 {33 11}}
|
||||
do_test resolver01-3.5 {
|
||||
catchsql {
|
||||
SELECT x AS yy FROM t3 ORDER BY +yy
|
||||
}
|
||||
} {0 {11 33}}
|
||||
|
||||
# This is the test case given in ticket [f617ea3125e9] (with table name
|
||||
# changed from "t1" to "t4". The behavior of (1) and (3) match with
|
||||
# PostgreSQL, but we intentionally break with PostgreSQL to provide
|
||||
# SQL92 behavior for case (2).
|
||||
#
|
||||
do_execsql_test resolver01-4.1 {
|
||||
CREATE TABLE t4(m CHAR(2));
|
||||
INSERT INTO t4 VALUES('az');
|
||||
INSERT INTO t4 VALUES('by');
|
||||
INSERT INTO t4 VALUES('cx');
|
||||
SELECT '1', substr(m,2) AS m FROM t4 ORDER BY m;
|
||||
SELECT '2', substr(m,2) AS m FROM t4 ORDER BY m COLLATE binary;
|
||||
SELECT '3', substr(m,2) AS m FROM t4 ORDER BY lower(m);
|
||||
} {1 x 1 y 1 z 2 x 2 y 2 z 3 z 3 y 3 x}
|
||||
|
||||
##########################################################################
|
||||
# Test cases for ticket [1c69be2dafc28]: Make sure the GROUP BY binds
|
||||
# more tightly to the input tables in all cases.
|
||||
#
|
||||
# This first case case has been wrong in SQLite for time out of mind.
|
||||
# For SQLite version 3.7.17 the answer was two rows, which is wrong.
|
||||
#
|
||||
do_execsql_test resolver01-5.1 {
|
||||
CREATE TABLE t5(m CHAR(2));
|
||||
INSERT INTO t5 VALUES('ax');
|
||||
INSERT INTO t5 VALUES('bx');
|
||||
INSERT INTO t5 VALUES('cy');
|
||||
SELECT count(*), substr(m,2,1) AS m FROM t5 GROUP BY m ORDER BY 1, 2;
|
||||
} {1 x 1 x 1 y}
|
||||
|
||||
# This case is unambiguous and has always been correct.
|
||||
#
|
||||
do_execsql_test resolver01-5.2 {
|
||||
SELECT count(*), substr(m,2,1) AS mx FROM t5 GROUP BY m ORDER BY 1, 2;
|
||||
} {1 x 1 x 1 y}
|
||||
|
||||
# This case is not allowed in standard SQL, but SQLite allows and does
|
||||
# the sensible thing.
|
||||
#
|
||||
do_execsql_test resolver01-5.3 {
|
||||
SELECT count(*), substr(m,2,1) AS mx FROM t5 GROUP BY mx ORDER BY 1, 2;
|
||||
} {1 y 2 x}
|
||||
do_execsql_test resolver01-5.4 {
|
||||
SELECT count(*), substr(m,2,1) AS mx FROM t5
|
||||
GROUP BY substr(m,2,1) ORDER BY 1, 2;
|
||||
} {1 y 2 x}
|
||||
|
||||
# These test case weere provided in the 2013-08-14 email from Rob Golsteijn
|
||||
# that originally reported the problem of ticket [1c69be2dafc28].
|
||||
#
|
||||
do_execsql_test resolver01-6.1 {
|
||||
CREATE TABLE t61(name);
|
||||
SELECT min(name) FROM t61 GROUP BY lower(name);
|
||||
} {}
|
||||
do_execsql_test resolver01-6.2 {
|
||||
SELECT min(name) AS name FROM t61 GROUP BY lower(name);
|
||||
} {}
|
||||
do_execsql_test resolver01-6.3 {
|
||||
CREATE TABLE t63(name);
|
||||
INSERT INTO t63 VALUES (NULL);
|
||||
INSERT INTO t63 VALUES ('abc');
|
||||
SELECT count(),
|
||||
NULLIF(name,'abc') AS name
|
||||
FROM t63
|
||||
GROUP BY lower(name);
|
||||
} {1 {} 1 {}}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -722,7 +722,11 @@ do_test shell1-3-31.1 {
|
||||
# Test the output of the ".dump" command
|
||||
#
|
||||
do_test shell1-4.1 {
|
||||
db close
|
||||
forcedelete test.db
|
||||
sqlite3 db test.db
|
||||
db eval {
|
||||
PRAGMA encoding=UTF16;
|
||||
CREATE TABLE t1(x);
|
||||
INSERT INTO t1 VALUES(null), (''), (1), (2.25), ('hello'), (x'807f');
|
||||
}
|
||||
@@ -752,6 +756,14 @@ INSERT INTO t1 VALUES(X'807f');}}
|
||||
# Test the output of ".mode tcl"
|
||||
#
|
||||
do_test shell1-4.3 {
|
||||
db close
|
||||
forcedelete test.db
|
||||
sqlite3 db test.db
|
||||
db eval {
|
||||
PRAGMA encoding=UTF8;
|
||||
CREATE TABLE t1(x);
|
||||
INSERT INTO t1 VALUES(null), (''), (1), (2.25), ('hello'), (x'807f');
|
||||
}
|
||||
catchcmd test.db ".mode tcl\nselect * from t1;"
|
||||
} {0 {""
|
||||
""
|
||||
|
||||
@@ -242,4 +242,30 @@ SELECT * FROM t1;}
|
||||
5,"this is 5"}}
|
||||
}
|
||||
|
||||
# Import columns containing quoted strings
|
||||
do_test shell5-1.9 {
|
||||
set out [open shell5.csv w]
|
||||
puts $out {1,"",11}
|
||||
puts $out {2,"x",22}
|
||||
puts $out {3,"""",33}
|
||||
puts $out {4,"hello",44}
|
||||
puts $out "5,55,\"\"\r"
|
||||
puts $out {6,66,"x"}
|
||||
puts $out {7,77,""""}
|
||||
puts $out {8,88,"hello"}
|
||||
puts $out {"",9,99}
|
||||
puts $out {"x",10,110}
|
||||
puts $out {"""",11,121}
|
||||
puts $out {"hello",12,132}
|
||||
close $out
|
||||
file delete -force test.db
|
||||
catchcmd test.db {.mode csv
|
||||
CREATE TABLE t1(a,b,c);
|
||||
.import shell5.csv t1
|
||||
}
|
||||
sqlite3 db test.db
|
||||
db eval {SELECT *, '|' FROM t1 ORDER BY rowid}
|
||||
} {1 {} 11 | 2 x 22 | 3 {"} 33 | 4 hello 44 | 5 55 {} | 6 66 x | 7 77 {"} | 8 88 hello | {} 9 99 | x 10 110 | {"} 11 121 | hello 12 132 |}
|
||||
db close
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -268,6 +268,7 @@ do_test table-5.2.1 {
|
||||
DROP TABLE IF EXISTS sqlite_stat1;
|
||||
DROP TABLE IF EXISTS sqlite_stat2;
|
||||
DROP TABLE IF EXISTS sqlite_stat3;
|
||||
DROP TABLE IF EXISTS sqlite_stat4;
|
||||
SELECT name FROM sqlite_master WHERE name GLOB 'sqlite_stat*';
|
||||
}
|
||||
} {}
|
||||
|
||||
+104
-34
@@ -14,7 +14,7 @@
|
||||
# $Id: tester.tcl,v 1.143 2009/04/09 01:23:49 drh Exp $
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# The commands provided by the code in this file to help with creating
|
||||
# The commands provided by the code in this file to help with creating
|
||||
# test cases are as follows:
|
||||
#
|
||||
# Commands to manipulate the db and the file-system at a high level:
|
||||
@@ -42,6 +42,7 @@
|
||||
#
|
||||
# Commands to execute/explain SQL statements:
|
||||
#
|
||||
# memdbsql SQL
|
||||
# stepsql DB SQL
|
||||
# execsql2 SQL
|
||||
# explain_no_trace SQL
|
||||
@@ -80,7 +81,7 @@
|
||||
# presql
|
||||
#
|
||||
|
||||
# Set the precision of FP arithmatic used by the interpreter. And
|
||||
# Set the precision of FP arithmatic used by the interpreter. And
|
||||
# configure SQLite to take database file locks on the page that begins
|
||||
# 64KB into the database file instead of the one 1GB in. This means
|
||||
# the code that handles that special case can be tested without creating
|
||||
@@ -90,7 +91,7 @@ set tcl_precision 15
|
||||
sqlite3_test_control_pending_byte 0x0010000
|
||||
|
||||
|
||||
# If the pager codec is available, create a wrapper for the [sqlite3]
|
||||
# If the pager codec is available, create a wrapper for the [sqlite3]
|
||||
# command that appends "-key {xyzzy}" to the command line. i.e. this:
|
||||
#
|
||||
# sqlite3 db test.db
|
||||
@@ -122,7 +123,7 @@ if {[info command sqlite_orig]==""} {
|
||||
}
|
||||
set res
|
||||
} else {
|
||||
# This command is not opening a new database connection. Pass the
|
||||
# This command is not opening a new database connection. Pass the
|
||||
# arguments through to the C implementation as the are.
|
||||
#
|
||||
uplevel 1 sqlite_orig $args
|
||||
@@ -291,6 +292,66 @@ proc do_delete_file {force args} {
|
||||
}
|
||||
}
|
||||
|
||||
if {$::tcl_platform(platform) eq "windows"} {
|
||||
proc do_remove_win32_dir {args} {
|
||||
set nRetry [getFileRetries] ;# Maximum number of retries.
|
||||
set nDelay [getFileRetryDelay] ;# Delay in ms before retrying.
|
||||
|
||||
foreach dirName $args {
|
||||
# On windows, sometimes even a [remove_win32_dir] can fail just after
|
||||
# a directory is emptied. The cause is usually "tag-alongs" - programs
|
||||
# like anti-virus software, automatic backup tools and various explorer
|
||||
# extensions that keep a file open a little longer than we expect,
|
||||
# causing the delete to fail.
|
||||
#
|
||||
# The solution is to wait a short amount of time before retrying the
|
||||
# removal.
|
||||
#
|
||||
if {$nRetry > 0} {
|
||||
for {set i 0} {$i < $nRetry} {incr i} {
|
||||
set rc [catch {
|
||||
remove_win32_dir $dirName
|
||||
} msg]
|
||||
if {$rc == 0} break
|
||||
if {$nDelay > 0} { after $nDelay }
|
||||
}
|
||||
if {$rc} { error $msg }
|
||||
} else {
|
||||
remove_win32_dir $dirName
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
proc do_delete_win32_file {args} {
|
||||
set nRetry [getFileRetries] ;# Maximum number of retries.
|
||||
set nDelay [getFileRetryDelay] ;# Delay in ms before retrying.
|
||||
|
||||
foreach fileName $args {
|
||||
# On windows, sometimes even a [delete_win32_file] can fail just after
|
||||
# a file is closed. The cause is usually "tag-alongs" - programs like
|
||||
# anti-virus software, automatic backup tools and various explorer
|
||||
# extensions that keep a file open a little longer than we expect,
|
||||
# causing the delete to fail.
|
||||
#
|
||||
# The solution is to wait a short amount of time before retrying the
|
||||
# delete.
|
||||
#
|
||||
if {$nRetry > 0} {
|
||||
for {set i 0} {$i < $nRetry} {incr i} {
|
||||
set rc [catch {
|
||||
delete_win32_file $fileName
|
||||
} msg]
|
||||
if {$rc == 0} break
|
||||
if {$nDelay > 0} { after $nDelay }
|
||||
}
|
||||
if {$rc} { error $msg }
|
||||
} else {
|
||||
delete_win32_file $fileName
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
proc execpresql {handle args} {
|
||||
trace remove execution $handle enter [list execpresql $handle]
|
||||
if {[info exists ::G(perm:presql)]} {
|
||||
@@ -312,8 +373,8 @@ proc do_not_use_codec {} {
|
||||
#
|
||||
if {[info exists cmdlinearg]==0} {
|
||||
|
||||
# Parse any options specified in the $argv array. This script accepts the
|
||||
# following options:
|
||||
# Parse any options specified in the $argv array. This script accepts the
|
||||
# following options:
|
||||
#
|
||||
# --pause
|
||||
# --soft-heap-limit=NN
|
||||
@@ -342,7 +403,7 @@ if {[info exists cmdlinearg]==0} {
|
||||
foreach a $argv {
|
||||
switch -regexp -- $a {
|
||||
{^-+pause$} {
|
||||
# Wait for user input before continuing. This is to give the user an
|
||||
# Wait for user input before continuing. This is to give the user an
|
||||
# opportunity to connect profiling tools to the process.
|
||||
puts -nonewline "Press RETURN to begin..."
|
||||
flush stdout
|
||||
@@ -405,8 +466,8 @@ if {[info exists cmdlinearg]==0} {
|
||||
# Install the malloc layer used to inject OOM errors. And the 'automatic'
|
||||
# extensions. This only needs to be done once for the process.
|
||||
#
|
||||
sqlite3_shutdown
|
||||
install_malloc_faultsim 1
|
||||
sqlite3_shutdown
|
||||
install_malloc_faultsim 1
|
||||
sqlite3_initialize
|
||||
autoinstall_test_functions
|
||||
|
||||
@@ -516,7 +577,7 @@ proc incr_ntest {} {
|
||||
}
|
||||
|
||||
|
||||
# Invoke the do_test procedure to run a single test
|
||||
# Invoke the do_test procedure to run a single test
|
||||
#
|
||||
proc do_test {name cmd expected} {
|
||||
global argv cmdlinearg
|
||||
@@ -525,7 +586,7 @@ proc do_test {name cmd expected} {
|
||||
|
||||
sqlite3_memdebug_settitle $name
|
||||
|
||||
# if {[llength $argv]==0} {
|
||||
# if {[llength $argv]==0} {
|
||||
# set go 1
|
||||
# } else {
|
||||
# set go 0
|
||||
@@ -628,13 +689,13 @@ proc do_realnum_test {name cmd expected} {
|
||||
|
||||
proc fix_testname {varname} {
|
||||
upvar $varname testname
|
||||
if {[info exists ::testprefix]
|
||||
if {[info exists ::testprefix]
|
||||
&& [string is digit [string range $testname 0 0]]
|
||||
} {
|
||||
set testname "${::testprefix}-$testname"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
proc do_execsql_test {testname sql {result {}}} {
|
||||
fix_testname testname
|
||||
uplevel do_test [list $testname] [list "execsql {$sql}"] [list [list {*}$result]]
|
||||
@@ -720,7 +781,7 @@ proc delete_all_data {} {
|
||||
}
|
||||
}
|
||||
|
||||
# Run an SQL script.
|
||||
# Run an SQL script.
|
||||
# Return the number of microseconds per statement.
|
||||
#
|
||||
proc speed_trial {name numstmt units sql} {
|
||||
@@ -984,6 +1045,15 @@ proc execsql2 {sql} {
|
||||
return $result
|
||||
}
|
||||
|
||||
# Use a temporary in-memory database to execute SQL statements
|
||||
#
|
||||
proc memdbsql {sql} {
|
||||
sqlite3 memdb :memory:
|
||||
set result [memdb eval $sql]
|
||||
memdb close
|
||||
return $result
|
||||
}
|
||||
|
||||
# Use the non-callback API to execute multiple SQL statements
|
||||
#
|
||||
proc stepsql {dbptr sql} {
|
||||
@@ -1098,7 +1168,7 @@ proc crashsql {args} {
|
||||
set crashfile ""
|
||||
set dc ""
|
||||
set sql [lindex $args end]
|
||||
|
||||
|
||||
for {set ii 0} {$ii < [llength $args]-1} {incr ii 2} {
|
||||
set z [lindex $args $ii]
|
||||
set n [string length $z]
|
||||
@@ -1117,7 +1187,7 @@ proc crashsql {args} {
|
||||
error "Compulsory option -file missing"
|
||||
}
|
||||
|
||||
# $crashfile gets compared to the native filename in
|
||||
# $crashfile gets compared to the native filename in
|
||||
# cfSync(), which can be different then what TCL uses by
|
||||
# default, so here we force it to the "nativename" format.
|
||||
set cfile [string map {\\ \\\\} [file nativename [file join [get_pwd] $crashfile]]]
|
||||
@@ -1152,7 +1222,7 @@ proc crashsql {args} {
|
||||
set r [catch {
|
||||
exec [info nameofexec] crash.tcl >@stdout
|
||||
} msg]
|
||||
|
||||
|
||||
# Windows/ActiveState TCL returns a slightly different
|
||||
# error message. We map that to the expected message
|
||||
# so that we don't have to change all of the test
|
||||
@@ -1162,7 +1232,7 @@ proc crashsql {args} {
|
||||
set msg "child process exited abnormally"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
lappend r $msg
|
||||
}
|
||||
|
||||
@@ -1188,7 +1258,7 @@ proc run_ioerr_prep {} {
|
||||
# Usage: do_ioerr_test <test number> <options...>
|
||||
#
|
||||
# This proc is used to implement test cases that check that IO errors
|
||||
# are correctly handled. The first argument, <test number>, is an integer
|
||||
# are correctly handled. The first argument, <test number>, is an integer
|
||||
# used to name the tests executed by this proc. Options are as follows:
|
||||
#
|
||||
# -tclprep TCL script to run to prepare test.
|
||||
@@ -1217,7 +1287,7 @@ proc do_ioerr_test {testname args} {
|
||||
# TEMPORARY: For 3.5.9, disable testing of extended result codes. There are
|
||||
# a couple of obscure IO errors that do not return them.
|
||||
set ::ioerropts(-erc) 0
|
||||
|
||||
|
||||
# Create a single TCL script from the TCL and SQL specified
|
||||
# as the body of the test.
|
||||
set ::ioerrorbody {}
|
||||
@@ -1241,7 +1311,7 @@ proc do_ioerr_test {testname args} {
|
||||
set ::TN $n
|
||||
incr ::ioerropts(-count) -1
|
||||
if {$::ioerropts(-count)<0} break
|
||||
|
||||
|
||||
# Skip this IO error if it was specified with the "-exclude" option.
|
||||
if {[info exists ::ioerropts(-exclude)]} {
|
||||
if {[lsearch $::ioerropts(-exclude) $n]!=-1} continue
|
||||
@@ -1250,7 +1320,7 @@ proc do_ioerr_test {testname args} {
|
||||
restore_prng_state
|
||||
}
|
||||
|
||||
# Delete the files test.db and test2.db, then execute the TCL and
|
||||
# Delete the files test.db and test2.db, then execute the TCL and
|
||||
# SQL (in that order) to prepare for the test case.
|
||||
do_test $testname.$n.1 {
|
||||
run_ioerr_prep
|
||||
@@ -1268,7 +1338,7 @@ proc do_ioerr_test {testname args} {
|
||||
}] $n
|
||||
|
||||
# Execute the TCL script created for the body of this test. If
|
||||
# at least N IO operations performed by SQLite as a result of
|
||||
# at least N IO operations performed by SQLite as a result of
|
||||
# the script, the Nth will fail.
|
||||
do_test $testname.$n.3 {
|
||||
set ::sqlite_io_error_hit 0
|
||||
@@ -1322,12 +1392,12 @@ proc do_ioerr_test {testname args} {
|
||||
set ::sqlite_io_error_hit 0
|
||||
set ::sqlite_io_error_pending 0
|
||||
|
||||
# Check that no page references were leaked. There should be
|
||||
# a single reference if there is still an active transaction,
|
||||
# Check that no page references were leaked. There should be
|
||||
# a single reference if there is still an active transaction,
|
||||
# or zero otherwise.
|
||||
#
|
||||
# UPDATE: If the IO error occurs after a 'BEGIN' but before any
|
||||
# locks are established on database files (i.e. if the error
|
||||
# locks are established on database files (i.e. if the error
|
||||
# occurs while attempting to detect a hot-journal file), then
|
||||
# there may 0 page references and an active transaction according
|
||||
# to [sqlite3_get_autocommit].
|
||||
@@ -1343,7 +1413,7 @@ proc do_ioerr_test {testname args} {
|
||||
} {1}
|
||||
}
|
||||
|
||||
# If there is an open database handle and no open transaction,
|
||||
# If there is an open database handle and no open transaction,
|
||||
# and the pager is not running in exclusive-locking mode,
|
||||
# check that the pager is in "unlocked" state. Theoretically,
|
||||
# if a call to xUnlock() failed due to an IO error the underlying
|
||||
@@ -1447,7 +1517,7 @@ proc allcksum {{db db}} {
|
||||
}
|
||||
|
||||
# Generate a checksum based on the contents of a single database with
|
||||
# a database connection. The name of the database is $dbname.
|
||||
# a database connection. The name of the database is $dbname.
|
||||
# Examples of $dbname are "temp" or "main".
|
||||
#
|
||||
proc dbcksum {db dbname} {
|
||||
@@ -1541,8 +1611,8 @@ proc drop_all_tables {{db db}} {
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# If a test script is executed with global variable $::G(perm:name) set to
|
||||
# "wal", then the tests are run in WAL mode. Otherwise, they should be run
|
||||
# in rollback mode. The following Tcl procs are used to make this less
|
||||
# "wal", then the tests are run in WAL mode. Otherwise, they should be run
|
||||
# in rollback mode. The following Tcl procs are used to make this less
|
||||
# intrusive:
|
||||
#
|
||||
# wal_set_journal_mode ?DB?
|
||||
@@ -1557,9 +1627,9 @@ proc drop_all_tables {{db db}} {
|
||||
# Otherwise (if not running a WAL permutation) this is a no-op.
|
||||
#
|
||||
# wal_is_wal_mode
|
||||
#
|
||||
#
|
||||
# Returns true if this test should be run in WAL mode. False otherwise.
|
||||
#
|
||||
#
|
||||
proc wal_is_wal_mode {} {
|
||||
expr {[permutation] eq "wal"}
|
||||
}
|
||||
@@ -1660,10 +1730,10 @@ proc slave_test_file {zFile} {
|
||||
}
|
||||
set ::sqlite_open_file_count 0
|
||||
|
||||
# Test that the global "shared-cache" setting was not altered by
|
||||
# Test that the global "shared-cache" setting was not altered by
|
||||
# the test script.
|
||||
#
|
||||
ifcapable shared_cache {
|
||||
ifcapable shared_cache {
|
||||
set res [expr {[sqlite3_enable_shared_cache] == $scs}]
|
||||
do_test ${tail}-sharedcachesetting [list set {} $res] 1
|
||||
}
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
|
||||
# 2013 August 29
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
# This file implements regression tests for SQLite library.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
source $testdir/malloc_common.tcl
|
||||
set ::testprefix tkt-9f2eb3abac
|
||||
|
||||
do_execsql_test 1.1 {
|
||||
CREATE TABLE t1(a,b,c,d,e, PRIMARY KEY(a,b,c,d,e));
|
||||
SELECT * FROM t1 WHERE a=? AND b=? AND c=? AND d=? AND e=?;
|
||||
} {}
|
||||
|
||||
do_execsql_test 1.2 {
|
||||
CREATE TABLE "a" (
|
||||
"b" integer NOT NULL,
|
||||
"c" integer NOT NULL,
|
||||
PRIMARY KEY ("b", "c")
|
||||
);
|
||||
|
||||
CREATE TABLE "d" (
|
||||
"e" integer NOT NULL,
|
||||
"g" integer NOT NULL,
|
||||
"f" integer NOT NULL,
|
||||
"h" integer NOT NULL,
|
||||
"i" character(10) NOT NULL,
|
||||
"j" int,
|
||||
PRIMARY KEY ("e", "g", "f", "h")
|
||||
);
|
||||
|
||||
CREATE TABLE "d_to_a" (
|
||||
"f_e" integer NOT NULL,
|
||||
"f_g" integer NOT NULL,
|
||||
"f_f" integer NOT NULL,
|
||||
"f_h" integer NOT NULL,
|
||||
"t_b" integer NOT NULL,
|
||||
"t_c" integer NOT NULL,
|
||||
"r" character NOT NULL,
|
||||
"s" integer,
|
||||
PRIMARY KEY ("f_e", "f_g", "f_f", "f_h", "t_b", "t_c")
|
||||
);
|
||||
|
||||
INSERT INTO d (g, e, h, f, j, i) VALUES ( 1, 1, 1, 1, 1, 1 );
|
||||
INSERT INTO a (b, c) VALUES ( 1, 1 );
|
||||
INSERT INTO d_to_a VALUES (1, 1, 1, 1, 1, 1, 1, 1);
|
||||
|
||||
DELETE FROM d_to_a
|
||||
WHERE f_g = 1 AND f_e = 1 AND f_h = 1 AND f_f = 1 AND t_b = 1 AND t_c = 1;
|
||||
|
||||
SELECT * FROM d_to_a;
|
||||
} {}
|
||||
|
||||
faultsim_delete_and_reopen
|
||||
do_execsql_test 2.0 { CREATE TABLE t1(a,b,c,d,e, PRIMARY KEY(a,b,c,d,e)) }
|
||||
do_execsql_test 2.1 { CREATE TABLE t2(x) }
|
||||
faultsim_save_and_close
|
||||
|
||||
do_faultsim_test 3 -faults oom* -prep {
|
||||
faultsim_restore_and_reopen
|
||||
execsql { SELECT 1 FROM sqlite_master }
|
||||
} -body {
|
||||
execsql { SELECT * FROM t1,t2 WHERE a=? AND b=? AND c=? AND d=? AND e=? }
|
||||
} -test {
|
||||
faultsim_test_result {0 {}}
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -16,11 +16,26 @@
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
ifcapable !stat3 {
|
||||
ifcapable !stat4&&!stat3 {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
proc s {blob} {
|
||||
set ret ""
|
||||
binary scan $blob c* bytes
|
||||
foreach b $bytes {
|
||||
set t [binary format c $b]
|
||||
if {[string is print $t]} {
|
||||
append ret $t
|
||||
} else {
|
||||
append ret .
|
||||
}
|
||||
}
|
||||
return $ret
|
||||
}
|
||||
db function s s
|
||||
|
||||
do_test tkt-cbd05-1.1 {
|
||||
db eval {
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY, b TEXT UNIQUE NOT NULL);
|
||||
@@ -39,18 +54,30 @@ do_test tkt-cbd05-1.1 {
|
||||
}
|
||||
} {10}
|
||||
do_test tkt-cbd05-1.2 {
|
||||
db eval {
|
||||
ANALYZE;
|
||||
db eval { ANALYZE; }
|
||||
ifcapable stat4 {
|
||||
db eval {
|
||||
PRAGMA writable_schema = 1;
|
||||
CREATE VIEW vvv AS
|
||||
SELECT tbl,idx,neq,nlt,ndlt,test_extract(sample,0) AS sample
|
||||
FROM sqlite_stat4;
|
||||
PRAGMA writable_schema = 0;
|
||||
}
|
||||
} else {
|
||||
db eval {
|
||||
CREATE VIEW vvv AS
|
||||
SELECT tbl,idx,neq,nlt,ndlt,sample FROM sqlite_stat3;
|
||||
}
|
||||
}
|
||||
} {}
|
||||
do_test tkt-cbd05-1.3 {
|
||||
execsql {
|
||||
SELECT tbl,idx,group_concat(sample,' ')
|
||||
FROM sqlite_stat3
|
||||
SELECT tbl,idx,group_concat(s(sample),' ')
|
||||
FROM vvv
|
||||
WHERE idx = 't1_x'
|
||||
GROUP BY tbl,idx
|
||||
}
|
||||
} {/t1 t1_x .[ ABCDEFGHI]{10}./}
|
||||
} {t1 t1_x { A B C D E F G H I}}
|
||||
|
||||
do_test tkt-cbd05-2.1 {
|
||||
db eval {
|
||||
@@ -77,11 +104,11 @@ do_test tkt-cbd05-2.2 {
|
||||
} {}
|
||||
do_test tkt-cbd05-2.3 {
|
||||
execsql {
|
||||
SELECT tbl,idx,group_concat(sample,' ')
|
||||
FROM sqlite_stat3
|
||||
SELECT tbl,idx,group_concat(s(sample),' ')
|
||||
FROM vvv
|
||||
WHERE idx = 't1_x'
|
||||
GROUP BY tbl,idx
|
||||
}
|
||||
} {/t1 t1_x .[ ABCDEFGHI]{10}./}
|
||||
} {t1 t1_x { A B C D E F G H I}}
|
||||
|
||||
finish_test
|
||||
|
||||
+1
-4
@@ -208,15 +208,12 @@ do_test tkt2822-5.4 {
|
||||
|
||||
# In "ORDER BY +b" the term is now an expression rather than
|
||||
# a label. It therefore matches by rule (3) instead of rule (2).
|
||||
#
|
||||
# 2013-04-13: This is busted. Changed to conform to PostgreSQL and
|
||||
# MySQL and Oracle behavior.
|
||||
#
|
||||
do_test tkt2822-5.5 {
|
||||
execsql {
|
||||
SELECT a AS b FROM t3 ORDER BY +b;
|
||||
}
|
||||
} {1 9}
|
||||
} {9 1}
|
||||
|
||||
# Tests for rule 2 in compound queries
|
||||
#
|
||||
|
||||
@@ -0,0 +1,187 @@
|
||||
# 2013-09-05
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
# TPC-H test queries.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix tpch01
|
||||
|
||||
do_execsql_test tpch01-1.0 {
|
||||
CREATE TABLE NATION ( N_NATIONKEY INTEGER NOT NULL,
|
||||
N_NAME CHAR(25) NOT NULL,
|
||||
N_REGIONKEY INTEGER NOT NULL,
|
||||
N_COMMENT VARCHAR(152));
|
||||
CREATE TABLE REGION ( R_REGIONKEY INTEGER NOT NULL,
|
||||
R_NAME CHAR(25) NOT NULL,
|
||||
R_COMMENT VARCHAR(152));
|
||||
CREATE TABLE PART ( P_PARTKEY INTEGER NOT NULL,
|
||||
P_NAME VARCHAR(55) NOT NULL,
|
||||
P_MFGR CHAR(25) NOT NULL,
|
||||
P_BRAND CHAR(10) NOT NULL,
|
||||
P_TYPE VARCHAR(25) NOT NULL,
|
||||
P_SIZE INTEGER NOT NULL,
|
||||
P_CONTAINER CHAR(10) NOT NULL,
|
||||
P_RETAILPRICE DECIMAL(15,2) NOT NULL,
|
||||
P_COMMENT VARCHAR(23) NOT NULL );
|
||||
CREATE TABLE SUPPLIER ( S_SUPPKEY INTEGER NOT NULL,
|
||||
S_NAME CHAR(25) NOT NULL,
|
||||
S_ADDRESS VARCHAR(40) NOT NULL,
|
||||
S_NATIONKEY INTEGER NOT NULL,
|
||||
S_PHONE CHAR(15) NOT NULL,
|
||||
S_ACCTBAL DECIMAL(15,2) NOT NULL,
|
||||
S_COMMENT VARCHAR(101) NOT NULL);
|
||||
CREATE TABLE PARTSUPP ( PS_PARTKEY INTEGER NOT NULL,
|
||||
PS_SUPPKEY INTEGER NOT NULL,
|
||||
PS_AVAILQTY INTEGER NOT NULL,
|
||||
PS_SUPPLYCOST DECIMAL(15,2) NOT NULL,
|
||||
PS_COMMENT VARCHAR(199) NOT NULL );
|
||||
CREATE TABLE CUSTOMER ( C_CUSTKEY INTEGER NOT NULL,
|
||||
C_NAME VARCHAR(25) NOT NULL,
|
||||
C_ADDRESS VARCHAR(40) NOT NULL,
|
||||
C_NATIONKEY INTEGER NOT NULL,
|
||||
C_PHONE CHAR(15) NOT NULL,
|
||||
C_ACCTBAL DECIMAL(15,2) NOT NULL,
|
||||
C_MKTSEGMENT CHAR(10) NOT NULL,
|
||||
C_COMMENT VARCHAR(117) NOT NULL);
|
||||
CREATE TABLE ORDERS ( O_ORDERKEY INTEGER NOT NULL,
|
||||
O_CUSTKEY INTEGER NOT NULL,
|
||||
O_ORDERSTATUS CHAR(1) NOT NULL,
|
||||
O_TOTALPRICE DECIMAL(15,2) NOT NULL,
|
||||
O_ORDERDATE DATE NOT NULL,
|
||||
O_ORDERPRIORITY CHAR(15) NOT NULL,
|
||||
O_CLERK CHAR(15) NOT NULL,
|
||||
O_SHIPPRIORITY INTEGER NOT NULL,
|
||||
O_COMMENT VARCHAR(79) NOT NULL);
|
||||
CREATE TABLE LINEITEM ( L_ORDERKEY INTEGER NOT NULL,
|
||||
L_PARTKEY INTEGER NOT NULL,
|
||||
L_SUPPKEY INTEGER NOT NULL,
|
||||
L_LINENUMBER INTEGER NOT NULL,
|
||||
L_QUANTITY DECIMAL(15,2) NOT NULL,
|
||||
L_EXTENDEDPRICE DECIMAL(15,2) NOT NULL,
|
||||
L_DISCOUNT DECIMAL(15,2) NOT NULL,
|
||||
L_TAX DECIMAL(15,2) NOT NULL,
|
||||
L_RETURNFLAG CHAR(1) NOT NULL,
|
||||
L_LINESTATUS CHAR(1) NOT NULL,
|
||||
L_SHIPDATE DATE NOT NULL,
|
||||
L_COMMITDATE DATE NOT NULL,
|
||||
L_RECEIPTDATE DATE NOT NULL,
|
||||
L_SHIPINSTRUCT CHAR(25) NOT NULL,
|
||||
L_SHIPMODE CHAR(10) NOT NULL,
|
||||
L_COMMENT VARCHAR(44) NOT NULL);
|
||||
CREATE INDEX npki on nation(N_NATIONKEY);
|
||||
CREATE INDEX rpki on region(R_REGIONKEY);
|
||||
CREATE INDEX ppki on part(P_PARTKEY);
|
||||
CREATE INDEX spki on supplier(S_SUPPKEY);
|
||||
CREATE INDEX pspki on partsupp(PS_PARTKEY, PS_SUPPKEY);
|
||||
CREATE INDEX cpki on customer(C_CUSTKEY);
|
||||
CREATE INDEX opki on orders(O_ORDERKEY);
|
||||
CREATE INDEX lpki on lineitem(L_ORDERKEY, L_LINENUMBER);
|
||||
CREATE INDEX nrki on nation(n_regionkey);
|
||||
CREATE INDEX snki on supplier(s_nationkey);
|
||||
CREATE INDEX cnki on customer(c_nationkey);
|
||||
CREATE INDEX ocki on orders(O_CUSTKEY);
|
||||
CREATE INDEX odi on orders(O_ORDERDATE);
|
||||
CREATE INDEX lpki2 on lineitem(L_PARTKEY);
|
||||
CREATE INDEX lski on lineitem(L_SUPPKEY);
|
||||
CREATE INDEX lsdi on lineitem(L_SHIPDATE);
|
||||
CREATE INDEX lcdi on lineitem(L_COMMITDATE);
|
||||
CREATE INDEX lrdi on lineitem(L_RECEIPTDATE);
|
||||
CREATE INDEX bootleg_nni on nation(N_NAME);
|
||||
CREATE INDEX bootleg_psi on part(p_size);
|
||||
CREATE INDEX bootleg_pti on part(p_type);
|
||||
ANALYZE sqlite_master;
|
||||
INSERT INTO sqlite_stat1 VALUES('LINEITEM','lrdi','600572 236');
|
||||
INSERT INTO sqlite_stat1 VALUES('LINEITEM','lcdi','600572 244');
|
||||
INSERT INTO sqlite_stat1 VALUES('LINEITEM','lsdi','600572 238');
|
||||
INSERT INTO sqlite_stat1 VALUES('LINEITEM','lski','600572 601');
|
||||
INSERT INTO sqlite_stat1 VALUES('LINEITEM','lpki2','600572 31');
|
||||
INSERT INTO sqlite_stat1 VALUES('LINEITEM','lpki','600572 5 1');
|
||||
INSERT INTO sqlite_stat1 VALUES('ORDERS','odi','150000 63');
|
||||
INSERT INTO sqlite_stat1 VALUES('ORDERS','ocki','150000 15');
|
||||
INSERT INTO sqlite_stat1 VALUES('ORDERS','opki','150000 1');
|
||||
INSERT INTO sqlite_stat1 VALUES('CUSTOMER','cnki','15000 600');
|
||||
INSERT INTO sqlite_stat1 VALUES('CUSTOMER','cpki','15000 1');
|
||||
INSERT INTO sqlite_stat1 VALUES('PARTSUPP','pspki','80000 4 1');
|
||||
INSERT INTO sqlite_stat1 VALUES('SUPPLIER','snki','1000 40');
|
||||
INSERT INTO sqlite_stat1 VALUES('SUPPLIER','spki','1000 1');
|
||||
INSERT INTO sqlite_stat1 VALUES('PART','bootleg_pti','20000 134');
|
||||
INSERT INTO sqlite_stat1 VALUES('PART','bootleg_psi','20000 400');
|
||||
INSERT INTO sqlite_stat1 VALUES('PART','ppki','20000 1');
|
||||
INSERT INTO sqlite_stat1 VALUES('REGION','rpki','5 1');
|
||||
INSERT INTO sqlite_stat1 VALUES('NATION','bootleg_nni','25 1');
|
||||
INSERT INTO sqlite_stat1 VALUES('NATION','nrki','25 5');
|
||||
INSERT INTO sqlite_stat1 VALUES('NATION','npki','25 1');
|
||||
ANALYZE sqlite_master;
|
||||
} {}
|
||||
|
||||
do_test tpch01-1.1 {
|
||||
unset -nocomplain ::eqpres
|
||||
set ::eqpres [db eval {EXPLAIN QUERY PLAN
|
||||
select
|
||||
o_year,
|
||||
sum(case
|
||||
when nation = 'EGYPT' then volume
|
||||
else 0
|
||||
end) / sum(volume) as mkt_share
|
||||
from
|
||||
(
|
||||
select
|
||||
strftime('%Y', o_orderdate) as o_year,
|
||||
l_extendedprice * (1 - l_discount) as volume,
|
||||
n2.n_name as nation
|
||||
from
|
||||
part,
|
||||
supplier,
|
||||
lineitem,
|
||||
orders,
|
||||
customer,
|
||||
nation n1,
|
||||
nation n2,
|
||||
region
|
||||
where
|
||||
p_partkey = l_partkey
|
||||
and s_suppkey = l_suppkey
|
||||
and l_orderkey = o_orderkey
|
||||
and o_custkey = c_custkey
|
||||
and c_nationkey = n1.n_nationkey
|
||||
and n1.n_regionkey = r_regionkey
|
||||
and r_name = 'MIDDLE EAST'
|
||||
and s_nationkey = n2.n_nationkey
|
||||
and o_orderdate between '1995-01-01' and '1996-12-31'
|
||||
and p_type = 'LARGE PLATED STEEL'
|
||||
) as all_nations
|
||||
group by
|
||||
o_year
|
||||
order by
|
||||
o_year;}]
|
||||
set ::eqpres
|
||||
} {/0 0 0 {SEARCH TABLE part USING INDEX bootleg_pti .P_TYPE=..} 0 1 2 {SEARCH TABLE lineitem USING INDEX lpki2 .L_PARTKEY=..}.*/}
|
||||
do_test tpch01-1.1b {
|
||||
set ::eqpres
|
||||
} {/.* customer .* nation AS n1 .* nation AS n2 .*/}
|
||||
|
||||
do_eqp_test tpch01-1.2 {
|
||||
select
|
||||
c_custkey, c_name, sum(l_extendedprice * (1 - l_discount)) as revenue,
|
||||
c_acctbal, n_name, c_address, c_phone, c_comment
|
||||
from
|
||||
customer, orders, lineitem, nation
|
||||
where
|
||||
c_custkey = o_custkey and l_orderkey = o_orderkey
|
||||
and o_orderdate >= '1994-08-01' and o_orderdate < date('1994-08-01', '+3 month')
|
||||
and l_returnflag = 'R' and c_nationkey = n_nationkey
|
||||
group by
|
||||
c_custkey, c_name, c_acctbal, c_phone, n_name, c_address, c_comment
|
||||
order by
|
||||
revenue desc;
|
||||
} {0 0 1 {SEARCH TABLE orders USING INDEX odi (O_ORDERDATE>? AND O_ORDERDATE<?)} 0 1 0 {SEARCH TABLE customer USING INDEX cpki (C_CUSTKEY=?)} 0 2 3 {SEARCH TABLE nation USING INDEX npki (N_NATIONKEY=?)} 0 3 2 {SEARCH TABLE lineitem USING INDEX lpki (L_ORDERKEY=?)} 0 0 0 {USE TEMP B-TREE FOR GROUP BY} 0 0 0 {USE TEMP B-TREE FOR ORDER BY}}
|
||||
@@ -1304,4 +1304,33 @@ do_test where-17.5 {
|
||||
}
|
||||
} {42 1 43 1}
|
||||
|
||||
# Ticket [be84e357c035d068135f20bcfe82761bbf95006b] 2013-09-03
|
||||
# Segfault during query involving LEFT JOIN column in the ORDER BY clause.
|
||||
#
|
||||
do_execsql_test where-18.1 {
|
||||
CREATE TABLE t181(a);
|
||||
CREATE TABLE t182(b,c);
|
||||
INSERT INTO t181 VALUES(1);
|
||||
SELECT DISTINCT a FROM t181 LEFT JOIN t182 ON a=b ORDER BY c IS NULL;
|
||||
} {1}
|
||||
do_execsql_test where-18.2 {
|
||||
SELECT DISTINCT a FROM t181 LEFT JOIN t182 ON a=b ORDER BY +c;
|
||||
} {1}
|
||||
do_execsql_test where-18.3 {
|
||||
SELECT DISTINCT a FROM t181 LEFT JOIN t182 ON a=b ORDER BY c;
|
||||
} {1}
|
||||
do_execsql_test where-18.4 {
|
||||
INSERT INTO t181 VALUES(1),(1),(1),(1);
|
||||
SELECT DISTINCT a FROM t181 LEFT JOIN t182 ON a=b ORDER BY +c;
|
||||
} {1}
|
||||
do_execsql_test where-18.5 {
|
||||
INSERT INTO t181 VALUES(2);
|
||||
SELECT DISTINCT a FROM t181 LEFT JOIN t182 ON a=b ORDER BY c IS NULL, +a;
|
||||
} {1 2}
|
||||
do_execsql_test where-18.6 {
|
||||
INSERT INTO t181 VALUES(2);
|
||||
SELECT DISTINCT a FROM t181 LEFT JOIN t182 ON a=b ORDER BY +a, +c IS NULL;
|
||||
} {1 2}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -701,6 +701,7 @@ do_test where2-11.4 {
|
||||
|
||||
# Verify that the OR clause is used in an outer loop even when
|
||||
# the OR clause scores slightly better on an inner loop.
|
||||
if {[permutation] != "no_optimization"} {
|
||||
do_execsql_test where2-12.1 {
|
||||
CREATE TABLE t12(x INTEGER PRIMARY KEY, y);
|
||||
CREATE INDEX t12y ON t12(y);
|
||||
@@ -709,6 +710,7 @@ do_execsql_test where2-12.1 {
|
||||
FROM t12 AS a JOIN t12 AS b ON a.y=b.x
|
||||
WHERE (b.x=$abc OR b.y=$abc);
|
||||
} {/.*SEARCH TABLE t12 AS b .*SEARCH TABLE t12 AS b .*/}
|
||||
}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -246,6 +246,12 @@ do_execsql_test where3-3.1 {
|
||||
0 0 1 {SCAN TABLE t302}
|
||||
0 1 0 {SEARCH TABLE t301 USING INTEGER PRIMARY KEY (rowid=?)}
|
||||
}
|
||||
do_execsql_test where3-3.2 {
|
||||
SELECT * FROM t301 WHERE c=3 AND a IS NULL;
|
||||
} {}
|
||||
do_execsql_test where3-3.3 {
|
||||
SELECT * FROM t301 WHERE c=3 AND a IS NOT NULL;
|
||||
} {1 2 3}
|
||||
|
||||
if 0 { # Query planner no longer does this
|
||||
# Verify that when there are multiple tables in a join which must be
|
||||
|
||||
+32
-3
@@ -781,11 +781,11 @@ do_test where9-6.8.2 {
|
||||
OR (b NOT NULL AND c NOT NULL AND d IS NULL)
|
||||
}
|
||||
} {1 {no query solution}}
|
||||
ifcapable stat3 {
|
||||
ifcapable stat4||stat3 {
|
||||
# When STAT3 is enabled, the "b NOT NULL" terms get translated
|
||||
# into b>NULL, which can be satified by the index t1b. It is a very
|
||||
# expensive way to do the query, but it works, and so a solution is possible.
|
||||
do_test where9-6.8.3-stat3 {
|
||||
do_test where9-6.8.3-stat4 {
|
||||
catchsql {
|
||||
UPDATE t1 INDEXED BY t1b SET a=a+100
|
||||
WHERE (b IS NULL AND c NOT NULL AND d NOT NULL)
|
||||
@@ -793,7 +793,7 @@ ifcapable stat3 {
|
||||
OR (b NOT NULL AND c NOT NULL AND d IS NULL)
|
||||
}
|
||||
} {0 {}}
|
||||
do_test where9-6.8.4-stat3 {
|
||||
do_test where9-6.8.4-stat4 {
|
||||
catchsql {
|
||||
DELETE FROM t1 INDEXED BY t1b
|
||||
WHERE (b IS NULL AND c NOT NULL AND d NOT NULL)
|
||||
@@ -851,6 +851,11 @@ do_test where9-7.0 {
|
||||
INSERT INTO t6 SELECT * FROM t5;
|
||||
ANALYZE t5;
|
||||
}
|
||||
ifcapable stat3 {
|
||||
sqlite3 db2 test.db
|
||||
db2 eval { DROP TABLE IF EXISTS sqlite_stat3 }
|
||||
db2 close
|
||||
}
|
||||
} {}
|
||||
do_test where9-7.1.1 {
|
||||
count_steps {
|
||||
@@ -951,4 +956,28 @@ do_test where9-9.1 {
|
||||
}
|
||||
} {1 2 3 4 8 9}
|
||||
|
||||
# Fix for ticket [bc878246eafe0f52c519e29049b2fe4a99491b27]
|
||||
# Incorrect result when OR is used in a join to the right of a LEFT JOIN
|
||||
#
|
||||
do_test where9-10.1 {
|
||||
db eval {
|
||||
CREATE TABLE t101 (id INTEGER PRIMARY KEY);
|
||||
INSERT INTO t101 VALUES (1);
|
||||
SELECT * FROM t101 AS t0
|
||||
LEFT JOIN t101 AS t1 ON t1.id BETWEEN 10 AND 20
|
||||
JOIN t101 AS t2 ON (t2.id = t0.id OR (t2.id<>555 AND t2.id=t1.id));
|
||||
}
|
||||
} {1 {} 1}
|
||||
do_test where9-10.2 {
|
||||
db eval {
|
||||
CREATE TABLE t102 (id TEXT UNIQUE NOT NULL);
|
||||
INSERT INTO t102 VALUES ('1');
|
||||
SELECT * FROM t102 AS t0
|
||||
LEFT JOIN t102 AS t1 ON t1.id GLOB 'abc%'
|
||||
JOIN t102 AS t2 ON (t2.id = t0.id OR (t2.id<>555 AND t2.id=t1.id));
|
||||
}
|
||||
} {1 {} 1}
|
||||
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -68,6 +68,12 @@ do_test whereA-1.7 {
|
||||
SELECT * FROM t1;
|
||||
}
|
||||
} {3 4.53 {} 2 hello world 1 2 3}
|
||||
do_execsql_test whereA-1.8 {
|
||||
SELECT * FROM t1 WHERE b=2 AND a IS NULL;
|
||||
} {}
|
||||
do_execsql_test whereA-1.9 {
|
||||
SELECT * FROM t1 WHERE b=2 AND a IS NOT NULL;
|
||||
} {1 2 3}
|
||||
|
||||
do_test whereA-2.1 {
|
||||
db eval {
|
||||
|
||||
@@ -112,4 +112,11 @@ foreach {tn sql} {
|
||||
} {/.*SCAN TABLE t2\y.*SEARCH TABLE t1\y.*/}
|
||||
}
|
||||
|
||||
do_execsql_test 4.0 {
|
||||
CREATE TABLE t4(a,b,c,d,e, PRIMARY KEY(a,b,c));
|
||||
CREATE INDEX t4adc ON t4(a,d,c);
|
||||
CREATE UNIQUE INDEX t4aebc ON t4(a,e,b,c);
|
||||
EXPLAIN QUERY PLAN SELECT rowid FROM t4 WHERE a=? AND b=?;
|
||||
} {/a=. AND b=./}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
# 2013 August 27
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
# This file implements regression tests for SQLite library. The
|
||||
# focus of this script is testing the file name handling provided
|
||||
# by the "win32-longpath" VFS.
|
||||
#
|
||||
|
||||
if {$tcl_platform(platform)!="windows"} return
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix win32longpath
|
||||
|
||||
db close
|
||||
set path [file nativename [get_pwd]]
|
||||
sqlite3 db [file join $path test.db] -vfs win32-longpath
|
||||
|
||||
do_test 1.1 {
|
||||
db eval {
|
||||
BEGIN EXCLUSIVE;
|
||||
CREATE TABLE t1(x);
|
||||
INSERT INTO t1 VALUES(1);
|
||||
INSERT INTO t1 VALUES(2);
|
||||
INSERT INTO t1 VALUES(3);
|
||||
INSERT INTO t1 VALUES(4);
|
||||
SELECT x FROM t1 ORDER BY x;
|
||||
COMMIT;
|
||||
}
|
||||
} {1 2 3 4}
|
||||
|
||||
set longPath(1) \\\\?\\$path\\[pid]
|
||||
make_win32_dir $longPath(1)
|
||||
|
||||
set longPath(2) $longPath(1)\\[string repeat X 255]
|
||||
make_win32_dir $longPath(2)
|
||||
|
||||
set longPath(3) $longPath(2)\\[string repeat Y 255]
|
||||
make_win32_dir $longPath(3)
|
||||
|
||||
set fileName $longPath(3)\\test.db
|
||||
|
||||
do_test 1.2 {
|
||||
list [catch {sqlite3 db2 [string range $fileName 4 end]} msg] $msg
|
||||
} {1 {unable to open database file}}
|
||||
|
||||
sqlite3 db3 $fileName -vfs win32-longpath
|
||||
|
||||
do_test 1.3 {
|
||||
db3 eval {
|
||||
BEGIN EXCLUSIVE;
|
||||
CREATE TABLE t1(x);
|
||||
INSERT INTO t1 VALUES(5);
|
||||
INSERT INTO t1 VALUES(6);
|
||||
INSERT INTO t1 VALUES(7);
|
||||
INSERT INTO t1 VALUES(8);
|
||||
SELECT x FROM t1 ORDER BY x;
|
||||
COMMIT;
|
||||
}
|
||||
} {5 6 7 8}
|
||||
|
||||
db3 close
|
||||
# puts " Database exists \{[exists_win32_path $fileName]\}"
|
||||
|
||||
sqlite3 db3 $fileName -vfs win32-longpath
|
||||
|
||||
do_test 1.4 {
|
||||
db3 eval {
|
||||
PRAGMA journal_mode = WAL;
|
||||
}
|
||||
} {wal}
|
||||
|
||||
do_test 1.5 {
|
||||
db3 eval {
|
||||
BEGIN EXCLUSIVE;
|
||||
INSERT INTO t1 VALUES(9);
|
||||
INSERT INTO t1 VALUES(10);
|
||||
INSERT INTO t1 VALUES(11);
|
||||
INSERT INTO t1 VALUES(12);
|
||||
SELECT x FROM t1 ORDER BY x;
|
||||
COMMIT;
|
||||
}
|
||||
} {5 6 7 8 9 10 11 12}
|
||||
|
||||
db3 close
|
||||
# puts " Database exists \{[exists_win32_path $fileName]\}"
|
||||
|
||||
do_delete_win32_file $fileName
|
||||
# puts " Files remaining \{[find_win32_file $longPath(3)\\*]\}"
|
||||
|
||||
do_remove_win32_dir $longPath(3)
|
||||
do_remove_win32_dir $longPath(2)
|
||||
do_remove_win32_dir $longPath(1)
|
||||
|
||||
finish_test
|
||||
+14
-1
@@ -23,6 +23,16 @@ set -u
|
||||
TMPSPACE=./mkpkg_tmp_dir
|
||||
VERSION=`cat $TOP/VERSION`
|
||||
|
||||
# Set global variable $ARTIFACT to the "3xxyyzz" string incorporated
|
||||
# into artifact filenames. And $VERSION2 to the "3.x.y[.z]" form.
|
||||
xx=`echo $VERSION|sed 's/3\.\([0-9]*\)\..*/\1/'`
|
||||
yy=`echo $VERSION|sed 's/3\.[^.]*\.\([0-9]*\).*/\1/'`
|
||||
zz=0
|
||||
set +e
|
||||
zz=`echo $VERSION|sed 's/3\.[^.]*\.[^.]*\.\([0-9]*\).*/\1/'|grep -v '\.'`
|
||||
set -e
|
||||
ARTIFACT=`printf "3%.2d%.2d%.2d" $xx $yy $zz`
|
||||
|
||||
rm -rf $TMPSPACE
|
||||
cp -R $TOP/autoconf $TMPSPACE
|
||||
|
||||
@@ -66,5 +76,8 @@ rm -rf autom4te.cache
|
||||
|
||||
cd ../
|
||||
./configure && make dist
|
||||
mv sqlite-$VERSION.tar.gz ../sqlite-amalgamation-$VERSION.tar.gz
|
||||
tar -xzf sqlite-$VERSION.tar.gz
|
||||
mv sqlite-$VERSION sqlite-autoconf-$ARTIFACT
|
||||
tar -czf sqlite-autoconf-$ARTIFACT.tar.gz sqlite-autoconf-$ARTIFACT
|
||||
mv sqlite-autoconf-$ARTIFACT.tar.gz ..
|
||||
|
||||
|
||||
+8
-2
@@ -137,7 +137,7 @@ proc section_comment {text} {
|
||||
|
||||
# Read the source file named $filename and write it into the
|
||||
# sqlite3.c output file. If any #include statements are seen,
|
||||
# process them approprately.
|
||||
# process them appropriately.
|
||||
#
|
||||
proc copy_file {filename} {
|
||||
global seen_hdr available_hdr out addstatic linemacros
|
||||
@@ -169,8 +169,14 @@ proc copy_file {filename} {
|
||||
} elseif {![info exists seen_hdr($hdr)]} {
|
||||
set seen_hdr($hdr) 1
|
||||
puts $out $line
|
||||
} elseif {[regexp {/\*\s+amalgamator:\s+keep\s+\*/} $line]} {
|
||||
# This include file must be kept because there was a "keep"
|
||||
# directive inside of a line comment.
|
||||
puts $out $line
|
||||
} else {
|
||||
puts $out "/* $line */"
|
||||
# Comment out the entire line, replacing any nested comment
|
||||
# begin/end markers with the harmless substring "**".
|
||||
puts $out "/* [string map [list /* ** */ **] $line] */"
|
||||
}
|
||||
} elseif {[regexp {^#ifdef __cplusplus} $line]} {
|
||||
puts $out "#if 0"
|
||||
|
||||
Reference in New Issue
Block a user