1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-08 14:02:16 +03:00

Merge recent trunk changes into the sessions branch.

FossilOrigin-Name: 7e068e39b3b31364271664e0afb1cd95a235c26f
This commit is contained in:
drh
2013-01-03 22:22:55 +00:00
42 changed files with 2495 additions and 324 deletions

View File

@@ -370,6 +370,7 @@ TESTSRC = \
$(TOP)/src/test_osinst.c \ $(TOP)/src/test_osinst.c \
$(TOP)/src/test_pcache.c \ $(TOP)/src/test_pcache.c \
$(TOP)/src/test_quota.c \ $(TOP)/src/test_quota.c \
$(TOP)/src/test_regexp.c \
$(TOP)/src/test_rtree.c \ $(TOP)/src/test_rtree.c \
$(TOP)/src/test_schema.c \ $(TOP)/src/test_schema.c \
$(TOP)/src/test_server.c \ $(TOP)/src/test_server.c \

View File

@@ -696,6 +696,7 @@ TESTSRC = \
$(TOP)\src\test_osinst.c \ $(TOP)\src\test_osinst.c \
$(TOP)\src\test_pcache.c \ $(TOP)\src\test_pcache.c \
$(TOP)\src\test_quota.c \ $(TOP)\src\test_quota.c \
$(TOP)\src\test_regexp.c \
$(TOP)\src\test_rtree.c \ $(TOP)\src\test_rtree.c \
$(TOP)\src\test_schema.c \ $(TOP)\src\test_schema.c \
$(TOP)\src\test_server.c \ $(TOP)\src\test_server.c \

View File

@@ -1 +1 @@
3.7.15 3.7.16

47
configure vendored
View File

@@ -1,6 +1,6 @@
#! /bin/sh #! /bin/sh
# Guess values for system-dependent variables and create Makefiles. # Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.62 for sqlite 3.7.15. # Generated by GNU Autoconf 2.62 for sqlite 3.7.16.
# #
# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
# 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. # 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
@@ -743,8 +743,8 @@ SHELL=${CONFIG_SHELL-/bin/sh}
# Identity of this package. # Identity of this package.
PACKAGE_NAME='sqlite' PACKAGE_NAME='sqlite'
PACKAGE_TARNAME='sqlite' PACKAGE_TARNAME='sqlite'
PACKAGE_VERSION='3.7.15' PACKAGE_VERSION='3.7.16'
PACKAGE_STRING='sqlite 3.7.15' PACKAGE_STRING='sqlite 3.7.16'
PACKAGE_BUGREPORT='' PACKAGE_BUGREPORT=''
# Factoring default headers for most tests. # Factoring default headers for most tests.
@@ -1484,7 +1484,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing. # 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. # This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF cat <<_ACEOF
\`configure' configures sqlite 3.7.15 to adapt to many kinds of systems. \`configure' configures sqlite 3.7.16 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]... Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1549,7 +1549,7 @@ fi
if test -n "$ac_init_help"; then if test -n "$ac_init_help"; then
case $ac_init_help in case $ac_init_help in
short | recursive ) echo "Configuration of sqlite 3.7.15:";; short | recursive ) echo "Configuration of sqlite 3.7.16:";;
esac esac
cat <<\_ACEOF cat <<\_ACEOF
@@ -1665,7 +1665,7 @@ fi
test -n "$ac_init_help" && exit $ac_status test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then if $ac_init_version; then
cat <<\_ACEOF cat <<\_ACEOF
sqlite configure 3.7.15 sqlite configure 3.7.16
generated by GNU Autoconf 2.62 generated by GNU Autoconf 2.62
Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
@@ -1679,7 +1679,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake. running configure, to aid debugging if configure makes a mistake.
It was created by sqlite $as_me 3.7.15, which was It was created by sqlite $as_me 3.7.16, which was
generated by GNU Autoconf 2.62. Invocation command line was generated by GNU Autoconf 2.62. Invocation command line was
$ $0 $@ $ $0 $@
@@ -3733,13 +3733,13 @@ if test "${lt_cv_nm_interface+set}" = set; then
else else
lt_cv_nm_interface="BSD nm" lt_cv_nm_interface="BSD nm"
echo "int some_variable = 0;" > conftest.$ac_ext echo "int some_variable = 0;" > conftest.$ac_ext
(eval echo "\"\$as_me:3737: $ac_compile\"" >&5) (eval echo "\"\$as_me:3736: $ac_compile\"" >&5)
(eval "$ac_compile" 2>conftest.err) (eval "$ac_compile" 2>conftest.err)
cat conftest.err >&5 cat conftest.err >&5
(eval echo "\"\$as_me:3740: $NM \\\"conftest.$ac_objext\\\"\"" >&5) (eval echo "\"\$as_me:3739: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
(eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
cat conftest.err >&5 cat conftest.err >&5
(eval echo "\"\$as_me:3743: output\"" >&5) (eval echo "\"\$as_me:3742: output\"" >&5)
cat conftest.out >&5 cat conftest.out >&5
if $GREP 'External.*some_variable' conftest.out > /dev/null; then if $GREP 'External.*some_variable' conftest.out > /dev/null; then
lt_cv_nm_interface="MS dumpbin" lt_cv_nm_interface="MS dumpbin"
@@ -4961,7 +4961,7 @@ ia64-*-hpux*)
;; ;;
*-*-irix6*) *-*-irix6*)
# Find out which ABI we are using. # Find out which ABI we are using.
echo '#line 4965 "configure"' > conftest.$ac_ext echo '#line 4964 "configure"' > conftest.$ac_ext
if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
(eval $ac_compile) 2>&5 (eval $ac_compile) 2>&5
ac_status=$? ac_status=$?
@@ -6830,11 +6830,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'` -e 's:$: $lt_compiler_flag:'`
(eval echo "\"\$as_me:6834: $lt_compile\"" >&5) (eval echo "\"\$as_me:6833: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err) (eval "$lt_compile" 2>conftest.err)
ac_status=$? ac_status=$?
cat conftest.err >&5 cat conftest.err >&5
echo "$as_me:6838: \$? = $ac_status" >&5 echo "$as_me:6837: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized # The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output. # So say no if there are warnings other than the usual output.
@@ -7169,11 +7169,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'` -e 's:$: $lt_compiler_flag:'`
(eval echo "\"\$as_me:7173: $lt_compile\"" >&5) (eval echo "\"\$as_me:7172: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err) (eval "$lt_compile" 2>conftest.err)
ac_status=$? ac_status=$?
cat conftest.err >&5 cat conftest.err >&5
echo "$as_me:7177: \$? = $ac_status" >&5 echo "$as_me:7176: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized # The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output. # So say no if there are warnings other than the usual output.
@@ -7274,11 +7274,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'` -e 's:$: $lt_compiler_flag:'`
(eval echo "\"\$as_me:7278: $lt_compile\"" >&5) (eval echo "\"\$as_me:7277: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err) (eval "$lt_compile" 2>out/conftest.err)
ac_status=$? ac_status=$?
cat out/conftest.err >&5 cat out/conftest.err >&5
echo "$as_me:7282: \$? = $ac_status" >&5 echo "$as_me:7281: \$? = $ac_status" >&5
if (exit $ac_status) && test -s out/conftest2.$ac_objext if (exit $ac_status) && test -s out/conftest2.$ac_objext
then then
# The compiler can only warn and ignore the option if not recognized # The compiler can only warn and ignore the option if not recognized
@@ -7329,11 +7329,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'` -e 's:$: $lt_compiler_flag:'`
(eval echo "\"\$as_me:7333: $lt_compile\"" >&5) (eval echo "\"\$as_me:7332: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err) (eval "$lt_compile" 2>out/conftest.err)
ac_status=$? ac_status=$?
cat out/conftest.err >&5 cat out/conftest.err >&5
echo "$as_me:7337: \$? = $ac_status" >&5 echo "$as_me:7336: \$? = $ac_status" >&5
if (exit $ac_status) && test -s out/conftest2.$ac_objext if (exit $ac_status) && test -s out/conftest2.$ac_objext
then then
# The compiler can only warn and ignore the option if not recognized # The compiler can only warn and ignore the option if not recognized
@@ -10142,7 +10142,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF cat > conftest.$ac_ext <<_LT_EOF
#line 10146 "configure" #line 10145 "configure"
#include "confdefs.h" #include "confdefs.h"
#if HAVE_DLFCN_H #if HAVE_DLFCN_H
@@ -10238,7 +10238,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF cat > conftest.$ac_ext <<_LT_EOF
#line 10242 "configure" #line 10241 "configure"
#include "confdefs.h" #include "confdefs.h"
#if HAVE_DLFCN_H #if HAVE_DLFCN_H
@@ -12908,7 +12908,6 @@ $as_echo "file not found" >&6; }
fi fi
fi fi
if test "${use_tcl}" = "no" ; then if test "${use_tcl}" = "no" ; then
@@ -14033,7 +14032,7 @@ exec 6>&1
# report actual input values of CONFIG_FILES etc. instead of their # report actual input values of CONFIG_FILES etc. instead of their
# values after options handling. # values after options handling.
ac_log=" ac_log="
This file was extended by sqlite $as_me 3.7.15, which was This file was extended by sqlite $as_me 3.7.16, which was
generated by GNU Autoconf 2.62. Invocation command line was generated by GNU Autoconf 2.62. Invocation command line was
CONFIG_FILES = $CONFIG_FILES CONFIG_FILES = $CONFIG_FILES
@@ -14086,7 +14085,7 @@ Report bugs to <bug-autoconf@gnu.org>."
_ACEOF _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_version="\\ ac_cs_version="\\
sqlite config.status 3.7.15 sqlite config.status 3.7.16
configured by $0, generated by GNU Autoconf 2.62, configured by $0, generated by GNU Autoconf 2.62,
with options \\"`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\" with options \\"`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"

View File

@@ -254,6 +254,7 @@ TESTSRC = \
$(TOP)/src/test_osinst.c \ $(TOP)/src/test_osinst.c \
$(TOP)/src/test_pcache.c \ $(TOP)/src/test_pcache.c \
$(TOP)/src/test_quota.c \ $(TOP)/src/test_quota.c \
$(TOP)/src/test_regexp.c \
$(TOP)/src/test_rtree.c \ $(TOP)/src/test_rtree.c \
$(TOP)/src/test_schema.c \ $(TOP)/src/test_schema.c \
$(TOP)/src/test_server.c \ $(TOP)/src/test_server.c \

View File

@@ -1,12 +1,12 @@
C Pull\sthe\slatest\strunk\schanges\sinto\sthe\ssessions\sbranch,\sand\sin\sparticular\nthe\scollating-sequence\srefactorization. C Merge\srecent\strunk\schanges\sinto\sthe\ssessions\sbranch.
D 2012-12-08T23:37:22.043 D 2013-01-03T22:22:55.634
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in 690d441a758cbffd13e814dc2724a721a6ebd400 F Makefile.in a48faa9e7dd7d556d84f5456eabe5825dd8a6282
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
F Makefile.msc 26fd6e94ef8ed7d8b8c84b96b8347c52485f6d83 F Makefile.msc f74e5635d39e882c915c8b988848a744b3fb3a6a
F Makefile.vxworks b18ad88e9a8c6a001f5cf4a389116a4f1a7ab45f F Makefile.vxworks b18ad88e9a8c6a001f5cf4a389116a4f1a7ab45f
F README cd04a36fbc7ea56932a4052d7d0b7f09f27c33d6 F README cd04a36fbc7ea56932a4052d7d0b7f09f27c33d6
F VERSION edab4af5a4623f8198833ea481ce98ab53750a8d F VERSION 6d4f66eaebabc42ef8c2a4d2d0caf4ce7ee81137
F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50 F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50
F addopcodes.awk 17dc593f791f874d2c23a0f9360850ded0286531 F addopcodes.awk 17dc593f791f874d2c23a0f9360850ded0286531
F art/sqlite370.eps aa97a671332b432a54e1d74ff5e8775be34200c2 F art/sqlite370.eps aa97a671332b432a54e1d74ff5e8775be34200c2
@@ -15,7 +15,7 @@ F art/sqlite370.jpg d512473dae7e378a67e28ff96a34da7cb331def2
F config.guess 226d9a188c6196f3033ffc651cbc9dcee1a42977 F config.guess 226d9a188c6196f3033ffc651cbc9dcee1a42977
F config.h.in 0921066a13130082764ab4ab6456f7b5bebe56de F config.h.in 0921066a13130082764ab4ab6456f7b5bebe56de
F config.sub 9ebe4c3b3dab6431ece34f16828b594fb420da55 F config.sub 9ebe4c3b3dab6431ece34f16828b594fb420da55
F configure 20ac96f94269b3e2417b91fac63a9db0eb0a9b15 x F configure 5f2564ac77bef7db2484083452b011822a02d515 x
F configure.ac 81c43d151d0b0e406be056394cc9ff4cb3fd0444 F configure.ac 81c43d151d0b0e406be056394cc9ff4cb3fd0444
F contrib/sqlitecon.tcl 210a913ad63f9f991070821e599d600bd913e0ad F contrib/sqlitecon.tcl 210a913ad63f9f991070821e599d600bd913e0ad
F doc/lemon.html 334dbf6621b8fb8790297ec1abf3cfa4621709d1 F doc/lemon.html 334dbf6621b8fb8790297ec1abf3cfa4621709d1
@@ -115,7 +115,7 @@ F ext/session/sqlite3session.h f374c9c4c96e08f67ac418871c29d423245c7673
F ext/session/test_session.c ea4dc9b4a1895c8e6bddcbfe3838d7eb57df2d99 F ext/session/test_session.c ea4dc9b4a1895c8e6bddcbfe3838d7eb57df2d99
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8 F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
F main.mk d87518f07b121bd397117bf1f144f399388c7e06 F main.mk f2fd62730fb5c7771f565f1ea9da70f481eb9577
F mkdll.sh 7d09b23c05d56532e9d44a50868eb4b12ff4f74a F mkdll.sh 7d09b23c05d56532e9d44a50868eb4b12ff4f74a
F mkextu.sh 416f9b7089d80e5590a29692c9d9280a10dbad9f F mkextu.sh 416f9b7089d80e5590a29692c9d9280a10dbad9f
F mkextw.sh 4123480947681d9b434a5e7b1ee08135abe409ac F mkextw.sh 4123480947681d9b434a5e7b1ee08135abe409ac
@@ -130,10 +130,10 @@ F src/alter.c f8db986c03eb0bfb221523fc9bbb9d0b70de3168
F src/analyze.c 7553068d21e32a57fc33ab6b2393fc8c1ba41410 F src/analyze.c 7553068d21e32a57fc33ab6b2393fc8c1ba41410
F src/attach.c ea5247f240e2c08afd608e9beb380814b86655e1 F src/attach.c ea5247f240e2c08afd608e9beb380814b86655e1
F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34 F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34
F src/backup.c cab40f2c1fe79d6eb93d3b4086c78c41ad2fa5d0 F src/backup.c 32e35a3a4ea55b45c0e5f74eeb793aec71491517
F src/bitvec.c 26675fe8e431dc555e6f2d0e11e651d172234aa1 F src/bitvec.c 26675fe8e431dc555e6f2d0e11e651d172234aa1
F src/btmutex.c 976f45a12e37293e32cae0281b15a21d48a8aaa7 F src/btmutex.c 976f45a12e37293e32cae0281b15a21d48a8aaa7
F src/btree.c eccee944cb2221e919d7a855e5928d8643194b14 F src/btree.c 7a80e4a67f32a2494c383a28a495bf3bd71cc230
F src/btree.h 3ad7964d6c5b1c7bff569aab6adfa075f8bf06cd F src/btree.h 3ad7964d6c5b1c7bff569aab6adfa075f8bf06cd
F src/btreeInt.h 4e5c2bd0f9b36b2a815a6d84f771a61a65830621 F src/btreeInt.h 4e5c2bd0f9b36b2a815a6d84f771a61a65830621
F src/build.c f4f86c07002c6f3ee96c1e34e0e993a962ef2c73 F src/build.c f4f86c07002c6f3ee96c1e34e0e993a962ef2c73
@@ -142,16 +142,16 @@ F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac
F src/ctime.c 72a70dcfda75d3a1f81041ce4573e7afddcd8e4e F src/ctime.c 72a70dcfda75d3a1f81041ce4573e7afddcd8e4e
F src/date.c 067a81c9942c497aafd2c260e13add8a7d0c7dd4 F src/date.c 067a81c9942c497aafd2c260e13add8a7d0c7dd4
F src/delete.c 9bc9463952bdc9fc43111b1f9c83a0af9b8e2239 F src/delete.c 9bc9463952bdc9fc43111b1f9c83a0af9b8e2239
F src/expr.c 0e41d66d868b37dbc0e041c342e0036fad27e705 F src/expr.c 4dff0b04eaaf133789279c6b8cd69175dfbb1691
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
F src/fkey.c dcb7c37a4bf526ded7b24a01a60fe071bcd160a2 F src/fkey.c 5b7a12e2f8620e855b0478a9a6798df9967bb277
F src/func.c 8147799b048065a1590805be464d05b4913e652c F src/func.c 8147799b048065a1590805be464d05b4913e652c
F src/global.c e59ecd2c553ad0d4bfbc84ca71231336f8993a7a F src/global.c e59ecd2c553ad0d4bfbc84ca71231336f8993a7a
F src/hash.c ac3470bbf1ca4ae4e306a8ecb0fdf1731810ffe4 F src/hash.c ac3470bbf1ca4ae4e306a8ecb0fdf1731810ffe4
F src/hash.h 2894c932d84d9f892d4b4023a75e501f83050970 F src/hash.h 2894c932d84d9f892d4b4023a75e501f83050970
F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08 F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08
F src/insert.c 36c17b9b97a9287aa8561f138d893ddf2b25d0b2 F src/insert.c 36c17b9b97a9287aa8561f138d893ddf2b25d0b2
F src/journal.c eb7b9f5e783266521bcd9b2b93d419a219411f71 F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d
F src/legacy.c a199d7683d60cef73089e892409113e69c23a99f F src/legacy.c a199d7683d60cef73089e892409113e69c23a99f
F src/lempar.c cdf0a000315332fc9b50b62f3b5e22e080a0952b F src/lempar.c cdf0a000315332fc9b50b62f3b5e22e080a0952b
F src/loadext.c f20382fbaeec832438a1ba7797bee3d3c8a6d51d F src/loadext.c f20382fbaeec832438a1ba7797bee3d3c8a6d51d
@@ -176,26 +176,26 @@ F src/os_unix.c ad459bb62eb6f3f6aae26d97b1a28fbac7bf0260
F src/os_win.c ce1f5db8a7bb4d6f2092b1b2cb9631bec54a6320 F src/os_win.c ce1f5db8a7bb4d6f2092b1b2cb9631bec54a6320
F src/pager.c 4092c907222cfd451c74fe6bd2fd64b342f7190f F src/pager.c 4092c907222cfd451c74fe6bd2fd64b342f7190f
F src/pager.h 1109a06578ec5574dc2c74cf8d9f69daf36fe3e0 F src/pager.h 1109a06578ec5574dc2c74cf8d9f69daf36fe3e0
F src/parse.y c2b4a6454ad77299b1443e2c483a560a9f16e724 F src/parse.y 5d5e12772845805fdfeb889163516b84fbb9ae95
F src/pcache.c f8043b433a57aba85384a531e3937a804432a346 F src/pcache.c f8043b433a57aba85384a531e3937a804432a346
F src/pcache.h 1b5dcc3dc8103d03e625b177023ee67764fa6b7c F src/pcache.h 1b5dcc3dc8103d03e625b177023ee67764fa6b7c
F src/pcache1.c 9fd22671c270b35131ef480bbc00392b8b5f8ab9 F src/pcache1.c 9fd22671c270b35131ef480bbc00392b8b5f8ab9
F src/pragma.c 015723c48072781d2740e310ab04dc92956b76d1 F src/pragma.c 8907c559d3127729d3bcedb1fe5c59fc196d3a17
F src/prepare.c 931ad0d852a0df48f79adcba6ce79ca5f475625c F src/prepare.c 931ad0d852a0df48f79adcba6ce79ca5f475625c
F src/printf.c 4a9f882f1c1787a8b494a2987765acf9d97ac21f F src/printf.c 4a9f882f1c1787a8b494a2987765acf9d97ac21f
F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50 F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50
F src/resolve.c cdd546d62da7763119ea1fa455a898959e03457f F src/resolve.c 521bdc0f6c7cf8246c0b9167d726d84005097c30
F src/rowset.c 64655f1a627c9c212d9ab497899e7424a34222e0 F src/rowset.c 64655f1a627c9c212d9ab497899e7424a34222e0
F src/select.c e6daa524bbdfa98f4abdb8cb281498f0047d3161 F src/select.c 395e458a6dc611cbe1179f424753f0c344957607
F src/shell.c e392dd1ccbb77cc1d75a8367a89b473c24bea019 F src/shell.c 11c9611580bb2ffce3a232f31f7f8cc310df0843
F src/sqlite.h.in 2be63c600ddc118753c6058639b282554d7f759c F src/sqlite.h.in 6a7a592aacc98674f39cb520cb7a7af87c2c2438
F src/sqlite3.rc fea433eb0a59f4c9393c8e6d76a6e2596b1fe0c0 F src/sqlite3.rc fea433eb0a59f4c9393c8e6d76a6e2596b1fe0c0
F src/sqlite3ext.h 6904f4aadf976f95241311fbffb00823075d9477 F src/sqlite3ext.h 6904f4aadf976f95241311fbffb00823075d9477
F src/sqliteInt.h e08e87a07d3cbbc57423c78f56b334579ef17741 F src/sqliteInt.h f3f74ba8e76a9a850bfc38a529e7d7ad8227d0be
F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
F src/status.c bedc37ec1a6bb9399944024d63f4c769971955a9 F src/status.c bedc37ec1a6bb9399944024d63f4c769971955a9
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
F src/tclsqlite.c 289be7b639406314813219ee7bc043d21f36ab12 F src/tclsqlite.c 0faa4b56ab352368b0bffa0874de5cf5c9d89c7e
F src/test1.c f62769c989146149590662ab02de4a813813a9c5 F src/test1.c f62769c989146149590662ab02de4a813813a9c5
F src/test2.c 4178056dd1e7d70f954ad8a1e3edb71a2a784daf F src/test2.c 4178056dd1e7d70f954ad8a1e3edb71a2a784daf
F src/test3.c 3c3c2407fa6ec7a19e24ae23f7cb439d0275a60d F src/test3.c 3c3c2407fa6ec7a19e24ae23f7cb439d0275a60d
@@ -229,6 +229,7 @@ F src/test_osinst.c 90a845c8183013d80eccb1f29e8805608516edba
F src/test_pcache.c a5cd24730cb43c5b18629043314548c9169abb00 F src/test_pcache.c a5cd24730cb43c5b18629043314548c9169abb00
F src/test_quota.c 0e0e2e3bf6766b101ecccd8c042b66e44e9be8f5 F src/test_quota.c 0e0e2e3bf6766b101ecccd8c042b66e44e9be8f5
F src/test_quota.h 8761e463b25e75ebc078bd67d70e39b9c817a0cb F src/test_quota.h 8761e463b25e75ebc078bd67d70e39b9c817a0cb
F src/test_regexp.c 8d91d00e45e899eb13575bec4870ce415900bec6
F src/test_rtree.c aba603c949766c4193f1068b91c787f57274e0d9 F src/test_rtree.c aba603c949766c4193f1068b91c787f57274e0d9
F src/test_schema.c 8c06ef9ddb240c7a0fcd31bc221a6a2aade58bf0 F src/test_schema.c 8c06ef9ddb240c7a0fcd31bc221a6a2aade58bf0
F src/test_server.c 2f99eb2837dfa06a4aacf24af24c6affdf66a84f F src/test_server.c 2f99eb2837dfa06a4aacf24af24c6affdf66a84f
@@ -249,7 +250,7 @@ F src/update.c abb0fcabe551dae0a133fd2a4370b5a8c23b1831
F src/utf.c 8d819e2e5104a430fc2005f018db14347c95a38f F src/utf.c 8d819e2e5104a430fc2005f018db14347c95a38f
F src/util.c 0af2e515dc0dabacec931bca39525f6c3f1c5455 F src/util.c 0af2e515dc0dabacec931bca39525f6c3f1c5455
F src/vacuum.c 2727bdd08847fcb6b2d2da6d14f018910e8645d3 F src/vacuum.c 2727bdd08847fcb6b2d2da6d14f018910e8645d3
F src/vdbe.c 85576363e303ffa5dc7d368af4cfd6bfbee96db1 F src/vdbe.c 4cf34269ba3a2f405eb4eb966c793baa07d863c0
F src/vdbe.h 1223e2548e0970cf96f573ff6b99f804a36ad683 F src/vdbe.h 1223e2548e0970cf96f573ff6b99f804a36ad683
F src/vdbeInt.h 2de43968dc47f1961d5bc76aa3cb68eacf433a7c F src/vdbeInt.h 2de43968dc47f1961d5bc76aa3cb68eacf433a7c
F src/vdbeapi.c 58fdcd56109c05876f69c25d47a138ef370d3647 F src/vdbeapi.c 58fdcd56109c05876f69c25d47a138ef370d3647
@@ -262,7 +263,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83
F src/wal.c f5c7b5027d0ed0e9bc9afeb4a3a8dfea762ec7d2 F src/wal.c f5c7b5027d0ed0e9bc9afeb4a3a8dfea762ec7d2
F src/wal.h 29c197540b19044e6cd73487017e5e47a1d3dac6 F src/wal.h 29c197540b19044e6cd73487017e5e47a1d3dac6
F src/walker.c 3d75ba73de15e0f8cd0737643badbeb0e002f07b F src/walker.c 3d75ba73de15e0f8cd0737643badbeb0e002f07b
F src/where.c 53b991af50dab230b319b098bcb90fc7cd82da47 F src/where.c b971ee2d1a4f5db1b4cfd5cb85e69f34e61781d0
F test/8_3_names.test 631ea964a3edb091cf73c3b540f6bcfdb36ce823 F test/8_3_names.test 631ea964a3edb091cf73c3b540f6bcfdb36ce823
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6
@@ -292,7 +293,7 @@ F test/attach3.test d89ccfe4fe6e2b5e368d480fcdfe4b496c54cf4e
F test/attach4.test 53bf502f17647c6d6c5add46dda6bac8b6f4665c F test/attach4.test 53bf502f17647c6d6c5add46dda6bac8b6f4665c
F test/attachmalloc.test 3a4bfca9545bfe906a8d2e622de10fbac5b711b0 F test/attachmalloc.test 3a4bfca9545bfe906a8d2e622de10fbac5b711b0
F test/auth.test 304e82f31592820d3bde26ab6b75deaa123e1a6f F test/auth.test 304e82f31592820d3bde26ab6b75deaa123e1a6f
F test/auth2.test 270baddc8b9c273682760cffba6739d907bd2882 F test/auth2.test a2a371aa6df15f8b0c8109b33d3d7f0f73e4c9aa
F test/auth3.test a4755e6a2a2fea547ffe63c874eb569e60a28eb5 F test/auth3.test a4755e6a2a2fea547ffe63c874eb569e60a28eb5
F test/autoinc.test bd30d372d00045252f6c2e41b5f41455e1975acf F test/autoinc.test bd30d372d00045252f6c2e41b5f41455e1975acf
F test/autoindex1.test 058d0b331ae6840a61bbee910d8cbae27bfd5991 F test/autoindex1.test 058d0b331ae6840a61bbee910d8cbae27bfd5991
@@ -395,15 +396,15 @@ F test/e_delete.test 89aa84d3d1bd284a0689ede04bce10226a5aeaa5
F test/e_droptrigger.test afd5c4d27dec607f5997a66bf7e2498a082cb235 F test/e_droptrigger.test afd5c4d27dec607f5997a66bf7e2498a082cb235
F test/e_dropview.test 583411e470458c5d76148542cfb5a5fa84c8f93e F test/e_dropview.test 583411e470458c5d76148542cfb5a5fa84c8f93e
F test/e_expr.test 5489424d3d9a452ac3701cdf4b680ae31a157894 F test/e_expr.test 5489424d3d9a452ac3701cdf4b680ae31a157894
F test/e_fkey.test a79ab1d3213c7ac64621eec28f8e8bb219775445 F test/e_fkey.test 89a2ff734a33693b997534eff90724573948be7b
F test/e_fts3.test 5c02288842e4f941896fd44afdef564dd5fc1459 F test/e_fts3.test 5c02288842e4f941896fd44afdef564dd5fc1459
F test/e_insert.test c6ac239a97cb16dfbd0c16496f8cd871b4068c0c F test/e_insert.test d5331cc95e101af2508159fc98b6801631659ffe
F test/e_reindex.test dfedfc32c5a282b0596c6537cbcd4217fbb1a216 F test/e_reindex.test dfedfc32c5a282b0596c6537cbcd4217fbb1a216
F test/e_resolve.test dcce9308fb13b934ce29591105d031d3e14fbba6 F test/e_resolve.test dcce9308fb13b934ce29591105d031d3e14fbba6
F test/e_select.test 07e8d81268ba1ffcaf1dc4bec48956af150c42f9 F test/e_select.test 07e8d81268ba1ffcaf1dc4bec48956af150c42f9
F test/e_select2.test 5c3d3da19c7b3e90ae444579db2b70098599ab92 F test/e_select2.test 5c3d3da19c7b3e90ae444579db2b70098599ab92
F test/e_update.test 161d5dc6a3ed9dd08f5264d13e20735d7a89f00c F test/e_update.test 161d5dc6a3ed9dd08f5264d13e20735d7a89f00c
F test/e_uri.test 9e190ca799d9190eec6e43f2aadf1d10c06a57a3 F test/e_uri.test bc240fbc6cbbbdff832ee05858432a25961ab36a
F test/e_vacuum.test 331da289ae186656cf5f2eb27f577a89c0c221af F test/e_vacuum.test 331da289ae186656cf5f2eb27f577a89c0c221af
F test/enc.test e54531cd6bf941ee6760be041dff19a104c7acea F test/enc.test e54531cd6bf941ee6760be041dff19a104c7acea
F test/enc2.test 796c59832e2b9a52842f382ffda8f3e989db03ad F test/enc2.test 796c59832e2b9a52842f382ffda8f3e989db03ad
@@ -419,12 +420,13 @@ F test/exists.test 8f7b27b61c2fbe5822f0a1f899c715d14e416e30
F test/expr.test 67c9fd6f8f829e239dc8b0f4a08a73c08b09196d F test/expr.test 67c9fd6f8f829e239dc8b0f4a08a73c08b09196d
F test/fallocate.test b5d34437bd7ab01d41b1464b8117aefd4d32160e F test/fallocate.test b5d34437bd7ab01d41b1464b8117aefd4d32160e
F test/filectrl.test 14fa712e42c4cb791e09dfd58a6a03efb47ef13a F test/filectrl.test 14fa712e42c4cb791e09dfd58a6a03efb47ef13a
F test/filefmt.test ffa17b5aebc3eb4b1e3be1ccb5ee906ffbd97f6e F test/filefmt.test dbee33e57818249cdffbbb7b13464635217beff1
F test/fkey1.test 01c7de578e11747e720c2d9aeef27f239853c4da F test/fkey1.test 01c7de578e11747e720c2d9aeef27f239853c4da
F test/fkey2.test 080969fe219b3b082b0e097ac18c6af2e5b0631f F test/fkey2.test 5aa44e7153928a1f002803f94aaab4c76a7ceac2
F test/fkey3.test 5ec899d12b13bcf1e9ef40eff7fb692fdb91392e F test/fkey3.test 5ec899d12b13bcf1e9ef40eff7fb692fdb91392e
F test/fkey4.test c6c8f9f9be885f95c85c7bceb26f243ad906fd49 F test/fkey4.test c6c8f9f9be885f95c85c7bceb26f243ad906fd49
F test/fkey_malloc.test c3a12acd053c976de09036498eef09b83afa4a80 F test/fkey5.test 0bf64f2d19ad80433ca0b24edbf604a18b353d5f
F test/fkey_malloc.test bb74c9cb8f8fceed03b58f8a7ef2df98520bbd51
F test/format4.test 1f0cac8ff3895e9359ed87e41aaabee982a812eb F test/format4.test 1f0cac8ff3895e9359ed87e41aaabee982a812eb
F test/fts-9fd058691.test 78b887e30ae6816df0e1fed6259de4b5a64ad33c F test/fts-9fd058691.test 78b887e30ae6816df0e1fed6259de4b5a64ad33c
F test/fts1a.test 46090311f85da51bb33bd5ce84f7948359c6d8d7 F test/fts1a.test 46090311f85da51bb33bd5ce84f7948359c6d8d7
@@ -567,6 +569,7 @@ F test/ioerr2.test 9d71166f8466eda510f1af6137bdabaa82b5408d
F test/ioerr3.test d3cec5e1a11ad6d27527d0d38573fbff14c71bdd F test/ioerr3.test d3cec5e1a11ad6d27527d0d38573fbff14c71bdd
F test/ioerr4.test f130fe9e71008577b342b8874d52984bd04ede2c F test/ioerr4.test f130fe9e71008577b342b8874d52984bd04ede2c
F test/ioerr5.test 2edfa4fb0f896f733071303b42224df8bedd9da4 F test/ioerr5.test 2edfa4fb0f896f733071303b42224df8bedd9da4
F test/ioerr6.test 13f0f9c31d706f0dd575995c369af07c0227e9a2
F test/join.test 8d63cc4d230a7affafa4b6ab0b97c49b8ccb365c F test/join.test 8d63cc4d230a7affafa4b6ab0b97c49b8ccb365c
F test/join2.test f2171c265e57ee298a27e57e7051d22962f9f324 F test/join2.test f2171c265e57ee298a27e57e7051d22962f9f324
F test/join3.test 6f0c774ff1ba0489e6c88a3e77b9d3528fb4fda0 F test/join3.test 6f0c774ff1ba0489e6c88a3e77b9d3528fb4fda0
@@ -625,7 +628,7 @@ F test/memdb.test 708a028d6d373e5b3842e4bdc8ba80998c9a4da6
F test/memleak.test 10b9c6c57e19fc68c32941495e9ba1c50123f6e2 F test/memleak.test 10b9c6c57e19fc68c32941495e9ba1c50123f6e2
F test/memsubsys1.test a8f9e37567453a5d1d9d37ec102d4d88ab6be33f F test/memsubsys1.test a8f9e37567453a5d1d9d37ec102d4d88ab6be33f
F test/memsubsys2.test 3a1c1a9de48e5726faa85108b02459fae8cb9ee9 F test/memsubsys2.test 3a1c1a9de48e5726faa85108b02459fae8cb9ee9
F test/minmax.test c61518429e66e228efc79661fbd2dc3e4924ec44 F test/minmax.test 42fbad0e81afaa6e0de41c960329f2b2c3526efd
F test/minmax2.test b44bae787fc7b227597b01b0ca5575c7cb54d3bc F test/minmax2.test b44bae787fc7b227597b01b0ca5575c7cb54d3bc
F test/minmax3.test cc1e8b010136db0d01a6f2a29ba5a9f321034354 F test/minmax3.test cc1e8b010136db0d01a6f2a29ba5a9f321034354
F test/minmax4.test 536a3360470633a177e42fbc19660d146b51daef F test/minmax4.test 536a3360470633a177e42fbc19660d146b51daef
@@ -663,7 +666,7 @@ F test/pagesize.test 1dd51367e752e742f58e861e65ed7390603827a0
F test/pcache.test 065aa286e722ab24f2e51792c1f093bf60656b16 F test/pcache.test 065aa286e722ab24f2e51792c1f093bf60656b16
F test/pcache2.test a83efe2dec0d392f814bfc998def1d1833942025 F test/pcache2.test a83efe2dec0d392f814bfc998def1d1833942025
F test/permutations.test 379cfbb9a5eea2499d05008c04d18ddb4f2c01a9 F test/permutations.test 379cfbb9a5eea2499d05008c04d18ddb4f2c01a9
F test/pragma.test a62f73293b0f0d79b0c87f8dd32d46fe53b0bd17 F test/pragma.test 5ce333cae37d86cfe9b3add840906e375e2272b0
F test/pragma2.test 3a55f82b954242c642f8342b17dffc8b47472947 F test/pragma2.test 3a55f82b954242c642f8342b17dffc8b47472947
F test/printf.test ec9870c4dce8686a37818e0bf1aba6e6a1863552 F test/printf.test ec9870c4dce8686a37818e0bf1aba6e6a1863552
F test/progress.test 5b075c3c790c7b2a61419bc199db87aaf48b8301 F test/progress.test 5b075c3c790c7b2a61419bc199db87aaf48b8301
@@ -676,9 +679,10 @@ F test/quote.test 215897dbe8de1a6f701265836d6601cc6ed103e6
F test/randexpr1.tcl 40dec52119ed3a2b8b2a773bce24b63a3a746459 F test/randexpr1.tcl 40dec52119ed3a2b8b2a773bce24b63a3a746459
F test/randexpr1.test eda062a97e60f9c38ae8d806b03b0ddf23d796df F test/randexpr1.test eda062a97e60f9c38ae8d806b03b0ddf23d796df
F test/rdonly.test c267d050a1d9a6a321de502b737daf28821a518d F test/rdonly.test c267d050a1d9a6a321de502b737daf28821a518d
F test/regexp1.test bbcb74e1bbdc20a7c0b9b2360deda14c4df1b46a
F test/reindex.test 44edd3966b474468b823d481eafef0c305022254 F test/reindex.test 44edd3966b474468b823d481eafef0c305022254
F test/releasetest.mk 2eced2f9ae701fd0a29e714a241760503ccba25a F test/releasetest.mk 2eced2f9ae701fd0a29e714a241760503ccba25a
F test/releasetest.tcl e48fd8e0e8abad89f30e08620790533ae4e02010 F test/releasetest.tcl 06d289d8255794073a58d2850742f627924545ce
F test/rollback.test a1b4784b864331eae8b2a98c189efa2a8b11ff07 F test/rollback.test a1b4784b864331eae8b2a98c189efa2a8b11ff07
F test/rowhash.test 0bc1d31415e4575d10cacf31e1a66b5cc0f8be81 F test/rowhash.test 0bc1d31415e4575d10cacf31e1a66b5cc0f8be81
F test/rowid.test f777404492adb0e00868fd706a3721328fd3af48 F test/rowid.test f777404492adb0e00868fd706a3721328fd3af48
@@ -709,6 +713,7 @@ F test/select9.test c0ca3cd87a8ebb04de2cb1402c77df55d911a0ea
F test/selectA.test 06d1032fa9009314c95394f2ca2e60d9f7ae8532 F test/selectA.test 06d1032fa9009314c95394f2ca2e60d9f7ae8532
F test/selectB.test 954e4e49cf1f896d61794e440669e03a27ceea25 F test/selectB.test 954e4e49cf1f896d61794e440669e03a27ceea25
F test/selectC.test 871fb55d884d3de5943c4057ebd22c2459e71977 F test/selectC.test 871fb55d884d3de5943c4057ebd22c2459e71977
F test/selectD.test 03f7c1ea8d5ab3c637cbc30fcbbbac96b988c162
F test/server1.test 46803bd3fe8b99b30dbc5ff38ffc756f5c13a118 F test/server1.test 46803bd3fe8b99b30dbc5ff38ffc756f5c13a118
F test/session.test c1a17c11ef7d01c24fe2b9f7871190d949a8e718 F test/session.test c1a17c11ef7d01c24fe2b9f7871190d949a8e718
F test/shared.test 1da9dbad400cee0d93f252ccf76e1ae007a63746 F test/shared.test 1da9dbad400cee0d93f252ccf76e1ae007a63746
@@ -796,6 +801,7 @@ F test/tkt-8454a207b9.test c583a9f814a82a2b5ba95207f55001c9f0cd816c
F test/tkt-91e2e8ba6f.test 08c4f94ae07696b05c9b822da0b4e5337a2f54c5 F test/tkt-91e2e8ba6f.test 08c4f94ae07696b05c9b822da0b4e5337a2f54c5
F test/tkt-94c04eaadb.test fa9c71192f7e2ea2d51bf078bc34e8da6088bf71 F test/tkt-94c04eaadb.test fa9c71192f7e2ea2d51bf078bc34e8da6088bf71
F test/tkt-9d68c883.test 458f7d82a523d7644b54b497c986378a7d8c8b67 F test/tkt-9d68c883.test 458f7d82a523d7644b54b497c986378a7d8c8b67
F test/tkt-a7b7803e.test 159ef554234fa1f9fb318c751b284bd1cf858da4
F test/tkt-b1d3a2e531.test 610ef582413171b379652663111b1f996d9f8f78 F test/tkt-b1d3a2e531.test 610ef582413171b379652663111b1f996d9f8f78
F test/tkt-b351d95f9.test d14a503c414c5c58fdde3e80f9a3cfef986498c0 F test/tkt-b351d95f9.test d14a503c414c5c58fdde3e80f9a3cfef986498c0
F test/tkt-b72787b1.test a95e8cdad0b98af1853ac7f0afd4ab27b77bf5f3 F test/tkt-b72787b1.test a95e8cdad0b98af1853ac7f0afd4ab27b77bf5f3
@@ -931,7 +937,7 @@ F test/vacuum4.test d3f8ecff345f166911568f397d2432c16d2867d9
F test/varint.test ab7b110089a08b9926ed7390e7e97bdefeb74102 F test/varint.test ab7b110089a08b9926ed7390e7e97bdefeb74102
F test/veryquick.test 7701bb609fe8bf6535514e8b849a309e8f00573b F test/veryquick.test 7701bb609fe8bf6535514e8b849a309e8f00573b
F test/view.test b182a67ec43f490b156b5a710827a341be83dd17 F test/view.test b182a67ec43f490b156b5a710827a341be83dd17
F test/vtab1.test 36c9935e4be3b6350b31b6b697561b6fc3ab349a F test/vtab1.test 4403f987860ebddef1ce2de6db7216421035339d
F test/vtab2.test 7bcffc050da5c68f4f312e49e443063e2d391c0d F test/vtab2.test 7bcffc050da5c68f4f312e49e443063e2d391c0d
F test/vtab3.test baad99fd27217f5d6db10660522e0b7192446de1 F test/vtab3.test baad99fd27217f5d6db10660522e0b7192446de1
F test/vtab4.test 942f8b8280b3ea8a41dae20e7822d065ca1cb275 F test/vtab4.test 942f8b8280b3ea8a41dae20e7822d065ca1cb275
@@ -981,9 +987,9 @@ F test/where4.test e9b9e2f2f98f00379e6031db6a6fca29bae782a2
F test/where5.test fdf66f96d29a064b63eb543e28da4dfdccd81ad2 F test/where5.test fdf66f96d29a064b63eb543e28da4dfdccd81ad2
F test/where6.test 5da5a98cec820d488e82708301b96cb8c18a258b F test/where6.test 5da5a98cec820d488e82708301b96cb8c18a258b
F test/where7.test 5c566388f0cc318b0032ce860f4ac5548e3c265a F test/where7.test 5c566388f0cc318b0032ce860f4ac5548e3c265a
F test/where8.test a6c740fd286d7883e274e17b6230a9d672a7ab1f F test/where8.test 02619a9bfc6df7b19979a02852bac09c3c99477a
F test/where8m.test da346596e19d54f0aba35ebade032a7c47d79739 F test/where8m.test da346596e19d54f0aba35ebade032a7c47d79739
F test/where9.test bcab47eff78f1412a6aec1d6b8a3939d4a9db098 F test/where9.test 0157862ccf0cfdf1a4622cdf697e5e2f09a8de44
F test/whereA.test 24c234263c8fe358f079d5e57d884fb569d2da0a F test/whereA.test 24c234263c8fe358f079d5e57d884fb569d2da0a
F test/whereB.test 0def95db3bdec220a731c7e4bec5930327c1d8c5 F test/whereB.test 0def95db3bdec220a731c7e4bec5930327c1d8c5
F test/whereC.test 13ff5ec0dba407c0e0c075980c75b3275a6774e5 F test/whereC.test 13ff5ec0dba407c0e0c075980c75b3275a6774e5
@@ -995,7 +1001,7 @@ F test/win32lock.test b2a539e85ae6b2d78475e016a9636b4451dc7fb9
F test/zeroblob.test caaecfb4f908f7bc086ed238668049f96774d688 F test/zeroblob.test caaecfb4f908f7bc086ed238668049f96774d688
F test/zerodamage.test e7f77fded01dfcdf92ac2c5400f1e35d7a21463c F test/zerodamage.test e7f77fded01dfcdf92ac2c5400f1e35d7a21463c
F tool/build-all-msvc.bat 74fb6e5cca66ebdb6c9bbafb2f8b802f08146d38 x F tool/build-all-msvc.bat 74fb6e5cca66ebdb6c9bbafb2f8b802f08146d38 x
F tool/build-shell.sh b64a481901fc9ffe5ca8812a2a9255b6cfb77381 F tool/build-shell.sh 562df23cfdd25822b909b382afd5f99d968437fe
F tool/checkSpacing.c 810e51703529a204fc4e1eb060e9ab663e3c06d2 F tool/checkSpacing.c 810e51703529a204fc4e1eb060e9ab663e3c06d2
F tool/diffdb.c 7524b1b5df217c20cd0431f6789851a4e0cb191b F tool/diffdb.c 7524b1b5df217c20cd0431f6789851a4e0cb191b
F tool/extract.c 054069d81b095fbdc189a6f5d4466e40380505e2 F tool/extract.c 054069d81b095fbdc189a6f5d4466e40380505e2
@@ -1038,7 +1044,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381
F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac
P ba8d08b67021a32fda069c18b7eb93523e6f0d1f 92c9ab56b1c67b9468bec57ab1d2c483a69a2810 P 4f6d69ae94671df92b976525f75404c01270fef9 45c158b1a015e0295244982e7a61ecc55cca8436
R f06c7a4e8d9fd6f22d929caa0d8aff12 R 8d2ecc460dcc396acbf742a4b5125040
U drh U drh
Z 66550b6aeab54597acd3e06f02611eed Z c65bfb73ba1c154a624c7762ce7998dd

View File

@@ -1 +1 @@
4f6d69ae94671df92b976525f75404c01270fef9 7e068e39b3b31364271664e0afb1cd95a235c26f

View File

@@ -212,7 +212,12 @@ static int isFatalError(int rc){
** page iSrcPg from the source database. Copy this data into the ** page iSrcPg from the source database. Copy this data into the
** destination database. ** destination database.
*/ */
static int backupOnePage(sqlite3_backup *p, Pgno iSrcPg, const u8 *zSrcData){ static int backupOnePage(
sqlite3_backup *p, /* Backup handle */
Pgno iSrcPg, /* Source database page to backup */
const u8 *zSrcData, /* Source database page data */
int bUpdate /* True for an update, false otherwise */
){
Pager * const pDestPager = sqlite3BtreePager(p->pDest); Pager * const pDestPager = sqlite3BtreePager(p->pDest);
const int nSrcPgsz = sqlite3BtreeGetPageSize(p->pSrc); const int nSrcPgsz = sqlite3BtreeGetPageSize(p->pSrc);
int nDestPgsz = sqlite3BtreeGetPageSize(p->pDest); int nDestPgsz = sqlite3BtreeGetPageSize(p->pDest);
@@ -285,6 +290,9 @@ static int backupOnePage(sqlite3_backup *p, Pgno iSrcPg, const u8 *zSrcData){
*/ */
memcpy(zOut, zIn, nCopy); memcpy(zOut, zIn, nCopy);
((u8 *)sqlite3PagerGetExtra(pDestPg))[0] = 0; ((u8 *)sqlite3PagerGetExtra(pDestPg))[0] = 0;
if( iOff==0 && bUpdate==0 ){
sqlite3Put4byte(&zOut[28], sqlite3BtreeLastPage(p->pSrc));
}
} }
sqlite3PagerUnref(pDestPg); sqlite3PagerUnref(pDestPg);
} }
@@ -391,7 +399,7 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){
DbPage *pSrcPg; /* Source page object */ DbPage *pSrcPg; /* Source page object */
rc = sqlite3PagerGet(pSrcPager, iSrcPg, &pSrcPg); rc = sqlite3PagerGet(pSrcPager, iSrcPg, &pSrcPg);
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
rc = backupOnePage(p, iSrcPg, sqlite3PagerGetData(pSrcPg)); rc = backupOnePage(p, iSrcPg, sqlite3PagerGetData(pSrcPg), 0);
sqlite3PagerUnref(pSrcPg); sqlite3PagerUnref(pSrcPg);
} }
} }
@@ -639,7 +647,7 @@ void sqlite3BackupUpdate(sqlite3_backup *pBackup, Pgno iPage, const u8 *aData){
int rc; int rc;
assert( p->pDestDb ); assert( p->pDestDb );
sqlite3_mutex_enter(p->pDestDb->mutex); sqlite3_mutex_enter(p->pDestDb->mutex);
rc = backupOnePage(p, iPage, aData); rc = backupOnePage(p, iPage, aData, 1);
sqlite3_mutex_leave(p->pDestDb->mutex); sqlite3_mutex_leave(p->pDestDb->mutex);
assert( rc!=SQLITE_BUSY && rc!=SQLITE_LOCKED ); assert( rc!=SQLITE_BUSY && rc!=SQLITE_LOCKED );
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){

View File

@@ -8026,7 +8026,7 @@ char *sqlite3BtreeIntegrityCheck(
} }
i = PENDING_BYTE_PAGE(pBt); i = PENDING_BYTE_PAGE(pBt);
if( i<=sCheck.nPage ) setPageReferenced(&sCheck, i); if( i<=sCheck.nPage ) setPageReferenced(&sCheck, i);
sqlite3StrAccumInit(&sCheck.errMsg, zErr, sizeof(zErr), 20000); sqlite3StrAccumInit(&sCheck.errMsg, zErr, sizeof(zErr), SQLITE_MAX_LENGTH);
sCheck.errMsg.useMalloc = 2; sCheck.errMsg.useMalloc = 2;
/* Check the integrity of the freelist /* Check the integrity of the freelist

View File

@@ -3281,6 +3281,12 @@ void sqlite3ExplainExprList(Vdbe *pOut, ExprList *pList){
sqlite3ExplainPush(pOut); sqlite3ExplainPush(pOut);
sqlite3ExplainExpr(pOut, pList->a[i].pExpr); sqlite3ExplainExpr(pOut, pList->a[i].pExpr);
sqlite3ExplainPop(pOut); sqlite3ExplainPop(pOut);
if( pList->a[i].zName ){
sqlite3ExplainPrintf(pOut, " AS %s", pList->a[i].zName);
}
if( pList->a[i].bSpanIsTab ){
sqlite3ExplainPrintf(pOut, " (%s)", pList->a[i].zSpan);
}
if( i<pList->nExpr-1 ){ if( i<pList->nExpr-1 ){
sqlite3ExplainNL(pOut); sqlite3ExplainNL(pOut);
} }

View File

@@ -142,7 +142,7 @@
** A foreign key constraint requires that the key columns in the parent ** A foreign key constraint requires that the key columns in the parent
** table are collectively subject to a UNIQUE or PRIMARY KEY constraint. ** table are collectively subject to a UNIQUE or PRIMARY KEY constraint.
** Given that pParent is the parent table for foreign key constraint pFKey, ** Given that pParent is the parent table for foreign key constraint pFKey,
** search the schema a unique index on the parent key columns. ** search the schema for a unique index on the parent key columns.
** **
** If successful, zero is returned. If the parent key is an INTEGER PRIMARY ** If successful, zero is returned. If the parent key is an INTEGER PRIMARY
** KEY column, then output variable *ppIdx is set to NULL. Otherwise, *ppIdx ** KEY column, then output variable *ppIdx is set to NULL. Otherwise, *ppIdx
@@ -178,7 +178,7 @@
** into pParse. If an OOM error occurs, non-zero is returned and the ** into pParse. If an OOM error occurs, non-zero is returned and the
** pParse->db->mallocFailed flag is set. ** pParse->db->mallocFailed flag is set.
*/ */
static int locateFkeyIndex( int sqlite3FkLocateIndex(
Parse *pParse, /* Parse context to store any error in */ Parse *pParse, /* Parse context to store any error in */
Table *pParent, /* Parent table of FK constraint pFKey */ Table *pParent, /* Parent table of FK constraint pFKey */
FKey *pFKey, /* Foreign key to find index for */ FKey *pFKey, /* Foreign key to find index for */
@@ -275,7 +275,9 @@ static int locateFkeyIndex(
if( !pIdx ){ if( !pIdx ){
if( !pParse->disableTriggers ){ if( !pParse->disableTriggers ){
sqlite3ErrorMsg(pParse, "foreign key mismatch"); sqlite3ErrorMsg(pParse,
"foreign key mismatch - \"%w\" referencing \"%w\"",
pFKey->pFrom->zName, pFKey->zTo);
} }
sqlite3DbFree(pParse->db, aiCol); sqlite3DbFree(pParse->db, aiCol);
return 1; return 1;
@@ -736,7 +738,7 @@ void sqlite3FkCheck(
}else{ }else{
pTo = sqlite3LocateTable(pParse, 0, pFKey->zTo, zDb); pTo = sqlite3LocateTable(pParse, 0, pFKey->zTo, zDb);
} }
if( !pTo || locateFkeyIndex(pParse, pTo, pFKey, &pIdx, &aiFree) ){ if( !pTo || sqlite3FkLocateIndex(pParse, pTo, pFKey, &pIdx, &aiFree) ){
assert( isIgnoreErrors==0 || (regOld!=0 && regNew==0) ); assert( isIgnoreErrors==0 || (regOld!=0 && regNew==0) );
if( !isIgnoreErrors || db->mallocFailed ) return; if( !isIgnoreErrors || db->mallocFailed ) return;
if( pTo==0 ){ if( pTo==0 ){
@@ -816,7 +818,7 @@ void sqlite3FkCheck(
continue; continue;
} }
if( locateFkeyIndex(pParse, pTab, pFKey, &pIdx, &aiCol) ){ if( sqlite3FkLocateIndex(pParse, pTab, pFKey, &pIdx, &aiCol) ){
if( !isIgnoreErrors || db->mallocFailed ) return; if( !isIgnoreErrors || db->mallocFailed ) return;
continue; continue;
} }
@@ -871,7 +873,7 @@ u32 sqlite3FkOldmask(
} }
for(p=sqlite3FkReferences(pTab); p; p=p->pNextTo){ for(p=sqlite3FkReferences(pTab); p; p=p->pNextTo){
Index *pIdx = 0; Index *pIdx = 0;
locateFkeyIndex(pParse, pTab, p, &pIdx, 0); sqlite3FkLocateIndex(pParse, pTab, p, &pIdx, 0);
if( pIdx ){ if( pIdx ){
for(i=0; i<pIdx->nColumn; i++) mask |= COLUMN_MASK(pIdx->aiColumn[i]); for(i=0; i<pIdx->nColumn; i++) mask |= COLUMN_MASK(pIdx->aiColumn[i]);
} }
@@ -997,7 +999,7 @@ static Trigger *fkActionTrigger(
int i; /* Iterator variable */ int i; /* Iterator variable */
Expr *pWhen = 0; /* WHEN clause for the trigger */ Expr *pWhen = 0; /* WHEN clause for the trigger */
if( locateFkeyIndex(pParse, pTab, pFKey, &pIdx, &aiCol) ) return 0; if( sqlite3FkLocateIndex(pParse, pTab, pFKey, &pIdx, &aiCol) ) return 0;
assert( aiCol || pFKey->nCol==1 ); assert( aiCol || pFKey->nCol==1 );
for(i=0; i<pFKey->nCol; i++){ for(i=0; i<pFKey->nCol; i++){

View File

@@ -59,6 +59,14 @@ static int createFile(JournalFile *p){
assert(p->iSize<=p->nBuf); assert(p->iSize<=p->nBuf);
rc = sqlite3OsWrite(p->pReal, p->zBuf, p->iSize, 0); rc = sqlite3OsWrite(p->pReal, p->zBuf, p->iSize, 0);
} }
if( rc!=SQLITE_OK ){
/* If an error occurred while writing to the file, close it before
** returning. This way, SQLite uses the in-memory journal data to
** roll back changes made to the internal page-cache before this
** function was called. */
sqlite3OsClose(pReal);
p->pReal = 0;
}
} }
} }
return rc; return rc;

View File

@@ -435,8 +435,8 @@ oneselect(A) ::= SELECT distinct(D) selcollist(W) from(X) where_opt(Y)
// The "distinct" nonterminal is true (1) if the DISTINCT keyword is // The "distinct" nonterminal is true (1) if the DISTINCT keyword is
// present and false (0) if it is not. // present and false (0) if it is not.
// //
%type distinct {int} %type distinct {u16}
distinct(A) ::= DISTINCT. {A = 1;} distinct(A) ::= DISTINCT. {A = SF_Distinct;}
distinct(A) ::= ALL. {A = 0;} distinct(A) ::= ALL. {A = 0;}
distinct(A) ::= . {A = 0;} distinct(A) ::= . {A = 0;}
@@ -499,7 +499,8 @@ stl_prefix(A) ::= seltablist(X) joinop(Y). {
if( ALWAYS(A && A->nSrc>0) ) A->a[A->nSrc-1].jointype = (u8)Y; if( ALWAYS(A && A->nSrc>0) ) A->a[A->nSrc-1].jointype = (u8)Y;
} }
stl_prefix(A) ::= . {A = 0;} stl_prefix(A) ::= . {A = 0;}
seltablist(A) ::= stl_prefix(X) nm(Y) dbnm(D) as(Z) indexed_opt(I) on_opt(N) using_opt(U). { seltablist(A) ::= stl_prefix(X) nm(Y) dbnm(D) as(Z) indexed_opt(I)
on_opt(N) using_opt(U). {
A = sqlite3SrcListAppendFromTerm(pParse,X,&Y,&D,&Z,0,N,U); A = sqlite3SrcListAppendFromTerm(pParse,X,&Y,&D,&Z,0,N,U);
sqlite3SrcListIndexedBy(pParse, A, &I); sqlite3SrcListIndexedBy(pParse, A, &I);
} }
@@ -512,25 +513,23 @@ seltablist(A) ::= stl_prefix(X) nm(Y) dbnm(D) as(Z) indexed_opt(I) on_opt(N) usi
as(Z) on_opt(N) using_opt(U). { as(Z) on_opt(N) using_opt(U). {
if( X==0 && Z.n==0 && N==0 && U==0 ){ if( X==0 && Z.n==0 && N==0 && U==0 ){
A = F; A = F;
}else if( F->nSrc==1 ){
A = sqlite3SrcListAppendFromTerm(pParse,X,0,0,&Z,0,N,U);
if( A ){
struct SrcList_item *pNew = &A->a[A->nSrc-1];
struct SrcList_item *pOld = F->a;
pNew->zName = pOld->zName;
pNew->zDatabase = pOld->zDatabase;
pOld->zName = pOld->zDatabase = 0;
}
sqlite3SrcListDelete(pParse->db, F);
}else{ }else{
Select *pSubquery; Select *pSubquery;
sqlite3SrcListShiftJoinType(F); sqlite3SrcListShiftJoinType(F);
pSubquery = sqlite3SelectNew(pParse,0,F,0,0,0,0,0,0,0); pSubquery = sqlite3SelectNew(pParse,0,F,0,0,0,0,SF_NestedFrom,0,0);
A = sqlite3SrcListAppendFromTerm(pParse,X,0,0,&Z,pSubquery,N,U); A = sqlite3SrcListAppendFromTerm(pParse,X,0,0,&Z,pSubquery,N,U);
} }
} }
// A seltablist_paren nonterminal represents anything in a FROM that
// is contained inside parentheses. This can be either a subquery or
// a grouping of table and subqueries.
//
// %type seltablist_paren {Select*}
// %destructor seltablist_paren {sqlite3SelectDelete(pParse->db, $$);}
// seltablist_paren(A) ::= select(S). {A = S;}
// seltablist_paren(A) ::= seltablist(F). {
// sqlite3SrcListShiftJoinType(F);
// A = sqlite3SelectNew(pParse,0,F,0,0,0,0,0,0,0);
// }
%endif SQLITE_OMIT_SUBQUERY %endif SQLITE_OMIT_SUBQUERY
%type dbnm {Token} %type dbnm {Token}
@@ -653,7 +652,8 @@ where_opt(A) ::= WHERE expr(X). {A = X.pExpr;}
////////////////////////// The UPDATE command //////////////////////////////// ////////////////////////// The UPDATE command ////////////////////////////////
// //
%ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT %ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
cmd ::= UPDATE orconf(R) fullname(X) indexed_opt(I) SET setlist(Y) where_opt(W) orderby_opt(O) limit_opt(L). { cmd ::= UPDATE orconf(R) fullname(X) indexed_opt(I) SET setlist(Y) where_opt(W)
orderby_opt(O) limit_opt(L). {
sqlite3SrcListIndexedBy(pParse, X, &I); sqlite3SrcListIndexedBy(pParse, X, &I);
sqlite3ExprListCheckLength(pParse,Y,"set list"); sqlite3ExprListCheckLength(pParse,Y,"set list");
W = sqlite3LimitWhere(pParse, X, W, O, L.pLimit, L.pOffset, "UPDATE"); W = sqlite3LimitWhere(pParse, X, W, O, L.pLimit, L.pOffset, "UPDATE");
@@ -661,7 +661,8 @@ cmd ::= UPDATE orconf(R) fullname(X) indexed_opt(I) SET setlist(Y) where_opt(W)
} }
%endif %endif
%ifndef SQLITE_ENABLE_UPDATE_DELETE_LIMIT %ifndef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
cmd ::= UPDATE orconf(R) fullname(X) indexed_opt(I) SET setlist(Y) where_opt(W). { cmd ::= UPDATE orconf(R) fullname(X) indexed_opt(I) SET setlist(Y)
where_opt(W). {
sqlite3SrcListIndexedBy(pParse, X, &I); sqlite3SrcListIndexedBy(pParse, X, &I);
sqlite3ExprListCheckLength(pParse,Y,"set list"); sqlite3ExprListCheckLength(pParse,Y,"set list");
sqlite3Update(pParse,X,Y,W,R); sqlite3Update(pParse,X,Y,W,R);

View File

@@ -948,9 +948,11 @@ void sqlite3Pragma(
if( sqlite3ReadSchema(pParse) ) goto pragma_out; if( sqlite3ReadSchema(pParse) ) goto pragma_out;
pTab = sqlite3FindTable(db, zRight, zDb); pTab = sqlite3FindTable(db, zRight, zDb);
if( pTab ){ if( pTab ){
int i; int i, k;
int nHidden = 0; int nHidden = 0;
Column *pCol; Column *pCol;
Index *pPk;
for(pPk=pTab->pIndex; pPk && pPk->autoIndex!=2; pPk=pPk->pNext){}
sqlite3VdbeSetNumCols(v, 6); sqlite3VdbeSetNumCols(v, 6);
pParse->nMem = 6; pParse->nMem = 6;
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "cid", SQLITE_STATIC); sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "cid", SQLITE_STATIC);
@@ -975,8 +977,14 @@ void sqlite3Pragma(
}else{ }else{
sqlite3VdbeAddOp2(v, OP_Null, 0, 5); sqlite3VdbeAddOp2(v, OP_Null, 0, 5);
} }
sqlite3VdbeAddOp2(v, OP_Integer, if( (pCol->colFlags & COLFLAG_PRIMKEY)==0 ){
(pCol->colFlags&COLFLAG_PRIMKEY)!=0, 6); k = 0;
}else if( pPk==0 ){
k = 1;
}else{
for(k=1; ALWAYS(k<=pTab->nCol) && pPk->aiColumn[k-1]!=i; k++){}
}
sqlite3VdbeAddOp2(v, OP_Integer, k, 6);
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 6); sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 6);
} }
} }
@@ -1114,6 +1122,120 @@ void sqlite3Pragma(
}else }else
#endif /* !defined(SQLITE_OMIT_FOREIGN_KEY) */ #endif /* !defined(SQLITE_OMIT_FOREIGN_KEY) */
#ifndef SQLITE_OMIT_FOREIGN_KEY
if( sqlite3StrICmp(zLeft, "foreign_key_check")==0 ){
FKey *pFK; /* A foreign key constraint */
Table *pTab; /* Child table contain "REFERENCES" keyword */
Table *pParent; /* Parent table that child points to */
Index *pIdx; /* Index in the parent table */
int i; /* Loop counter: Foreign key number for pTab */
int j; /* Loop counter: Field of the foreign key */
HashElem *k; /* Loop counter: Next table in schema */
int x; /* result variable */
int regResult; /* 3 registers to hold a result row */
int regKey; /* Register to hold key for checking the FK */
int regRow; /* Registers to hold a row from pTab */
int addrTop; /* Top of a loop checking foreign keys */
int addrOk; /* Jump here if the key is OK */
int *aiCols; /* child to parent column mapping */
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
regResult = pParse->nMem+1;
pParse->nMem += 4;
regKey = ++pParse->nMem;
regRow = ++pParse->nMem;
v = sqlite3GetVdbe(pParse);
sqlite3VdbeSetNumCols(v, 4);
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "table", SQLITE_STATIC);
sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "rowid", SQLITE_STATIC);
sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "parent", SQLITE_STATIC);
sqlite3VdbeSetColName(v, 3, COLNAME_NAME, "fkid", SQLITE_STATIC);
sqlite3CodeVerifySchema(pParse, iDb);
k = sqliteHashFirst(&db->aDb[iDb].pSchema->tblHash);
while( k ){
if( zRight ){
pTab = sqlite3LocateTable(pParse, 0, zRight, zDb);
k = 0;
}else{
pTab = (Table*)sqliteHashData(k);
k = sqliteHashNext(k);
}
if( pTab==0 || pTab->pFKey==0 ) continue;
sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName);
if( pTab->nCol+regRow>pParse->nMem ) pParse->nMem = pTab->nCol + regRow;
sqlite3OpenTable(pParse, 0, iDb, pTab, OP_OpenRead);
sqlite3VdbeAddOp4(v, OP_String8, 0, regResult, 0, pTab->zName,
P4_TRANSIENT);
for(i=1, pFK=pTab->pFKey; pFK; i++, pFK=pFK->pNextFrom){
pParent = sqlite3LocateTable(pParse, 0, pFK->zTo, zDb);
if( pParent==0 ) break;
pIdx = 0;
sqlite3TableLock(pParse, iDb, pParent->tnum, 0, pParent->zName);
x = sqlite3FkLocateIndex(pParse, pParent, pFK, &pIdx, 0);
if( x==0 ){
if( pIdx==0 ){
sqlite3OpenTable(pParse, i, iDb, pParent, OP_OpenRead);
}else{
KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIdx);
sqlite3VdbeAddOp3(v, OP_OpenRead, i, pIdx->tnum, iDb);
sqlite3VdbeChangeP4(v, -1, (char*)pKey, P4_KEYINFO_HANDOFF);
}
}else{
k = 0;
break;
}
}
if( pFK ) break;
if( pParse->nTab<i ) pParse->nTab = i;
addrTop = sqlite3VdbeAddOp1(v, OP_Rewind, 0);
for(i=1, pFK=pTab->pFKey; pFK; i++, pFK=pFK->pNextFrom){
pParent = sqlite3LocateTable(pParse, 0, pFK->zTo, zDb);
assert( pParent!=0 );
pIdx = 0;
aiCols = 0;
x = sqlite3FkLocateIndex(pParse, pParent, pFK, &pIdx, &aiCols);
assert( x==0 );
addrOk = sqlite3VdbeMakeLabel(v);
if( pIdx==0 ){
int iKey = pFK->aCol[0].iFrom;
assert( iKey>=0 && iKey<pTab->nCol );
if( iKey!=pTab->iPKey ){
sqlite3VdbeAddOp3(v, OP_Column, 0, iKey, regRow);
sqlite3ColumnDefault(v, pTab, iKey, regRow);
sqlite3VdbeAddOp2(v, OP_IsNull, regRow, addrOk);
sqlite3VdbeAddOp2(v, OP_MustBeInt, regRow,
sqlite3VdbeCurrentAddr(v)+3);
}else{
sqlite3VdbeAddOp2(v, OP_Rowid, 0, regRow);
}
sqlite3VdbeAddOp3(v, OP_NotExists, i, 0, regRow);
sqlite3VdbeAddOp2(v, OP_Goto, 0, addrOk);
sqlite3VdbeJumpHere(v, sqlite3VdbeCurrentAddr(v)-2);
}else{
for(j=0; j<pFK->nCol; j++){
sqlite3ExprCodeGetColumnOfTable(v, pTab, 0,
aiCols ? aiCols[j] : pFK->aCol[0].iFrom, regRow+j);
sqlite3VdbeAddOp2(v, OP_IsNull, regRow+j, addrOk);
}
sqlite3VdbeAddOp3(v, OP_MakeRecord, regRow, pFK->nCol, regKey);
sqlite3VdbeChangeP4(v, -1,
sqlite3IndexAffinityStr(v,pIdx), P4_TRANSIENT);
sqlite3VdbeAddOp4Int(v, OP_Found, i, addrOk, regKey, 0);
}
sqlite3VdbeAddOp2(v, OP_Rowid, 0, regResult+1);
sqlite3VdbeAddOp4(v, OP_String8, 0, regResult+2, 0,
pFK->zTo, P4_TRANSIENT);
sqlite3VdbeAddOp2(v, OP_Integer, i-1, regResult+3);
sqlite3VdbeAddOp2(v, OP_ResultRow, regResult, 4);
sqlite3VdbeResolveLabel(v, addrOk);
sqlite3DbFree(db, aiCols);
}
sqlite3VdbeAddOp2(v, OP_Next, 0, addrTop+1);
sqlite3VdbeJumpHere(v, addrTop);
}
}else
#endif /* !defined(SQLITE_OMIT_FOREIGN_KEY) */
#ifndef NDEBUG #ifndef NDEBUG
if( sqlite3StrICmp(zLeft, "parser_trace")==0 ){ if( sqlite3StrICmp(zLeft, "parser_trace")==0 ){
if( zRight ){ if( zRight ){

View File

@@ -150,6 +150,35 @@ static int nameInUsingClause(IdList *pUsing, const char *zCol){
return 0; return 0;
} }
/*
** Subqueries stores the original database, table and column names for their
** result sets in ExprList.a[].zSpan, in the form "DATABASE.TABLE.COLUMN".
** Check to see if the zSpan given to this routine matches the zDb, zTab,
** and zCol. If any of zDb, zTab, and zCol are NULL then those fields will
** match anything.
*/
int sqlite3MatchSpanName(
const char *zSpan,
const char *zCol,
const char *zTab,
const char *zDb
){
int n;
for(n=0; ALWAYS(zSpan[n]) && zSpan[n]!='.'; n++){}
if( zDb && sqlite3StrNICmp(zSpan, zDb, n)!=0 ){
return 0;
}
zSpan += n+1;
for(n=0; ALWAYS(zSpan[n]) && zSpan[n]!='.'; n++){}
if( zTab && sqlite3StrNICmp(zSpan, zTab, n)!=0 ){
return 0;
}
zSpan += n+1;
if( zCol && sqlite3StrICmp(zSpan, zCol)!=0 ){
return 0;
}
return 1;
}
/* /*
** Given the name of a column of the form X.Y.Z or Y.Z or just Z, look up ** Given the name of a column of the form X.Y.Z or Y.Z or just Z, look up
@@ -206,6 +235,20 @@ static int lookupName(
pExpr->pTab = 0; pExpr->pTab = 0;
ExprSetIrreducible(pExpr); ExprSetIrreducible(pExpr);
/* Translate the schema name in zDb into a pointer to the corresponding
** schema. If not found, pSchema will remain NULL and nothing will match
** resulting in an appropriate error message toward the end of this routine
*/
if( zDb ){
for(i=0; i<db->nDb; i++){
assert( db->aDb[i].zName );
if( sqlite3StrICmp(db->aDb[i].zName,zDb)==0 ){
pSchema = db->aDb[i].pSchema;
break;
}
}
}
/* Start at the inner-most context and move outward until a match is found */ /* Start at the inner-most context and move outward until a match is found */
while( pNC && cnt==0 ){ while( pNC && cnt==0 ){
ExprList *pEList; ExprList *pEList;
@@ -214,31 +257,36 @@ static int lookupName(
if( pSrcList ){ if( pSrcList ){
for(i=0, pItem=pSrcList->a; i<pSrcList->nSrc; i++, pItem++){ for(i=0, pItem=pSrcList->a; i<pSrcList->nSrc; i++, pItem++){
Table *pTab; Table *pTab;
int iDb;
Column *pCol; Column *pCol;
pTab = pItem->pTab; pTab = pItem->pTab;
assert( pTab!=0 && pTab->zName!=0 ); assert( pTab!=0 && pTab->zName!=0 );
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
assert( pTab->nCol>0 ); assert( pTab->nCol>0 );
if( pItem->pSelect && (pItem->pSelect->selFlags & SF_NestedFrom)!=0 ){
ExprList *pEList = pItem->pSelect->pEList;
int hit = 0;
for(j=0; j<pEList->nExpr; j++){
if( sqlite3MatchSpanName(pEList->a[j].zSpan, zCol, zTab, zDb) ){
cnt++;
cntTab = 2;
pMatch = pItem;
pExpr->iColumn = j;
hit = 1;
}
}
if( hit || zTab==0 ) continue;
}
if( zDb && pTab->pSchema!=pSchema ){
continue;
}
if( zTab ){ if( zTab ){
if( pItem->zAlias ){ const char *zTabName = pItem->zAlias ? pItem->zAlias : pTab->zName;
char *zTabName = pItem->zAlias; assert( zTabName!=0 );
if( sqlite3StrICmp(zTabName, zTab)!=0 ) continue; if( sqlite3StrICmp(zTabName, zTab)!=0 ){
}else{
char *zTabName = pTab->zName;
if( NEVER(zTabName==0) || sqlite3StrICmp(zTabName, zTab)!=0 ){
continue; continue;
} }
if( zDb!=0 && sqlite3StrICmp(db->aDb[iDb].zName, zDb)!=0 ){
continue;
}
}
} }
if( 0==(cntTab++) ){ if( 0==(cntTab++) ){
pExpr->iTable = pItem->iCursor;
pExpr->pTab = pTab;
pSchema = pTab->pSchema;
pMatch = pItem; pMatch = pItem;
} }
for(j=0, pCol=pTab->aCol; j<pTab->nCol; j++, pCol++){ for(j=0, pCol=pTab->aCol; j<pTab->nCol; j++, pCol++){
@@ -252,17 +300,19 @@ static int lookupName(
if( nameInUsingClause(pItem->pUsing, zCol) ) continue; if( nameInUsingClause(pItem->pUsing, zCol) ) continue;
} }
cnt++; cnt++;
pExpr->iTable = pItem->iCursor;
pExpr->pTab = pTab;
pMatch = pItem; pMatch = pItem;
pSchema = pTab->pSchema;
/* Substitute the rowid (column -1) for the INTEGER PRIMARY KEY */ /* Substitute the rowid (column -1) for the INTEGER PRIMARY KEY */
pExpr->iColumn = j==pTab->iPKey ? -1 : (i16)j; pExpr->iColumn = j==pTab->iPKey ? -1 : (i16)j;
break; break;
} }
} }
} }
if( pMatch ){
pExpr->iTable = pMatch->iCursor;
pExpr->pTab = pMatch->pTab;
pSchema = pExpr->pTab->pSchema;
} }
} /* if( pSrcList ) */
#ifndef SQLITE_OMIT_TRIGGER #ifndef SQLITE_OMIT_TRIGGER
/* If we have not already resolved the name, then maybe /* If we have not already resolved the name, then maybe
@@ -1033,23 +1083,6 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
return WRC_Abort; return WRC_Abort;
} }
/* Set up the local name-context to pass to sqlite3ResolveExprNames() to
** resolve the result-set expression list.
*/
sNC.ncFlags = NC_AllowAgg;
sNC.pSrcList = p->pSrc;
sNC.pNext = pOuterNC;
/* Resolve names in the result set. */
pEList = p->pEList;
assert( pEList!=0 );
for(i=0; i<pEList->nExpr; i++){
Expr *pX = pEList->a[i].pExpr;
if( sqlite3ResolveExprNames(&sNC, pX) ){
return WRC_Abort;
}
}
/* Recursively resolve names in all subqueries /* Recursively resolve names in all subqueries
*/ */
for(i=0; i<p->pSrc->nSrc; i++){ for(i=0; i<p->pSrc->nSrc; i++){
@@ -1077,6 +1110,23 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
} }
} }
/* Set up the local name-context to pass to sqlite3ResolveExprNames() to
** resolve the result-set expression list.
*/
sNC.ncFlags = NC_AllowAgg;
sNC.pSrcList = p->pSrc;
sNC.pNext = pOuterNC;
/* Resolve names in the result set. */
pEList = p->pEList;
assert( pEList!=0 );
for(i=0; i<pEList->nExpr; i++){
Expr *pX = pEList->a[i].pExpr;
if( sqlite3ResolveExprNames(&sNC, pX) ){
return WRC_Abort;
}
}
/* If there are no aggregate functions in the result-set, and no GROUP BY /* If there are no aggregate functions in the result-set, and no GROUP BY
** expression, do not allow aggregates in any of the other expressions. ** expression, do not allow aggregates in any of the other expressions.
*/ */

View File

@@ -55,7 +55,7 @@ Select *sqlite3SelectNew(
ExprList *pGroupBy, /* the GROUP BY clause */ ExprList *pGroupBy, /* the GROUP BY clause */
Expr *pHaving, /* the HAVING clause */ Expr *pHaving, /* the HAVING clause */
ExprList *pOrderBy, /* the ORDER BY clause */ ExprList *pOrderBy, /* the ORDER BY clause */
int isDistinct, /* true if the DISTINCT keyword is present */ u16 selFlags, /* Flag parameters, such as SF_Distinct */
Expr *pLimit, /* LIMIT value. NULL means not used */ Expr *pLimit, /* LIMIT value. NULL means not used */
Expr *pOffset /* OFFSET value. NULL means no offset */ Expr *pOffset /* OFFSET value. NULL means no offset */
){ ){
@@ -79,7 +79,7 @@ Select *sqlite3SelectNew(
pNew->pGroupBy = pGroupBy; pNew->pGroupBy = pGroupBy;
pNew->pHaving = pHaving; pNew->pHaving = pHaving;
pNew->pOrderBy = pOrderBy; pNew->pOrderBy = pOrderBy;
pNew->selFlags = isDistinct ? SF_Distinct : 0; pNew->selFlags = selFlags;
pNew->op = TK_SELECT; pNew->op = TK_SELECT;
pNew->pLimit = pLimit; pNew->pLimit = pLimit;
pNew->pOffset = pOffset; pNew->pOffset = pOffset;
@@ -1336,8 +1336,6 @@ static int selectColumnsFromExprList(
/* Get an appropriate name for the column /* Get an appropriate name for the column
*/ */
p = sqlite3ExprSkipCollate(pEList->a[i].pExpr); p = sqlite3ExprSkipCollate(pEList->a[i].pExpr);
assert( p->pRight==0 || ExprHasProperty(p->pRight, EP_IntValue)
|| p->pRight->u.zToken==0 || p->pRight->u.zToken[0]!=0 );
if( (zName = pEList->a[i].zName)!=0 ){ if( (zName = pEList->a[i].zName)!=0 ){
/* If the column contains an "AS <name>" phrase, use <name> as the name */ /* If the column contains an "AS <name>" phrase, use <name> as the name */
zName = sqlite3DbStrDup(db, zName); zName = sqlite3DbStrDup(db, zName);
@@ -1375,6 +1373,9 @@ static int selectColumnsFromExprList(
for(j=cnt=0; j<i; j++){ for(j=cnt=0; j<i; j++){
if( sqlite3StrICmp(aCol[j].zName, zName)==0 ){ if( sqlite3StrICmp(aCol[j].zName, zName)==0 ){
char *zNewName; char *zNewName;
int k;
for(k=nName-1; k>1 && sqlite3Isdigit(zName[k]); k--){}
if( zName[k]==':' ) nName = k;
zName[nName] = 0; zName[nName] = 0;
zNewName = sqlite3MPrintf(db, "%s:%d", zName, ++cnt); zNewName = sqlite3MPrintf(db, "%s:%d", zName, ++cnt);
sqlite3DbFree(db, zName); sqlite3DbFree(db, zName);
@@ -3160,34 +3161,43 @@ static int flattenSubquery(
#endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */ #endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */
/* /*
** Analyze the SELECT statement passed as an argument to see if it ** Based on the contents of the AggInfo structure indicated by the first
** is a min() or max() query. Return WHERE_ORDERBY_MIN or WHERE_ORDERBY_MAX if ** argument, this function checks if the following are true:
** it is, or 0 otherwise. At present, a query is considered to be
** a min()/max() query if:
** **
** 1. There is a single object in the FROM clause. ** * the query contains just a single aggregate function,
** * the aggregate function is either min() or max(), and
** * the argument to the aggregate function is a column value.
** **
** 2. There is a single expression in the result set, and it is ** If all of the above are true, then WHERE_ORDERBY_MIN or WHERE_ORDERBY_MAX
** either min(x) or max(x), where x is a column reference. ** is returned as appropriate. Also, *ppMinMax is set to point to the
** list of arguments passed to the aggregate before returning.
**
** Or, if the conditions above are not met, *ppMinMax is set to 0 and
** WHERE_ORDERBY_NORMAL is returned.
*/ */
static u8 minMaxQuery(Select *p){ static u8 minMaxQuery(AggInfo *pAggInfo, ExprList **ppMinMax){
Expr *pExpr; int eRet = WHERE_ORDERBY_NORMAL; /* Return value */
ExprList *pEList = p->pEList;
if( pEList->nExpr!=1 ) return WHERE_ORDERBY_NORMAL; *ppMinMax = 0;
pExpr = pEList->a[0].pExpr; if( pAggInfo->nFunc==1 ){
if( pExpr->op!=TK_AGG_FUNCTION ) return 0; Expr *pExpr = pAggInfo->aFunc[0].pExpr; /* Aggregate function */
if( NEVER(ExprHasProperty(pExpr, EP_xIsSelect)) ) return 0; ExprList *pEList = pExpr->x.pList; /* Arguments to agg function */
pEList = pExpr->x.pList;
if( pEList==0 || pEList->nExpr!=1 ) return 0; assert( pExpr->op==TK_AGG_FUNCTION );
if( pEList->a[0].pExpr->op!=TK_AGG_COLUMN ) return WHERE_ORDERBY_NORMAL; if( pEList && pEList->nExpr==1 && pEList->a[0].pExpr->op==TK_AGG_COLUMN ){
assert( !ExprHasProperty(pExpr, EP_IntValue) ); const char *zFunc = pExpr->u.zToken;
if( sqlite3StrICmp(pExpr->u.zToken,"min")==0 ){ if( sqlite3StrICmp(zFunc, "min")==0 ){
return WHERE_ORDERBY_MIN; eRet = WHERE_ORDERBY_MIN;
}else if( sqlite3StrICmp(pExpr->u.zToken,"max")==0 ){ *ppMinMax = pEList;
return WHERE_ORDERBY_MAX; }else if( sqlite3StrICmp(zFunc, "max")==0 ){
eRet = WHERE_ORDERBY_MAX;
*ppMinMax = pEList;
} }
return WHERE_ORDERBY_NORMAL; }
}
assert( *ppMinMax==0 || (*ppMinMax)->nExpr==1 );
return eRet;
} }
/* /*
@@ -3282,6 +3292,7 @@ static int selectExpander(Walker *pWalker, Select *p){
ExprList *pEList; ExprList *pEList;
struct SrcList_item *pFrom; struct SrcList_item *pFrom;
sqlite3 *db = pParse->db; sqlite3 *db = pParse->db;
Expr *pE, *pRight, *pExpr;
if( db->mallocFailed ){ if( db->mallocFailed ){
return WRC_Abort; return WRC_Abort;
@@ -3367,7 +3378,7 @@ static int selectExpander(Walker *pWalker, Select *p){
** that need expanding. ** that need expanding.
*/ */
for(k=0; k<pEList->nExpr; k++){ for(k=0; k<pEList->nExpr; k++){
Expr *pE = pEList->a[k].pExpr; pE = pEList->a[k].pExpr;
if( pE->op==TK_ALL ) break; if( pE->op==TK_ALL ) break;
assert( pE->op!=TK_DOT || pE->pRight!=0 ); assert( pE->op!=TK_DOT || pE->pRight!=0 );
assert( pE->op!=TK_DOT || (pE->pLeft!=0 && pE->pLeft->op==TK_ID) ); assert( pE->op!=TK_DOT || (pE->pLeft!=0 && pE->pLeft->op==TK_ID) );
@@ -3385,10 +3396,18 @@ static int selectExpander(Walker *pWalker, Select *p){
int longNames = (flags & SQLITE_FullColNames)!=0 int longNames = (flags & SQLITE_FullColNames)!=0
&& (flags & SQLITE_ShortColNames)==0; && (flags & SQLITE_ShortColNames)==0;
/* When processing FROM-clause subqueries, it is always the case
** that full_column_names=OFF and short_column_names=ON. The
** sqlite3ResultSetOfSelect() routine makes it so. */
assert( (p->selFlags & SF_NestedFrom)==0
|| ((flags & SQLITE_FullColNames)==0 &&
(flags & SQLITE_ShortColNames)!=0) );
for(k=0; k<pEList->nExpr; k++){ for(k=0; k<pEList->nExpr; k++){
Expr *pE = a[k].pExpr; pE = a[k].pExpr;
assert( pE->op!=TK_DOT || pE->pRight!=0 ); pRight = pE->pRight;
if( pE->op!=TK_ALL && (pE->op!=TK_DOT || pE->pRight->op!=TK_ALL) ){ assert( pE->op!=TK_DOT || pRight!=0 );
if( pE->op!=TK_ALL && (pE->op!=TK_DOT || pRight->op!=TK_ALL) ){
/* This particular expression does not need to be expanded. /* This particular expression does not need to be expanded.
*/ */
pNew = sqlite3ExprListAppend(pParse, pNew, a[k].pExpr); pNew = sqlite3ExprListAppend(pParse, pNew, a[k].pExpr);
@@ -3403,32 +3422,43 @@ static int selectExpander(Walker *pWalker, Select *p){
/* This expression is a "*" or a "TABLE.*" and needs to be /* This expression is a "*" or a "TABLE.*" and needs to be
** expanded. */ ** expanded. */
int tableSeen = 0; /* Set to 1 when TABLE matches */ int tableSeen = 0; /* Set to 1 when TABLE matches */
char *zTName; /* text of name of TABLE */ char *zTName = 0; /* text of name of TABLE */
if( pE->op==TK_DOT ){ if( pE->op==TK_DOT ){
assert( pE->pLeft!=0 ); assert( pE->pLeft!=0 );
assert( !ExprHasProperty(pE->pLeft, EP_IntValue) ); assert( !ExprHasProperty(pE->pLeft, EP_IntValue) );
zTName = pE->pLeft->u.zToken; zTName = pE->pLeft->u.zToken;
}else{
zTName = 0;
} }
for(i=0, pFrom=pTabList->a; i<pTabList->nSrc; i++, pFrom++){ for(i=0, pFrom=pTabList->a; i<pTabList->nSrc; i++, pFrom++){
Table *pTab = pFrom->pTab; Table *pTab = pFrom->pTab;
Select *pSub = pFrom->pSelect;
char *zTabName = pFrom->zAlias; char *zTabName = pFrom->zAlias;
const char *zSchemaName = 0;
int iDb;
if( zTabName==0 ){ if( zTabName==0 ){
zTabName = pTab->zName; zTabName = pTab->zName;
} }
if( db->mallocFailed ) break; if( db->mallocFailed ) break;
if( pSub==0 || (pSub->selFlags & SF_NestedFrom)==0 ){
pSub = 0;
if( zTName && sqlite3StrICmp(zTName, zTabName)!=0 ){ if( zTName && sqlite3StrICmp(zTName, zTabName)!=0 ){
continue; continue;
} }
tableSeen = 1; iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
zSchemaName = iDb>=0 ? db->aDb[iDb].zName : "*";
}
for(j=0; j<pTab->nCol; j++){ for(j=0; j<pTab->nCol; j++){
Expr *pExpr, *pRight;
char *zName = pTab->aCol[j].zName; char *zName = pTab->aCol[j].zName;
char *zColname; /* The computed column name */ char *zColname; /* The computed column name */
char *zToFree; /* Malloced string that needs to be freed */ char *zToFree; /* Malloced string that needs to be freed */
Token sColname; /* Computed column name as a token */ Token sColname; /* Computed column name as a token */
assert( zName );
if( zTName && pSub
&& sqlite3MatchSpanName(pSub->pEList->a[j].zSpan, 0, zTName, 0)==0
){
continue;
}
/* If a column is marked as 'hidden' (currently only possible /* If a column is marked as 'hidden' (currently only possible
** for virtual tables), do not include it in the expanded ** for virtual tables), do not include it in the expanded
** result-set list. ** result-set list.
@@ -3437,6 +3467,7 @@ static int selectExpander(Walker *pWalker, Select *p){
assert(IsVirtual(pTab)); assert(IsVirtual(pTab));
continue; continue;
} }
tableSeen = 1;
if( i>0 && zTName==0 ){ if( i>0 && zTName==0 ){
if( (pFrom->jointype & JT_NATURAL)!=0 if( (pFrom->jointype & JT_NATURAL)!=0
@@ -3459,6 +3490,10 @@ static int selectExpander(Walker *pWalker, Select *p){
Expr *pLeft; Expr *pLeft;
pLeft = sqlite3Expr(db, TK_ID, zTabName); pLeft = sqlite3Expr(db, TK_ID, zTabName);
pExpr = sqlite3PExpr(pParse, TK_DOT, pLeft, pRight, 0); pExpr = sqlite3PExpr(pParse, TK_DOT, pLeft, pRight, 0);
if( zSchemaName ){
pLeft = sqlite3Expr(db, TK_ID, zSchemaName);
pExpr = sqlite3PExpr(pParse, TK_DOT, pLeft, pExpr, 0);
}
if( longNames ){ if( longNames ){
zColname = sqlite3MPrintf(db, "%s.%s", zTabName, zName); zColname = sqlite3MPrintf(db, "%s.%s", zTabName, zName);
zToFree = zColname; zToFree = zColname;
@@ -3470,6 +3505,18 @@ static int selectExpander(Walker *pWalker, Select *p){
sColname.z = zColname; sColname.z = zColname;
sColname.n = sqlite3Strlen30(zColname); sColname.n = sqlite3Strlen30(zColname);
sqlite3ExprListSetName(pParse, pNew, &sColname, 0); sqlite3ExprListSetName(pParse, pNew, &sColname, 0);
if( pNew && (p->selFlags & SF_NestedFrom)!=0 ){
struct ExprList_item *pX = &pNew->a[pNew->nExpr-1];
if( pSub ){
pX->zSpan = sqlite3DbStrDup(db, pSub->pEList->a[j].zSpan);
testcase( pX->zSpan==0 );
}else{
pX->zSpan = sqlite3MPrintf(db, "%s.%s.%s",
zSchemaName, zTabName, zColname);
testcase( pX->zSpan==0 );
}
pX->bSpanIsTab = 1;
}
sqlite3DbFree(db, zToFree); sqlite3DbFree(db, zToFree);
} }
} }
@@ -4527,11 +4574,17 @@ int sqlite3Select(
** Refer to code and comments in where.c for details. ** Refer to code and comments in where.c for details.
*/ */
ExprList *pMinMax = 0; ExprList *pMinMax = 0;
u8 flag = minMaxQuery(p); u8 flag = WHERE_ORDERBY_NORMAL;
assert( p->pGroupBy==0 );
assert( flag==0 );
if( p->pHaving==0 ){
flag = minMaxQuery(&sAggInfo, &pMinMax);
}
assert( flag==0 || (pMinMax!=0 && pMinMax->nExpr==1) );
if( flag ){ if( flag ){
assert( !ExprHasProperty(p->pEList->a[0].pExpr, EP_xIsSelect) ); pMinMax = sqlite3ExprListDup(db, pMinMax, 0);
assert( p->pEList->a[0].pExpr->x.pList->nExpr==1 );
pMinMax = sqlite3ExprListDup(db, p->pEList->a[0].pExpr->x.pList,0);
pDel = pMinMax; pDel = pMinMax;
if( pMinMax && !db->mallocFailed ){ if( pMinMax && !db->mallocFailed ){
pMinMax->a[0].sortOrder = flag!=WHERE_ORDERBY_MIN ?1:0; pMinMax->a[0].sortOrder = flag!=WHERE_ORDERBY_MIN ?1:0;

View File

@@ -1479,6 +1479,12 @@ static void open_db(struct callback_data *p){
} }
#ifndef SQLITE_OMIT_LOAD_EXTENSION #ifndef SQLITE_OMIT_LOAD_EXTENSION
sqlite3_enable_load_extension(p->db, 1); sqlite3_enable_load_extension(p->db, 1);
#endif
#ifdef SQLITE_ENABLE_REGEXP
{
extern int sqlite3_add_regexp_func(sqlite3*);
sqlite3_add_regexp_func(db);
}
#endif #endif
} }
} }

View File

@@ -1587,7 +1587,7 @@ struct sqlite3_mem_methods {
** [SQLITE_USE_URI] symbol defined. ** [SQLITE_USE_URI] symbol defined.
** **
** [[SQLITE_CONFIG_COVERING_INDEX_SCAN]] <dt>SQLITE_CONFIG_COVERING_INDEX_SCAN ** [[SQLITE_CONFIG_COVERING_INDEX_SCAN]] <dt>SQLITE_CONFIG_COVERING_INDEX_SCAN
** <dd> This option taks a single integer argument which is interpreted as ** <dd> This option takes a single integer argument which is interpreted as
** a boolean in order to enable or disable the use of covering indices for ** a boolean in order to enable or disable the use of covering indices for
** full table scans in the query optimizer. The default setting is determined ** full table scans in the query optimizer. The default setting is determined
** by the [SQLITE_ALLOW_COVERING_INDEX_SCAN] compile-time option, or is "on" ** by the [SQLITE_ALLOW_COVERING_INDEX_SCAN] compile-time option, or is "on"

View File

@@ -1494,18 +1494,18 @@ struct UnpackedRecord {
struct Index { struct Index {
char *zName; /* Name of this index */ char *zName; /* Name of this index */
int *aiColumn; /* Which columns are used by this index. 1st is 0 */ int *aiColumn; /* Which columns are used by this index. 1st is 0 */
tRowcnt *aiRowEst; /* Result of ANALYZE: Est. rows selected by each column */ tRowcnt *aiRowEst; /* From ANALYZE: Est. rows selected by each column */
Table *pTable; /* The SQL table being indexed */ Table *pTable; /* The SQL table being indexed */
char *zColAff; /* String defining the affinity of each column */ char *zColAff; /* String defining the affinity of each column */
Index *pNext; /* The next index associated with the same table */ Index *pNext; /* The next index associated with the same table */
Schema *pSchema; /* Schema containing this index */ Schema *pSchema; /* Schema containing this index */
u8 *aSortOrder; /* Array of size Index.nColumn. True==DESC, False==ASC */ u8 *aSortOrder; /* for each column: True==DESC, False==ASC */
char **azColl; /* Array of collation sequence names for index */ char **azColl; /* Array of collation sequence names for index */
int nColumn; /* Number of columns in the table used by this index */ int tnum; /* DB Page containing root of this index */
int tnum; /* Page containing root of this index in database file */ u16 nColumn; /* Number of columns in table used by this index */
u8 onError; /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */ u8 onError; /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */
u8 autoIndex; /* True if is automatically created (ex: by UNIQUE) */ unsigned autoIndex:2; /* 1==UNIQUE, 2==PRIMARY KEY, 0==CREATE INDEX */
u8 bUnordered; /* Use this index for == or IN queries only */ unsigned bUnordered:1; /* Use this index for == or IN queries only */
#ifdef SQLITE_ENABLE_STAT3 #ifdef SQLITE_ENABLE_STAT3
int nSample; /* Number of elements in aSample[] */ int nSample; /* Number of elements in aSample[] */
tRowcnt avgEq; /* Average nEq value for key values not in aSample */ tRowcnt avgEq; /* Average nEq value for key values not in aSample */
@@ -1779,6 +1779,14 @@ struct Expr {
** list of "ID = expr" items in an UPDATE. A list of expressions can ** list of "ID = expr" items in an UPDATE. A list of expressions can
** also be used as the argument to a function, in which case the a.zName ** also be used as the argument to a function, in which case the a.zName
** field is not used. ** field is not used.
**
** By default the Expr.zSpan field holds a human-readable description of
** the expression that is used in the generation of error messages and
** column labels. In this case, Expr.zSpan is typically the text of a
** column expression as it exists in a SELECT statement. However, if
** the bSpanIsTab flag is set, then zSpan is overloaded to mean the name
** of the result column in the form: DATABASE.TABLE.COLUMN. This later
** form is used for name resolution with nested FROM clauses.
*/ */
struct ExprList { struct ExprList {
int nExpr; /* Number of expressions on the list */ int nExpr; /* Number of expressions on the list */
@@ -1788,7 +1796,8 @@ struct ExprList {
char *zName; /* Token associated with this expression */ char *zName; /* Token associated with this expression */
char *zSpan; /* Original text of the expression */ char *zSpan; /* Original text of the expression */
u8 sortOrder; /* 1 for DESC or 0 for ASC */ u8 sortOrder; /* 1 for DESC or 0 for ASC */
u8 done; /* A flag to indicate when processing is finished */ unsigned done :1; /* A flag to indicate when processing is finished */
unsigned bSpanIsTab :1; /* zSpan holds DB.TABLE.COLUMN */
u16 iOrderByCol; /* For ORDER BY, column number in result set */ u16 iOrderByCol; /* For ORDER BY, column number in result set */
u16 iAlias; /* Index into Parse.aAlias[] for zName */ u16 iAlias; /* Index into Parse.aAlias[] for zName */
} *a; /* Alloc a power of two greater or equal to nExpr */ } *a; /* Alloc a power of two greater or equal to nExpr */
@@ -2110,6 +2119,7 @@ struct Select {
#define SF_UseSorter 0x0040 /* Sort using a sorter */ #define SF_UseSorter 0x0040 /* Sort using a sorter */
#define SF_Values 0x0080 /* Synthesized from VALUES clause */ #define SF_Values 0x0080 /* Synthesized from VALUES clause */
#define SF_Materialize 0x0100 /* Force materialization of views */ #define SF_Materialize 0x0100 /* Force materialization of views */
#define SF_NestedFrom 0x0200 /* Part of a parenthesized FROM clause */
/* /*
@@ -2826,7 +2836,7 @@ Index *sqlite3CreateIndex(Parse*,Token*,Token*,SrcList*,ExprList*,int,Token*,
void sqlite3DropIndex(Parse*, SrcList*, int); void sqlite3DropIndex(Parse*, SrcList*, int);
int sqlite3Select(Parse*, Select*, SelectDest*); int sqlite3Select(Parse*, Select*, SelectDest*);
Select *sqlite3SelectNew(Parse*,ExprList*,SrcList*,Expr*,ExprList*, Select *sqlite3SelectNew(Parse*,ExprList*,SrcList*,Expr*,ExprList*,
Expr*,ExprList*,int,Expr*,Expr*); Expr*,ExprList*,u16,Expr*,Expr*);
void sqlite3SelectDelete(sqlite3*, Select*); void sqlite3SelectDelete(sqlite3*, Select*);
Table *sqlite3SrcListLookup(Parse*, SrcList*); Table *sqlite3SrcListLookup(Parse*, SrcList*);
int sqlite3IsReadOnly(Parse*, Table*, int); int sqlite3IsReadOnly(Parse*, Table*, int);
@@ -3083,6 +3093,7 @@ void sqlite3NestedParse(Parse*, const char*, ...);
void sqlite3ExpirePreparedStatements(sqlite3*); void sqlite3ExpirePreparedStatements(sqlite3*);
int sqlite3CodeSubselect(Parse *, Expr *, int, int); int sqlite3CodeSubselect(Parse *, Expr *, int, int);
void sqlite3SelectPrep(Parse*, Select*, NameContext*); void sqlite3SelectPrep(Parse*, Select*, NameContext*);
int sqlite3MatchSpanName(const char*, const char*, const char*, const char*);
int sqlite3ResolveExprNames(NameContext*, Expr*); int sqlite3ResolveExprNames(NameContext*, Expr*);
void sqlite3ResolveSelectNames(Parse*, Select*, NameContext*); void sqlite3ResolveSelectNames(Parse*, Select*, NameContext*);
int sqlite3ResolveOrderGroupBy(Parse*, Select*, ExprList*, const char*); int sqlite3ResolveOrderGroupBy(Parse*, Select*, ExprList*, const char*);
@@ -3221,8 +3232,10 @@ const char *sqlite3JournalModename(int);
#endif #endif
#ifndef SQLITE_OMIT_FOREIGN_KEY #ifndef SQLITE_OMIT_FOREIGN_KEY
void sqlite3FkDelete(sqlite3 *, Table*); void sqlite3FkDelete(sqlite3 *, Table*);
int sqlite3FkLocateIndex(Parse*,Table*,FKey*,Index**,int**);
#else #else
#define sqlite3FkDelete(a,b) #define sqlite3FkDelete(a,b)
#define sqlite3FkLocateIndex(a,b,c,d,e)
#endif #endif

View File

@@ -3833,6 +3833,8 @@ static void init_all(Tcl_Interp *interp){
#if defined(SQLITE_ENABLE_SESSION) && defined(SQLITE_ENABLE_PREUPDATE_HOOK) #if defined(SQLITE_ENABLE_SESSION) && defined(SQLITE_ENABLE_PREUPDATE_HOOK)
extern int TestSession_Init(Tcl_Interp*); extern int TestSession_Init(Tcl_Interp*);
#endif #endif
extern int Sqlitetestregexp_Init(Tcl_Interp*);
#if defined(SQLITE_ENABLE_FTS3) || defined(SQLITE_ENABLE_FTS4) #if defined(SQLITE_ENABLE_FTS3) || defined(SQLITE_ENABLE_FTS4)
extern int Sqlitetestfts3_Init(Tcl_Interp *interp); extern int Sqlitetestfts3_Init(Tcl_Interp *interp);
#endif #endif
@@ -3878,6 +3880,8 @@ static void init_all(Tcl_Interp *interp){
#if defined(SQLITE_ENABLE_SESSION) && defined(SQLITE_ENABLE_PREUPDATE_HOOK) #if defined(SQLITE_ENABLE_SESSION) && defined(SQLITE_ENABLE_PREUPDATE_HOOK)
TestSession_Init(interp); TestSession_Init(interp);
#endif #endif
Sqlitetestregexp_Init(interp);
#if defined(SQLITE_ENABLE_FTS3) || defined(SQLITE_ENABLE_FTS4) #if defined(SQLITE_ENABLE_FTS3) || defined(SQLITE_ENABLE_FTS4)
Sqlitetestfts3_Init(interp); Sqlitetestfts3_Init(interp);
#endif #endif

757
src/test_regexp.c Normal file
View File

@@ -0,0 +1,757 @@
/*
** 2012-11-13
**
** 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.
**
******************************************************************************
**
** The code in this file implements a compact but reasonably
** efficient regular-expression matcher for posix extended regular
** expressions against UTF8 text. The following syntax is supported:
**
** X* zero or more occurrences of X
** X+ one or more occurrences of X
** X? zero or one occurrences of X
** X{p,q} between p and q occurrences of X
** (X) match X
** X|Y X or Y
** ^X X occurring at the beginning of the string
** X$ X occurring at the end of the string
** . Match any single character
** \c Character c where c is one of \{}()[]|*+?.
** \c C-language escapes for c in afnrtv. ex: \t or \n
** \uXXXX Where XXXX is exactly 4 hex digits, unicode value XXXX
** \xXXX Where XXX is any number of hex digits, unicode value XXX
** [abc] Any single character from the set abc
** [^abc] Any single character not in the set abc
** [a-z] Any single character in the range a-z
** [^a-z] Any single character not in the range a-z
** \b Word boundary
** \w Word character. [A-Za-z0-9_]
** \W Non-word character
** \d Digit
** \D Non-digit
** \s Whitespace character
** \S Non-whitespace character
**
** A nondeterministic finite automaton (NFA) is used for matching, so the
** performance is bounded by O(N*M) where N is the size of the regular
** expression and M is the size of the input string. The matcher never
** exhibits exponential behavior. Note that the X{p,q} operator expands
** to p copies of X following by q-p copies of X? and that the size of the
** regular expression in the O(N*M) performance bound is computed after
** this expansion.
*/
#include <string.h>
#include <stdlib.h>
#include "sqlite3.h"
/* The end-of-input character */
#define RE_EOF 0 /* End of input */
/* The NFA is implemented as sequence of opcodes taken from the following
** set. Each opcode has a single integer argument.
*/
#define RE_OP_MATCH 1 /* Match the one character in the argument */
#define RE_OP_ANY 2 /* Match any one character. (Implements ".") */
#define RE_OP_ANYSTAR 3 /* Special optimized version of .* */
#define RE_OP_FORK 4 /* Continue to both next and opcode at iArg */
#define RE_OP_GOTO 5 /* Jump to opcode at iArg */
#define RE_OP_ACCEPT 6 /* Halt and indicate a successful match */
#define RE_OP_CC_INC 7 /* Beginning of a [...] character class */
#define RE_OP_CC_EXC 8 /* Beginning of a [^...] character class */
#define RE_OP_CC_VALUE 9 /* Single value in a character class */
#define RE_OP_CC_RANGE 10 /* Range of values in a character class */
#define RE_OP_WORD 11 /* Perl word character [A-Za-z0-9_] */
#define RE_OP_NOTWORD 12 /* Not a perl word character */
#define RE_OP_DIGIT 13 /* digit: [0-9] */
#define RE_OP_NOTDIGIT 14 /* Not a digit */
#define RE_OP_SPACE 15 /* space: [ \t\n\r\v\f] */
#define RE_OP_NOTSPACE 16 /* Not a digit */
#define RE_OP_BOUNDARY 17 /* Boundary between word and non-word */
/* Each opcode is a "state" in the NFA */
typedef unsigned short ReStateNumber;
/* Because this is an NFA and not a DFA, multiple states can be active at
** once. An instance of the following object records all active states in
** the NFA. The implementation is optimized for the common case where the
** number of actives states is small.
*/
typedef struct ReStateSet {
unsigned nState; /* Number of current states */
ReStateNumber *aState; /* Current states */
} ReStateSet;
/* An input string read one character at a time.
*/
typedef struct ReInput ReInput;
struct ReInput {
const unsigned char *z; /* All text */
int i; /* Next byte to read */
int mx; /* EOF when i>=mx */
};
/* A compiled NFA (or an NFA that is in the process of being compiled) is
** an instance of the following object.
*/
typedef struct ReCompiled ReCompiled;
struct ReCompiled {
ReInput sIn; /* Regular expression text */
const char *zErr; /* Error message to return */
char *aOp; /* Operators for the virtual machine */
int *aArg; /* Arguments to each operator */
unsigned (*xNextChar)(ReInput*); /* Next character function */
char zInit[12]; /* Initial text to match */
int nInit; /* Number of characters in zInit */
unsigned nState; /* Number of entries in aOp[] and aArg[] */
unsigned nAlloc; /* Slots allocated for aOp[] and aArg[] */
};
/* Add a state to the given state set if it is not already there */
static void re_add_state(ReStateSet *pSet, int newState){
unsigned i;
for(i=0; i<pSet->nState; i++) if( pSet->aState[i]==newState ) return;
pSet->aState[pSet->nState++] = newState;
}
/* Extract the next unicode character from *pzIn and return it. Advance
** *pzIn to the first byte past the end of the character returned. To
** be clear: this routine converts utf8 to unicode. This routine is
** optimized for the common case where the next character is a single byte.
*/
static unsigned re_next_char(ReInput *p){
unsigned c;
if( p->i>=p->mx ) return 0;
c = p->z[p->i++];
if( c>0x80 ){
if( (c&0xe0)==0xc0 && p->i<p->mx && (p->z[p->i]&0xc0)==0x80 ){
c = (c&0x1f)<<6 | (p->z[p->i++]&0x3f);
if( c<0x80 ) c = 0xfffd;
}else if( (c&0xf0)==0xe0 && p->i+1<p->mx && (p->z[p->i]&0xc0)==0x80
&& (p->z[p->i+1]&0xc0)==0x80 ){
c = (c&0x0f)<<12 | ((p->z[p->i]&0x3f)<<6) | (p->z[p->i+1]&0x3f);
p->i += 2;
if( c<0x3ff || (c>=0xd800 && c<=0xdfff) ) c = 0xfffd;
}else if( (c&0xf8)==0xf0 && p->i+3<p->mx && (p->z[p->i]&0xc0)==0x80
&& (p->z[p->i+1]&0xc0)==0x80 && (p->z[p->i+2]&0xc0)==0x80 ){
c = (c&0x07)<<18 | ((p->z[p->i]&0x3f)<<12) | ((p->z[p->i+1]&0x3f)<<6)
| (p->z[p->i+2]&0x3f);
p->i += 3;
if( c<0xffff ) c = 0xfffd;
}else{
c = 0xfffd;
}
}
return c;
}
static unsigned re_next_char_nocase(ReInput *p){
unsigned c = re_next_char(p);
if( c>='A' && c<='Z' ) c += 'a' - 'A';
return c;
}
/* Return true if c is a perl "word" character: [A-Za-z0-9_] */
static int re_word_char(int c){
return (c>='0' && c<='9') || (c>='a' && c<='z')
|| (c>='A' && c<='Z') || c=='_';
}
/* Return true if c is a "digit" character: [0-9] */
static int re_digit_char(int c){
return (c>='0' && c<='9');
}
/* Return true if c is a perl "space" character: [ \t\r\n\v\f] */
static int re_space_char(int c){
return c==' ' || c=='\t' || c=='\n' || c=='\v' || c=='\f';
}
/* Run a compiled regular expression on the zero-terminated input
** string zIn[]. Return true on a match and false if there is no match.
*/
int re_match(ReCompiled *pRe, const unsigned char *zIn, int nIn){
ReStateSet aStateSet[2], *pThis, *pNext;
ReStateNumber aSpace[100];
ReStateNumber *pToFree;
unsigned int i = 0;
unsigned int iSwap = 0;
int c = RE_EOF+1;
int cPrev = 0;
int rc = 0;
ReInput in;
in.z = zIn;
in.i = 0;
in.mx = nIn>=0 ? nIn : strlen((char*)zIn);
if( pRe->nInit ){
unsigned char x = pRe->zInit[0];
while( in.i+pRe->nInit<=in.mx
&& (zIn[in.i]!=x || memcmp(zIn+in.i, pRe->zInit, pRe->nInit)!=0)
){
in.i++;
}
if( in.i+pRe->nInit>in.mx ) return 0;
}
if( pRe->nState<=(sizeof(aSpace)/(sizeof(aSpace[0])*2)) ){
pToFree = 0;
aStateSet[0].aState = aSpace;
}else{
pToFree = sqlite3_malloc( sizeof(ReStateNumber)*2*pRe->nState );
if( pToFree==0 ) return -1;
aStateSet[0].aState = pToFree;
}
aStateSet[1].aState = &aStateSet[0].aState[pRe->nState];
pNext = &aStateSet[1];
pNext->nState = 0;
re_add_state(pNext, 0);
while( c!=RE_EOF && pNext->nState>0 ){
cPrev = c;
c = pRe->xNextChar(&in);
pThis = pNext;
pNext = &aStateSet[iSwap];
iSwap = 1 - iSwap;
pNext->nState = 0;
for(i=0; i<pThis->nState; i++){
int x = pThis->aState[i];
switch( pRe->aOp[x] ){
case RE_OP_MATCH: {
if( pRe->aArg[x]==c ) re_add_state(pNext, x+1);
break;
}
case RE_OP_ANY: {
re_add_state(pNext, x+1);
break;
}
case RE_OP_WORD: {
if( re_word_char(c) ) re_add_state(pNext, x+1);
break;
}
case RE_OP_NOTWORD: {
if( !re_word_char(c) ) re_add_state(pNext, x+1);
break;
}
case RE_OP_DIGIT: {
if( re_digit_char(c) ) re_add_state(pNext, x+1);
break;
}
case RE_OP_NOTDIGIT: {
if( !re_digit_char(c) ) re_add_state(pNext, x+1);
break;
}
case RE_OP_SPACE: {
if( re_space_char(c) ) re_add_state(pNext, x+1);
break;
}
case RE_OP_NOTSPACE: {
if( !re_space_char(c) ) re_add_state(pNext, x+1);
break;
}
case RE_OP_BOUNDARY: {
if( re_word_char(c)!=re_word_char(cPrev) ) re_add_state(pThis, x+1);
break;
}
case RE_OP_ANYSTAR: {
re_add_state(pNext, x);
re_add_state(pThis, x+1);
break;
}
case RE_OP_FORK: {
re_add_state(pThis, x+pRe->aArg[x]);
re_add_state(pThis, x+1);
break;
}
case RE_OP_GOTO: {
re_add_state(pThis, x+pRe->aArg[x]);
break;
}
case RE_OP_ACCEPT: {
rc = 1;
goto re_match_end;
}
case RE_OP_CC_INC:
case RE_OP_CC_EXC: {
int j = 1;
int n = pRe->aArg[x];
int hit = 0;
for(j=1; j>0 && j<n; j++){
if( pRe->aOp[x+j]==RE_OP_CC_VALUE ){
if( pRe->aArg[x+j]==c ){
hit = 1;
j = -1;
}
}else{
if( pRe->aArg[x+j]<=c && pRe->aArg[x+j+1]>=c ){
hit = 1;
j = -1;
}else{
j++;
}
}
}
if( pRe->aOp[x]==RE_OP_CC_EXC ) hit = !hit;
if( hit ) re_add_state(pNext, x+n);
break;
}
}
}
}
for(i=0; i<pNext->nState; i++){
if( pRe->aOp[pNext->aState[i]]==RE_OP_ACCEPT ){ rc = 1; break; }
}
re_match_end:
sqlite3_free(pToFree);
return rc;
}
/* Resize the opcode and argument arrays for an RE under construction.
*/
static int re_resize(ReCompiled *p, int N){
char *aOp;
int *aArg;
aOp = sqlite3_realloc(p->aOp, N*sizeof(p->aOp[0]));
if( aOp==0 ) return 1;
p->aOp = aOp;
aArg = sqlite3_realloc(p->aArg, N*sizeof(p->aArg[0]));
if( aArg==0 ) return 1;
p->aArg = aArg;
p->nAlloc = N;
return 0;
}
/* Insert a new opcode and argument into an RE under construction. The
** insertion point is just prior to existing opcode iBefore.
*/
static int re_insert(ReCompiled *p, int iBefore, int op, int arg){
int i;
if( p->nAlloc<=p->nState && re_resize(p, p->nAlloc*2) ) return 0;
for(i=p->nState; i>iBefore; i--){
p->aOp[i] = p->aOp[i-1];
p->aArg[i] = p->aArg[i-1];
}
p->nState++;
p->aOp[iBefore] = op;
p->aArg[iBefore] = arg;
return iBefore;
}
/* Append a new opcode and argument to the end of the RE under construction.
*/
static int re_append(ReCompiled *p, int op, int arg){
return re_insert(p, p->nState, op, arg);
}
/* Make a copy of N opcodes starting at iStart onto the end of the RE
** under construction.
*/
static void re_copy(ReCompiled *p, int iStart, int N){
if( p->nState+N>=p->nAlloc && re_resize(p, p->nAlloc*2+N) ) return;
memcpy(&p->aOp[p->nState], &p->aOp[iStart], N*sizeof(p->aOp[0]));
memcpy(&p->aArg[p->nState], &p->aArg[iStart], N*sizeof(p->aArg[0]));
p->nState += N;
}
/* Return true if c is a hexadecimal digit character: [0-9a-fA-F]
** If c is a hex digit, also set *pV = (*pV)*16 + valueof(c). If
** c is not a hex digit *pV is unchanged.
*/
static int re_hex(int c, int *pV){
if( c>='0' && c<='9' ){
c -= '0';
}else if( c>='a' && c<='f' ){
c -= 'a' - 10;
}else if( c>='A' && c<='F' ){
c -= 'A' - 10;
}else{
return 0;
}
*pV = (*pV)*16 + (c & 0xff);
return 1;
}
/* A backslash character has been seen, read the next character and
** return its intepretation.
*/
static unsigned re_esc_char(ReCompiled *p){
static const char zEsc[] = "afnrtv\\()*.+?[$^{|}]";
static const char zTrans[] = "\a\f\n\r\t\v";
int i, v = 0;
char c;
if( p->sIn.i>=p->sIn.mx ) return 0;
c = p->sIn.z[p->sIn.i];
if( c=='u' && p->sIn.i+5<p->sIn.mx ){
v = 0;
const unsigned char *zIn = p->sIn.z + p->sIn.i;
if( re_hex(zIn[1],&v)
&& re_hex(zIn[2],&v)
&& re_hex(zIn[3],&v)
&& re_hex(zIn[4],&v)
){
p->sIn.i += 5;
return v;
}
}
if( c=='x' ){
v = 0;
for(i=1; p->sIn.i<p->sIn.mx && re_hex(p->sIn.z[p->sIn.i+i], &v); i++){}
if( i>1 ){
p->sIn.i += i;
return v;
}
}
for(i=0; zEsc[i] && zEsc[i]!=c; i++){}
if( zEsc[i] ){
if( i<6 ) c = zTrans[i];
p->sIn.i++;
}else{
p->zErr = "unknown \\ escape";
}
return c;
}
/* Forward declaration */
static const char *re_subcompile_string(ReCompiled*);
/* Peek at the next byte of input */
static unsigned char rePeek(ReCompiled *p){
return p->sIn.i<p->sIn.mx ? p->sIn.z[p->sIn.i] : 0;
}
/* Compile RE text into a sequence of opcodes. Continue up to the
** first unmatched ")" character, then return. If an error is found,
** return a pointer to the error message string.
*/
static const char *re_subcompile_re(ReCompiled *p){
const char *zErr;
int iStart, iEnd, iGoto;
iStart = p->nState;
zErr = re_subcompile_string(p);
if( zErr ) return zErr;
while( rePeek(p)=='|' ){
iEnd = p->nState;
re_insert(p, iStart, RE_OP_FORK, iEnd + 2 - iStart);
iGoto = re_append(p, RE_OP_GOTO, 0);
p->sIn.i++;
zErr = re_subcompile_string(p);
if( zErr ) return zErr;
p->aArg[iGoto] = p->nState - iGoto;
}
return 0;
}
/* Compile an element of regular expression text (anything that can be
** an operand to the "|" operator). Return NULL on success or a pointer
** to the error message if there is a problem.
*/
static const char *re_subcompile_string(ReCompiled *p){
int iPrev = -1;
int iStart;
unsigned c;
const char *zErr;
while( (c = p->xNextChar(&p->sIn))!=0 ){
iStart = p->nState;
switch( c ){
case '|':
case '$':
case ')': {
p->sIn.i--;
return 0;
}
case '(': {
zErr = re_subcompile_re(p);
if( zErr ) return zErr;
if( rePeek(p)!=')' ) return "unmatched '('";
p->sIn.i++;
break;
}
case '.': {
if( rePeek(p)=='*' ){
re_append(p, RE_OP_ANYSTAR, 0);
p->sIn.i++;
}else{
re_append(p, RE_OP_ANY, 0);
}
break;
}
case '*': {
if( iPrev<0 ) return "'*' without operand";
re_insert(p, iPrev, RE_OP_GOTO, p->nState - iPrev + 1);
re_append(p, RE_OP_FORK, iPrev - p->nState + 1);
break;
}
case '+': {
if( iPrev<0 ) return "'+' without operand";
re_append(p, RE_OP_FORK, iPrev - p->nState);
break;
}
case '?': {
if( iPrev<0 ) return "'?' without operand";
re_insert(p, iPrev, RE_OP_FORK, p->nState - iPrev+1);
break;
}
case '{': {
int m = 0, n = 0;
int sz, j;
if( iPrev<0 ) return "'{m,n}' without operand";
while( (c=rePeek(p))>='0' && c<='9' ){ m = m*10 + c - '0'; p->sIn.i++; }
n = m;
if( c==',' ){
p->sIn.i++;
n = 0;
while( (c=rePeek(p))>='0' && c<='9' ){ n = n*10 + c-'0'; p->sIn.i++; }
}
if( c!='}' ) return "unmatched '{'";
if( n>0 && n<m ) return "n less than m in '{m,n}'";
p->sIn.i++;
sz = p->nState - iPrev;
if( m==0 ){
if( n==0 ) return "both m and n are zero in '{m,n}'";
re_insert(p, iPrev, RE_OP_FORK, sz+1);
n--;
}else{
for(j=1; j<m; j++) re_copy(p, iPrev, sz);
}
for(j=m; j<n; j++){
re_append(p, RE_OP_FORK, sz+1);
re_copy(p, iPrev, sz);
}
if( n==0 && m>0 ){
re_append(p, RE_OP_FORK, -sz);
}
break;
}
case '[': {
int iFirst = p->nState;
if( rePeek(p)=='^' ){
re_append(p, RE_OP_CC_EXC, 0);
p->sIn.i++;
}else{
re_append(p, RE_OP_CC_INC, 0);
}
while( (c = p->xNextChar(&p->sIn))!=0 ){
if( c=='[' && rePeek(p)==':' ){
return "POSIX character classes not supported";
}
if( c=='\\' ) c = re_esc_char(p);
if( rePeek(p)=='-' ){
re_append(p, RE_OP_CC_RANGE, c);
p->sIn.i++;
c = p->xNextChar(&p->sIn);
if( c=='\\' ) c = re_esc_char(p);
re_append(p, RE_OP_CC_RANGE, c);
}else{
re_append(p, RE_OP_CC_VALUE, c);
}
if( rePeek(p)==']' ){ p->sIn.i++; break; }
}
if( c==0 ) return "unclosed '['";
p->aArg[iFirst] = p->nState - iFirst;
break;
}
case '\\': {
int specialOp = 0;
switch( rePeek(p) ){
case 'b': specialOp = RE_OP_BOUNDARY; break;
case 'd': specialOp = RE_OP_DIGIT; break;
case 'D': specialOp = RE_OP_NOTDIGIT; break;
case 's': specialOp = RE_OP_SPACE; break;
case 'S': specialOp = RE_OP_NOTSPACE; break;
case 'w': specialOp = RE_OP_WORD; break;
case 'W': specialOp = RE_OP_NOTWORD; break;
}
if( specialOp ){
p->sIn.i++;
re_append(p, specialOp, 0);
}else{
c = re_esc_char(p);
re_append(p, RE_OP_MATCH, c);
}
break;
}
default: {
re_append(p, RE_OP_MATCH, c);
break;
}
}
iPrev = iStart;
}
return 0;
}
/* Free and reclaim all the memory used by a previously compiled
** regular expression. Applications should invoke this routine once
** for every call to re_compile() to avoid memory leaks.
*/
void re_free(ReCompiled *pRe){
if( pRe ){
sqlite3_free(pRe->aOp);
sqlite3_free(pRe->aArg);
sqlite3_free(pRe);
}
}
/*
** Compile a textual regular expression in zIn[] into a compiled regular
** expression suitable for us by re_match() and return a pointer to the
** compiled regular expression in *ppRe. Return NULL on success or an
** error message if something goes wrong.
*/
const char *re_compile(ReCompiled **ppRe, const char *zIn, int noCase){
ReCompiled *pRe;
const char *zErr;
int i, j;
*ppRe = 0;
pRe = sqlite3_malloc( sizeof(*pRe) );
if( pRe==0 ){
return "out of memory";
}
memset(pRe, 0, sizeof(*pRe));
pRe->xNextChar = noCase ? re_next_char_nocase : re_next_char;
if( re_resize(pRe, 30) ){
re_free(pRe);
return "out of memory";
}
if( zIn[0]=='^' ){
zIn++;
}else{
re_append(pRe, RE_OP_ANYSTAR, 0);
}
pRe->sIn.z = (unsigned char*)zIn;
pRe->sIn.i = 0;
pRe->sIn.mx = strlen((char*)pRe->sIn.z);
zErr = re_subcompile_re(pRe);
if( zErr ){
re_free(pRe);
return zErr;
}
if( rePeek(pRe)=='$' && pRe->sIn.i+1>=pRe->sIn.mx ){
re_append(pRe, RE_OP_MATCH, RE_EOF);
re_append(pRe, RE_OP_ACCEPT, 0);
*ppRe = pRe;
}else if( pRe->sIn.i>=pRe->sIn.mx ){
re_append(pRe, RE_OP_ACCEPT, 0);
*ppRe = pRe;
}else{
re_free(pRe);
return "unrecognized character";
}
if( pRe->aOp[0]==RE_OP_ANYSTAR ){
for(j=0, i=1; j<sizeof(pRe->zInit)-2 && pRe->aOp[i]==RE_OP_MATCH; i++){
unsigned x = pRe->aArg[i];
if( x<=127 ){
pRe->zInit[j++] = x;
}else if( x<=0xfff ){
pRe->zInit[j++] = 0xc0 | (x>>6);
pRe->zInit[j++] = 0x80 | (x&0x3f);
}else if( x<=0xffff ){
pRe->zInit[j++] = 0xd0 | (x>>12);
pRe->zInit[j++] = 0x80 | ((x>>6)&0x3f);
pRe->zInit[j++] = 0x80 | ((x>>6)&0x3f);
}else{
break;
}
}
if( j>0 && pRe->zInit[j-1]==0 ) j--;
pRe->nInit = j;
}
return pRe->zErr;
}
/*
** Implementation of the regexp() SQL function. This function implements
** the build-in REGEXP operator. The first argument to the function is the
** pattern and the second argument is the string. So, the SQL statements:
**
** A REGEXP B
**
** is implemented as regexp(B,A).
*/
static void re_sql_func(
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
ReCompiled *pRe; /* Compiled regular expression */
const char *zPattern; /* The regular expression */
const unsigned char *zStr;/* String being searched */
const char *zErr; /* Compile error message */
pRe = sqlite3_get_auxdata(context, 0);
if( pRe==0 ){
zPattern = (const char*)sqlite3_value_text(argv[0]);
if( zPattern==0 ) return;
zErr = re_compile(&pRe, zPattern, 0);
if( zErr ){
re_free(pRe);
sqlite3_result_error(context, zErr, -1);
return;
}
if( pRe==0 ){
sqlite3_result_error_nomem(context);
return;
}
sqlite3_set_auxdata(context, 0, pRe, (void(*)(void*))re_free);
}
zStr = (const unsigned char*)sqlite3_value_text(argv[1]);
if( zStr!=0 ){
sqlite3_result_int(context, re_match(pRe, zStr, -1));
}
}
/*
** Invoke this routine in order to install the REGEXP function in an
** SQLite database connection.
**
** Use:
**
** sqlite3_auto_extension(sqlite3_add_regexp_func);
**
** to cause this extension to be automatically loaded into each new
** database connection.
*/
int sqlite3_add_regexp_func(sqlite3 *db){
return sqlite3_create_function(db, "regexp", 2, SQLITE_UTF8, 0,
re_sql_func, 0, 0);
}
/***************************** Test Code ***********************************/
#ifdef SQLITE_TEST
#include <tcl.h>
extern int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb);
/* Implementation of the TCL command:
**
** sqlite3_add_regexp_func $DB
*/
static int tclSqlite3AddRegexpFunc(
void * clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
sqlite3 *db;
if( objc!=2 ){
Tcl_WrongNumArgs(interp, 1, objv, "DB");
return TCL_ERROR;
}
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
sqlite3_add_regexp_func(db);
return TCL_OK;
}
/* Register the sqlite3_add_regexp_func TCL command with the TCL interpreter.
*/
int Sqlitetestregexp_Init(Tcl_Interp *interp){
Tcl_CreateObjCommand(interp, "sqlite3_add_regexp_func",
tclSqlite3AddRegexpFunc, 0, 0);
return TCL_OK;
}
#endif /* SQLITE_TEST */
/**************************** End Of Test Code *******************************/

View File

@@ -1280,6 +1280,7 @@ case OP_Subtract: /* same as TK_MINUS, in1, in2, out3 */
case OP_Multiply: /* same as TK_STAR, in1, in2, out3 */ case OP_Multiply: /* same as TK_STAR, in1, in2, out3 */
case OP_Divide: /* same as TK_SLASH, in1, in2, out3 */ case OP_Divide: /* same as TK_SLASH, in1, in2, out3 */
case OP_Remainder: { /* same as TK_REM, in1, in2, out3 */ case OP_Remainder: { /* same as TK_REM, in1, in2, out3 */
char bIntint; /* Started out as two integer operands */
int flags; /* Combined MEM_* flags from both inputs */ int flags; /* Combined MEM_* flags from both inputs */
i64 iA; /* Integer value of left operand */ i64 iA; /* Integer value of left operand */
i64 iB; /* Integer value of right operand */ i64 iB; /* Integer value of right operand */
@@ -1296,6 +1297,7 @@ case OP_Remainder: { /* same as TK_REM, in1, in2, out3 */
if( (pIn1->flags & pIn2->flags & MEM_Int)==MEM_Int ){ if( (pIn1->flags & pIn2->flags & MEM_Int)==MEM_Int ){
iA = pIn1->u.i; iA = pIn1->u.i;
iB = pIn2->u.i; iB = pIn2->u.i;
bIntint = 1;
switch( pOp->opcode ){ switch( pOp->opcode ){
case OP_Add: if( sqlite3AddInt64(&iB,iA) ) goto fp_math; break; case OP_Add: if( sqlite3AddInt64(&iB,iA) ) goto fp_math; break;
case OP_Subtract: if( sqlite3SubInt64(&iB,iA) ) goto fp_math; break; case OP_Subtract: if( sqlite3SubInt64(&iB,iA) ) goto fp_math; break;
@@ -1316,6 +1318,7 @@ case OP_Remainder: { /* same as TK_REM, in1, in2, out3 */
pOut->u.i = iB; pOut->u.i = iB;
MemSetTypeFlag(pOut, MEM_Int); MemSetTypeFlag(pOut, MEM_Int);
}else{ }else{
bIntint = 0;
fp_math: fp_math:
rA = sqlite3VdbeRealValue(pIn1); rA = sqlite3VdbeRealValue(pIn1);
rB = sqlite3VdbeRealValue(pIn2); rB = sqlite3VdbeRealValue(pIn2);
@@ -1347,7 +1350,7 @@ fp_math:
} }
pOut->r = rB; pOut->r = rB;
MemSetTypeFlag(pOut, MEM_Real); MemSetTypeFlag(pOut, MEM_Real);
if( (flags & MEM_Real)==0 ){ if( (flags & MEM_Real)==0 && !bIntint ){
sqlite3VdbeIntegerAffinity(pOut); sqlite3VdbeIntegerAffinity(pOut);
} }
#endif #endif
@@ -2086,8 +2089,6 @@ case OP_BitNot: { /* same as TK_BITNOT, in1, out2 */
** **
** Check if OP_Once flag P1 is set. If so, jump to instruction P2. Otherwise, ** Check if OP_Once flag P1 is set. If so, jump to instruction P2. Otherwise,
** set the flag and fall through to the next instruction. ** set the flag and fall through to the next instruction.
**
** See also: JumpOnce
*/ */
case OP_Once: { /* jump */ case OP_Once: { /* jump */
assert( pOp->p1<p->nOnceFlag ); assert( pOp->p1<p->nOnceFlag );

View File

@@ -253,7 +253,7 @@ struct WhereCost {
#define WHERE_COLUMN_NULL 0x00080000 /* x IS NULL */ #define WHERE_COLUMN_NULL 0x00080000 /* x IS NULL */
#define WHERE_INDEXED 0x000f0000 /* Anything that uses an index */ #define WHERE_INDEXED 0x000f0000 /* Anything that uses an index */
#define WHERE_NOT_FULLSCAN 0x100f3000 /* Does not do a full table scan */ #define WHERE_NOT_FULLSCAN 0x100f3000 /* Does not do a full table scan */
#define WHERE_IN_ABLE 0x000f1000 /* Able to support an IN operator */ #define WHERE_IN_ABLE 0x080f1000 /* Able to support an IN operator */
#define WHERE_TOP_LIMIT 0x00100000 /* x<EXPR or x<=EXPR constraint */ #define WHERE_TOP_LIMIT 0x00100000 /* x<EXPR or x<=EXPR constraint */
#define WHERE_BTM_LIMIT 0x00200000 /* x>EXPR or x>=EXPR constraint */ #define WHERE_BTM_LIMIT 0x00200000 /* x>EXPR or x>=EXPR constraint */
#define WHERE_BOTH_LIMIT 0x00300000 /* Both x>EXPR and x<EXPR */ #define WHERE_BOTH_LIMIT 0x00300000 /* Both x>EXPR and x<EXPR */
@@ -403,7 +403,7 @@ static int whereClauseInsert(WhereClause *pWC, Expr *p, u8 wtFlags){
pWC->nSlot = sqlite3DbMallocSize(db, pWC->a)/sizeof(pWC->a[0]); pWC->nSlot = sqlite3DbMallocSize(db, pWC->a)/sizeof(pWC->a[0]);
} }
pTerm = &pWC->a[idx = pWC->nTerm++]; pTerm = &pWC->a[idx = pWC->nTerm++];
pTerm->pExpr = p; pTerm->pExpr = sqlite3ExprSkipCollate(p);
pTerm->wtFlags = wtFlags; pTerm->wtFlags = wtFlags;
pTerm->pWC = pWC; pTerm->pWC = pWC;
pTerm->iParent = -1; pTerm->iParent = -1;
@@ -1188,7 +1188,8 @@ static void exprAnalyze(
} }
pTerm = &pWC->a[idxTerm]; pTerm = &pWC->a[idxTerm];
pMaskSet = pWC->pMaskSet; pMaskSet = pWC->pMaskSet;
pExpr = sqlite3ExprSkipCollate(pTerm->pExpr); pExpr = pTerm->pExpr;
assert( pExpr->op!=TK_AS && pExpr->op!=TK_COLLATE );
prereqLeft = exprTableUsage(pMaskSet, pExpr->pLeft); prereqLeft = exprTableUsage(pMaskSet, pExpr->pLeft);
op = pExpr->op; op = pExpr->op;
if( op==TK_IN ){ if( op==TK_IN ){
@@ -2056,7 +2057,7 @@ static sqlite3_index_info *allocateIndexInfo(WhereBestIdx *p){
assert( (pTerm->eOperator&(pTerm->eOperator-1))==0 ); assert( (pTerm->eOperator&(pTerm->eOperator-1))==0 );
testcase( pTerm->eOperator==WO_IN ); testcase( pTerm->eOperator==WO_IN );
testcase( pTerm->eOperator==WO_ISNULL ); testcase( pTerm->eOperator==WO_ISNULL );
if( pTerm->eOperator & (WO_IN|WO_ISNULL) ) continue; if( pTerm->eOperator & (WO_ISNULL) ) continue;
if( pTerm->wtFlags & TERM_VNULL ) continue; if( pTerm->wtFlags & TERM_VNULL ) continue;
nTerm++; nTerm++;
} }
@@ -2104,15 +2105,18 @@ static sqlite3_index_info *allocateIndexInfo(WhereBestIdx *p){
pUsage; pUsage;
for(i=j=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){ for(i=j=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){
u8 op;
if( pTerm->leftCursor != pSrc->iCursor ) continue; if( pTerm->leftCursor != pSrc->iCursor ) continue;
assert( (pTerm->eOperator&(pTerm->eOperator-1))==0 ); assert( (pTerm->eOperator&(pTerm->eOperator-1))==0 );
testcase( pTerm->eOperator==WO_IN ); testcase( pTerm->eOperator==WO_IN );
testcase( pTerm->eOperator==WO_ISNULL ); testcase( pTerm->eOperator==WO_ISNULL );
if( pTerm->eOperator & (WO_IN|WO_ISNULL) ) continue; if( pTerm->eOperator & (WO_ISNULL) ) continue;
if( pTerm->wtFlags & TERM_VNULL ) continue; if( pTerm->wtFlags & TERM_VNULL ) continue;
pIdxCons[j].iColumn = pTerm->u.leftColumn; pIdxCons[j].iColumn = pTerm->u.leftColumn;
pIdxCons[j].iTermOffset = i; pIdxCons[j].iTermOffset = i;
pIdxCons[j].op = (u8)pTerm->eOperator; op = (u8)pTerm->eOperator;
if( op==WO_IN ) op = WO_EQ;
pIdxCons[j].op = op;
/* The direct assignment in the previous line is possible only because /* The direct assignment in the previous line is possible only because
** the WO_ and SQLITE_INDEX_CONSTRAINT_ codes are identical. The ** the WO_ and SQLITE_INDEX_CONSTRAINT_ codes are identical. The
** following asserts verify this fact. */ ** following asserts verify this fact. */
@@ -2122,7 +2126,7 @@ static sqlite3_index_info *allocateIndexInfo(WhereBestIdx *p){
assert( WO_GT==SQLITE_INDEX_CONSTRAINT_GT ); assert( WO_GT==SQLITE_INDEX_CONSTRAINT_GT );
assert( WO_GE==SQLITE_INDEX_CONSTRAINT_GE ); assert( WO_GE==SQLITE_INDEX_CONSTRAINT_GE );
assert( WO_MATCH==SQLITE_INDEX_CONSTRAINT_MATCH ); assert( WO_MATCH==SQLITE_INDEX_CONSTRAINT_MATCH );
assert( pTerm->eOperator & (WO_EQ|WO_LT|WO_LE|WO_GT|WO_GE|WO_MATCH) ); assert( pTerm->eOperator & (WO_IN|WO_EQ|WO_LT|WO_LE|WO_GT|WO_GE|WO_MATCH) );
j++; j++;
} }
for(i=0; i<nOrderBy; i++){ for(i=0; i<nOrderBy; i++){
@@ -2208,6 +2212,7 @@ static void bestVirtualIndex(WhereBestIdx *p){
WhereTerm *pTerm; WhereTerm *pTerm;
int i, j; int i, j;
int nOrderBy; int nOrderBy;
int bAllowIN; /* Allow IN optimizations */
double rCost; double rCost;
/* Make sure wsFlags is initialized to some sane value. Otherwise, if the /* Make sure wsFlags is initialized to some sane value. Otherwise, if the
@@ -2242,6 +2247,17 @@ static void bestVirtualIndex(WhereBestIdx *p){
assert( pTab->azModuleArg && pTab->azModuleArg[0] ); assert( pTab->azModuleArg && pTab->azModuleArg[0] );
assert( sqlite3GetVTable(pParse->db, pTab) ); assert( sqlite3GetVTable(pParse->db, pTab) );
/* Try once or twice. On the first attempt, allow IN optimizations.
** If an IN optimization is accepted by the virtual table xBestIndex
** method, but the pInfo->aConstrainUsage.omit flag is not set, then
** the query will not work because it might allow duplicate rows in
** output. In that case, run the xBestIndex method a second time
** without the IN constraints. Usually this loop only runs once.
** The loop will exit using a "break" statement.
*/
for(bAllowIN=1; 1; bAllowIN--){
assert( bAllowIN==0 || bAllowIN==1 );
/* Set the aConstraint[].usable fields and initialize all /* Set the aConstraint[].usable fields and initialize all
** output variables to zero. ** output variables to zero.
** **
@@ -2267,7 +2283,13 @@ static void bestVirtualIndex(WhereBestIdx *p){
for(i=0; i<pIdxInfo->nConstraint; i++, pIdxCons++){ for(i=0; i<pIdxInfo->nConstraint; i++, pIdxCons++){
j = pIdxCons->iTermOffset; j = pIdxCons->iTermOffset;
pTerm = &pWC->a[j]; pTerm = &pWC->a[j];
pIdxCons->usable = (pTerm->prereqRight&p->notReady) ? 0 : 1; if( (pTerm->prereqRight&p->notReady)==0
&& (bAllowIN || pTerm->eOperator!=WO_IN)
){
pIdxCons->usable = 1;
}else{
pIdxCons->usable = 0;
}
} }
memset(pUsage, 0, sizeof(pUsage[0])*pIdxInfo->nConstraint); memset(pUsage, 0, sizeof(pUsage[0])*pIdxInfo->nConstraint);
if( pIdxInfo->needToFreeIdxStr ){ if( pIdxInfo->needToFreeIdxStr ){
@@ -2289,11 +2311,22 @@ static void bestVirtualIndex(WhereBestIdx *p){
} }
pIdxCons = *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint; pIdxCons = *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint;
for(i=0; i<pIdxInfo->nConstraint; i++){ for(i=0; i<pIdxInfo->nConstraint; i++, pIdxCons++){
if( pUsage[i].argvIndex>0 ){ if( pUsage[i].argvIndex>0 ){
p->cost.used |= pWC->a[pIdxCons[i].iTermOffset].prereqRight; j = pIdxCons->iTermOffset;
pTerm = &pWC->a[j];
p->cost.used |= pTerm->prereqRight;
if( pTerm->eOperator==WO_IN && pUsage[i].omit==0 ){
/* Do not attempt to use an IN constraint if the virtual table
** says that the equivalent EQ constraint cannot be safely omitted.
** If we do attempt to use such a constraint, some rows might be
** repeated in the output. */
break;
} }
} }
}
if( i>=pIdxInfo->nConstraint ) break;
}
/* If there is an ORDER BY clause, and the selected virtual table index /* If there is an ORDER BY clause, and the selected virtual table index
** does not satisfy it, increase the cost of the scan accordingly. This ** does not satisfy it, increase the cost of the scan accordingly. This
@@ -4063,6 +4096,7 @@ static Bitmask codeOneLoopStart(
** to access the data. ** to access the data.
*/ */
int iReg; /* P3 Value for OP_VFilter */ int iReg; /* P3 Value for OP_VFilter */
int addrNotFound;
sqlite3_index_info *pVtabIdx = pLevel->plan.u.pVtabIdx; sqlite3_index_info *pVtabIdx = pLevel->plan.u.pVtabIdx;
int nConstraint = pVtabIdx->nConstraint; int nConstraint = pVtabIdx->nConstraint;
struct sqlite3_index_constraint_usage *aUsage = struct sqlite3_index_constraint_usage *aUsage =
@@ -4072,11 +4106,18 @@ static Bitmask codeOneLoopStart(
sqlite3ExprCachePush(pParse); sqlite3ExprCachePush(pParse);
iReg = sqlite3GetTempRange(pParse, nConstraint+2); iReg = sqlite3GetTempRange(pParse, nConstraint+2);
addrNotFound = pLevel->addrBrk;
for(j=1; j<=nConstraint; j++){ for(j=1; j<=nConstraint; j++){
for(k=0; k<nConstraint; k++){ for(k=0; k<nConstraint; k++){
if( aUsage[k].argvIndex==j ){ if( aUsage[k].argvIndex==j ){
int iTerm = aConstraint[k].iTermOffset; WhereTerm *pTerm = &pWC->a[aConstraint[k].iTermOffset];
sqlite3ExprCode(pParse, pWC->a[iTerm].pExpr->pRight, iReg+j+1); int iTarget = iReg+j+1;
if( pTerm->eOperator & WO_IN ){
codeEqualityTerm(pParse, pTerm, pLevel, iTarget);
addrNotFound = pLevel->addrNxt;
}else{
sqlite3ExprCode(pParse, pTerm->pExpr->pRight, iTarget);
}
break; break;
} }
} }
@@ -4084,7 +4125,7 @@ static Bitmask codeOneLoopStart(
} }
sqlite3VdbeAddOp2(v, OP_Integer, pVtabIdx->idxNum, iReg); sqlite3VdbeAddOp2(v, OP_Integer, pVtabIdx->idxNum, iReg);
sqlite3VdbeAddOp2(v, OP_Integer, j-1, iReg+1); sqlite3VdbeAddOp2(v, OP_Integer, j-1, iReg+1);
sqlite3VdbeAddOp4(v, OP_VFilter, iCur, addrBrk, iReg, pVtabIdx->idxStr, sqlite3VdbeAddOp4(v, OP_VFilter, iCur, addrNotFound, iReg, pVtabIdx->idxStr,
pVtabIdx->needToFreeIdxStr ? P4_MPRINTF : P4_STATIC); pVtabIdx->needToFreeIdxStr ? P4_MPRINTF : P4_STATIC);
pVtabIdx->needToFreeIdxStr = 0; pVtabIdx->needToFreeIdxStr = 0;
for(j=0; j<nConstraint; j++){ for(j=0; j<nConstraint; j++){

View File

@@ -131,12 +131,12 @@ do_test auth2-2.3 {
} }
set ::authargs set ::authargs
} {SQLITE_SELECT {} {} {} {} } {SQLITE_SELECT {} {} {} {}
SQLITE_READ v2 a main {}
SQLITE_READ v2 b main {}
SQLITE_READ t2 x main v2 SQLITE_READ t2 x main v2
SQLITE_READ t2 y main v2 SQLITE_READ t2 y main v2
SQLITE_READ t2 y main v2 SQLITE_READ t2 y main v2
SQLITE_READ t2 z main v2 SQLITE_READ t2 z main v2
SQLITE_READ v2 a main {}
SQLITE_READ v2 b main {}
SQLITE_SELECT {} {} {} v2 SQLITE_SELECT {} {} {} v2
} }
do_test auth2-2.4 { do_test auth2-2.4 {
@@ -149,20 +149,20 @@ do_test auth2-2.4 {
} }
set ::authargs set ::authargs
} {SQLITE_SELECT {} {} {} {} } {SQLITE_SELECT {} {} {} {}
SQLITE_READ v2 b main {}
SQLITE_READ v2 a main {}
SQLITE_READ t2 x main v2 SQLITE_READ t2 x main v2
SQLITE_READ t2 y main v2 SQLITE_READ t2 y main v2
SQLITE_READ t2 y main v2 SQLITE_READ t2 y main v2
SQLITE_READ t2 z main v2 SQLITE_READ t2 z main v2
SQLITE_READ v2 b main {}
SQLITE_READ v2 a main {}
SQLITE_SELECT {} {} {} v2 SQLITE_SELECT {} {} {} v2
SQLITE_SELECT {} {} {} {} SQLITE_SELECT {} {} {} {}
SQLITE_READ v2 b main {}
SQLITE_READ v2 a main {}
SQLITE_READ t2 x main v2 SQLITE_READ t2 x main v2
SQLITE_READ t2 y main v2 SQLITE_READ t2 y main v2
SQLITE_READ t2 y main v2 SQLITE_READ t2 y main v2
SQLITE_READ t2 z main v2 SQLITE_READ t2 z main v2
SQLITE_READ v2 b main {}
SQLITE_READ v2 a main {}
SQLITE_SELECT {} {} {} v2 SQLITE_SELECT {} {} {} v2
} }
db2 close db2 close

View File

@@ -627,7 +627,8 @@ proc test_efkey_57 {tn isError sql} {
execsql $sql execsql $sql
do_test e_fkey-18.$tn { do_test e_fkey-18.$tn {
catchsql { INSERT INTO t2 VALUES(NULL) } catchsql { INSERT INTO t2 VALUES(NULL) }
} [lindex {{0 {}} {1 {foreign key mismatch}}} $isError] } [lindex {{0 {}} {/1 {foreign key mismatch - ".*" referencing ".*"}/}} \
$isError]
} }
test_efkey_57 2 0 { CREATE TABLE t1(x PRIMARY KEY) } test_efkey_57 2 0 { CREATE TABLE t1(x PRIMARY KEY) }
test_efkey_57 3 0 { CREATE TABLE t1(x UNIQUE) } test_efkey_57 3 0 { CREATE TABLE t1(x UNIQUE) }
@@ -698,16 +699,16 @@ do_test e_fkey-19.2 {
} {} } {}
do_test e_fkey-19.2 { do_test e_fkey-19.2 {
catchsql { INSERT INTO child4 VALUES('xxx', 5) } catchsql { INSERT INTO child4 VALUES('xxx', 5) }
} {1 {foreign key mismatch}} } {1 {foreign key mismatch - "child4" referencing "parent"}}
do_test e_fkey-19.3 { do_test e_fkey-19.3 {
catchsql { INSERT INTO child5 VALUES('xxx', 6) } catchsql { INSERT INTO child5 VALUES('xxx', 6) }
} {1 {foreign key mismatch}} } {1 {foreign key mismatch - "child5" referencing "parent"}}
do_test e_fkey-19.4 { do_test e_fkey-19.4 {
catchsql { INSERT INTO child6 VALUES(2, 3) } catchsql { INSERT INTO child6 VALUES(2, 3) }
} {1 {foreign key mismatch}} } {1 {foreign key mismatch - "child6" referencing "parent"}}
do_test e_fkey-19.5 { do_test e_fkey-19.5 {
catchsql { INSERT INTO child7 VALUES(3) } catchsql { INSERT INTO child7 VALUES(3) }
} {1 {foreign key mismatch}} } {1 {foreign key mismatch - "child7" referencing "parent"}}
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
# Test errors in the database schema that are detected while preparing # Test errors in the database schema that are detected while preparing
@@ -765,12 +766,12 @@ do_test e_fkey-20.1 {
foreach {tn tbl ptbl err} { foreach {tn tbl ptbl err} {
2 c1 {} "no such table: main.nosuchtable" 2 c1 {} "no such table: main.nosuchtable"
3 c2 p2 "foreign key mismatch" 3 c2 p2 "foreign key mismatch - \"c2\" referencing \"p2\""
4 c3 p3 "foreign key mismatch" 4 c3 p3 "foreign key mismatch - \"c3\" referencing \"p3\""
5 c4 p4 "foreign key mismatch" 5 c4 p4 "foreign key mismatch - \"c4\" referencing \"p4\""
6 c5 p5 "foreign key mismatch" 6 c5 p5 "foreign key mismatch - \"c5\" referencing \"p5\""
7 c6 p6 "foreign key mismatch" 7 c6 p6 "foreign key mismatch - \"c6\" referencing \"p6\""
8 c7 p7 "foreign key mismatch" 8 c7 p7 "foreign key mismatch - \"c7\" referencing \"p7\""
} { } {
do_test e_fkey-20.$tn.1 { do_test e_fkey-20.$tn.1 {
catchsql "INSERT INTO $tbl VALUES('a', 'b')" catchsql "INSERT INTO $tbl VALUES('a', 'b')"
@@ -820,22 +821,22 @@ do_test e_fkey-21.2 {
} {} } {}
do_test e_fkey-21.3 { do_test e_fkey-21.3 {
catchsql { INSERT INTO child9 VALUES('I') } catchsql { INSERT INTO child9 VALUES('I') }
} {1 {foreign key mismatch}} } {1 {foreign key mismatch - "child9" referencing "parent2"}}
do_test e_fkey-21.4 { do_test e_fkey-21.4 {
catchsql { INSERT INTO child9 VALUES('II') } catchsql { INSERT INTO child9 VALUES('II') }
} {1 {foreign key mismatch}} } {1 {foreign key mismatch - "child9" referencing "parent2"}}
do_test e_fkey-21.5 { do_test e_fkey-21.5 {
catchsql { INSERT INTO child9 VALUES(NULL) } catchsql { INSERT INTO child9 VALUES(NULL) }
} {1 {foreign key mismatch}} } {1 {foreign key mismatch - "child9" referencing "parent2"}}
do_test e_fkey-21.6 { do_test e_fkey-21.6 {
catchsql { INSERT INTO child10 VALUES('I', 'II', 'III') } catchsql { INSERT INTO child10 VALUES('I', 'II', 'III') }
} {1 {foreign key mismatch}} } {1 {foreign key mismatch - "child10" referencing "parent2"}}
do_test e_fkey-21.7 { do_test e_fkey-21.7 {
catchsql { INSERT INTO child10 VALUES(1, 2, 3) } catchsql { INSERT INTO child10 VALUES(1, 2, 3) }
} {1 {foreign key mismatch}} } {1 {foreign key mismatch - "child10" referencing "parent2"}}
do_test e_fkey-21.8 { do_test e_fkey-21.8 {
catchsql { INSERT INTO child10 VALUES(NULL, NULL, NULL) } catchsql { INSERT INTO child10 VALUES(NULL, NULL, NULL) }
} {1 {foreign key mismatch}} } {1 {foreign key mismatch - "child10" referencing "parent2"}}
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
# Test errors that are reported when creating the child table. # Test errors that are reported when creating the child table.
@@ -1151,7 +1152,7 @@ do_test e_fkey-28.8 {
CREATE TABLE c(a, b, FOREIGN KEY(a,b) REFERENCES p); CREATE TABLE c(a, b, FOREIGN KEY(a,b) REFERENCES p);
} }
catchsql {DELETE FROM p} catchsql {DELETE FROM p}
} {1 {foreign key mismatch}} } {1 {foreign key mismatch - "c" referencing "p"}}
do_test e_fkey-28.9 { do_test e_fkey-28.9 {
drop_all_tables drop_all_tables
execsql { execsql {
@@ -1159,7 +1160,7 @@ do_test e_fkey-28.9 {
CREATE TABLE c(a REFERENCES p); CREATE TABLE c(a REFERENCES p);
} }
catchsql {DELETE FROM p} catchsql {DELETE FROM p}
} {1 {foreign key mismatch}} } {1 {foreign key mismatch - "c" referencing "p"}}
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
@@ -2729,11 +2730,11 @@ do_test e_fkey-60.3 {
do_test e_fkey-60.4 { do_test e_fkey-60.4 {
execsql { CREATE TABLE nosuchtable(x PRIMARY KEY) } execsql { CREATE TABLE nosuchtable(x PRIMARY KEY) }
catchsql { DELETE FROM p } catchsql { DELETE FROM p }
} {1 {foreign key mismatch}} } {1 {foreign key mismatch - "c2" referencing "p"}}
do_test e_fkey-60.5 { do_test e_fkey-60.5 {
execsql { DROP TABLE c1 } execsql { DROP TABLE c1 }
catchsql { DELETE FROM p } catchsql { DELETE FROM p }
} {1 {foreign key mismatch}} } {1 {foreign key mismatch - "c2" referencing "p"}}
do_test e_fkey-60.6 { do_test e_fkey-60.6 {
execsql { DROP TABLE c2 } execsql { DROP TABLE c2 }
execsql { DELETE FROM p } execsql { DELETE FROM p }

View File

@@ -141,8 +141,8 @@ do_insert_tests e_insert-0 {
delete_all_data delete_all_data
# EVIDENCE-OF: R-20288-20462 The first form (with the "VALUES" keyword) # EVIDENCE-OF: R-21490-41092 The first form (with the "VALUES" keyword)
# creates a single new row in an existing table. # creates one or more new rows in an existing table.
# #
do_insert_tests e_insert-1.1 { do_insert_tests e_insert-1.1 {
0 "SELECT count(*) FROM a2" {0} 0 "SELECT count(*) FROM a2" {0}
@@ -152,11 +152,14 @@ do_insert_tests e_insert-1.1 {
2a "INSERT INTO a2(a, b) VALUES(1, 2)" {} 2a "INSERT INTO a2(a, b) VALUES(1, 2)" {}
2b "SELECT count(*) FROM a2" {2} 2b "SELECT count(*) FROM a2" {2}
3a "INSERT INTO a2(a) VALUES(3),(4)" {}
3b "SELECT count(*) FROM a2" {4}
} }
# EVIDENCE-OF: R-36040-20870 If no column-list is specified then the # EVIDENCE-OF: R-53616-44976 If no column-list is specified then the
# number of values must be the same as the number of columns in the # number of values inserted into each row must be the same as the number
# table. # of columns in the table.
# #
# A test in the block above verifies that if the VALUES list has the # A test in the block above verifies that if the VALUES list has the
# correct number of columns (for table a2, 3 columns) works. So these # correct number of columns (for table a2, 3 columns) works. So these
@@ -171,9 +174,10 @@ do_insert_tests e_insert-1.2 -error {
4 "INSERT INTO a2 VALUES(1,2,3,4,5)" {a2 3 5} 4 "INSERT INTO a2 VALUES(1,2,3,4,5)" {a2 3 5}
} }
# EVIDENCE-OF: R-04006-57648 In this case the result of evaluating the # EVIDENCE-OF: R-34231-22576 In this case the result of evaluating the
# left-most expression in the VALUES list is inserted into the left-most # left-most expression in each term of the VALUES list is inserted into
# column of the new row, and so on. # the left-most column of the each new row, and forth for each
# subsequent expression.
# #
delete_all_data delete_all_data
do_insert_tests e_insert-1.3 { do_insert_tests e_insert-1.3 {
@@ -187,8 +191,9 @@ do_insert_tests e_insert-1.3 {
3b "SELECT * FROM a2 WHERE oid=last_insert_rowid()" {2 x y} 3b "SELECT * FROM a2 WHERE oid=last_insert_rowid()" {2 x y}
} }
# EVIDENCE-OF: R-62524-00361 If a column-list is specified, then the # EVIDENCE-OF: R-44710-64652 If a column-list is specified, then the
# number of values must match the number of specified columns. # number of values in each term of the VALUS list must match the number
# of specified columns.
# #
do_insert_tests e_insert-1.4 -error { do_insert_tests e_insert-1.4 -error {
%d values for %d columns %d values for %d columns

View File

@@ -261,9 +261,9 @@ foreach {tn uri error} "
} }
# EVIDENCE-OF: R-09651-31805 If "ro" is specified, then the database is # EVIDENCE-OF: R-43036-46756 If "ro" is specified, then the database is
# opened for read-only access, just as if the SQLITE_OPEN_READONLY flag # opened for read-only access, just as if the SQLITE_OPEN_READONLY flag
# had been set in the third argument to sqlite3_prepare_v2(). # had been set in the third argument to sqlite3_open_v2().
# #
# EVIDENCE-OF: R-40137-26050 If the mode option is set to "rw", then the # EVIDENCE-OF: R-40137-26050 If the mode option is set to "rw", then the
# database is opened for read-write (but not create) access, as if # database is opened for read-write (but not create) access, as if

View File

@@ -213,4 +213,39 @@ do_execsql_test filefmt-3.3 {
PRAGMA integrity_check; PRAGMA integrity_check;
} {ok} } {ok}
reset_db
do_execsql_test filefmt-4.1 {
PRAGMA auto_vacuum = 1;
CREATE TABLE t1(x, y);
CREATE TABLE t2(x, y);
INSERT INTO t1 VALUES(randomblob(100), randomblob(100));
INSERT INTO t1 VALUES(randomblob(100), randomblob(100));
INSERT INTO t1 VALUES(randomblob(100), randomblob(100));
INSERT INTO t1 VALUES(randomblob(100), randomblob(100));
INSERT INTO t1 VALUES(randomblob(100), randomblob(100));
INSERT INTO t1 VALUES(randomblob(100), randomblob(100));
INSERT INTO t2 SELECT randomblob(100), randomblob(100) FROM t1;
INSERT INTO t2 SELECT randomblob(100), randomblob(100) FROM t1;
INSERT INTO t2 SELECT randomblob(100), randomblob(100) FROM t1;
INSERT INTO t2 SELECT randomblob(100), randomblob(100) FROM t1;
}
do_test filefmt-4.2 {
sql36231 { INSERT INTO t2 SELECT * FROM t1 }
} {}
do_test filefmt-4.3 {
forcedelete bak.db
db backup bak.db
} {}
do_test filefmt-4.4 {
sqlite3 db2 bak.db
db2 eval { PRAGMA integrity_check }
} {ok}
db2 close
finish_test finish_test

View File

@@ -139,14 +139,21 @@ set FkeySimpleTests {
4.17 "UPDATE t7 SET a = 10" {0 {}} 4.17 "UPDATE t7 SET a = 10" {0 {}}
5.1 "INSERT INTO t9 VALUES(1, 3)" {1 {no such table: main.nosuchtable}} 5.1 "INSERT INTO t9 VALUES(1, 3)" {1 {no such table: main.nosuchtable}}
5.2 "INSERT INTO t10 VALUES(1, 3)" {1 {foreign key mismatch}} 5.2 "INSERT INTO t10 VALUES(1, 3)"
{1 {foreign key mismatch - "t10" referencing "t9"}}
} }
do_test fkey2-1.1.0 { do_test fkey2-1.1.0 {
execsql [string map {/D/ {}} $FkeySimpleSchema] execsql [string map {/D/ {}} $FkeySimpleSchema]
} {} } {}
foreach {tn zSql res} $FkeySimpleTests { foreach {tn zSql res} $FkeySimpleTests {
do_test fkey2-1.1.$tn { catchsql $zSql } $res do_test fkey2-1.1.$tn.1 { catchsql $zSql } $res
do_test fkey2-1.1.$tn.2 { execsql {PRAGMA foreign_key_check(t1)} } {}
do_test fkey2-1.1.$tn.3 { execsql {PRAGMA foreign_key_check(t2)} } {}
do_test fkey2-1.1.$tn.4 { execsql {PRAGMA foreign_key_check(t3)} } {}
do_test fkey2-1.1.$tn.5 { execsql {PRAGMA foreign_key_check(t4)} } {}
do_test fkey2-1.1.$tn.6 { execsql {PRAGMA foreign_key_check(t7)} } {}
do_test fkey2-1.1.$tn.7 { execsql {PRAGMA foreign_key_check(t8)} } {}
} }
drop_all_tables drop_all_tables
@@ -155,6 +162,12 @@ do_test fkey2-1.2.0 {
} {} } {}
foreach {tn zSql res} $FkeySimpleTests { foreach {tn zSql res} $FkeySimpleTests {
do_test fkey2-1.2.$tn { catchsql $zSql } $res do_test fkey2-1.2.$tn { catchsql $zSql } $res
do_test fkey2-1.2.$tn.2 { execsql {PRAGMA foreign_key_check(t1)} } {}
do_test fkey2-1.2.$tn.3 { execsql {PRAGMA foreign_key_check(t2)} } {}
do_test fkey2-1.2.$tn.4 { execsql {PRAGMA foreign_key_check(t3)} } {}
do_test fkey2-1.2.$tn.5 { execsql {PRAGMA foreign_key_check(t4)} } {}
do_test fkey2-1.2.$tn.6 { execsql {PRAGMA foreign_key_check(t7)} } {}
do_test fkey2-1.2.$tn.7 { execsql {PRAGMA foreign_key_check(t8)} } {}
} }
drop_all_tables drop_all_tables
@@ -165,6 +178,12 @@ do_test fkey2-1.3.0 {
foreach {tn zSql res} $FkeySimpleTests { foreach {tn zSql res} $FkeySimpleTests {
if {$res == "0 {}"} { set res {0 1} } if {$res == "0 {}"} { set res {0 1} }
do_test fkey2-1.3.$tn { catchsql $zSql } $res do_test fkey2-1.3.$tn { catchsql $zSql } $res
do_test fkey2-1.3.$tn.2 { execsql {PRAGMA foreign_key_check(t1)} } {}
do_test fkey2-1.3.$tn.3 { execsql {PRAGMA foreign_key_check(t2)} } {}
do_test fkey2-1.3.$tn.4 { execsql {PRAGMA foreign_key_check(t3)} } {}
do_test fkey2-1.3.$tn.5 { execsql {PRAGMA foreign_key_check(t4)} } {}
do_test fkey2-1.3.$tn.6 { execsql {PRAGMA foreign_key_check(t7)} } {}
do_test fkey2-1.3.$tn.7 { execsql {PRAGMA foreign_key_check(t8)} } {}
} }
execsql { PRAGMA count_changes = 0 } execsql { PRAGMA count_changes = 0 }
drop_all_tables drop_all_tables
@@ -681,7 +700,7 @@ foreach zSql [list {
do_test fkey2-10.1.[incr tn] { do_test fkey2-10.1.[incr tn] {
execsql $zSql execsql $zSql
catchsql { INSERT INTO c DEFAULT VALUES } catchsql { INSERT INTO c DEFAULT VALUES }
} {1 {foreign key mismatch}} } {/1 {foreign key mismatch - "c" referencing "."}/}
} }
# "rowid" cannot be used as part of a child or parent key definition # "rowid" cannot be used as part of a child or parent key definition
@@ -709,7 +728,7 @@ do_test fkey2-10.2.1 {
INSERT INTO t1(rowid, a, b) VALUES(1, 1, 1); INSERT INTO t1(rowid, a, b) VALUES(1, 1, 1);
INSERT INTO t2 VALUES(1, 1); INSERT INTO t2 VALUES(1, 1);
} }
} {1 {foreign key mismatch}} } {1 {foreign key mismatch - "t2" referencing "t1"}}
do_test fkey2-10.2.2 { do_test fkey2-10.2.2 {
drop_all_tables drop_all_tables
catchsql { catchsql {
@@ -1223,7 +1242,7 @@ do_test fkey-2.14.3.8 {
CREATE TABLE cc(a, b, FOREIGN KEY(a, b) REFERENCES pp(x, z)); CREATE TABLE cc(a, b, FOREIGN KEY(a, b) REFERENCES pp(x, z));
} }
catchsql { INSERT INTO cc VALUES(1, 2) } catchsql { INSERT INTO cc VALUES(1, 2) }
} {1 {foreign key mismatch}} } {1 {foreign key mismatch - "cc" referencing "pp"}}
do_test fkey-2.14.3.9 { do_test fkey-2.14.3.9 {
execsql { DROP TABLE cc } execsql { DROP TABLE cc }
} {} } {}

310
test/fkey5.test Normal file
View File

@@ -0,0 +1,310 @@
# 2012 December 17
#
# 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 tests the PRAGMA foreign_key_check command.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
ifcapable {!foreignkey} {
finish_test
return
}
do_test fkey5-1.1 {
db eval {
CREATE TABLE p1(a INTEGER PRIMARY KEY); INSERT INTO p1 VALUES(88),(89);
CREATE TABLE p2(a INT PRIMARY KEY); INSERT INTO p2 VALUES(77),(78);
CREATE TABLE p3(a TEXT PRIMARY KEY);
INSERT INTO p3 VALUES(66),(67),('alpha'),('BRAVO');
CREATE TABLE p4(a TEXT PRIMARY KEY COLLATE nocase);
INSERT INTO p4 VALUES('alpha'),('BRAVO'),('55'),('Delta'),('ECHO');
CREATE TABLE p5(a INTEGER PRIMARY KEY, b, c, UNIQUE(b,c));
INSERT INTO p5 VALUES(1,'Alpha','abc'),(2,'beta','def');
CREATE TABLE p6(a INTEGER PRIMARY KEY, b TEXT COLLATE nocase,
c TEXT COLLATE rtrim, UNIQUE(b,c));
INSERT INTO p6 VALUES(1,'Alpha','abc '),(2,'bETA','def ');
CREATE TABLE c1(x INTEGER PRIMARY KEY references p1);
CREATE TABLE c2(x INTEGER PRIMARY KEY references p2);
CREATE TABLE c3(x INTEGER PRIMARY KEY references p3);
CREATE TABLE c4(x INTEGER PRIMARY KEY references p4);
CREATE TABLE c5(x INT references p1);
CREATE TABLE c6(x INT references p2);
CREATE TABLE c7(x INT references p3);
CREATE TABLE c8(x INT references p4);
CREATE TABLE c9(x TEXT UNIQUE references p1);
CREATE TABLE c10(x TEXT UNIQUE references p2);
CREATE TABLE c11(x TEXT UNIQUE references p3);
CREATE TABLE c12(x TEXT UNIQUE references p4);
CREATE TABLE c13(x TEXT COLLATE nocase references p3);
CREATE TABLE c14(x TEXT COLLATE nocase references p4);
CREATE TABLE c15(x, y, FOREIGN KEY(x,y) REFERENCES p5(b,c));
CREATE TABLE c16(x, y, FOREIGN KEY(x,y) REFERENCES p5(c,b));
CREATE TABLE c17(x, y, FOREIGN KEY(x,y) REFERENCES p6(b,c));
CREATE TABLE c18(x, y, FOREIGN KEY(x,y) REFERENCES p6(c,b));
CREATE TABLE c19(x TEXT COLLATE nocase, y TEXT COLLATE rtrim,
FOREIGN KEY(x,y) REFERENCES p5(b,c));
CREATE TABLE c20(x TEXT COLLATE nocase, y TEXT COLLATE rtrim,
FOREIGN KEY(x,y) REFERENCES p5(c,b));
CREATE TABLE c21(x TEXT COLLATE nocase, y TEXT COLLATE rtrim,
FOREIGN KEY(x,y) REFERENCES p6(b,c));
CREATE TABLE c22(x TEXT COLLATE nocase, y TEXT COLLATE rtrim,
FOREIGN KEY(x,y) REFERENCES p6(c,b));
PRAGMA foreign_key_check;
}
} {}
do_test fkey5-1.2 {
db eval {
INSERT INTO c1 VALUES(90),(87),(88);
PRAGMA foreign_key_check;
}
} {c1 87 p1 0 c1 90 p1 0}
do_test fkey5-1.3 {
db eval {
PRAGMA foreign_key_check(c1);
}
} {c1 87 p1 0 c1 90 p1 0}
do_test fkey5-1.4 {
db eval {
PRAGMA foreign_key_check(c2);
}
} {}
do_test fkey5-2.0 {
db eval {
INSERT INTO c5 SELECT x FROM c1;
DELETE FROM c1;
PRAGMA foreign_key_check;
}
} {c5 1 p1 0 c5 3 p1 0}
do_test fkey5-2.1 {
db eval {
PRAGMA foreign_key_check(c5);
}
} {c5 1 p1 0 c5 3 p1 0}
do_test fkey5-2.2 {
db eval {
PRAGMA foreign_key_check(c1);
}
} {}
do_test fkey5-3.0 {
db eval {
INSERT INTO c9 SELECT x FROM c5;
DELETE FROM c5;
PRAGMA foreign_key_check;
}
} {c9 1 p1 0 c9 3 p1 0}
do_test fkey5-3.1 {
db eval {
PRAGMA foreign_key_check(c9);
}
} {c9 1 p1 0 c9 3 p1 0}
do_test fkey5-3.2 {
db eval {
PRAGMA foreign_key_check(c5);
}
} {}
do_test fkey5-4.0 {
db eval {
DELETE FROM c9;
INSERT INTO c2 VALUES(79),(77),(76);
PRAGMA foreign_key_check;
}
} {c2 76 p2 0 c2 79 p2 0}
do_test fkey5-4.1 {
db eval {
PRAGMA foreign_key_check(c2);
}
} {c2 76 p2 0 c2 79 p2 0}
do_test fkey5-4.2 {
db eval {
INSERT INTO c6 SELECT x FROM c2;
DELETE FROM c2;
PRAGMA foreign_key_check;
}
} {c6 1 p2 0 c6 3 p2 0}
do_test fkey5-4.3 {
db eval {
PRAGMA foreign_key_check(c6);
}
} {c6 1 p2 0 c6 3 p2 0}
do_test fkey5-4.4 {
db eval {
INSERT INTO c10 SELECT x FROM c6;
DELETE FROM c6;
PRAGMA foreign_key_check;
}
} {c10 1 p2 0 c10 3 p2 0}
do_test fkey5-4.5 {
db eval {
PRAGMA foreign_key_check(c10);
}
} {c10 1 p2 0 c10 3 p2 0}
do_test fkey5-5.0 {
db eval {
DELETE FROM c10;
INSERT INTO c3 VALUES(68),(67),(65);
PRAGMA foreign_key_check;
}
} {c3 65 p3 0 c3 68 p3 0}
do_test fkey5-5.1 {
db eval {
PRAGMA foreign_key_check(c3);
}
} {c3 65 p3 0 c3 68 p3 0}
do_test fkey5-5.2 {
db eval {
INSERT INTO c7 SELECT x FROM c3;
INSERT INTO c7 VALUES('Alpha'),('alpha'),('foxtrot');
DELETE FROM c3;
PRAGMA foreign_key_check;
}
} {c7 1 p3 0 c7 3 p3 0 c7 4 p3 0 c7 6 p3 0}
do_test fkey5-5.3 {
db eval {
PRAGMA foreign_key_check(c7);
}
} {c7 1 p3 0 c7 3 p3 0 c7 4 p3 0 c7 6 p3 0}
do_test fkey5-5.4 {
db eval {
INSERT INTO c11 SELECT x FROM c7;
DELETE FROM c7;
PRAGMA foreign_key_check;
}
} {c11 1 p3 0 c11 3 p3 0 c11 4 p3 0 c11 6 p3 0}
do_test fkey5-5.5 {
db eval {
PRAGMA foreign_key_check(c11);
}
} {c11 1 p3 0 c11 3 p3 0 c11 4 p3 0 c11 6 p3 0}
do_test fkey5-6.0 {
db eval {
DELETE FROM c11;
INSERT INTO c4 VALUES(54),(55),(56);
PRAGMA foreign_key_check;
}
} {c4 54 p4 0 c4 56 p4 0}
do_test fkey5-6.1 {
db eval {
PRAGMA foreign_key_check(c4);
}
} {c4 54 p4 0 c4 56 p4 0}
do_test fkey5-6.2 {
db eval {
INSERT INTO c8 SELECT x FROM c4;
INSERT INTO c8 VALUES('Alpha'),('ALPHA'),('foxtrot');
DELETE FROM c4;
PRAGMA foreign_key_check;
}
} {c8 1 p4 0 c8 3 p4 0 c8 6 p4 0}
do_test fkey5-6.3 {
db eval {
PRAGMA foreign_key_check(c8);
}
} {c8 1 p4 0 c8 3 p4 0 c8 6 p4 0}
do_test fkey5-6.4 {
db eval {
INSERT INTO c12 SELECT x FROM c8;
DELETE FROM c8;
PRAGMA foreign_key_check;
}
} {c12 1 p4 0 c12 3 p4 0 c12 6 p4 0}
do_test fkey5-6.5 {
db eval {
PRAGMA foreign_key_check(c12);
}
} {c12 1 p4 0 c12 3 p4 0 c12 6 p4 0}
do_test fkey5-7.1 {
db eval {
INSERT OR IGNORE INTO c13 SELECT * FROM c12;
INSERT OR IGNORE INTO C14 SELECT * FROM c12;
DELETE FROM c12;
PRAGMA foreign_key_check;
}
} {c14 1 p4 0 c14 3 p4 0 c14 6 p4 0 c13 1 p3 0 c13 2 p3 0 c13 3 p3 0 c13 4 p3 0 c13 5 p3 0 c13 6 p3 0}
do_test fkey5-7.2 {
db eval {
PRAGMA foreign_key_check(c14);
}
} {c14 1 p4 0 c14 3 p4 0 c14 6 p4 0}
do_test fkey5-7.3 {
db eval {
PRAGMA foreign_key_check(c13);
}
} {c13 1 p3 0 c13 2 p3 0 c13 3 p3 0 c13 4 p3 0 c13 5 p3 0 c13 6 p3 0}
do_test fkey5-8.0 {
db eval {
DELETE FROM c13;
DELETE FROM c14;
INSERT INTO c19 VALUES('alpha','abc');
PRAGMA foreign_key_check(c19);
}
} {c19 1 p5 0}
do_test fkey5-8.1 {
db eval {
DELETE FROM c19;
INSERT INTO c19 VALUES('Alpha','abc');
PRAGMA foreign_key_check(c19);
}
} {}
do_test fkey5-8.2 {
db eval {
INSERT INTO c20 VALUES('Alpha','abc');
PRAGMA foreign_key_check(c20);
}
} {c20 1 p5 0}
do_test fkey5-8.3 {
db eval {
DELETE FROM c20;
INSERT INTO c20 VALUES('abc','Alpha');
PRAGMA foreign_key_check(c20);
}
} {}
do_test fkey5-8.4 {
db eval {
INSERT INTO c21 VALUES('alpha','abc ');
PRAGMA foreign_key_check(c21);
}
} {}
do_test fkey5-8.5 {
db eval {
DELETE FROM c21;
INSERT INTO c19 VALUES('Alpha','abc');
PRAGMA foreign_key_check(c21);
}
} {}
do_test fkey5-8.6 {
db eval {
INSERT INTO c22 VALUES('Alpha','abc');
PRAGMA foreign_key_check(c22);
}
} {c22 1 p6 0}
do_test fkey5-8.7 {
db eval {
DELETE FROM c22;
INSERT INTO c22 VALUES('abc ','ALPHA');
PRAGMA foreign_key_check(c22);
}
} {}
finish_test

View File

@@ -29,6 +29,7 @@ do_malloc_test fkey_malloc-1 -sqlprep {
INSERT INTO t2 VALUES('aaa'); INSERT INTO t2 VALUES('aaa');
UPDATE t1 SET a = 'bbb'; UPDATE t1 SET a = 'bbb';
DELETE FROM t1; DELETE FROM t1;
PRAGMA foreign_key_check;
} }
do_malloc_test fkey_malloc-2 -sqlprep { do_malloc_test fkey_malloc-2 -sqlprep {
@@ -128,5 +129,3 @@ do_malloc_test fkey_malloc-7 -sqlprep {
} }
finish_test finish_test

83
test/ioerr6.test Normal file
View File

@@ -0,0 +1,83 @@
# 2012 December 18
#
# The author disclaims copyright to this source code. In place of
# a legal notice, here is a blessing:
#
# May you do good and not evil.
# May you find forgiveness for yourself and forgive others.
# May you share freely, never taking more than you give.
#
#***********************************************************************
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
source $testdir/malloc_common.tcl
set ::testprefix ioerr6
ifcapable !atomicwrite {
puts "skipping tests - not compiled with SQLITE_ENABLE_ATOMIC_WRITE..."
finish_test
return
}
faultsim_save_and_close
do_test 1.1 {
testvfs shmfault -default true
shmfault devchar atomic
sqlite3 db test.db
execsql {
CREATE TABLE t1(a, b);
CREATE INDEX i1 ON t1(a, b);
INSERT INTO t1 VALUES(1, 2);
INSERT INTO t1 VALUES(2, 4);
INSERT INTO t1 VALUES(3, 6);
INSERT INTO t1 VALUES(4, 8);
}
# Cause the first call to xWrite() to fail with SQLITE_FULL.
shmfault full 2 1
catchsql { INSERT INTO t1 VALUES(5, 10) }
} {1 {database or disk is full}}
do_test 1.2 {
execsql { PRAGMA integrity_check }
} {ok}
db close
shmfault delete
do_faultsim_test 2 -faults full* -prep {
shmfault devchar atomic
faultsim_restore
sqlite3 db test.db
} -body {
db eval {
CREATE TABLE t1(x PRIMARY KEY);
INSERT INTO t1 VALUES('abc');
}
} -test {
set res [db one { PRAGMA integrity_check }]
if {$res != "ok"} {
error "integrity check: $res"
}
}
do_faultsim_test 2 -faults full* -prep {
shmfault devchar atomic
faultsim_restore
sqlite3 db test.db
} -body {
db eval {
CREATE TABLE t1(x);
CREATE TABLE t2(x);
}
} -test {
db eval { CREATE TABLE t3(x) }
if {[db one { PRAGMA integrity_check }] != "ok"} {
error "integrity check failed"
}
}
finish_test

View File

@@ -17,6 +17,7 @@
set testdir [file dirname $argv0] set testdir [file dirname $argv0]
source $testdir/tester.tcl source $testdir/tester.tcl
set ::testprefix minmax
do_test minmax-1.0 { do_test minmax-1.0 {
execsql { execsql {
@@ -536,7 +537,96 @@ do_test minmax-12.17 {
} }
} {5} } {5}
#-------------------------------------------------------------------------
reset_db
proc do_test_13 {op name sql1 sql2 res} {
set ::sqlite_search_count 0
uplevel [list do_execsql_test $name.1 $sql1 $res]
set a $::sqlite_search_count
set ::sqlite_search_count 0
uplevel [list do_execsql_test $name.2 $sql2 $res]
set b $::sqlite_search_count
uplevel [list do_test $name.3 [list expr "$a $op $b"] 1]
}
# Run a test named $name. Check that SQL statements $sql1 and $sql2 both
# return the same result, but that $sql2 increments the $sqlite_search_count
# variable more often (indicating that it is visiting more rows to determine
# the result).
#
proc do_test_13_opt {name sql1 sql2 res} {
uplevel [list do_test_13 < $name $sql1 $sql2 $res]
}
# Like [do_test_13_noopt], except this time check that the $sqlite_search_count
# variable is incremented the same number of times by both SQL statements.
#
proc do_test_13_noopt {name sql1 sql2 res} {
uplevel [list do_test_13 == $name $sql1 $sql2 $res]
}
do_execsql_test 13.1 {
CREATE TABLE t1(a, b, c);
INSERT INTO t1 VALUES('a', 1, 1);
INSERT INTO t1 VALUES('b', 6, 6);
INSERT INTO t1 VALUES('c', 5, 5);
INSERT INTO t1 VALUES('a', 4, 4);
INSERT INTO t1 VALUES('a', 5, 5);
INSERT INTO t1 VALUES('c', 6, 6);
INSERT INTO t1 VALUES('b', 4, 4);
INSERT INTO t1 VALUES('c', 7, 7);
INSERT INTO t1 VALUES('b', 2, 2);
INSERT INTO t1 VALUES('b', 3, 3);
INSERT INTO t1 VALUES('a', 3, 3);
INSERT INTO t1 VALUES('b', 5, 5);
INSERT INTO t1 VALUES('c', 4, 4);
INSERT INTO t1 VALUES('c', 3, 3);
INSERT INTO t1 VALUES('a', 2, 2);
SELECT * FROM t1 ORDER BY a, b, c;
} {a 1 1 a 2 2 a 3 3 a 4 4 a 5 5
b 2 2 b 3 3 b 4 4 b 5 5 b 6 6
c 3 3 c 4 4 c 5 5 c 6 6 c 7 7
}
do_execsql_test 13.2 { CREATE INDEX i1 ON t1(a, b, c) }
do_test_13_opt 13.3 {
SELECT min(b) FROM t1 WHERE a='b'
} {
SELECT min(c) FROM t1 WHERE a='b'
} {2}
do_test_13_opt 13.4 {
SELECT a, min(b) FROM t1 WHERE a='b'
} {
SELECT a, min(c) FROM t1 WHERE a='b'
} {b 2}
do_test_13_opt 13.4 {
SELECT a||c, max(b)+4 FROM t1 WHERE a='c'
} {
SELECT a||c, max(c)+4 FROM t1 WHERE a='c'
} {c7 11}
do_test_13_noopt 13.5 {
SELECT a||c, max(b+1) FROM t1 WHERE a='c'
} {
SELECT a||c, max(c+1) FROM t1 WHERE a='c'
} {c7 8}
do_test_13_noopt 13.6 {
SELECT count(b) FROM t1 WHERE a='c'
} {
SELECT count(c) FROM t1 WHERE a='c'
} {5}
do_test_13_noopt 13.7 {
SELECT min(b), count(b) FROM t1 WHERE a='a';
} {
SELECT min(c), count(c) FROM t1 WHERE a='a';
} {1 5}
finish_test finish_test

View File

@@ -534,12 +534,20 @@ do_test pragma-6.2.2 {
b DEFAULT (5+3), b DEFAULT (5+3),
c TEXT, c TEXT,
d INTEGER DEFAULT NULL, d INTEGER DEFAULT NULL,
e TEXT DEFAULT '' e TEXT DEFAULT '',
UNIQUE(b,c,d),
PRIMARY KEY(e,b,c)
); );
PRAGMA table_info(t5); PRAGMA table_info(t5);
} }
} {0 a TEXT 0 CURRENT_TIMESTAMP 0 1 b {} 0 5+3 0 2 c TEXT 0 <<NULL>> 0 3 d INTEGER 0 NULL 0 4 e TEXT 0 '' 0} } {0 a TEXT 0 CURRENT_TIMESTAMP 0 1 b {} 0 5+3 2 2 c TEXT 0 <<NULL>> 3 3 d INTEGER 0 NULL 0 4 e TEXT 0 '' 1}
db nullvalue {} db nullvalue {}
do_test pragma-6.2.3 {
execsql {
CREATE TABLE t2_3(a,b INTEGER PRIMARY KEY,c);
pragma table_info(t2_3)
}
} {0 a {} 0 {} 0 1 b INTEGER 0 {} 1 2 c {} 0 {} 0}
ifcapable {foreignkey} { ifcapable {foreignkey} {
do_test pragma-6.3.1 { do_test pragma-6.3.1 {
execsql { execsql {
@@ -1619,5 +1627,3 @@ do_test 22.4.3 {
} {ok} } {ok}
finish_test finish_test

211
test/regexp1.test Normal file
View File

@@ -0,0 +1,211 @@
# 2012 December 31
#
# 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 test for the REGEXP operator in test_regexp.c.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
do_test regexp1-1.1 {
sqlite3_add_regexp_func db
db eval {
CREATE TABLE t1(x INTEGER PRIMARY KEY, y TEXT);
INSERT INTO t1 VALUES(1, 'For since by man came death,');
INSERT INTO t1 VALUES(2, 'by man came also the resurrection of the dead.');
INSERT INTO t1 VALUES(3, 'For as in Adam all die,');
INSERT INTO t1 VALUES(4, 'even so in Christ shall all be made alive.');
SELECT x FROM t1 WHERE y REGEXP '^For ' ORDER BY x;
}
} {1 3}
do_execsql_test regexp1-1.2 {
SELECT x FROM t1 WHERE y REGEXP 'by|in' ORDER BY x;
} {1 2 3 4}
do_execsql_test regexp1-1.3 {
SELECT x FROM t1 WHERE y REGEXP 'by|Christ' ORDER BY x;
} {1 2 4}
do_execsql_test regexp1-1.4 {
SELECT x FROM t1 WHERE y REGEXP 'shal+ al+' ORDER BY x;
} {4}
do_execsql_test regexp1-1.5 {
SELECT x FROM t1 WHERE y REGEXP 'shall x*y*z*all' ORDER BY x;
} {4}
do_execsql_test regexp1-1.6 {
SELECT x FROM t1 WHERE y REGEXP 'shallx?y? ?z?all' ORDER BY x;
} {4}
do_execsql_test regexp1-1.7 {
SELECT x FROM t1 WHERE y REGEXP 'r{2}' ORDER BY x;
} {2}
do_execsql_test regexp1-1.8 {
SELECT x FROM t1 WHERE y REGEXP 'r{3}' ORDER BY x;
} {}
do_execsql_test regexp1-1.9 {
SELECT x FROM t1 WHERE y REGEXP 'r{1}' ORDER BY x;
} {1 2 3 4}
do_execsql_test regexp1-1.10 {
SELECT x FROM t1 WHERE y REGEXP 'ur{2,10}e' ORDER BY x;
} {2}
do_execsql_test regexp1-1.11 {
SELECT x FROM t1 WHERE y REGEXP '[Aa]dam' ORDER BY x;
} {3}
do_execsql_test regexp1-1.12 {
SELECT x FROM t1 WHERE y REGEXP '[^Aa]dam' ORDER BY x;
} {}
do_execsql_test regexp1-1.13 {
SELECT x FROM t1 WHERE y REGEXP '[^b-zB-Z]dam' ORDER BY x;
} {3}
do_execsql_test regexp1-1.14 {
SELECT x FROM t1 WHERE y REGEXP 'alive' ORDER BY x;
} {4}
do_execsql_test regexp1-1.15 {
SELECT x FROM t1 WHERE y REGEXP '^alive' ORDER BY x;
} {}
do_execsql_test regexp1-1.16 {
SELECT x FROM t1 WHERE y REGEXP 'alive$' ORDER BY x;
} {}
do_execsql_test regexp1-1.17 {
SELECT x FROM t1 WHERE y REGEXP 'alive.$' ORDER BY x;
} {4}
do_execsql_test regexp1-1.18 {
SELECT x FROM t1 WHERE y REGEXP 'alive\.$' ORDER BY x;
} {4}
do_execsql_test regexp1-1.19 {
SELECT x FROM t1 WHERE y REGEXP 'ma[nd]' ORDER BY x;
} {1 2 4}
do_execsql_test regexp1-1.20 {
SELECT x FROM t1 WHERE y REGEXP '\bma[nd]' ORDER BY x;
} {1 2 4}
do_execsql_test regexp1-1.21 {
SELECT x FROM t1 WHERE y REGEXP 'ma[nd]\b' ORDER BY x;
} {1 2}
do_execsql_test regexp1-1.22 {
SELECT x FROM t1 WHERE y REGEXP 'ma\w' ORDER BY x;
} {1 2 4}
do_execsql_test regexp1-1.23 {
SELECT x FROM t1 WHERE y REGEXP 'ma\W' ORDER BY x;
} {}
do_execsql_test regexp1-1.24 {
SELECT x FROM t1 WHERE y REGEXP '\sma\w' ORDER BY x;
} {1 2 4}
do_execsql_test regexp1-1.25 {
SELECT x FROM t1 WHERE y REGEXP '\Sma\w' ORDER BY x;
} {}
do_execsql_test regexp1-1.26 {
SELECT x FROM t1 WHERE y REGEXP 'alive\S$' ORDER BY x;
} {4}
do_execsql_test regexp1-1.27 {
SELECT x FROM t1 WHERE y REGEXP
'\b(unto|us|son|given|his|name|called|' ||
'wonderful|councelor|mighty|god|everlasting|father|' ||
'prince|peace|alive)\b';
} {4}
do_execsql_test regexp1-2.1 {
SELECT 'aaaabbbbcccc' REGEXP 'ab*c',
'aaaacccc' REGEXP 'ab*c';
} {1 1}
do_execsql_test regexp1-2.2 {
SELECT 'aaaabbbbcccc' REGEXP 'ab+c',
'aaaacccc' REGEXP 'ab+c';
} {1 0}
do_execsql_test regexp1-2.3 {
SELECT 'aaaabbbbcccc' REGEXP 'ab?c',
'aaaacccc' REGEXP 'ab?c';
} {0 1}
do_execsql_test regexp1-2.4 {
SELECT 'aaaabbbbbbcccc' REGEXP 'ab{3,5}c',
'aaaabbbbbcccc' REGEXP 'ab{3,5}c',
'aaaabbbbcccc' REGEXP 'ab{3,5}c',
'aaaabbbcccc' REGEXP 'ab{3,5}c',
'aaaabbcccc' REGEXP 'ab{3,5}c',
'aaaabcccc' REGEXP 'ab{3,5}c'
} {0 1 1 1 0 0}
do_execsql_test regexp1-2.5 {
SELECT 'aaaabbbbcccc' REGEXP 'a(a|b|c)+c',
'aaaabbbbcccc' REGEXP '^a(a|b|c){11}c$',
'aaaabbbbcccc' REGEXP '^a(a|b|c){10}c$',
'aaaabbbbcccc' REGEXP '^a(a|b|c){9}c$'
} {1 0 1 0}
do_execsql_test regexp1-2.6 {
SELECT 'aaaabbbbcccc' REGEXP '^a(a|bb|c)+c$',
'aaaabbbbcccc' REGEXP '^a(a|bbb|c)+c$',
'aaaabbbbcccc' REGEXP '^a(a|bbbb|c)+c$'
} {1 0 1}
do_execsql_test regexp1-2.7 {
SELECT 'aaaabbbbcccc' REGEXP '^a([ac]+|bb){3}c$',
'aaaabbbbcccc' REGEXP '^a([ac]+|bb){4}c$',
'aaaabbbbcccc' REGEXP '^a([ac]+|bb){5}c$'
} {0 1 1}
do_execsql_test regexp1-2.8 {
SELECT 'abc*def+ghi.jkl[mno]pqr' REGEXP 'c.d',
'abc*def+ghi.jkl[mno]pqr' REGEXP 'c\*d',
'abc*def+ghi.jkl[mno]pqr' REGEXP 'f\+g',
'abc*def+ghi.jkl[mno]pqr' REGEXP 'i\.j',
'abc*def+ghi.jkl[mno]pqr' REGEXP 'l\[mno\]p'
} {1 1 1 1 1}
do_test regexp1-2.9 {
set v1 "abc\ndef"
db eval {SELECT $v1 REGEXP '^abc\ndef$'}
} {1}
do_test regexp1-2.10 {
set v1 "abc\adef"
db eval {SELECT $v1 REGEXP '^abc\adef$'}
} {1}
do_test regexp1-2.11 {
set v1 "abc\tdef"
db eval {SELECT $v1 REGEXP '^abc\tdef$'}
} {1}
do_test regexp1-2.12 {
set v1 "abc\rdef"
db eval {SELECT $v1 REGEXP '^abc\rdef$'}
} {1}
do_test regexp1-2.13 {
set v1 "abc\fdef"
db eval {SELECT $v1 REGEXP '^abc\fdef$'}
} {1}
do_test regexp1-2.14 {
set v1 "abc\vdef"
db eval {SELECT $v1 REGEXP '^abc\vdef$'}
} {1}
do_execsql_test regexp1-2.15 {
SELECT 'abc\def' REGEXP '^abc\\def',
'abc(def' REGEXP '^abc\(def',
'abc)def' REGEXP '^abc\)def',
'abc*def' REGEXP '^abc\*def',
'abc.def' REGEXP '^abc\.def',
'abc+def' REGEXP '^abc\+def',
'abc?def' REGEXP '^abc\?def',
'abc[def' REGEXP '^abc\[def',
'abc$def' REGEXP '^abc\$',
'^def' REGEXP '\^def',
'abc{4}x' REGEXP '^abc\{4\}x$',
'abc|def' REGEXP '^abc\|def$'
} {1 1 1 1 1 1 1 1 1 1 1 1}
do_execsql_test regexp1-2.20 {
SELECT 'abc$¢€xyz' REGEXP '^abc\u0024\u00a2\u20acxyz$',
'abc$¢€xyz' REGEXP '^abc\u0024\u00A2\u20ACxyz$',
'abc$¢€xyz' REGEXP '^abc\x24\xa2\x20acxyz$'
} {1 1 1}
do_execsql_test regexp1-2.21 {
SELECT 'abc$¢€xyz' REGEXP '^abc[\u0024][\u00a2][\u20ac]xyz$',
'abc$¢€xyz' REGEXP '^abc[\u0024\u00A2\u20AC]{3}xyz$',
'abc$¢€xyz' REGEXP '^abc[\x24][\xa2\x20ac]+xyz$'
} {1 1 1}
do_execsql_test regexp1-2.22 {
SELECT 'abc$¢€xyz' REGEXP '^abc[^\u0025-X][^ -\u007f][^\u20ab]xyz$'
} {1}
finish_test

View File

@@ -81,6 +81,22 @@ array set ::Configs {
-DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_DEFAULT_FILE_FORMAT=4
-DSQLITE_ENABLE_UPDATE_DELETE_LIMIT=1 -DSQLITE_ENABLE_UPDATE_DELETE_LIMIT=1
} }
"Check-Symbols" {
-DSQLITE_MEMDEBUG=1
-DSQLITE_ENABLE_FTS3_PARENTHESIS=1
-DSQLITE_ENABLE_FTS3=1
-DSQLITE_ENABLE_RTREE=1
-DSQLITE_ENABLE_MEMSYS5=1
-DSQLITE_ENABLE_MEMSYS3=1
-DSQLITE_ENABLE_COLUMN_METADATA=1
-DSQLITE_ENABLE_UPDATE_DELETE_LIMIT=1
-DSQLITE_SECURE_DELETE=1
-DSQLITE_SOUNDEX=1
-DSQLITE_ENABLE_ATOMIC_WRITE=1
-DSQLITE_ENABLE_IOTRACE=1
-DSQLITE_ENABLE_MEMORY_MANAGEMENT=1
-DSQLITE_ENABLE_OVERSIZE_CELL_CHECK=1
}
"Debug-One" { "Debug-One" {
-O2 -O2
-DSQLITE_DEBUG=1 -DSQLITE_DEBUG=1
@@ -164,7 +180,8 @@ array set ::Configs {
array set ::Platforms { array set ::Platforms {
Linux-x86_64 { Linux-x86_64 {
"Debug-One" "checksymbols test" "Check-Symbols" checksymbols
"Debug-One" test
"Secure-Delete" test "Secure-Delete" test
"Unlock-Notify" "QUICKTEST_INCLUDE=notify2.test test" "Unlock-Notify" "QUICKTEST_INCLUDE=notify2.test test"
"Update-Delete-Limit" test "Update-Delete-Limit" test
@@ -330,6 +347,7 @@ proc main {argv} {
# If the configuration included the SQLITE_DEBUG option, then remove # If the configuration included the SQLITE_DEBUG option, then remove
# it and run veryquick.test. If it did not include the SQLITE_DEBUG option # it and run veryquick.test. If it did not include the SQLITE_DEBUG option
# add it and run veryquick.test. # add it and run veryquick.test.
if {$target!="checksymbols"} {
set debug_idx [lsearch -glob $config_options -DSQLITE_DEBUG*] set debug_idx [lsearch -glob $config_options -DSQLITE_DEBUG*]
if {$debug_idx < 0} { if {$debug_idx < 0} {
run_test_suite "${zConfig}_debug" test [ run_test_suite "${zConfig}_debug" test [
@@ -340,6 +358,7 @@ proc main {argv} {
lreplace $config_options $debug_idx $debug_idx lreplace $config_options $debug_idx $debug_idx
] ]
} }
}
} }
} }

155
test/selectD.test Normal file
View File

@@ -0,0 +1,155 @@
# 2012 December 19
#
# The author disclaims copyright to this source code. In place of
# a legal notice, here is a blessing:
#
# May you do good and not evil.
# May you find forgiveness for yourself and forgive others.
# May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for name resolution in SELECT
# statements that have parenthesized FROM clauses.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
for {set i 1} {$i<=2} {incr i} {
db close
forcedelete test$i.db
sqlite3 db test$i.db
if {$i==2} {
optimization_control db query-flattener off
}
do_test selectD-$i.0 {
db eval {
ATTACH ':memory:' AS aux1;
CREATE TABLE t1(a,b); INSERT INTO t1 VALUES(111,'x1');
CREATE TABLE t2(a,b); INSERT INTO t2 VALUES(222,'x2');
CREATE TEMP TABLE t3(a,b); INSERT INTO t3 VALUES(333,'x3');
CREATE TABLE main.t4(a,b); INSERT INTO main.t4 VALUES(444,'x4');
CREATE TABLE aux1.t4(a,b); INSERT INTO aux1.t4 VALUES(555,'x5');
}
} {}
do_test selectD-$i.1 {
db eval {
SELECT *
FROM (t1), (t2), (t3), (t4)
WHERE t4.a=t3.a+111
AND t3.a=t2.a+111
AND t2.a=t1.a+111;
}
} {111 x1 222 x2 333 x3 444 x4}
do_test selectD-$i.2.1 {
db eval {
SELECT *
FROM t1 JOIN (t2 JOIN (t3 JOIN t4 ON t4.a=t3.a+111)
ON t3.a=t2.a+111)
ON t2.a=t1.a+111;
}
} {111 x1 222 x2 333 x3 444 x4}
do_test selectD-$i.2.2 {
db eval {
SELECT t3.a
FROM t1 JOIN (t2 JOIN (t3 JOIN t4 ON t4.a=t3.a+111)
ON t3.a=t2.a+111)
ON t2.a=t1.a+111;
}
} {333}
do_test selectD-$i.2.3 {
db eval {
SELECT t3.*
FROM t1 JOIN (t2 JOIN (t3 JOIN t4 ON t4.a=t3.a+111)
ON t3.a=t2.a+111)
ON t2.a=t1.a+111;
}
} {333 x3}
do_test selectD-$i.2.3 {
db eval {
SELECT t3.*, t2.*
FROM t1 JOIN (t2 JOIN (t3 JOIN t4 ON t4.a=t3.a+111)
ON t3.a=t2.a+111)
ON t2.a=t1.a+111;
}
} {333 x3 222 x2}
do_test selectD-$i.2.4 {
db eval {
SELECT *
FROM t1 JOIN (t2 JOIN (main.t4 JOIN aux1.t4 ON aux1.t4.a=main.t4.a+111)
ON main.t4.a=t2.a+222)
ON t2.a=t1.a+111;
}
} {111 x1 222 x2 444 x4 555 x5}
do_test selectD-$i.2.5 {
db eval {
SELECT *
FROM t1 JOIN (t2 JOIN (main.t4 AS x JOIN aux1.t4 ON aux1.t4.a=x.a+111)
ON x.a=t2.a+222)
ON t2.a=t1.a+111;
}
} {111 x1 222 x2 444 x4 555 x5}
do_test selectD-$i.2.6 {
catchsql {
SELECT *
FROM t1 JOIN (t2 JOIN (main.t4 JOIN aux.t4 ON aux.t4.a=main.t4.a+111)
ON main.t4.a=t2.a+222)
ON t2.a=t1.a+111;
}
} {1 {no such table: aux.t4}}
do_test selectD-$i.2.7 {
db eval {
SELECT x.a, y.b
FROM t1 JOIN (t2 JOIN (main.t4 x JOIN aux1.t4 y ON y.a=x.a+111)
ON x.a=t2.a+222)
ON t2.a=t1.a+111;
}
} {444 x5}
do_test selectD-$i.3 {
db eval {
UPDATE t2 SET a=111;
UPDATE t3 SET a=111;
UPDATE t4 SET a=111;
SELECT *
FROM t1 JOIN (t2 JOIN (t3 JOIN t4 USING(a)) USING (a)) USING (a);
}
} {111 x1 x2 x3 x4}
do_test selectD-$i.4 {
db eval {
UPDATE t2 SET a=111;
UPDATE t3 SET a=111;
UPDATE t4 SET a=111;
SELECT *
FROM t1 LEFT JOIN (t2 LEFT JOIN (t3 LEFT JOIN t4 USING(a))
USING (a))
USING (a);
}
} {111 x1 x2 x3 x4}
do_test selectD-$i.5 {
db eval {
UPDATE t3 SET a=222;
UPDATE t4 SET a=222;
SELECT *
FROM (t1 LEFT JOIN t2 USING(a)) JOIN (t3 LEFT JOIN t4 USING(a))
ON t1.a=t3.a-111;
}
} {111 x1 x2 222 x3 x4}
do_test selectD-$i.6 {
db eval {
UPDATE t4 SET a=333;
SELECT *
FROM (t1 LEFT JOIN t2 USING(a)) JOIN (t3 LEFT JOIN t4 USING(a))
ON t1.a=t3.a-111;
}
} {111 x1 x2 222 x3 {}}
do_test selectD-$i.7 {
db eval {
SELECT t1.*, t2.*, t3.*, t4.b
FROM (t1 LEFT JOIN t2 USING(a)) JOIN (t3 LEFT JOIN t4 USING(a))
ON t1.a=t3.a-111;
}
} {111 x1 111 x2 222 x3 {}}
}
finish_test

84
test/tkt-a7b7803e.test Normal file
View File

@@ -0,0 +1,84 @@
# 2012 December 19
#
# The author disclaims copyright to this source code. In place of
# a legal notice, here is a blessing:
#
# May you do good and not evil.
# May you find forgiveness for yourself and forgive others.
# May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library. Specifically,
# it tests that ticket [a7b7803e8d1e8699cd8a460a38133b98892d2e17] has
# been fixed.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
source $testdir/lock_common.tcl
source $testdir/malloc_common.tcl
do_test tkt-a7b7803e.1 {
db eval {
CREATE TABLE t1(a,b);
INSERT INTO t1 VALUES(0,'first'),(99,'fuzzy');
SELECT (t1.a==0) AS x, b
FROM t1
WHERE a=0 OR x;
}
} {1 first}
do_test tkt-a7b7803e.2 {
db eval {
SELECT a, (t1.b='fuzzy') AS x
FROM t1
WHERE x
}
} {99 1}
do_test tkt-a7b7803e.3 {
db eval {
SELECT (a=99) AS x, (t1.b='fuzzy') AS y, *
FROM t1
WHERE x AND y
}
} {1 1 99 fuzzy}
do_test tkt-a7b7803e.4 {
db eval {
SELECT (a=99) AS x, (t1.b='first') AS y, *
FROM t1
WHERE x OR y
ORDER BY a
}
} {0 1 0 first 1 0 99 fuzzy}
do_test tkt-a7b7803e.5 {
db eval {
SELECT (M.a=99) AS x, M.b, (N.b='first') AS y, N.b
FROM t1 M, t1 N
WHERE x OR y
ORDER BY M.a, N.a
}
} {0 first 1 first 1 fuzzy 1 first 1 fuzzy 0 fuzzy}
do_test tkt-a7b7803e.6 {
db eval {
SELECT (M.a=99) AS x, M.b, (N.b='first') AS y, N.b
FROM t1 M, t1 N
WHERE x AND y
ORDER BY M.a, N.a
}
} {1 fuzzy 1 first}
do_test tkt-a7b7803e.7 {
db eval {
SELECT (M.a=99) AS x, M.b, (N.b='first') AS y, N.b
FROM t1 M JOIN t1 N ON x AND y
ORDER BY M.a, N.a
}
} {1 fuzzy 1 first}
do_test tkt-a7b7803e.8 {
db eval {
SELECT (M.a=99) AS x, M.b, (N.b='first') AS y, N.b
FROM t1 M JOIN t1 N ON x
ORDER BY M.a, N.a
}
} {1 fuzzy 1 first 1 fuzzy 0 fuzzy}
finish_test

View File

@@ -1091,12 +1091,54 @@ do_test vtab1.13-3 {
} {15 {} 16} } {15 {} 16}
do_test vtab1-14.001 {
execsql {SELECT rowid, * FROM echo_c WHERE +rowid IN (1,2,3)}
} {1 3 G H 2 {} 15 16 3 15 {} 16}
do_test vtab1-14.002 {
execsql {SELECT rowid, * FROM echo_c WHERE rowid IN (1,2,3)}
} {1 3 G H 2 {} 15 16 3 15 {} 16}
do_test vtab1-14.003 {
execsql {SELECT rowid, * FROM echo_c WHERE +rowid IN (0,1,5,2,'a',3,NULL)}
} {1 3 G H 2 {} 15 16 3 15 {} 16}
do_test vtab1-14.004 {
execsql {SELECT rowid, * FROM echo_c WHERE rowid IN (0,1,5,'a',2,3,NULL)}
} {1 3 G H 2 {} 15 16 3 15 {} 16}
do_test vtab1-14.005 {
execsql {SELECT rowid, * FROM echo_c WHERE rowid NOT IN (0,1,5,'a',2,3)}
} {}
do_test vtab1-14.006 {
execsql {SELECT rowid, * FROM echo_c WHERE rowid NOT IN (0,5,'a',2,3)}
} {1 3 G H}
do_test vtab1-14.007 {
execsql {SELECT rowid, * FROM echo_c WHERE +rowid NOT IN (0,5,'a',2,3,NULL)}
} {}
do_test vtab1-14.008 {
execsql {SELECT rowid, * FROM echo_c WHERE rowid NOT IN (0,5,'a',2,3,NULL)}
} {}
do_test vtab1-14.011 {
execsql {SELECT * FROM echo_c WHERE +a IN (1,3,8,'x',NULL,15,24)}
} {3 G H 15 {} 16}
do_test vtab1-14.012 {
execsql {SELECT * FROM echo_c WHERE a IN (1,3,8,'x',NULL,15,24)}
} {3 G H 15 {} 16}
do_test vtab1-14.013 {
execsql {SELECT * FROM echo_c WHERE a NOT IN (1,8,'x',15,24)}
} {3 G H}
do_test vtab1-14.014 {
execsql {SELECT * FROM echo_c WHERE a NOT IN (1,8,'x',NULL,15,24)}
} {}
do_test vtab1-14.015 {
execsql {SELECT * FROM echo_c WHERE +a NOT IN (1,8,'x',NULL,15,24)}
} {}
do_test vtab1-14.1 { do_test vtab1-14.1 {
execsql { DELETE FROM c } execsql { DELETE FROM c }
set echo_module "" set echo_module ""
execsql { SELECT * FROM echo_c WHERE rowid IN (1, 2, 3) } execsql { SELECT * FROM echo_c WHERE rowid IN (1, 2, 3) }
set echo_module set echo_module
} [list xBestIndex {SELECT rowid, * FROM 'c'} xFilter {SELECT rowid, * FROM 'c'}] } {/xBestIndex {SELECT rowid, . FROM 'c' WHERE rowid = .} xFilter {SELECT rowid, . FROM 'c' WHERE rowid = .} 1/}
do_test vtab1-14.2 { do_test vtab1-14.2 {
set echo_module "" set echo_module ""
@@ -1114,7 +1156,7 @@ do_test vtab1-14.4 {
set echo_module "" set echo_module ""
execsql { SELECT * FROM echo_c WHERE a IN (1, 2) } execsql { SELECT * FROM echo_c WHERE a IN (1, 2) }
set echo_module set echo_module
} [list xBestIndex {SELECT rowid, * FROM 'c'} xFilter {SELECT rowid, * FROM 'c'}] } {/xBestIndex {SELECT rowid, . FROM 'c' WHERE a = .} xFilter {SELECT rowid, . FROM 'c' WHERE a = .} 1/}
do_test vtab1-15.1 { do_test vtab1-15.1 {
execsql { execsql {

View File

@@ -290,6 +290,20 @@ do_test where8-3.15 {
} }
} {I I I I I I I I I I II II II II II II II II II II III III III III III 9 1} } {I I I I I I I I I I II II II II II II II II II II III III III III III 9 1}
do_test where8-3.21 {
execsql_status {
SELECT a, d FROM t1, (t2) WHERE (a=d OR b=e) AND a<5 ORDER BY a
}
} {1 1 2 2 3 3 4 2 4 4 0 0}
do_test where8-3.22 {
execsql_status {
SELECT a, d FROM ((((((t1))), (((t2))))))
WHERE (a=d OR b=e) AND a<5 ORDER BY a
}
} {1 1 2 2 3 3 4 2 4 4 0 0}
#----------------------------------------------------------------------- #-----------------------------------------------------------------------
# The following tests - where8-4.* - verify that adding or removing # The following tests - where8-4.* - verify that adding or removing
# indexes does not change the results returned by various queries. # indexes does not change the results returned by various queries.

View File

@@ -232,7 +232,7 @@ do_test where9-1.3.3 {
} {90 91 92 97 scan 98 sort 0} } {90 91 92 97 scan 98 sort 0}
do_test where9-1.3.4 { do_test where9-1.3.4 {
count_steps { count_steps {
SELECT a FROM t4 SELECT a FROM (t4)
WHERE (b IS NULL AND c NOT NULL AND d NOT NULL) WHERE (b IS NULL AND c NOT NULL AND d NOT NULL)
OR (b NOT NULL AND c NOT NULL AND d IS NULL) OR (b NOT NULL AND c NOT NULL AND d IS NULL)
OR (b NOT NULL AND c IS NULL AND d NOT NULL) OR (b NOT NULL AND c IS NULL AND d NOT NULL)
@@ -876,5 +876,21 @@ do_test where9-8.1 {
ORDER BY +a; ORDER BY +a;
} }
} {2 3 4 5 {} {} 5 55 3 4 5 6 2 4 5 55} } {2 3 4 5 {} {} 5 55 3 4 5 6 2 4 5 55}
do_test where9-8.2 {
db eval {
SELECT *
FROM t81 LEFT JOIN (t82) ON y=b JOIN t83
WHERE c==p OR d==p
ORDER BY +a;
}
} {2 3 4 5 {} {} 5 55 3 4 5 6 2 4 5 55}
do_test where9-8.3 {
db eval {
SELECT *
FROM (t81) LEFT JOIN (main.t82) ON y=b JOIN t83
WHERE c==p OR d==p
ORDER BY +a;
}
} {2 3 4 5 {} {} 5 55 3 4 5 6 2 4 5 55}
finish_test finish_test

View File

@@ -15,7 +15,9 @@ gcc -o sqlite3 -g -Os -I. \
-DSQLITE_ENABLE_STAT3 \ -DSQLITE_ENABLE_STAT3 \
-DSQLITE_ENABLE_FTS4 \ -DSQLITE_ENABLE_FTS4 \
-DSQLITE_ENABLE_RTREE \ -DSQLITE_ENABLE_RTREE \
-DSQLITE_ENABLE_REGEXP \
-DHAVE_READLINE \ -DHAVE_READLINE \
-DHAVE_USLEEP=1 \ -DHAVE_USLEEP=1 \
../sqlite/src/shell.c ../sqlite/src/test_vfstrace.c \ ../sqlite/src/shell.c ../sqlite/src/test_vfstrace.c \
../sqlite/src/test_regexp.c \
sqlite3.c -ldl -lreadline -lncurses sqlite3.c -ldl -lreadline -lncurses