Compare commits
185 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 176b04c476 | |||
| 8b04094c4f | |||
| 51ddfef74d | |||
| 42470513b7 | |||
| a7d8d4a07a | |||
| 0d3485f019 | |||
| 0f503f6696 | |||
| 3fee67533e | |||
| 776a578c21 | |||
| 67d4bbf6c1 | |||
| b0f23784f6 | |||
| 5cad178b86 | |||
| 21f0f694ff | |||
| a7eaa518f8 | |||
| 67c4ce131b | |||
| c9f1a7d1df | |||
| 6127d73abc | |||
| 7bdbe59829 | |||
| d8b4befdef | |||
| 0e8075ab78 | |||
| 44d441313a | |||
| 9c0fee296a | |||
| f1c43ea647 | |||
| 0ca23aa437 | |||
| 9d59e3b1bf | |||
| ab6098cfa6 | |||
| 3ddc3809bf | |||
| 407cfe994d | |||
| 632f0ed265 | |||
| 3fb7bd5ee0 | |||
| 55b2e8b062 | |||
| 662a1426cb | |||
| 4d17e30624 | |||
| ba34b79f15 | |||
| 099b385d17 | |||
| bc3c4e0830 | |||
| 3be2b860d0 | |||
| a1c467f51f | |||
| c5edbd1cf6 | |||
| a94c484584 | |||
| 4049ede97d | |||
| 0db20c490a | |||
| 45e4cb8e77 | |||
| 6d0053cfa7 | |||
| e7a377046d | |||
| 42c93b5e9f | |||
| 24ec37c3b3 | |||
| 657a7a66c3 | |||
| ddf4972063 | |||
| 52a0753152 | |||
| e58b2b4a80 | |||
| baca9807f9 | |||
| 7ae0549961 | |||
| b47e4c2819 | |||
| fb645d20bc | |||
| e021890954 | |||
| 1e6f334645 | |||
| 40942f22f1 | |||
| 5777380d19 | |||
| 7e398c04fe | |||
| b2e9640155 | |||
| 1b22ad8ae6 | |||
| 4bb4293b2a | |||
| 7f8653a257 | |||
| fa9011ec70 | |||
| 747cc9425d | |||
| 1f8f131a8b | |||
| feecc9f547 | |||
| 70149ba47e | |||
| 68d4f07577 | |||
| 0d08072b68 | |||
| a7e16a2f05 | |||
| bc7819d176 | |||
| b14d14696b | |||
| 05edf729f7 | |||
| 91be05a910 | |||
| 39b6bd5e17 | |||
| 5f0922b96c | |||
| e8dd6a4e77 | |||
| aae0f74e64 | |||
| 50f9f6c649 | |||
| 8718f0b613 | |||
| 0bff34aea3 | |||
| c6920cdb0c | |||
| fad1ad0526 | |||
| 3083d5f5ea | |||
| bb05976dac | |||
| 898ec7927a | |||
| 730629680a | |||
| eefef9ae80 | |||
| 1b1a1dda9e | |||
| 2d7a691fba | |||
| 531d01cae0 | |||
| 1f9f576695 | |||
| 1e06c70eb0 | |||
| a3944bc4fe | |||
| 676c869d52 | |||
| 15de3ce9ab | |||
| eca6d60bfa | |||
| 8ddf686267 | |||
| 4b17455ab2 | |||
| b3617e9d2d | |||
| a4656e390a | |||
| 3dc864b575 | |||
| ce5de60ff9 | |||
| e9cfe87843 | |||
| 601ec240a9 | |||
| 34a224a13b | |||
| 903fdd4834 | |||
| dee1cb3006 | |||
| c3b93d9e59 | |||
| f43fef29bb | |||
| 606411bf91 | |||
| 17267fe393 | |||
| 745912efac | |||
| a79e2a2d28 | |||
| 7601294ad3 | |||
| 5abe1d3d53 | |||
| 1862271f7c | |||
| 1e0cfd7184 | |||
| 1e25d20cca | |||
| f824b41e64 | |||
| 271d7c2677 | |||
| 578277c257 | |||
| d97471e1ad | |||
| be2ee38283 | |||
| f4a72788a4 | |||
| 60fe2352f5 | |||
| 329cb9eb88 | |||
| 239c84fc62 | |||
| c90fa01dbf | |||
| 0336140cd9 | |||
| dcc29e0d1d | |||
| a7da40f377 | |||
| 678f3b33cc | |||
| 16953469a6 | |||
| 30cdb992dd | |||
| a55a839ab3 | |||
| 6f6e60ddb1 | |||
| 39065807dd | |||
| fadc0e34be | |||
| 6859d3245a | |||
| 7b7a9cf263 | |||
| c7e93f58d5 | |||
| c54246ffdf | |||
| c2a878ed0a | |||
| c16592cd1b | |||
| 6a5a13df97 | |||
| 4b0229ae1f | |||
| 6e6d9833cc | |||
| 6b37b762ed | |||
| 13162ef975 | |||
| 33941691a5 | |||
| f2b32e8915 | |||
| 351ae772a3 | |||
| 863fd4905c | |||
| 329eaaf0b3 | |||
| 8794c68a35 | |||
| e8f1490f55 | |||
| 8b7e93adbc | |||
| 23ed8109b6 | |||
| 40803caa1d | |||
| b9edded0fd | |||
| 513c9a1ff3 | |||
| 8737d46ea1 | |||
| 82ab4f6b1a | |||
| d510197276 | |||
| e1c9a4ebf9 | |||
| 8729642112 | |||
| 5f323787bd | |||
| 8873aea390 | |||
| 29f6a365cc | |||
| 70bd2124ed | |||
| 7dec804d42 | |||
| e1db9343d5 | |||
| 552562c48f | |||
| 381bdacc8f | |||
| 8ab79d6135 | |||
| 02c4aa39e7 | |||
| 8c333cfc0d | |||
| 17b74817c0 | |||
| 7937f63220 | |||
| c5eb176a09 | |||
| cd39cda00c | |||
| 78197e0f8b |
+2
-1
@@ -440,6 +440,7 @@ TESTSRC += \
|
||||
$(TOP)/ext/expert/sqlite3expert.c \
|
||||
$(TOP)/ext/expert/test_expert.c \
|
||||
$(TOP)/ext/misc/amatch.c \
|
||||
$(TOP)/ext/misc/appendvfs.c \
|
||||
$(TOP)/ext/misc/carray.c \
|
||||
$(TOP)/ext/misc/cksumvfs.c \
|
||||
$(TOP)/ext/misc/closure.c \
|
||||
@@ -1267,7 +1268,7 @@ fuzztest: fuzzcheck$(TEXE) $(FUZZDATA) sessionfuzz$(TEXE) $(TOP)/test/sessionfuz
|
||||
./sessionfuzz$(TEXE) run $(TOP)/test/sessionfuzz-data1.db
|
||||
|
||||
valgrindfuzz: fuzzcheck$(TEXT) $(FUZZDATA) sessionfuzz$(TEXE) $(TOP)/test/sessionfuzz-data1.db
|
||||
valgrind ./fuzzcheck$(TEXE) --cell-size-check --limit-mem 10M --timeout 600 $(FUZZDATA)
|
||||
valgrind ./fuzzcheck$(TEXE) --cell-size-check --limit-mem 10M $(FUZZDATA)
|
||||
valgrind ./sessionfuzz$(TEXE) run $(TOP)/test/sessionfuzz-data1.db
|
||||
|
||||
# The veryquick.test TCL tests.
|
||||
|
||||
@@ -1560,6 +1560,7 @@ TESTEXT = \
|
||||
$(TOP)\ext\expert\sqlite3expert.c \
|
||||
$(TOP)\ext\expert\test_expert.c \
|
||||
$(TOP)\ext\misc\amatch.c \
|
||||
$(TOP)\ext\misc\appendvfs.c \
|
||||
$(TOP)\ext\misc\carray.c \
|
||||
$(TOP)\ext\misc\cksumvfs.c \
|
||||
$(TOP)\ext\misc\closure.c \
|
||||
|
||||
@@ -303,6 +303,9 @@ OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_SESSION=1
|
||||
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_PREUPDATE_HOOK=1
|
||||
!ENDIF
|
||||
|
||||
# Always enable math functions on Windows
|
||||
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_MATH_FUNCTIONS
|
||||
|
||||
# Should the rbu extension be enabled? If so, add compilation options
|
||||
# to enable it.
|
||||
#
|
||||
|
||||
@@ -111,14 +111,34 @@ AC_MSG_CHECKING([for whether to support dynamic extensions])
|
||||
AC_MSG_RESULT($enable_dynamic_extensions)
|
||||
#-----------------------------------------------------------------------
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
# --enable-math
|
||||
#
|
||||
AC_ARG_ENABLE(math, [AS_HELP_STRING(
|
||||
[--enable-math], [SQL math functions [default=yes]])],
|
||||
[], [enable_math=yes])
|
||||
AC_MSG_CHECKING([SQL math functions])
|
||||
if test x"$enable_math" = "xyes"; then
|
||||
BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_ENABLE_MATH_FUNCTIONS"
|
||||
AC_MSG_RESULT([enabled])
|
||||
AC_SEARCH_LIBS(ceil, m)
|
||||
else
|
||||
AC_MSG_RESULT([disabled])
|
||||
fi
|
||||
#-----------------------------------------------------------------------
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
# --enable-fts4
|
||||
#
|
||||
AC_ARG_ENABLE(fts4, [AS_HELP_STRING(
|
||||
[--enable-fts4], [include fts4 support [default=yes]])],
|
||||
[], [enable_fts4=yes])
|
||||
AC_MSG_CHECKING([FTS4 extension])
|
||||
if test x"$enable_fts4" = "xyes"; then
|
||||
BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_ENABLE_FTS4"
|
||||
AC_MSG_RESULT([enabled])
|
||||
else
|
||||
AC_MSG_RESULT([disabled])
|
||||
fi
|
||||
#-----------------------------------------------------------------------
|
||||
|
||||
@@ -128,8 +148,12 @@ fi
|
||||
AC_ARG_ENABLE(fts3, [AS_HELP_STRING(
|
||||
[--enable-fts3], [include fts3 support [default=no]])],
|
||||
[], [])
|
||||
AC_MSG_CHECKING([FTS3 extension])
|
||||
if test x"$enable_fts3" = "xyes" -a x"$enable_fts4" = "xno"; then
|
||||
BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_ENABLE_FTS3"
|
||||
AC_MSG_RESULT([enabled])
|
||||
else
|
||||
AC_MSG_RESULT([disabled])
|
||||
fi
|
||||
#-----------------------------------------------------------------------
|
||||
|
||||
@@ -139,9 +163,13 @@ fi
|
||||
AC_ARG_ENABLE(fts5, [AS_HELP_STRING(
|
||||
[--enable-fts5], [include fts5 support [default=yes]])],
|
||||
[], [enable_fts5=yes])
|
||||
AC_MSG_CHECKING([FTS5 extension])
|
||||
if test x"$enable_fts5" = "xyes"; then
|
||||
AC_MSG_RESULT([enabled])
|
||||
AC_SEARCH_LIBS(log, m)
|
||||
BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_ENABLE_FTS5"
|
||||
else
|
||||
AC_MSG_RESULT([disabled])
|
||||
fi
|
||||
#-----------------------------------------------------------------------
|
||||
|
||||
@@ -151,8 +179,12 @@ fi
|
||||
AC_ARG_ENABLE(json1, [AS_HELP_STRING(
|
||||
[--enable-json1], [include json1 support [default=yes]])],
|
||||
[],[enable_json1=yes])
|
||||
AC_MSG_CHECKING([JSON functions])
|
||||
if test x"$enable_json1" = "xyes"; then
|
||||
BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_ENABLE_JSON1"
|
||||
AC_MSG_RESULT([enabled])
|
||||
else
|
||||
AC_MSG_RESULT([disabled])
|
||||
fi
|
||||
#-----------------------------------------------------------------------
|
||||
|
||||
@@ -162,8 +194,12 @@ fi
|
||||
AC_ARG_ENABLE(rtree, [AS_HELP_STRING(
|
||||
[--enable-rtree], [include rtree support [default=yes]])],
|
||||
[], [enable_rtree=yes])
|
||||
AC_MSG_CHECKING([RTREE extension])
|
||||
if test x"$enable_rtree" = "xyes"; then
|
||||
BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_ENABLE_RTREE -DSQLITE_ENABLE_GEOPOLY"
|
||||
AC_MSG_RESULT([enabled])
|
||||
else
|
||||
AC_MSG_RESULT([disabled])
|
||||
fi
|
||||
#-----------------------------------------------------------------------
|
||||
|
||||
@@ -173,8 +209,12 @@ fi
|
||||
AC_ARG_ENABLE(session, [AS_HELP_STRING(
|
||||
[--enable-session], [enable the session extension [default=no]])],
|
||||
[], [])
|
||||
AC_MSG_CHECKING([Session extension])
|
||||
if test x"$enable_session" = "xyes"; then
|
||||
BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_ENABLE_SESSION -DSQLITE_ENABLE_PREUPDATE_HOOK"
|
||||
AC_MSG_RESULT([enabled])
|
||||
else
|
||||
AC_MSG_RESULT([disabled])
|
||||
fi
|
||||
#-----------------------------------------------------------------------
|
||||
|
||||
@@ -184,9 +224,13 @@ fi
|
||||
AC_ARG_ENABLE(debug, [AS_HELP_STRING(
|
||||
[--enable-debug], [build with debugging features enabled [default=no]])],
|
||||
[], [])
|
||||
AC_MSG_CHECKING([Build type])
|
||||
if test x"$enable_debug" = "xyes"; then
|
||||
BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_DEBUG -DSQLITE_ENABLE_SELECTTRACE -DSQLITE_ENABLE_WHERETRACE"
|
||||
CFLAGS="-g -O0"
|
||||
AC_MSG_RESULT([debug])
|
||||
else
|
||||
AC_MSG_RESULT([release])
|
||||
fi
|
||||
#-----------------------------------------------------------------------
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#! /bin/sh
|
||||
# Guess values for system-dependent variables and create Makefiles.
|
||||
# Generated by GNU Autoconf 2.69 for sqlite 3.35.0.
|
||||
# Generated by GNU Autoconf 2.69 for sqlite 3.35.2.
|
||||
#
|
||||
#
|
||||
# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
|
||||
@@ -726,8 +726,8 @@ MAKEFLAGS=
|
||||
# Identity of this package.
|
||||
PACKAGE_NAME='sqlite'
|
||||
PACKAGE_TARNAME='sqlite'
|
||||
PACKAGE_VERSION='3.35.0'
|
||||
PACKAGE_STRING='sqlite 3.35.0'
|
||||
PACKAGE_VERSION='3.35.2'
|
||||
PACKAGE_STRING='sqlite 3.35.2'
|
||||
PACKAGE_BUGREPORT=''
|
||||
PACKAGE_URL=''
|
||||
|
||||
@@ -904,9 +904,9 @@ enable_debug
|
||||
enable_amalgamation
|
||||
enable_load_extension
|
||||
enable_math
|
||||
enable_all
|
||||
enable_memsys5
|
||||
enable_memsys3
|
||||
enable_all
|
||||
enable_fts3
|
||||
enable_fts4
|
||||
enable_fts5
|
||||
@@ -1467,7 +1467,7 @@ if test "$ac_init_help" = "long"; then
|
||||
# Omit some internal or obsolete options to make the list less imposing.
|
||||
# This message is too long to be a string in the A/UX 3.1 sh.
|
||||
cat <<_ACEOF
|
||||
\`configure' configures sqlite 3.35.0 to adapt to many kinds of systems.
|
||||
\`configure' configures sqlite 3.35.2 to adapt to many kinds of systems.
|
||||
|
||||
Usage: $0 [OPTION]... [VAR=VALUE]...
|
||||
|
||||
@@ -1532,7 +1532,7 @@ fi
|
||||
|
||||
if test -n "$ac_init_help"; then
|
||||
case $ac_init_help in
|
||||
short | recursive ) echo "Configuration of sqlite 3.35.0:";;
|
||||
short | recursive ) echo "Configuration of sqlite 3.35.2:";;
|
||||
esac
|
||||
cat <<\_ACEOF
|
||||
|
||||
@@ -1559,9 +1559,9 @@ Optional Features:
|
||||
--disable-load-extension
|
||||
Disable loading of external extensions
|
||||
--disable-math Disable math functions
|
||||
--enable-all Enable FTS4, FTS5, Geopoly, JSON, RTree, Sessions
|
||||
--enable-memsys5 Enable MEMSYS5
|
||||
--enable-memsys3 Enable MEMSYS3
|
||||
--enable-all Enable FTS4, FTS5, Geopoly, JSON, RTree, Sessions
|
||||
--enable-fts3 Enable the FTS3 extension
|
||||
--enable-fts4 Enable the FTS4 extension
|
||||
--enable-fts5 Enable the FTS5 extension
|
||||
@@ -1660,7 +1660,7 @@ fi
|
||||
test -n "$ac_init_help" && exit $ac_status
|
||||
if $ac_init_version; then
|
||||
cat <<\_ACEOF
|
||||
sqlite configure 3.35.0
|
||||
sqlite configure 3.35.2
|
||||
generated by GNU Autoconf 2.69
|
||||
|
||||
Copyright (C) 2012 Free Software Foundation, Inc.
|
||||
@@ -2079,7 +2079,7 @@ cat >config.log <<_ACEOF
|
||||
This file contains any messages produced by compilers while
|
||||
running configure, to aid debugging if configure makes a mistake.
|
||||
|
||||
It was created by sqlite $as_me 3.35.0, which was
|
||||
It was created by sqlite $as_me 3.35.2, which was
|
||||
generated by GNU Autoconf 2.69. Invocation command line was
|
||||
|
||||
$ $0 $@
|
||||
@@ -11251,10 +11251,16 @@ if test "${enable_debug+set}" = set; then :
|
||||
enableval=$enable_debug;
|
||||
fi
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build type" >&5
|
||||
$as_echo_n "checking build type... " >&6; }
|
||||
if test "${enable_debug}" = "yes" ; then
|
||||
TARGET_DEBUG="-DSQLITE_DEBUG=1 -DSQLITE_ENABLE_SELECTTRACE -DSQLITE_ENABLE_WHERETRACE -O0"
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: debug" >&5
|
||||
$as_echo "debug" >&6; }
|
||||
else
|
||||
TARGET_DEBUG="-DNDEBUG"
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: release" >&5
|
||||
$as_echo "release" >&6; }
|
||||
fi
|
||||
|
||||
|
||||
@@ -11490,6 +11496,16 @@ fi
|
||||
|
||||
fi
|
||||
|
||||
|
||||
########
|
||||
# The --enable-all argument is short-hand to enable
|
||||
# multiple extensions.
|
||||
# Check whether --enable-all was given.
|
||||
if test "${enable_all+set}" = set; then :
|
||||
enableval=$enable_all;
|
||||
fi
|
||||
|
||||
|
||||
##########
|
||||
# Do we want to support memsys3 and/or memsys5
|
||||
#
|
||||
@@ -11524,15 +11540,6 @@ else
|
||||
$as_echo "no" >&6; }
|
||||
fi
|
||||
|
||||
########
|
||||
# The --enable-extensions argument is short-hand to enable
|
||||
# multiple extensions.
|
||||
# Check whether --enable-all was given.
|
||||
if test "${enable_all+set}" = set; then :
|
||||
enableval=$enable_all;
|
||||
fi
|
||||
|
||||
|
||||
#########
|
||||
# See whether we should enable Full Text Search extensions
|
||||
# Check whether --enable-fts3 was given.
|
||||
@@ -11540,15 +11547,26 @@ if test "${enable_fts3+set}" = set; then :
|
||||
enableval=$enable_fts3;
|
||||
fi
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to support FTS3" >&5
|
||||
$as_echo_n "checking whether to support FTS3... " >&6; }
|
||||
if test "${enable_fts3}" = "yes" ; then
|
||||
OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_FTS3"
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
|
||||
$as_echo "yes" >&6; }
|
||||
else
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
|
||||
$as_echo "no" >&6; }
|
||||
fi
|
||||
# Check whether --enable-fts4 was given.
|
||||
if test "${enable_fts4+set}" = set; then :
|
||||
enableval=$enable_fts4;
|
||||
fi
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to support FTS4" >&5
|
||||
$as_echo_n "checking whether to support FTS4... " >&6; }
|
||||
if test "${enable_fts4}" = "yes" -o "${enable_all}" = "yes" ; then
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
|
||||
$as_echo "yes" >&6; }
|
||||
OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_FTS4"
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing log" >&5
|
||||
$as_echo_n "checking for library containing log... " >&6; }
|
||||
@@ -11606,13 +11624,20 @@ if test "$ac_res" != no; then :
|
||||
|
||||
fi
|
||||
|
||||
else
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
|
||||
$as_echo "no" >&6; }
|
||||
fi
|
||||
# Check whether --enable-fts5 was given.
|
||||
if test "${enable_fts5+set}" = set; then :
|
||||
enableval=$enable_fts5;
|
||||
fi
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to support FTS5" >&5
|
||||
$as_echo_n "checking whether to support FTS5... " >&6; }
|
||||
if test "${enable_fts5}" = "yes" -o "${enable_all}" = "yes" ; then
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
|
||||
$as_echo "yes" >&6; }
|
||||
OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_FTS5"
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing log" >&5
|
||||
$as_echo_n "checking for library containing log... " >&6; }
|
||||
@@ -11670,6 +11695,9 @@ if test "$ac_res" != no; then :
|
||||
|
||||
fi
|
||||
|
||||
else
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
|
||||
$as_echo "no" >&6; }
|
||||
fi
|
||||
|
||||
#########
|
||||
@@ -11679,8 +11707,15 @@ if test "${enable_json1+set}" = set; then :
|
||||
enableval=$enable_json1;
|
||||
fi
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to support JSON" >&5
|
||||
$as_echo_n "checking whether to support JSON... " >&6; }
|
||||
if test "${enable_json1}" = "yes" -o "${enable_all}" = "yes" ; then
|
||||
OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_JSON1"
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
|
||||
$as_echo "yes" >&6; }
|
||||
else
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
|
||||
$as_echo "no" >&6; }
|
||||
fi
|
||||
|
||||
#########
|
||||
@@ -11691,8 +11726,15 @@ if test "${enable_update_limit+set}" = set; then :
|
||||
enableval=$enable_update_limit;
|
||||
fi
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to support LIMIT on UPDATE and DELETE statements" >&5
|
||||
$as_echo_n "checking whether to support LIMIT on UPDATE and DELETE statements... " >&6; }
|
||||
if test "${enable_update_limit}" = "yes" ; then
|
||||
OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_UPDATE_DELETE_LIMIT"
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
|
||||
$as_echo "yes" >&6; }
|
||||
else
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
|
||||
$as_echo "no" >&6; }
|
||||
fi
|
||||
|
||||
#########
|
||||
@@ -11704,9 +11746,16 @@ else
|
||||
enable_geopoly=no
|
||||
fi
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to support GEOPOLY" >&5
|
||||
$as_echo_n "checking whether to support GEOPOLY... " >&6; }
|
||||
if test "${enable_geopoly}" = "yes" -o "${enable_all}" = "yes" ; then
|
||||
OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_GEOPOLY"
|
||||
enable_rtree=yes
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
|
||||
$as_echo "yes" >&6; }
|
||||
else
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
|
||||
$as_echo "no" >&6; }
|
||||
fi
|
||||
|
||||
#########
|
||||
@@ -11716,8 +11765,15 @@ if test "${enable_rtree+set}" = set; then :
|
||||
enableval=$enable_rtree;
|
||||
fi
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to support RTREE" >&5
|
||||
$as_echo_n "checking whether to support RTREE... " >&6; }
|
||||
if test "${enable_rtree}" = "yes" ; then
|
||||
OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_RTREE"
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
|
||||
$as_echo "yes" >&6; }
|
||||
else
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
|
||||
$as_echo "no" >&6; }
|
||||
fi
|
||||
|
||||
#########
|
||||
@@ -11727,9 +11783,16 @@ if test "${enable_session+set}" = set; then :
|
||||
enableval=$enable_session;
|
||||
fi
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to support SESSION" >&5
|
||||
$as_echo_n "checking whether to support SESSION... " >&6; }
|
||||
if test "${enable_session}" = "yes" -o "${enable_all}" = "yes" ; then
|
||||
OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_SESSION"
|
||||
OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_PREUPDATE_HOOK"
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
|
||||
$as_echo "yes" >&6; }
|
||||
else
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
|
||||
$as_echo "no" >&6; }
|
||||
fi
|
||||
|
||||
#########
|
||||
@@ -12315,7 +12378,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
|
||||
# report actual input values of CONFIG_FILES etc. instead of their
|
||||
# values after options handling.
|
||||
ac_log="
|
||||
This file was extended by sqlite $as_me 3.35.0, which was
|
||||
This file was extended by sqlite $as_me 3.35.2, which was
|
||||
generated by GNU Autoconf 2.69. Invocation command line was
|
||||
|
||||
CONFIG_FILES = $CONFIG_FILES
|
||||
@@ -12381,7 +12444,7 @@ _ACEOF
|
||||
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
|
||||
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
|
||||
ac_cs_version="\\
|
||||
sqlite config.status 3.35.0
|
||||
sqlite config.status 3.35.2
|
||||
configured by $0, generated by GNU Autoconf 2.69,
|
||||
with options \\"\$ac_cs_config\\"
|
||||
|
||||
|
||||
+42
-6
@@ -555,10 +555,13 @@ AC_SEARCH_LIBS(fdatasync, [rt])
|
||||
#########
|
||||
# check for debug enabled
|
||||
AC_ARG_ENABLE(debug, AC_HELP_STRING([--enable-debug],[enable debugging & verbose explain]))
|
||||
AC_MSG_CHECKING([build type])
|
||||
if test "${enable_debug}" = "yes" ; then
|
||||
TARGET_DEBUG="-DSQLITE_DEBUG=1 -DSQLITE_ENABLE_SELECTTRACE -DSQLITE_ENABLE_WHERETRACE -O0"
|
||||
AC_MSG_RESULT([debug])
|
||||
else
|
||||
TARGET_DEBUG="-DNDEBUG"
|
||||
AC_MSG_RESULT([release])
|
||||
fi
|
||||
AC_SUBST(TARGET_DEBUG)
|
||||
|
||||
@@ -602,6 +605,13 @@ else
|
||||
AC_SEARCH_LIBS(ceil, m)
|
||||
fi
|
||||
|
||||
|
||||
########
|
||||
# The --enable-all argument is short-hand to enable
|
||||
# multiple extensions.
|
||||
AC_ARG_ENABLE(all, AC_HELP_STRING([--enable-all],
|
||||
[Enable FTS4, FTS5, Geopoly, JSON, RTree, Sessions]))
|
||||
|
||||
##########
|
||||
# Do we want to support memsys3 and/or memsys5
|
||||
#
|
||||
@@ -624,37 +634,47 @@ else
|
||||
AC_MSG_RESULT([no])
|
||||
fi
|
||||
|
||||
########
|
||||
# The --enable-extensions argument is short-hand to enable
|
||||
# multiple extensions.
|
||||
AC_ARG_ENABLE(all, AC_HELP_STRING([--enable-all],
|
||||
[Enable FTS4, FTS5, Geopoly, JSON, RTree, Sessions]))
|
||||
|
||||
#########
|
||||
# See whether we should enable Full Text Search extensions
|
||||
AC_ARG_ENABLE(fts3, AC_HELP_STRING([--enable-fts3],
|
||||
[Enable the FTS3 extension]))
|
||||
AC_MSG_CHECKING([whether to support FTS3])
|
||||
if test "${enable_fts3}" = "yes" ; then
|
||||
OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_FTS3"
|
||||
AC_MSG_RESULT([yes])
|
||||
else
|
||||
AC_MSG_RESULT([no])
|
||||
fi
|
||||
AC_ARG_ENABLE(fts4, AC_HELP_STRING([--enable-fts4],
|
||||
[Enable the FTS4 extension]))
|
||||
AC_MSG_CHECKING([whether to support FTS4])
|
||||
if test "${enable_fts4}" = "yes" -o "${enable_all}" = "yes" ; then
|
||||
AC_MSG_RESULT([yes])
|
||||
OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_FTS4"
|
||||
AC_SEARCH_LIBS([log],[m])
|
||||
else
|
||||
AC_MSG_RESULT([no])
|
||||
fi
|
||||
AC_ARG_ENABLE(fts5, AC_HELP_STRING([--enable-fts5],
|
||||
[Enable the FTS5 extension]))
|
||||
AC_MSG_CHECKING([whether to support FTS5])
|
||||
if test "${enable_fts5}" = "yes" -o "${enable_all}" = "yes" ; then
|
||||
AC_MSG_RESULT([yes])
|
||||
OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_FTS5"
|
||||
AC_SEARCH_LIBS([log],[m])
|
||||
else
|
||||
AC_MSG_RESULT([no])
|
||||
fi
|
||||
|
||||
#########
|
||||
# See whether we should enable JSON1
|
||||
AC_ARG_ENABLE(json1, AC_HELP_STRING([--enable-json1],[Enable the JSON1 extension]))
|
||||
AC_MSG_CHECKING([whether to support JSON])
|
||||
if test "${enable_json1}" = "yes" -o "${enable_all}" = "yes" ; then
|
||||
OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_JSON1"
|
||||
AC_MSG_RESULT([yes])
|
||||
else
|
||||
AC_MSG_RESULT([no])
|
||||
fi
|
||||
|
||||
#########
|
||||
@@ -662,8 +682,12 @@ fi
|
||||
# statements.
|
||||
AC_ARG_ENABLE(update-limit, AC_HELP_STRING([--enable-update-limit],
|
||||
[Enable the UPDATE/DELETE LIMIT clause]))
|
||||
AC_MSG_CHECKING([whether to support LIMIT on UPDATE and DELETE statements])
|
||||
if test "${enable_update_limit}" = "yes" ; then
|
||||
OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_UPDATE_DELETE_LIMIT"
|
||||
AC_MSG_RESULT([yes])
|
||||
else
|
||||
AC_MSG_RESULT([no])
|
||||
fi
|
||||
|
||||
#########
|
||||
@@ -671,26 +695,38 @@ fi
|
||||
AC_ARG_ENABLE(geopoly, AC_HELP_STRING([--enable-geopoly],
|
||||
[Enable the GEOPOLY extension]),
|
||||
[enable_geopoly=yes],[enable_geopoly=no])
|
||||
AC_MSG_CHECKING([whether to support GEOPOLY])
|
||||
if test "${enable_geopoly}" = "yes" -o "${enable_all}" = "yes" ; then
|
||||
OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_GEOPOLY"
|
||||
enable_rtree=yes
|
||||
AC_MSG_RESULT([yes])
|
||||
else
|
||||
AC_MSG_RESULT([no])
|
||||
fi
|
||||
|
||||
#########
|
||||
# See whether we should enable RTREE
|
||||
AC_ARG_ENABLE(rtree, AC_HELP_STRING([--enable-rtree],
|
||||
[Enable the RTREE extension]))
|
||||
AC_MSG_CHECKING([whether to support RTREE])
|
||||
if test "${enable_rtree}" = "yes" ; then
|
||||
OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_RTREE"
|
||||
AC_MSG_RESULT([yes])
|
||||
else
|
||||
AC_MSG_RESULT([no])
|
||||
fi
|
||||
|
||||
#########
|
||||
# See whether we should enable the SESSION extension
|
||||
AC_ARG_ENABLE(session, AC_HELP_STRING([--enable-session],
|
||||
[Enable the SESSION extension]))
|
||||
AC_MSG_CHECKING([whether to support SESSION])
|
||||
if test "${enable_session}" = "yes" -o "${enable_all}" = "yes" ; then
|
||||
OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_SESSION"
|
||||
OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_PREUPDATE_HOOK"
|
||||
AC_MSG_RESULT([yes])
|
||||
else
|
||||
AC_MSG_RESULT([no])
|
||||
fi
|
||||
|
||||
#########
|
||||
|
||||
+2
-2
@@ -5212,9 +5212,9 @@ static int fts3EvalNearTrim(
|
||||
);
|
||||
if( res ){
|
||||
nNew = (int)(pOut - pPhrase->doclist.pList) - 1;
|
||||
if( nNew>=0 ){
|
||||
assert_fts3_nc( nNew<=pPhrase->doclist.nList && nNew>0 );
|
||||
if( nNew>=0 && nNew<=pPhrase->doclist.nList ){
|
||||
assert( pPhrase->doclist.pList[nNew]=='\0' );
|
||||
assert( nNew<=pPhrase->doclist.nList && nNew>0 );
|
||||
memset(&pPhrase->doclist.pList[nNew], 0, pPhrase->doclist.nList - nNew);
|
||||
pPhrase->doclist.nList = nNew;
|
||||
}
|
||||
|
||||
@@ -493,6 +493,11 @@ static int getNextNode(
|
||||
if( *zInput=='(' ){
|
||||
int nConsumed = 0;
|
||||
pParse->nNest++;
|
||||
#if !defined(SQLITE_MAX_EXPR_DEPTH)
|
||||
if( pParse->nNest>1000 ) return SQLITE_ERROR;
|
||||
#elif SQLITE_MAX_EXPR_DEPTH>0
|
||||
if( pParse->nNest>SQLITE_MAX_EXPR_DEPTH ) return SQLITE_ERROR;
|
||||
#endif
|
||||
rc = fts3ExprParse(pParse, zInput+1, nInput-1, ppExpr, &nConsumed);
|
||||
*pnConsumed = (int)(zInput - z) + 1 + nConsumed;
|
||||
return rc;
|
||||
|
||||
@@ -285,6 +285,7 @@ static int unicodeOpen(
|
||||
pCsr->aInput = (const unsigned char *)aInput;
|
||||
if( aInput==0 ){
|
||||
pCsr->nInput = 0;
|
||||
pCsr->aInput = (const unsigned char*)"";
|
||||
}else if( nInput<0 ){
|
||||
pCsr->nInput = (int)strlen(aInput);
|
||||
}else{
|
||||
|
||||
@@ -4335,17 +4335,20 @@ static int fts3IncrmergeLoad(
|
||||
while( reader.aNode && rc==SQLITE_OK ) rc = nodeReaderNext(&reader);
|
||||
blobGrowBuffer(&pNode->key, reader.term.n, &rc);
|
||||
if( rc==SQLITE_OK ){
|
||||
memcpy(pNode->key.a, reader.term.a, reader.term.n);
|
||||
assert_fts3_nc( reader.term.n>0 || reader.aNode==0 );
|
||||
if( reader.term.n>0 ){
|
||||
memcpy(pNode->key.a, reader.term.a, reader.term.n);
|
||||
}
|
||||
pNode->key.n = reader.term.n;
|
||||
if( i>0 ){
|
||||
char *aBlock = 0;
|
||||
int nBlock = 0;
|
||||
pNode = &pWriter->aNodeWriter[i-1];
|
||||
pNode->iBlock = reader.iChild;
|
||||
rc = sqlite3Fts3ReadBlock(p, reader.iChild, &aBlock, &nBlock, 0);
|
||||
rc = sqlite3Fts3ReadBlock(p, reader.iChild, &aBlock, &nBlock,0);
|
||||
blobGrowBuffer(&pNode->block,
|
||||
MAX(nBlock, p->nNodeSize)+FTS3_NODE_PADDING, &rc
|
||||
);
|
||||
);
|
||||
if( rc==SQLITE_OK ){
|
||||
memcpy(pNode->block.a, aBlock, nBlock);
|
||||
pNode->block.n = nBlock;
|
||||
|
||||
+10
-4
@@ -4822,6 +4822,9 @@ static void fts5DoclistIterNext(Fts5DoclistIter *pIter){
|
||||
}
|
||||
|
||||
pIter->aPoslist = p;
|
||||
if( &pIter->aPoslist[pIter->nPoslist]>pIter->aEof ){
|
||||
pIter->aPoslist = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4830,9 +4833,11 @@ static void fts5DoclistIterInit(
|
||||
Fts5DoclistIter *pIter
|
||||
){
|
||||
memset(pIter, 0, sizeof(*pIter));
|
||||
pIter->aPoslist = pBuf->p;
|
||||
pIter->aEof = &pBuf->p[pBuf->n];
|
||||
fts5DoclistIterNext(pIter);
|
||||
if( pBuf->n>0 ){
|
||||
pIter->aPoslist = pBuf->p;
|
||||
pIter->aEof = &pBuf->p[pBuf->n];
|
||||
fts5DoclistIterNext(pIter);
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
@@ -5594,8 +5599,9 @@ int sqlite3Fts5IterNextFrom(Fts5IndexIter *pIndexIter, i64 iMatch){
|
||||
const char *sqlite3Fts5IterTerm(Fts5IndexIter *pIndexIter, int *pn){
|
||||
int n;
|
||||
const char *z = (const char*)fts5MultiIterTerm((Fts5Iter*)pIndexIter, &n);
|
||||
assert_nc( z || n<=1 );
|
||||
*pn = n-1;
|
||||
return &z[1];
|
||||
return (z ? &z[1] : 0);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -2177,7 +2177,8 @@ static int fts5ApiPhraseFirst(
|
||||
int n;
|
||||
int rc = fts5CsrPoslist(pCsr, iPhrase, &pIter->a, &n);
|
||||
if( rc==SQLITE_OK ){
|
||||
pIter->b = &pIter->a[n];
|
||||
assert( pIter->a || n==0 );
|
||||
pIter->b = (pIter->a ? &pIter->a[n] : 0);
|
||||
*piCol = 0;
|
||||
*piOff = 0;
|
||||
fts5ApiPhraseNext(pCtx, pIter, piCol, piOff);
|
||||
@@ -2236,7 +2237,8 @@ static int fts5ApiPhraseFirstColumn(
|
||||
rc = sqlite3Fts5ExprPhraseCollist(pCsr->pExpr, iPhrase, &pIter->a, &n);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
pIter->b = &pIter->a[n];
|
||||
assert( pIter->a || n==0 );
|
||||
pIter->b = (pIter->a ? &pIter->a[n] : 0);
|
||||
*piCol = 0;
|
||||
fts5ApiPhraseNextColumn(pCtx, pIter, piCol);
|
||||
}
|
||||
@@ -2244,7 +2246,8 @@ static int fts5ApiPhraseFirstColumn(
|
||||
int n;
|
||||
rc = fts5CsrPoslist(pCsr, iPhrase, &pIter->a, &n);
|
||||
if( rc==SQLITE_OK ){
|
||||
pIter->b = &pIter->a[n];
|
||||
assert( pIter->a || n==0 );
|
||||
pIter->b = (pIter->a ? &pIter->a[n] : 0);
|
||||
if( n<=0 ){
|
||||
*piCol = -1;
|
||||
}else if( pIter->a[0]==0x01 ){
|
||||
@@ -2722,7 +2725,7 @@ int sqlite3Fts5GetTokenizer(
|
||||
*pzErr = sqlite3_mprintf("no such tokenizer: %s", azArg[0]);
|
||||
}else{
|
||||
rc = pMod->x.xCreate(
|
||||
pMod->pUserData, &azArg[1], (nArg?nArg-1:0), &pConfig->pTok
|
||||
pMod->pUserData, (azArg?&azArg[1]:0), (nArg?nArg-1:0), &pConfig->pTok
|
||||
);
|
||||
pConfig->pTokApi = &pMod->x;
|
||||
if( rc!=SQLITE_OK ){
|
||||
|
||||
@@ -211,7 +211,7 @@ static int fts5tokConnectMethod(
|
||||
|
||||
rc = pApi->xFindTokenizer(pApi, zModule, &pTokCtx, &pTab->tok);
|
||||
if( rc==SQLITE_OK ){
|
||||
const char **azArg = (const char **)&azDequote[1];
|
||||
const char **azArg = (nDequote>1 ? (const char **)&azDequote[1] : 0);
|
||||
int nArg = nDequote>0 ? nDequote-1 : 0;
|
||||
rc = pTab->tok.xCreate(pTokCtx, azArg, nArg, &pTab->pTok);
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+220
-116
@@ -14,24 +14,23 @@
|
||||
** appended onto the end of some other file, such as an executable.
|
||||
**
|
||||
** A special record must appear at the end of the file that identifies the
|
||||
** file as an appended database and provides an offset to page 1. For
|
||||
** best performance page 1 should be located at a disk page boundary, though
|
||||
** that is not required.
|
||||
** file as an appended database and provides the offset to the first page
|
||||
** of the exposed content. (Or, it is the length of the content prefix.)
|
||||
** For best performance page 1 should be located at a disk page boundary,
|
||||
** though that is not required.
|
||||
**
|
||||
** When opening a database using this VFS, the connection might treat
|
||||
** the file as an ordinary SQLite database, or it might treat is as a
|
||||
** database appended onto some other file. Here are the rules:
|
||||
** the file as an ordinary SQLite database, or it might treat it as a
|
||||
** database appended onto some other file. The decision is made by
|
||||
** applying the following rules in order:
|
||||
**
|
||||
** (1) When opening a new empty file, that file is treated as an ordinary
|
||||
** database.
|
||||
** (1) An empty file is an ordinary database.
|
||||
**
|
||||
** (2) When opening a file that begins with the standard SQLite prefix
|
||||
** string "SQLite format 3", that file is treated as an ordinary
|
||||
** database.
|
||||
** (2) If the file ends with the appendvfs trailer string
|
||||
** "Start-Of-SQLite3-NNNNNNNN" that file is an appended database.
|
||||
**
|
||||
** (3) When opening a file that ends with the appendvfs trailer string
|
||||
** "Start-Of-SQLite3-NNNNNNNN" that file is treated as an appended
|
||||
** database.
|
||||
** (3) If the file begins with the standard SQLite prefix string
|
||||
** "SQLite format 3", that file is an ordinary database.
|
||||
**
|
||||
** (4) If none of the above apply and the SQLITE_OPEN_CREATE flag is
|
||||
** set, then a new database is appended to the already existing file.
|
||||
@@ -39,13 +38,13 @@
|
||||
** (5) Otherwise, SQLITE_CANTOPEN is returned.
|
||||
**
|
||||
** To avoid unnecessary complications with the PENDING_BYTE, the size of
|
||||
** the file containing the database is limited to 1GB. This VFS will refuse
|
||||
** to read or write past the 1GB mark. This restriction might be lifted in
|
||||
** future versions. For now, if you need a large database, then keep the
|
||||
** database in a separate file.
|
||||
** the file containing the database is limited to 1GiB. (1073741824 bytes)
|
||||
** This VFS will not read or write past the 1GiB mark. This restriction
|
||||
** might be lifted in future versions. For now, if you need a larger
|
||||
** database, then keep it in a separate file.
|
||||
**
|
||||
** If the file being opened is not an appended database, then this shim is
|
||||
** a pass-through into the default underlying VFS.
|
||||
** If the file being opened is a plain database (not an appended one), then
|
||||
** this shim is a pass-through into the default underlying VFS. (rule 3)
|
||||
**/
|
||||
#include "sqlite3ext.h"
|
||||
SQLITE_EXTENSION_INIT1
|
||||
@@ -58,17 +57,27 @@ SQLITE_EXTENSION_INIT1
|
||||
** 123456789 123456789 12345
|
||||
**
|
||||
** The NNNNNNNN represents a 64-bit big-endian unsigned integer which is
|
||||
** the offset to page 1.
|
||||
** the offset to page 1, and also the length of the prefix content.
|
||||
*/
|
||||
#define APND_MARK_PREFIX "Start-Of-SQLite3-"
|
||||
#define APND_MARK_PREFIX_SZ 17
|
||||
#define APND_MARK_SIZE 25
|
||||
#define APND_MARK_FOS_SZ 8
|
||||
#define APND_MARK_SIZE (APND_MARK_PREFIX_SZ+APND_MARK_FOS_SZ)
|
||||
|
||||
/*
|
||||
** Maximum size of the combined prefix + database + append-mark. This
|
||||
** must be less than 0x40000000 to avoid locking issues on Windows.
|
||||
*/
|
||||
#define APND_MAX_SIZE (65536*15259)
|
||||
#define APND_MAX_SIZE (0x40000000)
|
||||
|
||||
/*
|
||||
** Try to align the database to an even multiple of APND_ROUNDUP bytes.
|
||||
*/
|
||||
#ifndef APND_ROUNDUP
|
||||
#define APND_ROUNDUP 4096
|
||||
#endif
|
||||
#define APND_ALIGN_MASK ((sqlite3_int64)(APND_ROUNDUP-1))
|
||||
#define APND_START_ROUNDUP(fsz) (((fsz)+APND_ALIGN_MASK) & ~APND_ALIGN_MASK)
|
||||
|
||||
/*
|
||||
** Forward declaration of objects used by this utility
|
||||
@@ -82,11 +91,45 @@ typedef struct ApndFile ApndFile;
|
||||
#define ORIGVFS(p) ((sqlite3_vfs*)((p)->pAppData))
|
||||
#define ORIGFILE(p) ((sqlite3_file*)(((ApndFile*)(p))+1))
|
||||
|
||||
/* An open file */
|
||||
/* An open appendvfs file
|
||||
**
|
||||
** An instance of this structure describes the appended database file.
|
||||
** A separate sqlite3_file object is always appended. The appended
|
||||
** sqlite3_file object (which can be accessed using ORIGFILE()) describes
|
||||
** the entire file, including the prefix, the database, and the
|
||||
** append-mark.
|
||||
**
|
||||
** The structure of an AppendVFS database is like this:
|
||||
**
|
||||
** +-------------+---------+----------+-------------+
|
||||
** | prefix-file | padding | database | append-mark |
|
||||
** +-------------+---------+----------+-------------+
|
||||
** ^ ^
|
||||
** | |
|
||||
** iPgOne iMark
|
||||
**
|
||||
**
|
||||
** "prefix file" - file onto which the database has been appended.
|
||||
** "padding" - zero or more bytes inserted so that "database"
|
||||
** starts on an APND_ROUNDUP boundary
|
||||
** "database" - The SQLite database file
|
||||
** "append-mark" - The 25-byte "Start-Of-SQLite3-NNNNNNNN" that indicates
|
||||
** the offset from the start of prefix-file to the start
|
||||
** of "database".
|
||||
**
|
||||
** The size of the database is iMark - iPgOne.
|
||||
**
|
||||
** The NNNNNNNN in the "Start-Of-SQLite3-NNNNNNNN" suffix is the value
|
||||
** of iPgOne stored as a big-ending 64-bit integer.
|
||||
**
|
||||
** iMark will be the size of the underlying file minus 25 (APND_MARKSIZE).
|
||||
** Or, iMark is -1 to indicate that it has not yet been written.
|
||||
*/
|
||||
struct ApndFile {
|
||||
sqlite3_file base; /* IO methods */
|
||||
sqlite3_int64 iPgOne; /* File offset to page 1 */
|
||||
sqlite3_int64 iMark; /* Start of the append-mark */
|
||||
sqlite3_file base; /* Subclass. MUST BE FIRST! */
|
||||
sqlite3_int64 iPgOne; /* Offset to the start of the database */
|
||||
sqlite3_int64 iMark; /* Offset of the append mark. -1 if unwritten */
|
||||
/* Always followed by another sqlite3_file that describes the whole file */
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -178,8 +221,6 @@ static const sqlite3_io_methods apnd_io_methods = {
|
||||
apndUnfetch /* xUnfetch */
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*
|
||||
** Close an apnd-file.
|
||||
*/
|
||||
@@ -197,22 +238,37 @@ static int apndRead(
|
||||
int iAmt,
|
||||
sqlite_int64 iOfst
|
||||
){
|
||||
ApndFile *p = (ApndFile *)pFile;
|
||||
ApndFile *paf = (ApndFile *)pFile;
|
||||
pFile = ORIGFILE(pFile);
|
||||
return pFile->pMethods->xRead(pFile, zBuf, iAmt, iOfst+p->iPgOne);
|
||||
return pFile->pMethods->xRead(pFile, zBuf, iAmt, paf->iPgOne+iOfst);
|
||||
}
|
||||
|
||||
/*
|
||||
** Add the append-mark onto the end of the file.
|
||||
** Add the append-mark onto what should become the end of the file.
|
||||
* If and only if this succeeds, internal ApndFile.iMark is updated.
|
||||
* Parameter iWriteEnd is the appendvfs-relative offset of the new mark.
|
||||
*/
|
||||
static int apndWriteMark(ApndFile *p, sqlite3_file *pFile){
|
||||
int i;
|
||||
static int apndWriteMark(
|
||||
ApndFile *paf,
|
||||
sqlite3_file *pFile,
|
||||
sqlite_int64 iWriteEnd
|
||||
){
|
||||
sqlite_int64 iPgOne = paf->iPgOne;
|
||||
unsigned char a[APND_MARK_SIZE];
|
||||
int i = APND_MARK_FOS_SZ;
|
||||
int rc;
|
||||
assert(pFile == ORIGFILE(paf));
|
||||
memcpy(a, APND_MARK_PREFIX, APND_MARK_PREFIX_SZ);
|
||||
for(i=0; i<8; i++){
|
||||
a[APND_MARK_PREFIX_SZ+i] = (p->iPgOne >> (56 - i*8)) & 0xff;
|
||||
while( --i >= 0 ){
|
||||
a[APND_MARK_PREFIX_SZ+i] = (unsigned char)(iPgOne & 0xff);
|
||||
iPgOne >>= 8;
|
||||
}
|
||||
return pFile->pMethods->xWrite(pFile, a, APND_MARK_SIZE, p->iMark);
|
||||
iWriteEnd += paf->iPgOne;
|
||||
if( SQLITE_OK==(rc = pFile->pMethods->xWrite
|
||||
(pFile, a, APND_MARK_SIZE, iWriteEnd)) ){
|
||||
paf->iMark = iWriteEnd;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -224,38 +280,28 @@ static int apndWrite(
|
||||
int iAmt,
|
||||
sqlite_int64 iOfst
|
||||
){
|
||||
int rc;
|
||||
ApndFile *p = (ApndFile *)pFile;
|
||||
ApndFile *paf = (ApndFile *)pFile;
|
||||
sqlite_int64 iWriteEnd = iOfst + iAmt;
|
||||
if( iWriteEnd>=APND_MAX_SIZE ) return SQLITE_FULL;
|
||||
pFile = ORIGFILE(pFile);
|
||||
if( iOfst+iAmt>=APND_MAX_SIZE ) return SQLITE_FULL;
|
||||
rc = pFile->pMethods->xWrite(pFile, zBuf, iAmt, iOfst+p->iPgOne);
|
||||
if( rc==SQLITE_OK && iOfst + iAmt + p->iPgOne > p->iMark ){
|
||||
sqlite3_int64 sz = 0;
|
||||
rc = pFile->pMethods->xFileSize(pFile, &sz);
|
||||
if( rc==SQLITE_OK ){
|
||||
p->iMark = sz - APND_MARK_SIZE;
|
||||
if( iOfst + iAmt + p->iPgOne > p->iMark ){
|
||||
p->iMark = p->iPgOne + iOfst + iAmt;
|
||||
rc = apndWriteMark(p, pFile);
|
||||
}
|
||||
}
|
||||
/* If append-mark is absent or will be overwritten, write it. */
|
||||
if( paf->iMark < 0 || paf->iPgOne + iWriteEnd > paf->iMark ){
|
||||
int rc = apndWriteMark(paf, pFile, iWriteEnd);
|
||||
if( SQLITE_OK!=rc ) return rc;
|
||||
}
|
||||
return rc;
|
||||
return pFile->pMethods->xWrite(pFile, zBuf, iAmt, paf->iPgOne+iOfst);
|
||||
}
|
||||
|
||||
/*
|
||||
** Truncate an apnd-file.
|
||||
*/
|
||||
static int apndTruncate(sqlite3_file *pFile, sqlite_int64 size){
|
||||
int rc;
|
||||
ApndFile *p = (ApndFile *)pFile;
|
||||
ApndFile *paf = (ApndFile *)pFile;
|
||||
pFile = ORIGFILE(pFile);
|
||||
rc = pFile->pMethods->xTruncate(pFile, size+p->iPgOne+APND_MARK_SIZE);
|
||||
if( rc==SQLITE_OK ){
|
||||
p->iMark = p->iPgOne+size;
|
||||
rc = apndWriteMark(p, pFile);
|
||||
}
|
||||
return rc;
|
||||
/* The append mark goes out first so truncate failure does not lose it. */
|
||||
if( SQLITE_OK!=apndWriteMark(paf, pFile, size) ) return SQLITE_IOERR;
|
||||
/* Truncate underlying file just past append mark */
|
||||
return pFile->pMethods->xTruncate(pFile, paf->iMark+APND_MARK_SIZE);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -268,16 +314,12 @@ static int apndSync(sqlite3_file *pFile, int flags){
|
||||
|
||||
/*
|
||||
** Return the current file-size of an apnd-file.
|
||||
** If the append mark is not yet there, the file-size is 0.
|
||||
*/
|
||||
static int apndFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
|
||||
ApndFile *p = (ApndFile *)pFile;
|
||||
int rc;
|
||||
pFile = ORIGFILE(p);
|
||||
rc = pFile->pMethods->xFileSize(pFile, pSize);
|
||||
if( rc==SQLITE_OK && p->iPgOne ){
|
||||
*pSize -= p->iPgOne + APND_MARK_SIZE;
|
||||
}
|
||||
return rc;
|
||||
ApndFile *paf = (ApndFile *)pFile;
|
||||
*pSize = ( paf->iMark >= 0 )? (paf->iMark - paf->iPgOne) : 0;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -308,12 +350,13 @@ static int apndCheckReservedLock(sqlite3_file *pFile, int *pResOut){
|
||||
** File control method. For custom operations on an apnd-file.
|
||||
*/
|
||||
static int apndFileControl(sqlite3_file *pFile, int op, void *pArg){
|
||||
ApndFile *p = (ApndFile *)pFile;
|
||||
ApndFile *paf = (ApndFile *)pFile;
|
||||
int rc;
|
||||
pFile = ORIGFILE(pFile);
|
||||
if( op==SQLITE_FCNTL_SIZE_HINT ) *(sqlite3_int64*)pArg += paf->iPgOne;
|
||||
rc = pFile->pMethods->xFileControl(pFile, op, pArg);
|
||||
if( rc==SQLITE_OK && op==SQLITE_FCNTL_VFSNAME ){
|
||||
*(char**)pArg = sqlite3_mprintf("apnd(%lld)/%z", p->iPgOne, *(char**)pArg);
|
||||
*(char**)pArg = sqlite3_mprintf("apnd(%lld)/%z", paf->iPgOne,*(char**)pArg);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
@@ -372,6 +415,9 @@ static int apndFetch(
|
||||
void **pp
|
||||
){
|
||||
ApndFile *p = (ApndFile *)pFile;
|
||||
if( p->iMark < 0 || iOfst+iAmt > p->iMark ){
|
||||
return SQLITE_IOERR; /* Cannot read what is not yet there. */
|
||||
}
|
||||
pFile = ORIGFILE(pFile);
|
||||
return pFile->pMethods->xFetch(pFile, iOfst+p->iPgOne, iAmt, pp);
|
||||
}
|
||||
@@ -383,95 +429,153 @@ static int apndUnfetch(sqlite3_file *pFile, sqlite3_int64 iOfst, void *pPage){
|
||||
return pFile->pMethods->xUnfetch(pFile, iOfst+p->iPgOne, pPage);
|
||||
}
|
||||
|
||||
/*
|
||||
** Check to see if the file is an ordinary SQLite database file.
|
||||
*/
|
||||
static int apndIsOrdinaryDatabaseFile(sqlite3_int64 sz, sqlite3_file *pFile){
|
||||
int rc;
|
||||
char zHdr[16];
|
||||
static const char aSqliteHdr[] = "SQLite format 3";
|
||||
if( sz<512 ) return 0;
|
||||
rc = pFile->pMethods->xRead(pFile, zHdr, sizeof(zHdr), 0);
|
||||
if( rc ) return 0;
|
||||
return memcmp(zHdr, aSqliteHdr, sizeof(zHdr))==0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Try to read the append-mark off the end of a file. Return the
|
||||
** start of the appended database if the append-mark is present. If
|
||||
** there is no append-mark, return -1;
|
||||
** start of the appended database if the append-mark is present.
|
||||
** If there is no valid append-mark, return -1;
|
||||
**
|
||||
** An append-mark is only valid if the NNNNNNNN start-of-database offset
|
||||
** indicates that the appended database contains at least one page. The
|
||||
** start-of-database value must be a multiple of 512.
|
||||
*/
|
||||
static sqlite3_int64 apndReadMark(sqlite3_int64 sz, sqlite3_file *pFile){
|
||||
int rc, i;
|
||||
sqlite3_int64 iMark;
|
||||
int msbs = 8 * (APND_MARK_FOS_SZ-1);
|
||||
unsigned char a[APND_MARK_SIZE];
|
||||
|
||||
if( sz<=APND_MARK_SIZE ) return -1;
|
||||
if( APND_MARK_SIZE!=(sz & 0x1ff) ) return -1;
|
||||
rc = pFile->pMethods->xRead(pFile, a, APND_MARK_SIZE, sz-APND_MARK_SIZE);
|
||||
if( rc ) return -1;
|
||||
if( memcmp(a, APND_MARK_PREFIX, APND_MARK_PREFIX_SZ)!=0 ) return -1;
|
||||
iMark = ((sqlite3_int64)(a[APND_MARK_PREFIX_SZ]&0x7f))<<56;
|
||||
for(i=1; i<8; i++){
|
||||
iMark += (sqlite3_int64)a[APND_MARK_PREFIX_SZ+i]<<(56-8*i);
|
||||
iMark = ((sqlite3_int64)(a[APND_MARK_PREFIX_SZ] & 0x7f)) << msbs;
|
||||
for(i=1; i<8; i++){
|
||||
msbs -= 8;
|
||||
iMark |= (sqlite3_int64)a[APND_MARK_PREFIX_SZ+i]<<msbs;
|
||||
}
|
||||
if( iMark > (sz - APND_MARK_SIZE - 512) ) return -1;
|
||||
if( iMark & 0x1ff ) return -1;
|
||||
return iMark;
|
||||
}
|
||||
|
||||
static const char apvfsSqliteHdr[] = "SQLite format 3";
|
||||
/*
|
||||
** Check to see if the file is an appendvfs SQLite database file.
|
||||
** Return true iff it is such. Parameter sz is the file's size.
|
||||
*/
|
||||
static int apndIsAppendvfsDatabase(sqlite3_int64 sz, sqlite3_file *pFile){
|
||||
int rc;
|
||||
char zHdr[16];
|
||||
sqlite3_int64 iMark = apndReadMark(sz, pFile);
|
||||
if( iMark>=0 ){
|
||||
/* If file has the correct end-marker, the expected odd size, and the
|
||||
** SQLite DB type marker where the end-marker puts it, then it
|
||||
** is an appendvfs database.
|
||||
*/
|
||||
rc = pFile->pMethods->xRead(pFile, zHdr, sizeof(zHdr), iMark);
|
||||
if( SQLITE_OK==rc
|
||||
&& memcmp(zHdr, apvfsSqliteHdr, sizeof(zHdr))==0
|
||||
&& (sz & 0x1ff) == APND_MARK_SIZE
|
||||
&& sz>=512+APND_MARK_SIZE
|
||||
){
|
||||
return 1; /* It's an appendvfs database */
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Check to see if the file is an ordinary SQLite database file.
|
||||
** Return true iff so. Parameter sz is the file's size.
|
||||
*/
|
||||
static int apndIsOrdinaryDatabaseFile(sqlite3_int64 sz, sqlite3_file *pFile){
|
||||
char zHdr[16];
|
||||
if( apndIsAppendvfsDatabase(sz, pFile) /* rule 2 */
|
||||
|| (sz & 0x1ff) != 0
|
||||
|| SQLITE_OK!=pFile->pMethods->xRead(pFile, zHdr, sizeof(zHdr), 0)
|
||||
|| memcmp(zHdr, apvfsSqliteHdr, sizeof(zHdr))!=0
|
||||
){
|
||||
return 0;
|
||||
}else{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Open an apnd file handle.
|
||||
*/
|
||||
static int apndOpen(
|
||||
sqlite3_vfs *pVfs,
|
||||
sqlite3_vfs *pApndVfs,
|
||||
const char *zName,
|
||||
sqlite3_file *pFile,
|
||||
int flags,
|
||||
int *pOutFlags
|
||||
){
|
||||
ApndFile *p;
|
||||
sqlite3_file *pSubFile;
|
||||
sqlite3_vfs *pSubVfs;
|
||||
ApndFile *pApndFile = (ApndFile*)pFile;
|
||||
sqlite3_file *pBaseFile = ORIGFILE(pFile);
|
||||
sqlite3_vfs *pBaseVfs = ORIGVFS(pApndVfs);
|
||||
int rc;
|
||||
sqlite3_int64 sz;
|
||||
pSubVfs = ORIGVFS(pVfs);
|
||||
sqlite3_int64 sz = 0;
|
||||
if( (flags & SQLITE_OPEN_MAIN_DB)==0 ){
|
||||
return pSubVfs->xOpen(pSubVfs, zName, pFile, flags, pOutFlags);
|
||||
/* The appendvfs is not to be used for transient or temporary databases.
|
||||
** Just use the base VFS open to initialize the given file object and
|
||||
** open the underlying file. (Appendvfs is then unused for this file.)
|
||||
*/
|
||||
return pBaseVfs->xOpen(pBaseVfs, zName, pFile, flags, pOutFlags);
|
||||
}
|
||||
p = (ApndFile*)pFile;
|
||||
memset(p, 0, sizeof(*p));
|
||||
pSubFile = ORIGFILE(pFile);
|
||||
memset(pApndFile, 0, sizeof(ApndFile));
|
||||
pFile->pMethods = &apnd_io_methods;
|
||||
rc = pSubVfs->xOpen(pSubVfs, zName, pSubFile, flags, pOutFlags);
|
||||
if( rc ) goto apnd_open_done;
|
||||
rc = pSubFile->pMethods->xFileSize(pSubFile, &sz);
|
||||
if( rc ){
|
||||
pSubFile->pMethods->xClose(pSubFile);
|
||||
goto apnd_open_done;
|
||||
pApndFile->iMark = -1; /* Append mark not yet written */
|
||||
|
||||
rc = pBaseVfs->xOpen(pBaseVfs, zName, pBaseFile, flags, pOutFlags);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = pBaseFile->pMethods->xFileSize(pBaseFile, &sz);
|
||||
}
|
||||
if( apndIsOrdinaryDatabaseFile(sz, pSubFile) ){
|
||||
memmove(pFile, pSubFile, pSubVfs->szOsFile);
|
||||
if( rc ){
|
||||
pBaseFile->pMethods->xClose(pBaseFile);
|
||||
pFile->pMethods = 0;
|
||||
return rc;
|
||||
}
|
||||
if( apndIsOrdinaryDatabaseFile(sz, pBaseFile) ){
|
||||
/* The file being opened appears to be just an ordinary DB. Copy
|
||||
** the base dispatch-table so this instance mimics the base VFS.
|
||||
*/
|
||||
memmove(pApndFile, pBaseFile, pBaseVfs->szOsFile);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
p->iMark = 0;
|
||||
p->iPgOne = apndReadMark(sz, pFile);
|
||||
if( p->iPgOne>0 ){
|
||||
pApndFile->iPgOne = apndReadMark(sz, pFile);
|
||||
if( pApndFile->iPgOne>=0 ){
|
||||
pApndFile->iMark = sz - APND_MARK_SIZE; /* Append mark found */
|
||||
return SQLITE_OK;
|
||||
}
|
||||
if( (flags & SQLITE_OPEN_CREATE)==0 ){
|
||||
pSubFile->pMethods->xClose(pSubFile);
|
||||
pBaseFile->pMethods->xClose(pBaseFile);
|
||||
rc = SQLITE_CANTOPEN;
|
||||
pFile->pMethods = 0;
|
||||
}else{
|
||||
/* Round newly added appendvfs location to #define'd page boundary.
|
||||
** Note that nothing has yet been written to the underlying file.
|
||||
** The append mark will be written along with first content write.
|
||||
** Until then, paf->iMark value indicates it is not yet written.
|
||||
*/
|
||||
pApndFile->iPgOne = APND_START_ROUNDUP(sz);
|
||||
}
|
||||
p->iPgOne = (sz+0xfff) & ~(sqlite3_int64)0xfff;
|
||||
apnd_open_done:
|
||||
if( rc ) pFile->pMethods = 0;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Delete an apnd file.
|
||||
** For an appendvfs, this could mean delete the appendvfs portion,
|
||||
** leaving the appendee as it was before it gained an appendvfs.
|
||||
** For now, this code deletes the underlying file too.
|
||||
*/
|
||||
static int apndDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
|
||||
return ORIGVFS(pVfs)->xDelete(ORIGVFS(pVfs), zPath, dirSync);
|
||||
}
|
||||
|
||||
/*
|
||||
** All other VFS methods are pass-thrus.
|
||||
*/
|
||||
static int apndDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
|
||||
return ORIGVFS(pVfs)->xDelete(ORIGVFS(pVfs), zPath, dirSync);
|
||||
}
|
||||
static int apndAccess(
|
||||
sqlite3_vfs *pVfs,
|
||||
const char *zPath,
|
||||
|
||||
@@ -167,6 +167,14 @@ static void ieee754func(
|
||||
int isNeg = 0;
|
||||
m = sqlite3_value_int64(argv[0]);
|
||||
e = sqlite3_value_int64(argv[1]);
|
||||
|
||||
/* Limit the range of e. Ticket 22dea1cfdb9151e4 2021-03-02 */
|
||||
if( e>10000 ){
|
||||
e = 10000;
|
||||
}else if( e<-10000 ){
|
||||
e = -10000;
|
||||
}
|
||||
|
||||
if( m<0 ){
|
||||
isNeg = 1;
|
||||
m = -m;
|
||||
|
||||
@@ -268,6 +268,14 @@ tablE t1 USING FTs5(c);
|
||||
DELETE FROM t1 WHERE rowid = 1;
|
||||
INSERT INTO t1 VALUES('a b c');
|
||||
}
|
||||
4 {
|
||||
creAte virTUal tablE t1 USING FTs5(c);
|
||||
INSERT INTO t1 VALUES('a b c');
|
||||
INSERT INTO t1 VALUES('a b c');
|
||||
} {
|
||||
DELETE FROM t1 WHERE rowid = 1;
|
||||
INSERT INTO t1 VALUES('a b c');
|
||||
}
|
||||
|
||||
} {
|
||||
forcedelete test.db test.db2
|
||||
|
||||
@@ -4828,22 +4828,24 @@ static int rbuVfsShmLock(sqlite3_file *pFile, int ofst, int n, int flags){
|
||||
#endif
|
||||
|
||||
assert( p->openFlags & (SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_TEMP_DB) );
|
||||
if( pRbu && (pRbu->eStage==RBU_STAGE_OAL || pRbu->eStage==RBU_STAGE_MOVE) ){
|
||||
/* Magic number 1 is the WAL_CKPT_LOCK lock. Preventing SQLite from
|
||||
** taking this lock also prevents any checkpoints from occurring.
|
||||
** todo: really, it's not clear why this might occur, as
|
||||
** wal_autocheckpoint ought to be turned off. */
|
||||
if( pRbu && (
|
||||
pRbu->eStage==RBU_STAGE_OAL
|
||||
|| pRbu->eStage==RBU_STAGE_MOVE
|
||||
|| pRbu->eStage==RBU_STAGE_DONE
|
||||
)){
|
||||
/* Prevent SQLite from taking a shm-lock on the target file when it
|
||||
** is supplying heap memory to the upper layer in place of *-shm
|
||||
** segments. */
|
||||
if( ofst==WAL_LOCK_CKPT && n==1 ) rc = SQLITE_BUSY;
|
||||
}else{
|
||||
int bCapture = 0;
|
||||
if( pRbu && pRbu->eStage==RBU_STAGE_CAPTURE ){
|
||||
bCapture = 1;
|
||||
}
|
||||
|
||||
if( bCapture==0 || 0==(flags & SQLITE_SHM_UNLOCK) ){
|
||||
rc = p->pReal->pMethods->xShmLock(p->pReal, ofst, n, flags);
|
||||
if( bCapture && rc==SQLITE_OK ){
|
||||
pRbu->mLock |= (1 << ofst);
|
||||
pRbu->mLock |= ((1<<n) - 1) << ofst;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,187 @@
|
||||
# 2021 Februar 20
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
if {![info exists testdir]} {
|
||||
set testdir [file join [file dirname [info script]] .. .. test]
|
||||
}
|
||||
source [file join [file dirname [info script]] session_common.tcl]
|
||||
source $testdir/tester.tcl
|
||||
ifcapable !session {finish_test; return}
|
||||
|
||||
set testprefix sessionnoop
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test plan:
|
||||
#
|
||||
# 1.*: Test that concatenating changesets cannot produce a noop UPDATE.
|
||||
# 2.*: Test that rebasing changesets cannot produce a noop UPDATE.
|
||||
# 3.*: Test that sqlite3changeset_apply() ignores noop UPDATE changes.
|
||||
#
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE TABLE t1(a PRIMARY KEY, b, c, d);
|
||||
INSERT INTO t1 VALUES(1, 1, 1, 1);
|
||||
INSERT INTO t1 VALUES(2, 2, 2, 2);
|
||||
INSERT INTO t1 VALUES(3, 3, 3, 3);
|
||||
}
|
||||
|
||||
proc do_concat_test {tn sql1 sql2 res} {
|
||||
uplevel [list do_test $tn [subst -nocommands {
|
||||
set C1 [changeset_from_sql {$sql1}]
|
||||
set C2 [changeset_from_sql {$sql2}]
|
||||
set C3 [sqlite3changeset_concat [set C1] [set C2]]
|
||||
set got [list]
|
||||
sqlite3session_foreach elem [set C3] { lappend got [set elem] }
|
||||
set got
|
||||
}] [list {*}$res]]
|
||||
}
|
||||
|
||||
do_concat_test 1.1 {
|
||||
UPDATE t1 SET c=c+1;
|
||||
} {
|
||||
UPDATE t1 SET c=c-1;
|
||||
} {
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_execsql_test 2.0 {
|
||||
CREATE TABLE t1(a PRIMARY KEY, b, c);
|
||||
INSERT INTO t1 VALUES(1, 1, 1);
|
||||
INSERT INTO t1 VALUES(2, 2, 2);
|
||||
INSERT INTO t1 VALUES(3, 3, 3);
|
||||
}
|
||||
|
||||
proc do_rebase_test {tn sql_local sql_remote conflict_res expected} {
|
||||
proc xConflict {args} [list return $conflict_res]
|
||||
|
||||
uplevel [list \
|
||||
do_test $tn [subst -nocommands {
|
||||
execsql BEGIN
|
||||
set c_remote [changeset_from_sql {$sql_remote}]
|
||||
execsql ROLLBACK
|
||||
|
||||
execsql BEGIN
|
||||
set c_local [changeset_from_sql {$sql_local}]
|
||||
set base [sqlite3changeset_apply_v2 db [set c_remote] xConflict]
|
||||
execsql ROLLBACK
|
||||
|
||||
sqlite3rebaser_create R
|
||||
R config [set base]
|
||||
set res [list]
|
||||
sqlite3session_foreach elem [R rebase [set c_local]] {
|
||||
lappend res [set elem]
|
||||
}
|
||||
R delete
|
||||
set res
|
||||
}] [list {*}$expected]
|
||||
]
|
||||
}
|
||||
|
||||
do_rebase_test 2.1 {
|
||||
UPDATE t1 SET c=2 WHERE a=1; -- local
|
||||
} {
|
||||
UPDATE t1 SET c=3 WHERE a=1; -- remote
|
||||
} OMIT {
|
||||
{UPDATE t1 0 X.. {i 1 {} {} i 3} {{} {} {} {} i 2}}
|
||||
}
|
||||
|
||||
do_rebase_test 2.2 {
|
||||
UPDATE t1 SET c=2 WHERE a=1; -- local
|
||||
} {
|
||||
UPDATE t1 SET c=3 WHERE a=1; -- remote
|
||||
} REPLACE {
|
||||
}
|
||||
|
||||
do_rebase_test 2.3.1 {
|
||||
UPDATE t1 SET c=4 WHERE a=1; -- local
|
||||
} {
|
||||
UPDATE t1 SET c=4 WHERE a=1 -- remote
|
||||
} OMIT {
|
||||
{UPDATE t1 0 X.. {i 1 {} {} i 4} {{} {} {} {} i 4}}
|
||||
}
|
||||
|
||||
do_rebase_test 2.3.2 {
|
||||
UPDATE t1 SET c=5 WHERE a=1; -- local
|
||||
} {
|
||||
UPDATE t1 SET c=5 WHERE a=1 -- remote
|
||||
} REPLACE {
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 3.0 {
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
|
||||
INSERT INTO t1 VALUES(1, 1, 1);
|
||||
INSERT INTO t1 VALUES(2, 2, 2);
|
||||
INSERT INTO t1 VALUES(3, 3, 3);
|
||||
INSERT INTO t1 VALUES(4, 4, 4);
|
||||
}
|
||||
|
||||
# Arg $pkstr contains one character for each column in the table. An
|
||||
# "X" for PK column, or a "." for a non-PK.
|
||||
#
|
||||
proc mk_tbl_header {name pkstr} {
|
||||
set ret [binary format H2c 54 [string length $pkstr]]
|
||||
foreach i [split $pkstr {}] {
|
||||
if {$i=="X"} {
|
||||
append ret [binary format H2 01]
|
||||
} else {
|
||||
if {$i!="."} {error "bad pkstr: $pkstr ($i)"}
|
||||
append ret [binary format H2 00]
|
||||
}
|
||||
}
|
||||
append ret $name
|
||||
append ret [binary format H2 00]
|
||||
set ret
|
||||
}
|
||||
|
||||
proc mk_update_change {args} {
|
||||
set ret [binary format H2H2 17 00]
|
||||
foreach a $args {
|
||||
if {$a==""} {
|
||||
append ret [binary format H2 00]
|
||||
} else {
|
||||
append ret [binary format H2W 01 $a]
|
||||
}
|
||||
}
|
||||
set ret
|
||||
}
|
||||
|
||||
proc xConflict {args} { return "ABORT" }
|
||||
do_test 3.1 {
|
||||
set C [mk_tbl_header t1 X..]
|
||||
append C [mk_update_change 1 {} 1 {} {} 500]
|
||||
append C [mk_update_change 2 {} {} {} {} {}]
|
||||
append C [mk_update_change 3 3 {} {} 600 {}]
|
||||
append C [mk_update_change 4 {} {} {} {} {}]
|
||||
|
||||
sqlite3changeset_apply_v2 db $C xConflict
|
||||
} {}
|
||||
do_execsql_test 3.2 {
|
||||
SELECT * FROM t1
|
||||
} {
|
||||
1 1 500
|
||||
2 2 2
|
||||
3 600 3
|
||||
4 4 4
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -69,7 +69,9 @@ foreach {tn wo} {
|
||||
} {
|
||||
reset_db
|
||||
|
||||
do_execsql_test 2.$tn.0 "CREATE TABLE t1(a INTEGER PRIMARY KEY, b) $wo ;"
|
||||
do_execsql_test 2.$tn.0.1 "CREATE TABLE t1(a INTEGER PRIMARY KEY, b) $wo ;"
|
||||
do_execsql_test 2.$tn.0.2 "CREATE TABLE t2(a INTEGER PRIMARY KEY, b) $wo ;"
|
||||
do_execsql_test 2.$tn.0.3 "CREATE TABLE t3(a INTEGER PRIMARY KEY, b) $wo ;"
|
||||
|
||||
do_iterator_test 1.1 t1 {
|
||||
INSERT INTO t1 VALUES(1, 'two');
|
||||
@@ -94,6 +96,27 @@ foreach {tn wo} {
|
||||
} {
|
||||
{DELETE t1 0 X. {i 1 t four} {}}
|
||||
}
|
||||
|
||||
do_execsql_test 2.$tn.5 {
|
||||
INSERT INTO t1 VALUES(1, 'one');
|
||||
INSERT INTO t1 VALUES(2, 'two');
|
||||
INSERT INTO t1 VALUES(3, 'three');
|
||||
}
|
||||
|
||||
do_iterator_test 2.$tn.6 t2 {
|
||||
INSERT INTO t2 SELECT a, b FROM t1
|
||||
} {
|
||||
{INSERT t2 0 X. {} {i 1 t one}}
|
||||
{INSERT t2 0 X. {} {i 2 t two}}
|
||||
{INSERT t2 0 X. {} {i 3 t three}}
|
||||
}
|
||||
do_iterator_test 2.$tn.7 t3 {
|
||||
INSERT INTO t3 SELECT * FROM t1
|
||||
} {
|
||||
{INSERT t3 0 X. {} {i 1 t one}}
|
||||
{INSERT t3 0 X. {} {i 2 t two}}
|
||||
{INSERT t3 0 X. {} {i 3 t three}}
|
||||
}
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -91,6 +91,7 @@ struct sqlite3_changeset_iter {
|
||||
SessionBuffer tblhdr; /* Buffer to hold apValue/zTab/abPK/ */
|
||||
int bPatchset; /* True if this is a patchset */
|
||||
int bInvert; /* True to invert changeset */
|
||||
int bSkipEmpty; /* Skip noop UPDATE changes */
|
||||
int rc; /* Iterator error code */
|
||||
sqlite3_stmt *pConflict; /* Points to conflicting row, if any */
|
||||
char *zTab; /* Current table */
|
||||
@@ -2620,7 +2621,8 @@ static int sessionChangesetStart(
|
||||
void *pIn,
|
||||
int nChangeset, /* Size of buffer pChangeset in bytes */
|
||||
void *pChangeset, /* Pointer to buffer containing changeset */
|
||||
int bInvert /* True to invert changeset */
|
||||
int bInvert, /* True to invert changeset */
|
||||
int bSkipEmpty /* True to skip empty UPDATE changes */
|
||||
){
|
||||
sqlite3_changeset_iter *pRet; /* Iterator to return */
|
||||
int nByte; /* Number of bytes to allocate for iterator */
|
||||
@@ -2641,6 +2643,7 @@ static int sessionChangesetStart(
|
||||
pRet->in.pIn = pIn;
|
||||
pRet->in.bEof = (xInput ? 0 : 1);
|
||||
pRet->bInvert = bInvert;
|
||||
pRet->bSkipEmpty = bSkipEmpty;
|
||||
|
||||
/* Populate the output variable and return success. */
|
||||
*pp = pRet;
|
||||
@@ -2655,7 +2658,7 @@ int sqlite3changeset_start(
|
||||
int nChangeset, /* Size of buffer pChangeset in bytes */
|
||||
void *pChangeset /* Pointer to buffer containing changeset */
|
||||
){
|
||||
return sessionChangesetStart(pp, 0, 0, nChangeset, pChangeset, 0);
|
||||
return sessionChangesetStart(pp, 0, 0, nChangeset, pChangeset, 0, 0);
|
||||
}
|
||||
int sqlite3changeset_start_v2(
|
||||
sqlite3_changeset_iter **pp, /* OUT: Changeset iterator handle */
|
||||
@@ -2664,7 +2667,7 @@ int sqlite3changeset_start_v2(
|
||||
int flags
|
||||
){
|
||||
int bInvert = !!(flags & SQLITE_CHANGESETSTART_INVERT);
|
||||
return sessionChangesetStart(pp, 0, 0, nChangeset, pChangeset, bInvert);
|
||||
return sessionChangesetStart(pp, 0, 0, nChangeset, pChangeset, bInvert, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2675,7 +2678,7 @@ int sqlite3changeset_start_strm(
|
||||
int (*xInput)(void *pIn, void *pData, int *pnData),
|
||||
void *pIn
|
||||
){
|
||||
return sessionChangesetStart(pp, xInput, pIn, 0, 0, 0);
|
||||
return sessionChangesetStart(pp, xInput, pIn, 0, 0, 0, 0);
|
||||
}
|
||||
int sqlite3changeset_start_v2_strm(
|
||||
sqlite3_changeset_iter **pp, /* OUT: Changeset iterator handle */
|
||||
@@ -2684,7 +2687,7 @@ int sqlite3changeset_start_v2_strm(
|
||||
int flags
|
||||
){
|
||||
int bInvert = !!(flags & SQLITE_CHANGESETSTART_INVERT);
|
||||
return sessionChangesetStart(pp, xInput, pIn, 0, 0, bInvert);
|
||||
return sessionChangesetStart(pp, xInput, pIn, 0, 0, bInvert, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2810,11 +2813,14 @@ static int sessionReadRecord(
|
||||
SessionInput *pIn, /* Input data */
|
||||
int nCol, /* Number of values in record */
|
||||
u8 *abPK, /* Array of primary key flags, or NULL */
|
||||
sqlite3_value **apOut /* Write values to this array */
|
||||
sqlite3_value **apOut, /* Write values to this array */
|
||||
int *pbEmpty
|
||||
){
|
||||
int i; /* Used to iterate through columns */
|
||||
int rc = SQLITE_OK;
|
||||
|
||||
assert( pbEmpty==0 || *pbEmpty==0 );
|
||||
if( pbEmpty ) *pbEmpty = 1;
|
||||
for(i=0; i<nCol && rc==SQLITE_OK; i++){
|
||||
int eType = 0; /* Type of value (SQLITE_NULL, TEXT etc.) */
|
||||
if( abPK && abPK[i]==0 ) continue;
|
||||
@@ -2826,6 +2832,7 @@ static int sessionReadRecord(
|
||||
eType = pIn->aData[pIn->iNext++];
|
||||
assert( apOut[i]==0 );
|
||||
if( eType ){
|
||||
if( pbEmpty ) *pbEmpty = 0;
|
||||
apOut[i] = sqlite3ValueNew(0);
|
||||
if( !apOut[i] ) rc = SQLITE_NOMEM;
|
||||
}
|
||||
@@ -3005,31 +3012,27 @@ static int sessionChangesetReadTblhdr(sqlite3_changeset_iter *p){
|
||||
}
|
||||
|
||||
/*
|
||||
** Advance the changeset iterator to the next change.
|
||||
** Advance the changeset iterator to the next change. The differences between
|
||||
** this function and sessionChangesetNext() are that
|
||||
**
|
||||
** If both paRec and pnRec are NULL, then this function works like the public
|
||||
** API sqlite3changeset_next(). If SQLITE_ROW is returned, then the
|
||||
** sqlite3changeset_new() and old() APIs may be used to query for values.
|
||||
** * If pbEmpty is not NULL and the change is a no-op UPDATE (an UPDATE
|
||||
** that modifies no columns), this function sets (*pbEmpty) to 1.
|
||||
**
|
||||
** Otherwise, if paRec and pnRec are not NULL, then a pointer to the change
|
||||
** record is written to *paRec before returning and the number of bytes in
|
||||
** the record to *pnRec.
|
||||
**
|
||||
** Either way, this function returns SQLITE_ROW if the iterator is
|
||||
** successfully advanced to the next change in the changeset, an SQLite
|
||||
** error code if an error occurs, or SQLITE_DONE if there are no further
|
||||
** changes in the changeset.
|
||||
** * If the iterator is configured to skip no-op UPDATEs,
|
||||
** sessionChangesetNext() does that. This function does not.
|
||||
*/
|
||||
static int sessionChangesetNext(
|
||||
static int sessionChangesetNextOne(
|
||||
sqlite3_changeset_iter *p, /* Changeset iterator */
|
||||
u8 **paRec, /* If non-NULL, store record pointer here */
|
||||
int *pnRec, /* If non-NULL, store size of record here */
|
||||
int *pbNew /* If non-NULL, true if new table */
|
||||
int *pbNew, /* If non-NULL, true if new table */
|
||||
int *pbEmpty
|
||||
){
|
||||
int i;
|
||||
u8 op;
|
||||
|
||||
assert( (paRec==0 && pnRec==0) || (paRec && pnRec) );
|
||||
assert( pbEmpty==0 || *pbEmpty==0 );
|
||||
|
||||
/* If the iterator is in the error-state, return immediately. */
|
||||
if( p->rc!=SQLITE_OK ) return p->rc;
|
||||
@@ -3102,13 +3105,13 @@ static int sessionChangesetNext(
|
||||
/* If this is an UPDATE or DELETE, read the old.* record. */
|
||||
if( p->op!=SQLITE_INSERT && (p->bPatchset==0 || p->op==SQLITE_DELETE) ){
|
||||
u8 *abPK = p->bPatchset ? p->abPK : 0;
|
||||
p->rc = sessionReadRecord(&p->in, p->nCol, abPK, apOld);
|
||||
p->rc = sessionReadRecord(&p->in, p->nCol, abPK, apOld, 0);
|
||||
if( p->rc!=SQLITE_OK ) return p->rc;
|
||||
}
|
||||
|
||||
/* If this is an INSERT or UPDATE, read the new.* record. */
|
||||
if( p->op!=SQLITE_DELETE ){
|
||||
p->rc = sessionReadRecord(&p->in, p->nCol, 0, apNew);
|
||||
p->rc = sessionReadRecord(&p->in, p->nCol, 0, apNew, pbEmpty);
|
||||
if( p->rc!=SQLITE_OK ) return p->rc;
|
||||
}
|
||||
|
||||
@@ -3135,6 +3138,37 @@ static int sessionChangesetNext(
|
||||
return SQLITE_ROW;
|
||||
}
|
||||
|
||||
/*
|
||||
** Advance the changeset iterator to the next change.
|
||||
**
|
||||
** If both paRec and pnRec are NULL, then this function works like the public
|
||||
** API sqlite3changeset_next(). If SQLITE_ROW is returned, then the
|
||||
** sqlite3changeset_new() and old() APIs may be used to query for values.
|
||||
**
|
||||
** Otherwise, if paRec and pnRec are not NULL, then a pointer to the change
|
||||
** record is written to *paRec before returning and the number of bytes in
|
||||
** the record to *pnRec.
|
||||
**
|
||||
** Either way, this function returns SQLITE_ROW if the iterator is
|
||||
** successfully advanced to the next change in the changeset, an SQLite
|
||||
** error code if an error occurs, or SQLITE_DONE if there are no further
|
||||
** changes in the changeset.
|
||||
*/
|
||||
static int sessionChangesetNext(
|
||||
sqlite3_changeset_iter *p, /* Changeset iterator */
|
||||
u8 **paRec, /* If non-NULL, store record pointer here */
|
||||
int *pnRec, /* If non-NULL, store size of record here */
|
||||
int *pbNew /* If non-NULL, true if new table */
|
||||
){
|
||||
int bEmpty;
|
||||
int rc;
|
||||
do {
|
||||
bEmpty = 0;
|
||||
rc = sessionChangesetNextOne(p, paRec, pnRec, pbNew, &bEmpty);
|
||||
}while( rc==SQLITE_ROW && p->bSkipEmpty && bEmpty);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Advance an iterator created by sqlite3changeset_start() to the next
|
||||
** change in the changeset. This function may return SQLITE_ROW, SQLITE_DONE
|
||||
@@ -3407,9 +3441,9 @@ static int sessionChangesetInvert(
|
||||
|
||||
/* Read the old.* and new.* records for the update change. */
|
||||
pInput->iNext += 2;
|
||||
rc = sessionReadRecord(pInput, nCol, 0, &apVal[0]);
|
||||
rc = sessionReadRecord(pInput, nCol, 0, &apVal[0], 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sessionReadRecord(pInput, nCol, 0, &apVal[nCol]);
|
||||
rc = sessionReadRecord(pInput, nCol, 0, &apVal[nCol], 0);
|
||||
}
|
||||
|
||||
/* Write the new old.* record. Consists of the PK columns from the
|
||||
@@ -4357,7 +4391,7 @@ static int sessionRetryConstraints(
|
||||
memset(&pApply->constraints, 0, sizeof(SessionBuffer));
|
||||
|
||||
rc = sessionChangesetStart(
|
||||
&pIter2, 0, 0, cons.nBuf, cons.aBuf, pApply->bInvertConstraints
|
||||
&pIter2, 0, 0, cons.nBuf, cons.aBuf, pApply->bInvertConstraints, 1
|
||||
);
|
||||
if( rc==SQLITE_OK ){
|
||||
size_t nByte = 2*pApply->nCol*sizeof(sqlite3_value*);
|
||||
@@ -4613,8 +4647,8 @@ int sqlite3changeset_apply_v2(
|
||||
int flags
|
||||
){
|
||||
sqlite3_changeset_iter *pIter; /* Iterator to skip through changeset */
|
||||
int bInverse = !!(flags & SQLITE_CHANGESETAPPLY_INVERT);
|
||||
int rc = sessionChangesetStart(&pIter, 0, 0, nChangeset, pChangeset,bInverse);
|
||||
int bInv = !!(flags & SQLITE_CHANGESETAPPLY_INVERT);
|
||||
int rc = sessionChangesetStart(&pIter, 0, 0, nChangeset, pChangeset, bInv, 1);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sessionChangesetApply(
|
||||
db, pIter, xFilter, xConflict, pCtx, ppRebase, pnRebase, flags
|
||||
@@ -4672,7 +4706,7 @@ int sqlite3changeset_apply_v2_strm(
|
||||
){
|
||||
sqlite3_changeset_iter *pIter; /* Iterator to skip through changeset */
|
||||
int bInverse = !!(flags & SQLITE_CHANGESETAPPLY_INVERT);
|
||||
int rc = sessionChangesetStart(&pIter, xInput, pIn, 0, 0, bInverse);
|
||||
int rc = sessionChangesetStart(&pIter, xInput, pIn, 0, 0, bInverse, 1);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sessionChangesetApply(
|
||||
db, pIter, xFilter, xConflict, pCtx, ppRebase, pnRebase, flags
|
||||
@@ -5292,7 +5326,7 @@ static void sessionAppendPartialUpdate(
|
||||
int n1 = sessionSerialLen(a1);
|
||||
int n2 = sessionSerialLen(a2);
|
||||
if( pIter->abPK[i] || a2[0]==0 ){
|
||||
if( !pIter->abPK[i] ) bData = 1;
|
||||
if( !pIter->abPK[i] && a1[0] ) bData = 1;
|
||||
memcpy(pOut, a1, n1);
|
||||
pOut += n1;
|
||||
}else if( a2[0]!=0xFF ){
|
||||
|
||||
@@ -550,18 +550,23 @@ int sqlite3changeset_next(sqlite3_changeset_iter *pIter);
|
||||
** call to [sqlite3changeset_next()] must have returned [SQLITE_ROW]. If this
|
||||
** is not the case, this function returns [SQLITE_MISUSE].
|
||||
**
|
||||
** If argument pzTab is not NULL, then *pzTab is set to point to a
|
||||
** nul-terminated utf-8 encoded string containing the name of the table
|
||||
** affected by the current change. The buffer remains valid until either
|
||||
** sqlite3changeset_next() is called on the iterator or until the
|
||||
** conflict-handler function returns. If pnCol is not NULL, then *pnCol is
|
||||
** set to the number of columns in the table affected by the change. If
|
||||
** pbIndirect is not NULL, then *pbIndirect is set to true (1) if the change
|
||||
** Arguments pOp, pnCol and pzTab may not be NULL. Upon return, three
|
||||
** outputs are set through these pointers:
|
||||
**
|
||||
** *pOp is set to one of [SQLITE_INSERT], [SQLITE_DELETE] or [SQLITE_UPDATE],
|
||||
** depending on the type of change that the iterator currently points to;
|
||||
**
|
||||
** *pnCol is set to the number of columns in the table affected by the change; and
|
||||
**
|
||||
** *pzTab is set to point to a nul-terminated utf-8 encoded string containing
|
||||
** the name of the table affected by the current change. The buffer remains
|
||||
** valid until either sqlite3changeset_next() is called on the iterator
|
||||
** or until the conflict-handler function returns.
|
||||
**
|
||||
** If pbIndirect is not NULL, then *pbIndirect is set to true (1) if the change
|
||||
** is an indirect change, or false (0) otherwise. See the documentation for
|
||||
** [sqlite3session_indirect()] for a description of direct and indirect
|
||||
** changes. Finally, if pOp is not NULL, then *pOp is set to one of
|
||||
** [SQLITE_INSERT], [SQLITE_DELETE] or [SQLITE_UPDATE], depending on the
|
||||
** type of change that the iterator currently points to.
|
||||
** changes.
|
||||
**
|
||||
** If no error occurs, SQLITE_OK is returned. If an error does occur, an
|
||||
** SQLite error code is returned. The values of the output variables may not
|
||||
|
||||
@@ -146,7 +146,10 @@ static int SQLITE_TCLAPI test_sql_exec_changeset(
|
||||
static int test_tcl_integer(Tcl_Interp *interp, const char *zVar){
|
||||
Tcl_Obj *pObj;
|
||||
int iVal = 0;
|
||||
pObj = Tcl_ObjGetVar2(interp, Tcl_NewStringObj(zVar, -1), 0, TCL_GLOBAL_ONLY);
|
||||
Tcl_Obj *pName = Tcl_NewStringObj(zVar, -1);
|
||||
Tcl_IncrRefCount(pName);
|
||||
pObj = Tcl_ObjGetVar2(interp, pName, 0, TCL_GLOBAL_ONLY);
|
||||
Tcl_DecrRefCount(pName);
|
||||
if( pObj ) Tcl_GetIntFromObj(0, pObj, &iVal);
|
||||
return iVal;
|
||||
}
|
||||
|
||||
@@ -360,6 +360,7 @@ TESTSRC = \
|
||||
#
|
||||
TESTSRC += \
|
||||
$(TOP)/ext/misc/amatch.c \
|
||||
$(TOP)/ext/misc/appendvfs.c \
|
||||
$(TOP)/ext/misc/carray.c \
|
||||
$(TOP)/ext/misc/cksumvfs.c \
|
||||
$(TOP)/ext/misc/closure.c \
|
||||
@@ -954,7 +955,7 @@ fuzztest: fuzzcheck$(EXE) $(FUZZDATA) sessionfuzz$(EXE) $(TOP)/test/sessionfuzz-
|
||||
./sessionfuzz run $(TOP)/test/sessionfuzz-data1.db
|
||||
|
||||
valgrindfuzz: fuzzcheck$(EXE) $(FUZZDATA) sessionfuzz$(EXE) $(TOP)/test/sessionfuzz-data1.db
|
||||
valgrind ./fuzzcheck$(EXE) --cell-size-check --limit-mem 10M --timeout 600 $(FUZZDATA)
|
||||
valgrind ./fuzzcheck$(EXE) --cell-size-check --limit-mem 10M $(FUZZDATA)
|
||||
valgrind ./sessionfuzz run $(TOP)/test/sessionfuzz-data1.db
|
||||
|
||||
# The veryquick.test TCL tests.
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
C Modify\sthe\sSQLITE_DBCONFIG_ENABLE_TRIGGER\ssetting\sso\sthat\sit\sonly\sdisables\nmain-schema\striggers\sand\sallows\sTEMP\strigger\sto\scontinue\soperating.\s\sThis\sis\nsafe,\ssince\sonly\sthe\sapplication\s(not\san\sattacker)\scan\sadd\sTEMP\striggers.\nIt\swill\salso\sall\sus\sto\sdisengage\sSQLITE_DBCONFIG_ENABLE_TRIGGER\son\sFossil\ndatabases\ssince\sFossil\shas\sno\smain-schema\striggers\sbut\sdoes\suse\sTEMP\striggers.
|
||||
D 2021-02-03T00:55:34.680
|
||||
C Version\s3.35.2
|
||||
D 2021-03-17T19:07:21.223
|
||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
|
||||
F Makefile.in 9cae1bffe5cb811216bf7425395e7fc0594daa2ce31f625835a9d0c3fb25315f
|
||||
F Makefile.in fe6cc1db11e02b308f3ab0ec2504344697b9eaaa410fa73f48d16a143462e5d3
|
||||
F Makefile.linux-gcc f609543700659711fbd230eced1f01353117621dccae7b9fb70daa64236c5241
|
||||
F Makefile.msc ad07bbd645132533e1fd7164a03acfa9afecda378b3787c10f62ab4c7c45e6ea
|
||||
F Makefile.msc 6b5428cef2af1288e02faeb602dabe68fbf2de7bc8a8e29c7299778ee08cd35c
|
||||
F README.md 1514a365ffca3c138e00c5cc839906108a01011a6b082bad19b09781e3aa498a
|
||||
F VERSION 92f3e4c5cdee6f0779aef1eae857dfc21d0eabb1f2af169dc90e63cd76b15bb2
|
||||
F VERSION 917118cdb116151873a90728339010d301b1623a3daf425c088bb2bec4c3baf9
|
||||
F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50
|
||||
F art/sqlite370.eps aa97a671332b432a54e1d74ff5e8775be34200c2
|
||||
F art/sqlite370.ico af56c1d00fee7cd4753e8631ed60703ed0fc6e90
|
||||
@@ -15,10 +15,10 @@ F art/sqlite370.jpg d512473dae7e378a67e28ff96a34da7cb331def2
|
||||
F autoconf/INSTALL 83e4a25da9fd053c7b3665eaaaf7919707915903
|
||||
F autoconf/Makefile.am a8d1d24affe52ebf8d7ddcf91aa973fa0316618ab95bb68c87cabf8faf527dc8
|
||||
F autoconf/Makefile.fallback 22fe523eb36dfce31e0f6349f782eb084e86a5620b2b0b4f84a2d6133f53f5ac
|
||||
F autoconf/Makefile.msc e0f1dafc48d000fd6ddfdb01815271528db55cbc7299ca888df5b93367f0d5a4
|
||||
F autoconf/Makefile.msc ebe7e66edbb2f453593cbde186d1a0fa0dcd8cae9977febcae27aef1dab5678d
|
||||
F autoconf/README.first 6c4f34fe115ff55d4e8dbfa3cecf04a0188292f7
|
||||
F autoconf/README.txt 4f04b0819303aabaa35fff5f7b257fb0c1ef95f1
|
||||
F autoconf/configure.ac 55be6fc04a5b030b367fe317b72dc8c0eafc4713991fe6182cf647b02fb782cb
|
||||
F autoconf/configure.ac a8ba2a9e61216f5093d44f3b7d2cb8fe1890d6b7dc330a02f802d8efaa1fdc79
|
||||
F autoconf/tea/Makefile.in b438a7020446c8a8156e8d97c8914a04833da6fd
|
||||
F autoconf/tea/README 3e9a3c060f29a44344ab50aec506f4db903fb873
|
||||
F autoconf/tea/aclocal.m4 52c47aac44ce0ddb1f918b6993e8beb8eee88f43
|
||||
@@ -34,8 +34,8 @@ F autoconf/tea/win/rules.vc c511f222b80064096b705dbeb97060ee1d6b6d63
|
||||
F config.guess 883205ddf25b46f10c181818bf42c09da9888884af96f79e1719264345053bd6
|
||||
F config.h.in 6376abec766e9a0785178b1823b5a587e9f1ccbc
|
||||
F config.sub c2d0260f17f3e4bc0b6808fccf1b291cb5e9126c14fc5890efc77b9fd0175559
|
||||
F configure 91893a81f698778dda4d8fb24bfca606ded31ef02bcfbc2ab072d30fb67138d6 x
|
||||
F configure.ac 412b65c6107e41c098ad7f5f2e6a3f74ac02ffc6e92b9a6264b9f1060c235a04
|
||||
F configure edca280db5c310f392526d97d9bccd0d30986114215f382d9f878f9001eb6d42 x
|
||||
F configure.ac 4e4b58b32f88c8da9914a2f2c3158f80e69907eccc019fcc7e3ba14ffd91c640
|
||||
F contrib/sqlitecon.tcl 210a913ad63f9f991070821e599d600bd913e0ad
|
||||
F doc/F2FS.txt c1d4a0ae9711cfe0e1d8b019d154f1c29e0d3abfe820787ba1e9ed7691160fcd
|
||||
F doc/lemon.html 1bb72ece6271df0d901d233551dd985f2c6ba30d09382cf2d321ed951ab57491
|
||||
@@ -84,11 +84,11 @@ F ext/fts3/README.content b9078d0843a094d86af0d48dffbff13c906702b4c3558012e67b9c
|
||||
F ext/fts3/README.syntax a19711dc5458c20734b8e485e75fb1981ec2427a
|
||||
F ext/fts3/README.tokenizers b92bdeb8b46503f0dd301d364efc5ef59ef9fa8e2758b8e742f39fa93a2e422d
|
||||
F ext/fts3/README.txt 8c18f41574404623b76917b9da66fcb0ab38328d
|
||||
F ext/fts3/fts3.c 4809e0b05af4519ad8bfa13d684f7ad635d1390a758299d2302f7e85c48ec160
|
||||
F ext/fts3/fts3.c 7b449348226a91cc851fe969f5c1932d4f00c359a32fd17f2afea92bf875147b
|
||||
F ext/fts3/fts3.h 3a10a0af180d502cecc50df77b1b22df142817fe
|
||||
F ext/fts3/fts3Int.h 045179f538c478ced266ca14327269cde8ad8d573c5be902230a5ebaa5636c59
|
||||
F ext/fts3/fts3_aux.c 96708c8b3a7d9b8ca1b68ea2b7e503e283f20e95f145becadedfad096dbd0f34
|
||||
F ext/fts3/fts3_expr.c f081e38da641724cd72c20e23b71db2bf4d0c9517c14637442f6910259f11a34
|
||||
F ext/fts3/fts3_expr.c 5853cd7a35a79d193614add9b4c461b2d56f465d90899ca4309f05d9d1536558
|
||||
F ext/fts3/fts3_hash.c 8b6e31bfb0844c27dc6092c2620bdb1fca17ed613072db057d96952c6bdb48b7
|
||||
F ext/fts3/fts3_hash.h 39cf6874dc239d6b4e30479b1975fe5b22a3caaf
|
||||
F ext/fts3/fts3_icu.c 305ce7fb6036484085b5556a9c8e62acdc7763f0f4cdf5fd538212a9f3720116
|
||||
@@ -100,9 +100,9 @@ F ext/fts3/fts3_tokenize_vtab.c 8d15b148e7d88a4280389a200b26e8d52abda4c4ec2e9a35
|
||||
F ext/fts3/fts3_tokenizer.c 6d8fc150c48238955d5182bf661498db0dd473c8a2a80e00c16994a646fa96e7
|
||||
F ext/fts3/fts3_tokenizer.h 64c6ef6c5272c51ebe60fc607a896e84288fcbc3
|
||||
F ext/fts3/fts3_tokenizer1.c 5c98225a53705e5ee34824087478cf477bdb7004
|
||||
F ext/fts3/fts3_unicode.c 4b9af6151c29b35ed09574937083cece7c31e911f69615e168a39677569b684d
|
||||
F ext/fts3/fts3_unicode.c de426ff05c1c2e7bce161cf6b706638419c3a1d9c2667de9cb9dc0458c18e226
|
||||
F ext/fts3/fts3_unicode2.c 416eb7e1e81142703520d284b768ca2751d40e31fa912cae24ba74860532bf0f
|
||||
F ext/fts3/fts3_write.c 723ed1b11ed46ad1b3a23c0d69fa39e77986783a82d5711bf87a5ce29e0a3b52
|
||||
F ext/fts3/fts3_write.c a5159accfd88f85fd3fc2298286d7a9427a02d1ea9a52b7c79730cff7a0bc03f
|
||||
F ext/fts3/fts3speed.tcl b54caf6a18d38174f1a6e84219950d85e98bb1e9
|
||||
F ext/fts3/mkfts3amal.tcl 252ecb7fe6467854f2aa237bf2c390b74e71f100
|
||||
F ext/fts3/tool/fts3cov.sh c331d006359456cf6f8f953e37f2b9c7d568f3863f00bb5f7eb87fea4ac01b73
|
||||
@@ -119,12 +119,12 @@ F ext/fts5/fts5_buffer.c 5a5fe0159752c0fb0a5a93c722e9db2662822709490769d482b76a6
|
||||
F ext/fts5/fts5_config.c be54f44fca491e96c6923a4b9a736f2da2b13811600eb6e38d1bcc91c4ea2e61
|
||||
F ext/fts5/fts5_expr.c 016bd06030679bd31b0f07ef87d62c42031e5da25cb3174a84e5b0f6ef4b47b0
|
||||
F ext/fts5/fts5_hash.c 1aa93c9b5f461afba66701ee226297dc78402b3bdde81e90a10de5fe3df14959
|
||||
F ext/fts5/fts5_index.c acbe3ccd36f5a7373009dfff02a11c4a817af73bc3ef8c340f2105d7d073f8b4
|
||||
F ext/fts5/fts5_main.c b4e4931c7fcc9acfa0c3b8b5e5e80b5b424b8d9207aae3a22b674bd35ccf149d
|
||||
F ext/fts5/fts5_index.c df5e18b705ac601e826576298a5ce23ef1e5d417fbfdb3feb5f702f89e5f6f41
|
||||
F ext/fts5/fts5_main.c d77648a52b8d73d13887306149912e420f7e0b2d7b3d7da2f54152bfa140ac02
|
||||
F ext/fts5/fts5_storage.c 58ba71e6cd3d43a5735815e7956ee167babb4d2cbfe206905174792af4d09d75
|
||||
F ext/fts5/fts5_tcl.c 39bcbae507f594aad778172fa914cad0f585bf92fd3b078c686e249282db0d95
|
||||
F ext/fts5/fts5_test_mi.c 08c11ec968148d4cb4119d96d819f8c1f329812c568bac3684f5464be177d3ee
|
||||
F ext/fts5/fts5_test_tok.c f96c6e193c466711d6d7828d5f190407fe7ab897062d371426dd3036f01258e7
|
||||
F ext/fts5/fts5_test_tok.c a2bed8edb25f6432e8cdb62aad5916935c19dba8dac2b8324950cfff397e25ff
|
||||
F ext/fts5/fts5_tokenize.c 5e251efb0f1af99a25ed50010ba6b1ad1250aca5921af1988fdcabe5ebc3cb43
|
||||
F ext/fts5/fts5_unicode2.c eca63dbc797f8ff0572e97caf4631389c0ab900d6364861b915bdd4735973f00
|
||||
F ext/fts5/fts5_varint.c e64d2113f6e1bfee0032972cffc1207b77af63319746951bf1d09885d1dadf80
|
||||
@@ -160,7 +160,7 @@ F ext/fts5/test/fts5connect.test 08030168fc96fc278fa81f28654fb7e90566f33aff269c0
|
||||
F ext/fts5/test/fts5content.test 213506436fb2c87567b8e31f6d43ab30aab99354cec74ed679f22aad0cdbf283
|
||||
F ext/fts5/test/fts5corrupt.test 77ae6f41a7eba10620efb921cf7dbe218b0ef232b04519deb43581cb17a57ebe
|
||||
F ext/fts5/test/fts5corrupt2.test 7453752ba12ce91690c469a6449d412561cc604b1dec994e16ab132952e7805f
|
||||
F ext/fts5/test/fts5corrupt3.test 5df97f353102f0078d0bb418d620652d03460ee1cceb2992a3b5ee6fb619b24e
|
||||
F ext/fts5/test/fts5corrupt3.test 1cad09897fc69084a904c921dee7f777e1c866964ee2ec2cc7a8a69cc3f1ab68
|
||||
F ext/fts5/test/fts5corrupt4.test f4c08e2182a48d8b70975fd869ee5391855c06d8a0ff87b6a2529e7c5a88a1d3
|
||||
F ext/fts5/test/fts5delete.test 619295b20dbc1d840b403ee07c878f52378849c3c02e44f2ee143b3e978a0aa7
|
||||
F ext/fts5/test/fts5detail.test 31b240dbf6d44ac3507e2f8b65f29fdc12465ffd531212378c7ce1066766f54e
|
||||
@@ -286,7 +286,7 @@ F ext/lsm1/tool/mklsm1c.tcl f31561bbee5349f0a554d1ad7236ac1991fc09176626f529f607
|
||||
F ext/misc/README.md d6dd0fe1d8af77040216798a6a2b0c46c73054d2f0ea544fbbcdccf6f238c240
|
||||
F ext/misc/amatch.c e3ad5532799cee9a97647f483f67f43b38796b84b5a8c60594fe782a4338f358
|
||||
F ext/misc/anycollseq.c 5ffdfde9829eeac52219136ad6aa7cd9a4edb3b15f4f2532de52f4a22525eddb
|
||||
F ext/misc/appendvfs.c 55121d311d408ba9c62c3cfa367408887638f02f9522dd9859891d0ee69a7eba
|
||||
F ext/misc/appendvfs.c bdc9de0a0e61c21327e975da178b4fd6f57de9c46123044aa6ee3a20798c5db2
|
||||
F ext/misc/blobio.c a867c4c4617f6ec223a307ebfe0eabb45e0992f74dd47722b96f3e631c0edb2a
|
||||
F ext/misc/btreeinfo.c d28ce349b40054eaa9473e835837bad7a71deec33ba13e39f963d50933bfa0f9
|
||||
F ext/misc/carray.c b75a0f207391038bf1540d3372f482a95c3613511c7c474db51ede1196321c7c
|
||||
@@ -304,7 +304,7 @@ F ext/misc/explain.c 0086fab288d4352ea638cf40ac382aad3b0dc5e845a1ea829a694c015fd
|
||||
F ext/misc/fileio.c 9b69e25da3b51d4a1d905a464ccb96709792ad627a742ba09215bc0d1447e7bd
|
||||
F ext/misc/fossildelta.c 1240b2d3e52eab1d50c160c7fe1902a9bd210e052dc209200a750bbf885402d5
|
||||
F ext/misc/fuzzer.c eae560134f66333e9e1ca4c8ffea75df42056e2ce8456734565dbe1c2a92bf3d
|
||||
F ext/misc/ieee754.c 5c7ca326361c7368f95f5743972eade3b8b24f60359ed7cba4706668a5682896
|
||||
F ext/misc/ieee754.c cd6ab89f85fda8a020559b3f4d03001a8a62dd856beda5af3f558621d12be913
|
||||
F ext/misc/json1.c f31e89171f932d1821c91f10d2cb4979fc0447030030a8bce70420cd43d074c0
|
||||
F ext/misc/memstat.c 3017a0832c645c0f8c773435620d663855f04690172316bd127270d1a7523d4d
|
||||
F ext/misc/memtrace.c 7c0d115d2ef716ad0ba632c91e05bd119cb16c1aedf3bec9f06196ead2d5537b
|
||||
@@ -359,7 +359,7 @@ F ext/rbu/rbu_common.tcl 60d904133ff843fe72cc0514e9dd2486707181e6e0fbab20979da28
|
||||
F ext/rbu/rbucollate.test cac528a9a46318cba42e61258bb42660bbbf4fdb9a8c863de5a54ad0c658d197
|
||||
F ext/rbu/rbucrash.test 000981a1fe8a6e4d9a684232f6a129e66a3ef595f5ed74655e2f9c68ffa613b4
|
||||
F ext/rbu/rbucrash2.test efa143cc94228eb0266d3f1abfbee60a5838a84cef7cc3fcb8c145b74d96fd41
|
||||
F ext/rbu/rbudiff.test 156957851136b63c143478518dc1bda6c832103cdbe8ac1d7cdd47edb3cbe0a3
|
||||
F ext/rbu/rbudiff.test abe895a8d479e4d33acb40e244e3d8e2cd25f55a18dfa8b9f83e13d00073f600
|
||||
F ext/rbu/rbudor.test e3e8623926012f43eebe51fedf06a102df2640750d971596b052495f2536db20
|
||||
F ext/rbu/rbuexpr.test 10d0420537c3bc7666e576d72adeffe7e86cfbb00dcc30aa9ce096c042415190
|
||||
F ext/rbu/rbufault.test 2d7f567b79d558f6e093c58808cab4354f8a174e3802f69e7790a9689b3c09f8
|
||||
@@ -379,7 +379,7 @@ F ext/rbu/rbuvacuum.test 55e101e90168c2b31df6c9638fe73dc7f7cc666b6142266d1563697
|
||||
F ext/rbu/rbuvacuum2.test b8e5b51dc8b2c0153373d024c0936be3f66f9234acbd6d0baab0869d56b14e6b
|
||||
F ext/rbu/rbuvacuum3.test 8addd82e4b83b4c93fa47428eae4fd0dbf410f8512c186f38e348feb49ba03dc
|
||||
F ext/rbu/rbuvacuum4.test a78898e438a44803eb2bc897ba3323373c9f277418e2d6d76e90f2f1dbccfd10
|
||||
F ext/rbu/sqlite3rbu.c 05c457c27e9340c944f34e850871a915a6b5ee1d823f7a0bb2b482ac6b1e1464
|
||||
F ext/rbu/sqlite3rbu.c e6531884442b72f9e0ba47036fb5c4641ea817ff659a642b3984c10b8535b0fd
|
||||
F ext/rbu/sqlite3rbu.h 1dc88ab7bd32d0f15890ea08d23476c4198d3da3056985403991f8c9cd389812
|
||||
F ext/rbu/test_rbu.c 03f6f177096a5f822d68d8e4069ad8907fe572c62ff2d19b141f59742821828a
|
||||
F ext/repair/README.md 92f5e8aae749a4dae14f02eea8e1bb42d4db2b6ce5e83dbcdd6b1446997e0c15
|
||||
@@ -451,19 +451,20 @@ F ext/session/sessionfault.test da273f2712b6411e85e71465a1733b8501dbf6f7
|
||||
F ext/session/sessionfault2.test dd593f80b6b4786f7adfe83c5939620bc505559770cc181332da26f29cddd7bb
|
||||
F ext/session/sessioninvert.test 04075517a9497a80d39c495ba6b44f3982c7371129b89e2c52219819bc105a25
|
||||
F ext/session/sessionmem.test f2a735db84a3e9e19f571033b725b0b2daf847f3f28b1da55a0c1a4e74f1de09
|
||||
F ext/session/sessionnoop.test a9366a36a95ef85f8a3687856ebef46983df399541174cb1ede2ee53b8011bc7
|
||||
F ext/session/sessionrebase.test ccfa716b23bd1d3b03217ee58cfd90c78d4b99f53e6a9a2f05e82363b9142810
|
||||
F ext/session/sessionstat1.test 218d351cf9fcd6648f125a26b607b140310160184723c2666091b54450a68fb5
|
||||
F ext/session/sessionwor.test 67b5ab91d4f93ce65ff1f58240ac5ddf73f8670facc1ffa49cef56293d52818d
|
||||
F ext/session/sqlite3session.c 1d0553077b55ffcfa69963c354e9bad3bace6ce79bbe7368e650c6ae1e106314
|
||||
F ext/session/sqlite3session.h f53c99731882bf59c7362855cdeba176ce1fe8eeba089e38a8cce0172f8473aa
|
||||
F ext/session/test_session.c 93ca965112d2b4d9d669c9c0be6b1e52942a268796050a145612df1eee175ce0
|
||||
F ext/session/sessionwor.test 6fd9a2256442cebde5b2284936ae9e0d54bde692d0f5fd009ecef8511f4cf3fc
|
||||
F ext/session/sqlite3session.c a7c5ac1acfe21d94b37921b29b0458d64d022a66b282338eee4aafa9c018cb1c
|
||||
F ext/session/sqlite3session.h f48662626e7a3176a188787a0bd360933dd46cccd98df01c208b02051c540fb7
|
||||
F ext/session/test_session.c 90ccf1c30c857bd2fb3f6c990163e8f389ddbdbdc7fa5baa2f6f5f287df41c08
|
||||
F ext/userauth/sqlite3userauth.h 7f3ea8c4686db8e40b0a0e7a8e0b00fac13aa7a3
|
||||
F ext/userauth/user-auth.txt e6641021a9210364665fe625d067617d03f27b04
|
||||
F ext/userauth/userauth.c 7f00cded7dcaa5d47f54539b290a43d2e59f4b1eb5f447545fa865f002fc80cb
|
||||
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
|
||||
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
|
||||
F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60
|
||||
F main.mk 443a4ec1ca89ad267cbde45dadc68861154b99c7bd26e7b7dc74303a664002b8
|
||||
F main.mk c6afb1c8bcacc4c3e320ab10259879bc927f0747401e184b64e8f4b78f057ab2
|
||||
F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83
|
||||
F mptest/config01.test 3c6adcbc50b991866855f1977ff172eb6d901271
|
||||
F mptest/config02.test 4415dfe36c48785f751e16e32c20b077c28ae504
|
||||
@@ -475,37 +476,37 @@ F spec.template 86a4a43b99ebb3e75e6b9a735d5fd293a24e90ca
|
||||
F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
|
||||
F sqlite3.1 fc7ad8990fc8409983309bb80de8c811a7506786
|
||||
F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a
|
||||
F src/alter.c 36cae0d6e3e91a1996e1a472f8c7242c31a4e38ba4295e3056da198c04fd2a87
|
||||
F src/alter.c 2d631213818b654faaf08755f26e934134c4769757ae9286981401cd6b571081
|
||||
F src/analyze.c 01c6c6765cb4d40b473b71d85535093730770bb186f2f473abac25f07fcdee5c
|
||||
F src/attach.c 87102aba5ddac8ef3a8a033ab657e4cae9cc8e846efe93b14029cfffaaf8831e
|
||||
F src/auth.c 8d1df0e2ef8bafbedd4f1fe4baff03eb27507da4bf6e449df3613d383c4018b2
|
||||
F src/attach.c 9cbe761e464025694df8e6f6ee4d9f41432c3a255ca9443ccbb4130eeb87cf72
|
||||
F src/auth.c 08954fdc4cc2da5264ba5b75cfd90b67a6fc7d1710a02ccf917c38eadec77853
|
||||
F src/backup.c 3014889fa06e20e6adfa0d07b60097eec1f6e5b06671625f476a714d2356513d
|
||||
F src/bitvec.c 17ea48eff8ba979f1f5b04cc484c7bb2be632f33
|
||||
F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6
|
||||
F src/btree.c 4da25694985ac8f5f714bfa58a6cd453f9161d7da9394a95605aaa4db2752757
|
||||
F src/btree.h 285f8377aa1353185a32bf455faafa9ff9a0d40d074d60509534d14990c7829e
|
||||
F src/btree.c bafa3a2e8b6622a3aa8791f90c8ecc70e8ae551ba9023f865213890f5b8a8994
|
||||
F src/btree.h 096cc53baa58be22b02c896d1cf933c38cfc6d65f9253c1367ece8cc88a24de5
|
||||
F src/btreeInt.h 7614cae30f95b6aed0c7cac7718276a55cfe2c77058cbfd8bef5b75329757331
|
||||
F src/build.c 118e1076282415229420d04f9cc25bb148a2c412d82ea3c319136d2122c842e5
|
||||
F src/build.c fec73c39d756f31d35ccbaa80fe1e040a8d675a318d4d30f41c444167bf3b860
|
||||
F src/callback.c d0b853dd413255d2e337b34545e54d888ea02f20da5ad0e63585b389624c4a6c
|
||||
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
|
||||
F src/ctime.c 2a322b9a3d75771fb4d99e0702851f4f68dda982507a0f798eefb0712969a410
|
||||
F src/date.c dace306a10d9b02ee553d454c8e1cf8d3c9b932e137738a6b15b90253a9bfc10
|
||||
F src/date.c e0632f335952b32401482d099321bbf12716b29d6e72836b53ae49683ebae4bf
|
||||
F src/dbpage.c 8a01e865bf8bc6d7b1844b4314443a6436c07c3efe1d488ed89e81719047833a
|
||||
F src/dbstat.c 3aa79fc3aed7ce906e4ea6c10e85d657299e304f6049861fe300053ac57de36c
|
||||
F src/delete.c 352ea931218c45a3daf17472d4141b9c7fc026d85da3f1ade404ea5bb6d67f77
|
||||
F src/expr.c 47c85263e6d179424e6b09e2c79db5704ab5b8cbc2fae2ee3285faa2566f2e74
|
||||
F src/delete.c 73f57a9a183532c344a3135cf8f2a5589376e39183e0b5f562d6b61b2af0f4d8
|
||||
F src/expr.c d681f0b48b1e16173ad8e1e8f7323cda120a0c517cb7a3d5b329c4e2c57f18bd
|
||||
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
|
||||
F src/fkey.c 02e4a3311885cd2b31eb17fd58dc2fc738cd2c823d0d39e4dd5595169c6f8bc3
|
||||
F src/func.c 2ea99e9e0531b7f020d5e8e167d25344d618afc718ddc94dd91fa8fef1c85a91
|
||||
F src/fkey.c e9063648396c58778f77583a678342fe4a9bc82436bf23c5f9f444f2df0fdaa4
|
||||
F src/func.c 479f6929be027eb0210cbdde9d3529c012facf082d64a6b854a9415940761e5e
|
||||
F src/global.c ed55af196a9b66e198aaeda3f5454c3aa7d7d050c6c938181fd044b70d180a81
|
||||
F src/hash.c 8d7dda241d0ebdafb6ffdeda3149a412d7df75102cecfc1021c98d6219823b19
|
||||
F src/hash.h 9d56a9079d523b648774c1784b74b89bd93fac7b365210157482e4319a468f38
|
||||
F src/hwtime.h cb1d7e3e1ed94b7aa6fde95ae2c2daccc3df826be26fc9ed7fd90d1750ae6144
|
||||
F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
|
||||
F src/insert.c 97be36c52c667a64aacbba76398544d224268d62444b67d011a077c486e375bb
|
||||
F src/insert.c 8942baede303a54ba3b6d06200d5b74c9bc25ababec8a55823e06309748cd4a3
|
||||
F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa
|
||||
F src/loadext.c 8c9c8cd2bd8eecdb06d9b6e89de7e9e65bae45cc8fc33609cc74023a5c296067
|
||||
F src/main.c 1c5de7b3fabcdf05f4fe563aab5d81d175b89c67a8678a12ba86629356afa356
|
||||
F src/main.c 2a7ece3a67c646e5fe9984ffe0277d6a76f80ce9715bf2faa591d8cb66b9d913
|
||||
F src/malloc.c c1af4ac5a463648cd2953fd4ac679b3ba9022ce5ec794a60806150ad69dfd33a
|
||||
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
|
||||
F src/mem1.c c12a42539b1ba105e3707d0e628ad70e611040d8f5e38cf942cee30c867083de
|
||||
@@ -513,7 +514,7 @@ F src/mem2.c b93b8762ab999a29ae7751532dadf0a1ac78040308a5fb1d17fcc365171d67eb
|
||||
F src/mem3.c 30301196cace2a085cbedee1326a49f4b26deff0af68774ca82c1f7c06fda4f6
|
||||
F src/mem5.c 9bf955937b07f8c32541c8a9991f33ce3173d944
|
||||
F src/memdb.c ab0632d42407e866d2b616bd19d4211ac0ad1b430f04c4e187d60005b8700b98
|
||||
F src/memjournal.c 90b2ca7e2f465d57c16b69d15a9f3e3294af61088eb4938f2f7664d5ac50f813
|
||||
F src/memjournal.c 431c70a111223a8a6e2e7e9f014afc6c88d818d357d866afc563195f2277d50e
|
||||
F src/msvc.h 3a15918220367a8876be3fa4f2abe423a861491e84b864fb2b7426bf022a28f8
|
||||
F src/mutex.c 5e3409715552348732e97b9194abe92fdfcd934cfb681df4ba0ab87ac6c18d25
|
||||
F src/mutex.h a7b2293c48db5f27007c3bdb21d438873637d12658f5a0bf8ad025bb96803c4a
|
||||
@@ -528,30 +529,30 @@ F src/os_setup.h 0dbaea40a7d36bf311613d31342e0b99e2536586
|
||||
F src/os_unix.c adbbcea4c63d3b400d405f60a5da4c01433753ec4a12e2dc695beb2bbd671fe9
|
||||
F src/os_win.c 77d39873836f1831a9b0b91894fec45ab0e9ca8e067dc8c549e1d1eca1566fe9
|
||||
F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
|
||||
F src/pager.c c49952ac5e9cc536778eff528091d79d38b3e45cbeeed4695dc05e207dc6547d
|
||||
F src/pager.c 970691daea03f9f15e34de671bd8675c1e136232b529e21bfd36d4dba6d41753
|
||||
F src/pager.h 4bf9b3213a4b2bebbced5eaa8b219cf25d4a82f385d093cd64b7e93e5285f66f
|
||||
F src/parse.y 67ba503780de64b967ae195b7e14c33531329228e1bc0b83d63324beb733680b
|
||||
F src/parse.y 2107aff88e361bbf8388fdede3fed20fda875f23ba7585ec83b20e3e16a95670
|
||||
F src/pcache.c 385ff064bca69789d199a98e2169445dc16e4291fa807babd61d4890c3b34177
|
||||
F src/pcache.h 4f87acd914cef5016fae3030343540d75f5b85a1877eed1a2a19b9f284248586
|
||||
F src/pcache1.c 6596e10baf3d8f84cc1585d226cf1ab26564a5f5caf85a15757a281ff977d51a
|
||||
F src/pragma.c 6daaaecc26a4b09481d21722525b079ce756751a43a79cc1d8f122d686806193
|
||||
F src/pcache1.c 388304fd2d91c39591080b5e0f3c62cfba87db20370e7e0554062bfb29740e9f
|
||||
F src/pragma.c eb42cb9bec189cf18cef5d8fcae56e13bb73ef2b019b198fb48740ced81bce95
|
||||
F src/pragma.h 8dc78ab7e9ec6ce3ded8332810a2066f1ef6267e2e03cd7356ee00276125c6cf
|
||||
F src/prepare.c f288cbc35f79eb32e162de7e80a63ebe00d80e639dcfac071bee11570cbdb16f
|
||||
F src/printf.c 30e92b638fac71dcd85cdea1d12ecfae354c9adee2c71e8e1ae4727cde7c91ed
|
||||
F src/prepare.c e21b54489b5c73b06ada15e6fc79b5c6f64b06701924a6ca98944ae59e06256f
|
||||
F src/printf.c 2b03a80d7c11bb422115dca175a18bf430e9c9dbaa0eee63b758f0c022f8f34f
|
||||
F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384
|
||||
F src/resolve.c f6761473ea4b51190fc52f8f2121498b78717266e106e7bff12849ea2d52165f
|
||||
F src/resolve.c dd47248c2c914feb0d4428c27d782e2723971d32cfa5536f49306d080df4d45a
|
||||
F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92
|
||||
F src/select.c 738cb746189f721f59972993c13085fa2975c4cbfd04ba26445f3b42c81237dc
|
||||
F src/shell.c.in 9ebc74e4f05cfbd0f4a36060fdaeff1da4e9af4458358722bc08c5a1ab9a0879
|
||||
F src/sqlite.h.in 8855a19f37ade8dad189a9e48233a2ebe1b46faf469c7eb0906a654e252dcc57
|
||||
F src/select.c e9c9c78567745b958a22d3f2bed054ec2ce0d67837cbd1c4faf3d9a660464a0b
|
||||
F src/shell.c.in 8df3912a7ca4873a1443d4adef1b25baee8c086ab479fd9c4f13ab03f98049ab
|
||||
F src/sqlite.h.in 3426a080ea1f222a73e3bd91e7eacbd30570a0117c03d42c6dde606f33e5e318
|
||||
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
|
||||
F src/sqlite3ext.h 61b38c073d5e1e96a3d45271b257aef27d0d13da2bea5347692ae579475cd95e
|
||||
F src/sqliteInt.h 0fda3b2c05b1559135aa2c4ecb8e75bd2085ba4433310bbb5427d97c2d81315d
|
||||
F src/sqliteInt.h 0f81c7eb3a40dda0b74d0acdc8f3b134346b40be780b1fe5cc24dd294a928d1a
|
||||
F src/sqliteLimit.h d7323ffea5208c6af2734574bae933ca8ed2ab728083caa117c9738581a31657
|
||||
F src/status.c 4b8bc2a6905163a38b739854a35b826c737333fab5b1f8e03fa7eb9a4799c4c1
|
||||
F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
|
||||
F src/tclsqlite.c 986b6391f02cd9b53c1d688be55899f6ffddeb8e8014cd83c1b73ff912579a71
|
||||
F src/test1.c 2197966d2f7211ef9eefaa6c3c7dd2c7d786d1f33f2aadef2f08c8c79eceec26
|
||||
F src/test1.c cff43d8e21be543b77651b4d2caf49bd6488fee220f8540ecd9f71d13169dbd1
|
||||
F src/test2.c 3efb99ab7f1fc8d154933e02ae1378bac9637da5
|
||||
F src/test3.c 61798bb0d38b915067a8c8e03f5a534b431181f802659a6616f9b4ff7d872644
|
||||
F src/test4.c 7c4420e01c577b5c4add2cb03119743b1a357543d347773b9e717195ea967159
|
||||
@@ -606,33 +607,33 @@ F src/test_window.c cdae419fdcea5bad6dcd9368c685abdad6deb59e9fc8b84b153de513d394
|
||||
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
|
||||
F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c
|
||||
F src/tokenize.c c64c49d7c2ec4490c2fef1f24350167ba16b03b0c6cee58ad1a1d70a4325d4e9
|
||||
F src/treeview.c 4b92992176fb2caefbe06ba5bd06e0e0ebcde3d5564758da672631f17aa51cda
|
||||
F src/trigger.c 0a242d65dd9b9822d4e990653eb4ece3557dcda01374934aa3cc1f9718d8dee3
|
||||
F src/treeview.c c6260e1fa5f41c361b2409edc9b0050bcaef5bc4d6abc467fbc45f0d7ccf3d84
|
||||
F src/trigger.c 861c3ec2c5b0fc830bdf82470454a9324fad70cbaa96d2e208fb54577c9e8d28
|
||||
F src/update.c 0f5a61f0787199983530a33f6fffe4f52742f35fcdf6ccfad1078b1a8bc17723
|
||||
F src/upsert.c df8f1727d62b5987c4fd302cd4d7c0c84ae57cd65683c5a34a740dfe24039235
|
||||
F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0
|
||||
F src/util.c 41c7a72da1df47864faa378a1c720b38adb288c6838cb6be5594511b6287a048
|
||||
F src/vacuum.c 492422c1463c076473bae1858799c7a0a5fe87a133d1223239447c422cd26286
|
||||
F src/vdbe.c 9b9a714318e49b59a282b4e175080dc53a07b8099895fa21613e6b80fbad3727
|
||||
F src/vdbe.h a71bf43572d3de57923d1928ac01ae8d355cd67e94462ba4f7462265cedbef9a
|
||||
F src/vdbeInt.h 3ca5e9fd6e095a8b6cf6bc3587a46fc93499503b2fe48951e1034ba9e2ce2f6e
|
||||
F src/vdbeapi.c c5e7cb2ab89a24d7f723e87b508f21bfb1359a04db5277d8a99fd1e015c12eb9
|
||||
F src/vdbeaux.c 2be30e4918126122fa358ef8303206cad0feffe17d320077c77ff5c2a34f3626
|
||||
F src/vdbe.c b79b222f07690874d436eef4ad5e76845b2796e7094b1d0545cc94333f0d8e50
|
||||
F src/vdbe.h 25dabb25c7e157b84e59260cfb5b466c3ac103ede9f36f4db371332c47601abe
|
||||
F src/vdbeInt.h 3df118924e1711f1bbc8e30c46260d0ab6c3b029b32dd411f789111f76434f3c
|
||||
F src/vdbeapi.c 4a43e303ec3354c785f453e881521969378e85628278ab74ba4a9df790c0d93b
|
||||
F src/vdbeaux.c fb51483c2bcaf45c5de63c26cce8649ef37f1332e8e035867033d21ef5e7fc2c
|
||||
F src/vdbeblob.c 253ed82894924c362a7fa3079551d3554cd1cdace39aa833da77d3bc67e7c1b1
|
||||
F src/vdbemem.c 947f2a65910edb4014dc981d33e414a68c51f169f9df8c4c493a0ba840b6eb1f
|
||||
F src/vdbesort.c f5b5e473a7cee44e47a94817b042fd7172cf3aa2c0a7928a8339d612bcfdec5a
|
||||
F src/vdbetrace.c 666c6fd9f1b62be6999e072a45b913e3c2c3518bc60dfd4d54fe304130acb724
|
||||
F src/vdbevtab.c f99b275366c5fc5e2d99f734729880994ab9500bdafde7fae3b02d562b9d323c
|
||||
F src/vtab.c 5f5fc793092f53bbdfde296c50f563fb7bda58cf48e9cf6a8bdfbc5abd409845
|
||||
F src/vtab.c 032a0165c147fda16927e6a3230e90c068d4af93f887ce94e26f678fe48e5e4c
|
||||
F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
|
||||
F src/wal.c 69e770e96fd56cc21608992bf2c6f1f3dc5cf2572d0495c6a643b06c3a679f14
|
||||
F src/wal.h c3aa7825bfa2fe0d85bef2db94655f99870a285778baa36307c0a16da32b226a
|
||||
F src/walker.c d9c4e454ebb9499e908aa62d55b8994c375cf5355ac78f60d45af17f7890701c
|
||||
F src/where.c 0e6abb22a2323fec80b450825593c26a2ad8f4815d1ee3af9969d8f6144bf681
|
||||
F src/whereInt.h ae03b5e3a4cca9bd9cb1b7d3c63faf8f1f177200fc8cecc87d3d0cab6ca338e6
|
||||
F src/wherecode.c 43a63441f8662ddf86b15975683a502ec33f08167e9636f4d19e38e265e95fd9
|
||||
F src/whereexpr.c a182038cf7d10aa9a95a96b8563a34f34990323cf307dee6559e995961966d43
|
||||
F src/window.c edd6f5e25a1e8f2b6f5305b7f5f7da7bb35f07f0d432b255b1d4c2fcab4205aa
|
||||
F src/walker.c d42d6c80ea363ef689a462e65eefcfe87deab924c50de5baa37ecb6af7d7ddaa
|
||||
F src/where.c 10d06b16670a1d2a992d52a9f08e49426d38a08fb0a7ae5f7f62fd023d560e1e
|
||||
F src/whereInt.h 446e5e8018f83358ef917cf32d8e6a86dc8430113d0b17e720f1839d3faa44c4
|
||||
F src/wherecode.c e57a8690311a75d06e723e8d379f9831de04aba300e07174d236e32a7f9c7a13
|
||||
F src/whereexpr.c 53452fe2fb07be2f4cb17f55cc721416fae0092c00717f106faf289c990b6494
|
||||
F src/window.c 7e89ac4b6cd6bb9b7772234a625d19c39b530f4ac06e43688a8b7e6a1ab512a2
|
||||
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
|
||||
F test/affinity2.test ce1aafc86e110685b324e9a763eab4f2a73f737842ec3b687bd965867de90627
|
||||
F test/affinity3.test eecb0dabee4b7765a8465439d5e99429279ffba23ca74a7eae270a452799f9e7
|
||||
@@ -640,17 +641,21 @@ F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
|
||||
F test/aggnested.test 2f65ec8132e0ca896de550b9908094d49ad65a99116a9d79deeb6017604ad4f6
|
||||
F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87
|
||||
F test/all.test 2ecb8bbd52416642e41c9081182a8df05d42c75637afd4488aace78cc4b69e13
|
||||
F test/alter.test 25e109787dc5e631e117eb6e1c57f96a572bb51228db3b4f8b5f41d665e2ccaa
|
||||
F test/alter.test f53d8a4ecd35f051c07e54a36beec5d0a30d30a9d98bc723f6cde6afbfb3c5ca
|
||||
F test/alter2.test a966ccfcddf9ce0a4e0e6ff1aca9e6e7948e0e242cd7e43fc091948521807687
|
||||
F test/alter3.test e487958dec7932453e0b83baf21d6b1e71d5e7d9a55bc20eadfa62a51ddffc29
|
||||
F test/alter4.test dfd6086faf461b27ca2d2999848dcd207edf23352fc1592d0005c0844f3f08cf
|
||||
F test/alterauth.test 63442ba61ceb0c1eeb63aac1f4f5cebfa509d352276059d27106ae256bafc959
|
||||
F test/alterauth2.test c0a1ddf5b93d93cb0d15ba7acaf0c5c6fb515bbe861ede75b2d3fabad33b6499
|
||||
F test/altercol.test 1d6a6fe698b81e626baea4881f5717f9bc53d7d07f1cd23ee7ad1b931f117ddf
|
||||
F test/alterlegacy.test 82022721ce0de29cedc9a7af63bc9fcc078b0ee000f8283b4b6ea9c3eab2f44b
|
||||
F test/alterauth2.test 794ac5cef251819fe364b4fe20f12f86e9c5d68070513c7fd26c17cb244c89af
|
||||
F test/altercol.test 3456f7cc4196ef8f7d82d245d6e91940eb12bc95c36c91ac4b512f6b5c9a4fa9
|
||||
F test/altercorrupt.test 584d707a80e106952d6382790c8919bcf9f0db678ed3a1c09fd98b7f9d1d3a10
|
||||
F test/alterdropcol.test 596623cb8a72d9570bfb8417b0f302810efe007873796f03c17a9e9ff28dade1
|
||||
F test/alterdropcol2.test 527fce683b200d620f560f666c44ae33e22728e990a10a48a543280dfd4b4d41
|
||||
F test/alterlegacy.test f38c6d06cda39e1f7b955bbce57f2e3ef5b7cb566d3d1234502093e228c15811
|
||||
F test/altermalloc.test 167a47de41b5c638f5f5c6efb59784002b196fff70f98d9b4ed3cd74a3fb80c9
|
||||
F test/altermalloc2.test fa7b1c1139ea39b8dec407cf1feb032ca8e0076bd429574969b619175ad0174b
|
||||
F test/altertab.test 6d7bbac2c4a6ef71b775094a3298fa3a92274d95034ee23157ffba92768e47e6
|
||||
F test/altermalloc3.test 2c7bbd8cf3e9c4a91e28675bb62bcc2ef70f227967fa74349f03d9f4642f0615
|
||||
F test/altertab.test 7691872aadfe00a94b459af9086504bcf399dd936336e486da1b182930744b77
|
||||
F test/altertab2.test b0d62f323ca5dab42b0bc028c52e310ebdd13e655e8fac070fe622bad7852c2b
|
||||
F test/altertab3.test 2b82fa2236a3a91553d53ae5555d8e723c7eec174c41f1fa62ff497355398479
|
||||
F test/amatch1.test b5ae7065f042b7f4c1c922933f4700add50cdb9f
|
||||
@@ -677,7 +682,7 @@ F test/atof1.test 10049623e77006691c4c2978c1dc8a3f75276377a53417811aa85bda7493f9
|
||||
F test/atomic.test 065a453dde33c77ff586d91ccaa6ed419829d492dbb1a5694b8a09f3f9d7d061
|
||||
F test/atomic2.test b6863b4aa552543874f80b42fb3063f1c8c2e3d8e56b6562f00a3cc347b5c1da
|
||||
F test/atrc.c c388fac43dbba05c804432a7135ae688b32e8f25818e9994ffba4b64cf60c27c
|
||||
F test/attach.test d42862c72fef3d54367d962d41dcfb5363442a4a1bd898c22ae950cea1aa0dd3
|
||||
F test/attach.test 54f8e49e88d0de48f6428267a678465863d2b8f72320612f35bd5c02e240bc2f
|
||||
F test/attach2.test 256bd240da1835fb8408dd59fb7ef71f8358c7a756c46662434d11d07ba3a0ce
|
||||
F test/attach3.test c59d92791070c59272e00183b7353eeb94915976
|
||||
F test/attach4.test aa05b1d8218b24eba5a7cccf4f224f514ba57ba705c9267f09d2bb63fed0eea1
|
||||
@@ -694,10 +699,11 @@ F test/autoindex4.test 49d3cd791a9baa16fb461d7ea3de80d019a819cf
|
||||
F test/autoindex5.test a5d72fe8c217cc0ea356dc6fa06a282a8a3fc53aa807709d79dba07a8f248102
|
||||
F test/autovacuum.test 0831cd34e14695d297187f7f6519265e3121c5b0a1720e548e86829e796129e9
|
||||
F test/autovacuum_ioerr2.test 8a367b224183ad801e0e24dcb7d1501f45f244b4
|
||||
F test/avfs.test 0c3a38e03cccb0fc3127838462dc05dc3f4c1480d770c084b388304c25de3652
|
||||
F test/avtrans.test b7dc25459ecbd86c6fa9c606ee3068f59d81e225118617dcf2bbb6ded2ade89e
|
||||
F test/backcompat.test 3e64cedda754c778ef6bbe417b6e7a295e662a4d
|
||||
F test/backup.test dd4a5ff756e3df3931dacb1791db0584d4bad989
|
||||
F test/backup2.test 1fd1ad8c5b3d2d5b9c0cce4143a4fc610d51ddc6ae16a7a122973d43e6b50bbd
|
||||
F test/backup2.test 8facb54df1388419d34b362ab1f7e233310ff3a3af64e8ad5ec47ba3c2bbe5cf
|
||||
F test/backup4.test 8f6fd48e0dfde77b9a3bb26dc471ede3e101df32
|
||||
F test/backup5.test ee5da6d7fe5082f5b9b0bbfa31d016f52412a2e4
|
||||
F test/backup_ioerr.test 4c3c7147cee85b024ecf6e150e090c32fdbb5135
|
||||
@@ -766,6 +772,7 @@ F test/collateA.test b8218ab90d1fa5c59dcf156efabb1b2599c580d6
|
||||
F test/collateB.test 1e68906951b846570f29f20102ed91d29e634854ee47454d725f2151ecac0b95
|
||||
F test/colmeta.test 2c765ea61ee37bc43bbe6d6047f89004e6508eb1
|
||||
F test/colname.test 87ad5458bb8709312dac0d6755fd30e8e4ca83298d0a9ef6e5c24277a3c3390e
|
||||
F test/columncount.test eff33d402a7b0fde0a52a1920d238af200ca573327021e0ce3b7e5688de41449
|
||||
F test/conflict.test ac0667090f66130ac77d5fb764655558ca6600dd6d88f670ca9123b61c448337
|
||||
F test/conflict2.test 5557909ce683b1073982f5d1b61dfb1d41e369533bfdaf003180c5bc87282dd1
|
||||
F test/conflict3.test 81865d9599609aca394fb3b9cd5f561d4729ea5b176bece3644f6ecb540f88ac
|
||||
@@ -815,7 +822,7 @@ F test/cursorhint.test 0175e4404181ace3ceca8b114eb0a98eae600d565aa4e2705abbe6614
|
||||
F test/cursorhint2.test 6f3aa9cb19e7418967a10ec6905209bcbb5968054da855fc36c8beee9ae9c42f
|
||||
F test/dataversion1.test 6e5e86ac681f0782e766ebcb56c019ae001522d114e0e111e5ebf68ccf2a7bb8
|
||||
F test/date.test 9b73bbeb1b82d9c1f44dec5cf563bf7da58d2373
|
||||
F test/date2.test 520a1708e4e14c682cf514560f3e9f2e5affa9d66560fbc2a6941ae291260daf
|
||||
F test/date2.test 7e12ec14aaf4d5e6294b4ba140445b0eca06ea50062a9c3a69c4ee13d0b6f8b1
|
||||
F test/dbdata.test 042f49acff3438f940eeba5868d3af080ae64ddf26ae78f80c92bec3ca7d8603
|
||||
F test/dbfuzz.c 73047c920d6210e5912c87cdffd9a1c281d4252e
|
||||
F test/dbfuzz001.test 55e1a3504f8dea84155e09912fe3b1c3ad77e0b1a938ec42ca03b8e51b321e30
|
||||
@@ -848,7 +855,7 @@ F test/e_delete.test ab39084f26ae1f033c940b70ebdbbd523dc4962e
|
||||
F test/e_droptrigger.test 235c610f8bf8ec44513e222b9085c7e49fad65ad0c1975ac2577109dd06fd8fa
|
||||
F test/e_dropview.test 74e405df7fa0f762e0c9445b166fe03955856532e2bb234c372f7c51228d75e7
|
||||
F test/e_expr.test 6ba7a51ece7b3e7fc145f14f924eed25ebb5a24e7b8596c78f3838d372cf0385
|
||||
F test/e_fkey.test 0b458b85f192cdb9e9933d5891848bb19bcc44d3f49faf111a375f2844a164d3
|
||||
F test/e_fkey.test a2907f749cccd0b2c30d8576b673002eebdcc1fc9964bae61e5117b1d54733e2
|
||||
F test/e_fts3.test 17ba7c373aba4d4f5696ba147ee23fd1a1ef70782af050e03e262ca187c5ee07
|
||||
F test/e_insert.test f02f7f17852b2163732c6611d193f84fc67bc641fb4882c77a464076e5eba80e
|
||||
F test/e_reindex.test 2b0e29344497d9a8a999453a003cb476b6b1d2eef2d6c120f83c2d3a429f3164
|
||||
@@ -962,9 +969,9 @@ F test/fts3conf.test c84bbaec81281c1788aa545ac6e78a6bd6cde2bdbbce2da261690e3659f
|
||||
F test/fts3corrupt.test 79a32ffdcd5254e2f7fa121d9656e61949ad049c3c6554229911b7ceac37c9c6
|
||||
F test/fts3corrupt2.test e318f0676e5e78d5a4b702637e2bb25265954c08a1b1e4aaf93c7880bb0c67d0
|
||||
F test/fts3corrupt3.test 0d5b69a0998b4adf868cc301fc78f3d0707745f1d984ce044c205cdb764b491f
|
||||
F test/fts3corrupt4.test e4662d37f02248301d8b58778eac380663e09a17a38dd5d6bb5ea4c927b9a575
|
||||
F test/fts3corrupt4.test b71512ec391d39da96d60d01959e4e9f20d4237a964a94abcf5f5a2ad28378c1
|
||||
F test/fts3corrupt5.test 0549f85ec4bd22e992f645f13c59b99d652f2f5e643dac75568bfd23a6db7ed5
|
||||
F test/fts3corrupt6.test b6c55218b704b0cef224b284c756f9c55d0afd0b3c3837618bffeaa8c31e0d8e
|
||||
F test/fts3corrupt6.test d5896a8d389bd824457772dc1e2d2023cd5c5cf8e42733607b5d632103018d8b
|
||||
F test/fts3cov.test 7eacdbefd756cfa4dc2241974e3db2834e9b372ca215880e00032222f32194cf
|
||||
F test/fts3d.test 2bd8c97bcb9975f2334147173b4872505b6a41359a4f9068960a36afe07a679f
|
||||
F test/fts3defer.test f4c20e4c7153d20a98ee49ee5f3faef624fefc9a067f8d8d629db380c4d9f1de
|
||||
@@ -1019,7 +1026,7 @@ F test/fts4noti.test 5553d7bb2e20bf4a06b23e849352efc022ce6309
|
||||
F test/fts4onepass.test d69ddc4ee3415e40b0c5d1d0408488a87614d4f63ba9c44f3e52db541d6b7cc7
|
||||
F test/fts4opt.test 0fd0cc84000743ff2a883b9b84b4a5be07249f0ba790c8848a757164cdd46b2a
|
||||
F test/fts4record.test a48508f69a84c9287c8019d3a1ae712f5730d8335ffaf8e2101e691d078950bb
|
||||
F test/fts4rename.test 15fd9985c2bce6dea20da2245b22029ec89bd4710ed317c4c53abbe3cfd0c880
|
||||
F test/fts4rename.test 2e0565ffd92b2c51f1a757df0b8f2ca30537197106fec09e943919801d173692
|
||||
F test/fts4umlaut.test fcaca4471de7e78c9d1f7e8976e3e8704d7d8ad979d57a739d00f3f757380429
|
||||
F test/fts4unicode.test 82a9c16b68ba2f358a856226bb2ee02f81583797bc4744061c54401bf1a0f4c9
|
||||
F test/fts4upfrom.test 8df5acb6e10ad73f393d1add082b042ab1db72567888847d098152121e507b34
|
||||
@@ -1038,7 +1045,7 @@ F test/fuzz3.test 9c813e6613b837cb7a277b0383cd66bfa07042b4cf0317157c35852f30043c
|
||||
F test/fuzz4.test c229bcdb45518a89e1d208a21343e061503460ac69fae1539320a89f572eb634
|
||||
F test/fuzz_common.tcl b7197de6ed1ee8250a4f82d67876f4561b42ee8cbbfc6160dcb66331bad3f830
|
||||
F test/fuzz_malloc.test f348276e732e814802e39f042b1f6da6362a610af73a528d8f76898fde6b22f2
|
||||
F test/fuzzcheck.c 95427205d6cedb8fdb95bf7738e95785c790febf782d9c1e6067baaa1adc871d
|
||||
F test/fuzzcheck.c 8f83829e6c4da26abf6aded7fe9f04e56d46a418c8d7b8b67e14cf6f2ee0a25c
|
||||
F test/fuzzdata1.db d36e88741b4f23bcbaaf55b006290669d03c6c891cf13c7b3a53bc1b097b693f
|
||||
F test/fuzzdata2.db 128b3feeb78918d075c9b14b48610145a0dd4c8d6f1ca7c2870c7e425f5bf31f
|
||||
F test/fuzzdata3.db c6586d3e3cef0fbc18108f9bb649aa77bfc38aba
|
||||
@@ -1046,17 +1053,17 @@ F test/fuzzdata4.db b502c7d5498261715812dd8b3c2005bad08b3a26e6489414bd13926cd3e4
|
||||
F test/fuzzdata5.db e35f64af17ec48926481cfaf3b3855e436bd40d1cfe2d59a9474cb4b748a52a5
|
||||
F test/fuzzdata6.db 92a80e4afc172c24f662a10a612d188fb272de4a9bd19e017927c95f737de6d7
|
||||
F test/fuzzdata7.db 0166b56fd7a6b9636a1d60ef0a060f86ddaecf99400a666bb6e5bbd7199ad1f2
|
||||
F test/fuzzdata8.db 977cb95f4a5d828056dea804a6de416debe3fa0182c77f47fe19a0554aaf4db0
|
||||
F test/fuzzdata8.db c8325de6fbdd24d030cd3a01384a2ff325dda5d5e3ff5d531a26ada3d9d7e010
|
||||
F test/fuzzer1.test 3d4c4b7e547aba5e5511a2991e3e3d07166cfbb8
|
||||
F test/fuzzer2.test a85ef814ce071293bce1ad8dffa217cbbaad4c14
|
||||
F test/fuzzerfault.test 8792cd77fd5bce765b05d0c8e01b9edcf8af8536
|
||||
F test/fuzzerfault.test f64c4aef4c9e9edf1d6dc0d3f1e65dcc81e67c996403c88d14f09b74807a42bc
|
||||
F test/gcfault.test dd28c228a38976d6336a3fc42d7e5f1ad060cb8c
|
||||
F test/gencol1.test b05e6c5edb9b10d48efb634ed07342441bddc89d225043e17095c36e567521a0
|
||||
F test/genesis.tcl 1e2e2e8e5cc4058549a154ff1892fe5c9de19f98
|
||||
F test/having.test a89236dd8d55aa50c4805f82ac9daf64d477a44d712d8209c118978d0ca21ec9
|
||||
F test/hexlit.test 4a6a5f46e3c65c4bf1fa06f5dd5a9507a5627751
|
||||
F test/hidden.test 23c1393a79e846d68fd902d72c85d5e5dcf98711
|
||||
F test/hook.test e97382e68e4379838e888756d653afd159f5f14780315ff97b70360d3d8485bc
|
||||
F test/hook.test fa54fa8afc842ae375f10c1f9fc0014fa59789052fc30c9eae19811fa3afa009
|
||||
F test/hook2.test b9ff3b8c6519fb67f33192f1afe86e7782ee4ac8
|
||||
F test/icu.test 716a6b89fbabe5cc63e0cd4c260befb08fd7b9d761f04d43669233292f0753b1
|
||||
F test/ieee754.test b0945d12be7d255f3dfa18e2511b17ca37e0edd2b803231c52d05b86c04ab26e
|
||||
@@ -1087,7 +1094,7 @@ F test/index6.test f172653b35b20233e59200e8b92a76db61bf7285437bf777b93b306ba26a4
|
||||
F test/index7.test b8a0ba2110fd517bb48c4e76d26d60f1ab2ed9e257b18d71f820d7e71e9f8570
|
||||
F test/index8.test bc2e3db70e8e62459aaa1bd7e4a9b39664f8f9d7
|
||||
F test/index9.test 0aa3e509dddf81f93380396e40e9bb386904c1054924ba8fa9bcdfe85a8e7721
|
||||
F test/indexedby.test f54aac21c06948872010a956fd02de5178c362c7785a9887cf0b8616be17883b
|
||||
F test/indexedby.test a3ca11f0819a9279619099f36b624bcaa315f7a1ed65c3ed2219c2a944683d2c
|
||||
F test/indexexpr1.test 284e119999d132cc8bf37735a928c9859b28e8e295d02b7a6a4f93977c7f9ba5
|
||||
F test/indexexpr2.test dba11dbb0a58fcba4cd694f46b4004976123b81b0501f525d43c9be59f0207b1
|
||||
F test/indexfault.test 98d78a8ff1f5335628b62f886a1cb7c7dac1ef6d48fa39c51ec871c87dce9811
|
||||
@@ -1135,10 +1142,10 @@ F test/kvtest.c feb4358fb022da8ebd098c45811f2f6507688bb6c43aa72b3e840df19026317b
|
||||
F test/lastinsert.test 42e948fd6442f07d60acbd15d33fb86473e0ef63
|
||||
F test/laststmtchanges.test ae613f53819206b3222771828d024154d51db200
|
||||
F test/lemon-test01.y 58b764610fd934e189ffbb0bbfa33d171b9cb06019b55bdc04d090d6767e11d7
|
||||
F test/like.test 47b81d5de2ff19d996d49a65d50ec9754246aacbe0e950b48d186d9d8171eaf0
|
||||
F test/like.test 0b7b4765ca59d95a1f92dfab9e4d810c9fb8280b5edd6332a01340a20db9e0ed
|
||||
F test/like2.test 3b2ee13149ba4a8a60b59756f4e5d345573852da
|
||||
F test/like3.test 03d1bdf848483b78d2cfd1db283d75c4ec2e37c8b8eccc006813f3978d78fbbd
|
||||
F test/limit.test 0c99a27a87b14c646a9d583c7c89fd06c352663e
|
||||
F test/limit.test 350f5d03c29e7dff9a2cde016f84f8d368d40bcd02fa2b2a52fa10c4bf3cbfaf
|
||||
F test/limit2.test 9409b033284642a859fafc95f29a5a6a557bd57c1f0d7c3f554bd64ed69df77e
|
||||
F test/loadext.test faa4f6eed07a5aac35d57fdd7bc07f8fc82464cfd327567c10cf0ba3c86cde04
|
||||
F test/loadext2.test 0408380b57adca04004247179837a18e866a74f7
|
||||
@@ -1218,6 +1225,8 @@ F test/notify1.test 669b2b743618efdc18ca4b02f45423d5d2304abf
|
||||
F test/notify2.test 2ecabaa1305083856b7c39cf32816b612740c161
|
||||
F test/notify3.test 10ff25cde502e72a92053a2f215d64bece4ef934
|
||||
F test/notnull.test a37b663d5bb728d66fc182016613fb8e4a0a4bbf3d75b8876a7527f7d4ed3f18
|
||||
F test/notnull2.test 965a893619751255e59c911a8c58504b3174a3788b1458b7c7365b232209711b
|
||||
F test/notnullfault.test 6126e31300632070ca6021698393c7fcf61ab4791bc2aa1d6d704242c0fcd4f8
|
||||
F test/null.test b7ff206a1c60fe01aa2abd33ef9ea83c93727d993ca8a613de86e925c9f2bc6f
|
||||
F test/nulls1.test 82c5bc33148405f21205865abf13c786084438d573a4ac4e87e11b6091cde526
|
||||
F test/numcast.test 5d126f7f581432e86a90d1e35cac625164aec4a1
|
||||
@@ -1254,7 +1263,7 @@ F test/parser1.test 6ccdf5e459a5dc4673d3273dc311a7e9742ca952dd0551a6a6320d27035c
|
||||
F test/pcache.test c8acbedd3b6fd0f9a7ca887a83b11d24a007972b
|
||||
F test/pcache2.test af7f3deb1a819f77a6d0d81534e97d1cf62cd442
|
||||
F test/percentile.test 4243af26b8f3f4555abe166f723715a1f74c77ff
|
||||
F test/permutations.test 661a4325a5717957a77836910ee164ba26594a502d7a3df0e1ae7b9cba829c5d
|
||||
F test/permutations.test 0a7cf0b6b1283cdd4f0d6e31cb7afbde81d20b1caef60b73914e85b6bf660b8a
|
||||
F test/pg_common.tcl 3b27542224db1e713ae387459b5d117c836a5f6e328846922993b6d2b7640d9f
|
||||
F test/pragma.test 50b91bedea9324d3ab48e793f908ee7d2c7dcf84bfa2281e792838be59641ec8
|
||||
F test/pragma2.test e5d5c176360c321344249354c0c16aec46214c9f
|
||||
@@ -1273,7 +1282,7 @@ F test/quick.test 1681febc928d686362d50057c642f77a02c62e57
|
||||
F test/quota-glob.test 32901e9eed6705d68ca3faee2a06b73b57cb3c26
|
||||
F test/quota.test bfb269ce81ea52f593f9648316cd5013d766dd2a
|
||||
F test/quota2.test 7dc12e08b11cbc4c16c9ba2aa2e040ea8d8ab4b8
|
||||
F test/quote.test 3f9238ab0e1db70dea89af9afa5859dbd759b0ce0a63da67d547553e2c316475
|
||||
F test/quote.test b8ddaba6b81dcf63bb31243219e28a2f96e04396adc50108cc7e5593019c3eb5
|
||||
F test/randexpr1.tcl 40dec52119ed3a2b8b2a773bce24b63a3a746459
|
||||
F test/randexpr1.test eda062a97e60f9c38ae8d806b03b0ddf23d796df
|
||||
F test/rbu.test 168573d353cd0fd10196b87b0caa322c144ef736
|
||||
@@ -1283,10 +1292,10 @@ F test/regexp1.test 497ea812f264d12b6198d6e50a76be4a1973a9d8
|
||||
F test/regexp2.test 40e894223b3d6672655481493f1be12012f2b33c
|
||||
F test/reindex.test cd9d6021729910ece82267b4f5e1b5ac2911a7566c43b43c176a6a4732e2118d
|
||||
F test/releasetest.tcl fb76d8fcc95ac29d6356cd9e52b726ab9e43a24082897618dfbcb7c2b0049153 x
|
||||
F test/releasetest_data.tcl b9cb30360759b80d92d4ea86b84ebfd8035b97f9078a482deb3cf9d0b2442655
|
||||
F test/releasetest_data.tcl 3d41ddb3f04f474ac9d925485da24ce6576ff0ebc4c7201c8a340bc09846c261
|
||||
F test/resetdb.test 8062cf10a09d8c048f8de7711e94571c38b38168db0e5877ba7561789e5eeb2b
|
||||
F test/resolver01.test f4022acafda7f4d40eca94dbf16bc5fc4ac30ceb
|
||||
F test/returning1.test 684e1c73d961422a7376c932fcdd6dacf02bad21d12f749cfe8c19991ef379f6
|
||||
F test/returning1.test 209b910c132cb2015bb1159f852c7124778004963c09095c42c3d2442110c56c
|
||||
F test/rollback.test 06680159bc6746d0f26276e339e3ae2f951c64812468308838e0a3362d911eaa
|
||||
F test/rollback2.test bc868d57899dc6972e2b4483faae0e03365a0556941474eec487ae21d8d38bb6
|
||||
F test/rollbackfault.test 0e646aeab8840c399cfbfa43daab46fd609cf04a
|
||||
@@ -1294,7 +1303,7 @@ F test/round1.test 768018b04522ca420b1aba8a24bd76091d269f3bce3902af3ec6ebcee41ab
|
||||
F test/rowallock.test 3f88ec6819489d0b2341c7a7528ae17c053ab7cc
|
||||
F test/rowhash.test 0bc1d31415e4575d10cacf31e1a66b5cc0f8be81
|
||||
F test/rowid.test bfbd7b97d9267660be3c8f28507c4ed7f205196b8877c0db42df347c2e8845e3
|
||||
F test/rowvalue.test 8964f95b253d3b5cc8dc1cfd0cdb7529bce3ecc6b6259e23c5f829f80f4d51cd
|
||||
F test/rowvalue.test b5436c767394a3f8fa5e7e474b2114ba430fdab34a5c8573c1b6256756534565
|
||||
F test/rowvalue2.test 060d238b7e5639a7c5630cb5e63e311b44efef2b
|
||||
F test/rowvalue3.test 3068f508753af69884b12125995f023da0dbb256
|
||||
F test/rowvalue4.test 02e35f7762371c2f57ebd856aa056eac56cb27ef7715a0bb31eac1895a745356
|
||||
@@ -1324,7 +1333,7 @@ F test/schema6.test e4bd1f23d368695eb9e7b51ef6e02ca0642ea2ab4a52579959826b5e7dce
|
||||
F test/schemafault.test 1936bceca55ac82c5efbcc9fc91a1933e45c8d1e1d106b9a7e56c972a5a2a51e
|
||||
F test/securedel.test 2f70b2449186a1921bd01ec9da407fbfa98c3a7a5521854c300c194b2ff09384
|
||||
F test/securedel2.test 2d54c28e46eb1fd6902089958b20b1b056c6f1c5
|
||||
F test/select1.test 0ed936740777f52858b6607f39ffac4b2b63b8fc7edf3ab2ebad3c3553ceecee
|
||||
F test/select1.test 3d23f66bf9ba77570acfe2ca5f1540ece17037cc64ab1a00efec9758ac29c268
|
||||
F test/select2.test 352480e0e9c66eda9c3044e412abdf5be0215b56
|
||||
F test/select3.test c49fbb758903f3718e2de5aa4655eda4838131cbea24a86db908f8b6889aa68c
|
||||
F test/select4.test e8a2502e3623f3058871030599a48abb35789d2244d5b380ecf3696873fdd4a4
|
||||
@@ -1439,7 +1448,7 @@ F test/temptable.test d2c9b87a54147161bcd1822e30c1d1cd891e5b30
|
||||
F test/temptable2.test d2940417496e2b9548e01d09990763fbe88c316504033256d51493e1f1a5ce6a
|
||||
F test/temptable3.test d11a0974e52b347e45ee54ef1923c91ed91e4637
|
||||
F test/temptrigger.test 38f0ca479b1822d3117069e014daabcaacefffcc
|
||||
F test/tester.tcl e5e4f5707fbf791ff8e06438fd0d4d71fe4c1d48753b7dd415efe72e853ef877
|
||||
F test/tester.tcl 19d2a19a6dd55a2b4e2b943963959a05a2c088495dd5f5274b04e0494ce86d66
|
||||
F test/thread001.test b61a29dd87cf669f5f6ac96124a7c97d71b0c80d9012746072055877055cf9ef
|
||||
F test/thread002.test e630504f8a06c00bf8bbe68528774dd96aeb2e58
|
||||
F test/thread003.test ee4c9efc3b86a6a2767516a37bd64251272560a7
|
||||
@@ -1632,7 +1641,7 @@ F test/tt3_vacuum.c 1753f45917699c9c1f66b64c717a717c9379f776
|
||||
F test/types.test bf816ce73c7dfcfe26b700c19f97ef4050d194ff
|
||||
F test/types2.test 1aeb81976841a91eef292723649b5c4fe3bc3cac
|
||||
F test/types3.test 99e009491a54f4dc02c06bdbc0c5eea56ae3e25a
|
||||
F test/unionall.test ca6f612930c79e30f41f804dff4cce949b61347930847642e333ecd5d79f5964
|
||||
F test/unionall.test 369dac51f4e7b94442b054d3d7f2e6755cd6994274718228878e3bd47c425f6d
|
||||
F test/unionall2.test c9a62db63350bcbce3a7bec50dd8c5410f08be33f8af435473756286d4657215
|
||||
F test/unionallfault.test 652bfbb630e6c43135965dc1e8f0a9a791da83aec885d626a632fe1909c56f73
|
||||
F test/unionvtab.test e1704ab1b4c1bb3ffc9da4681f8e85a0b909fd80b937984fc94b27415ac8e5a4
|
||||
@@ -1668,7 +1677,7 @@ F test/vacuum6.test d3173a54edc81d13d99e4cf4972232b3cbb52f1d56ed48c3a939ef4e751c
|
||||
F test/vacuummem.test 7b42abb3208bd82dd23a7536588396f295a314f2
|
||||
F test/varint.test bbce22cda8fc4d135bcc2b589574be8410614e62
|
||||
F test/veryquick.test 57ab846bacf7b90cf4e9a672721ea5c5b669b661
|
||||
F test/view.test fd48eddb32a35a98c3de70062ebac66ebf4a2bbfc75a1cc1109159ef8bfc47a9
|
||||
F test/view.test ea88361d5e9bc8eabf9f573185a16aea73a885be9b6c6a95ae84908913416a80
|
||||
F test/vtab1.test c5d9e90ed02bcacd776dcbb7360199d290f7f53c26b484ddece543060c54319f
|
||||
F test/vtab2.test 14d4ab26cee13ba6cf5c5601b158e4f57552d3b055cdd9406cf7f711e9c84082
|
||||
F test/vtab3.test b45f47d20f225ccc9c28dc915d92740c2dee311e
|
||||
@@ -1691,7 +1700,7 @@ F test/vtab_alter.test 736e66fb5ec7b4fee58229aa3ada2f27ec58bc58c00edae4836890c37
|
||||
F test/vtab_err.test dcc8b7b9cb67522b3fe7a272c73856829dae4ab7fdb30399aea1b6981bda2b65
|
||||
F test/vtab_shared.test 5253bff2355a9a3f014c15337da7e177ab0ef8ad
|
||||
F test/vtabdrop.test 65d4cf6722972e5499bdaf0c0d70ee3b8133944a4e4bc31862563f32a7edca12
|
||||
F test/wal.test 16180bc4becda176428ad02eaea437b4b8f5ae099314de443a4e12b2dcc007a2
|
||||
F test/wal.test b7cc6984709f54afbf8441747ced1f646af120bf0c1b1d847bfa39306fbea089
|
||||
F test/wal2.test 31f6e2c404b9f2cdf9ca19b105a1742fdc19653c2c936da39e3658c617524046
|
||||
F test/wal3.test 2a93004bc0fb2b5c29888964024695bade278ab2
|
||||
F test/wal4.test 4744e155cd6299c6bd99d3eab1c82f77db9cdb3c
|
||||
@@ -1773,15 +1782,17 @@ F test/window8.tcl f2711aa3571e4e6b0dad98db8d95fd6cb8d9db0c92bbdf535f153b07606a1
|
||||
F test/window8.test c4331b27a6f66d69fa8f8bab10cc731db1a81d293ae108a68f7c3487fa94e65b
|
||||
F test/window9.test 4d8c875b73febdbac9b8f2b52ec132b98f48261cdafd6b08db62bc6d8ff913fc
|
||||
F test/windowA.test 6d63dc1260daa17141a55007600581778523a8b420629f1282d2acfc36af23be
|
||||
F test/windowB.test 7a983ea1cc1cf72be7f378e4b32f6cb2d73014c5cd8b25aaee825164cd4269e5
|
||||
F test/windowB.test 6e601f8178ba8ba28b2f19e74fe613815084bb4a8d2ad942defc7d42e191e521
|
||||
F test/windowerr.tcl f5acd6fbc210d7b5546c0e879d157888455cd4a17a1d3f28f07c1c8a387019e0
|
||||
F test/windowerr.test a8b752402109c15aa1c5efe1b93ccb0ce1ef84fa964ae1cd6684dd0b3cc1819b
|
||||
F test/windowfault.test 72375ae71031eabf96bc88d0af128c8628a091ddc99b5a394e848b3df5fc17ad
|
||||
F test/windowfault.test d543d46571b32d19f198cb04b6505747fabf3cc369970daae47074ee793612be
|
||||
F test/windowpushd.test 5b9c114e8173c3addacf58a0fcd941437b14649f2033700184479a13f188ad00
|
||||
F test/with1.test 780be387f01e290e768bdfd1827280f9e37ba37223eb4736aba386864fac5a94
|
||||
F test/with2.test e0030e2f0267a910d6c0e4f46f2dfe941c1cc0d4f659ba69b3597728e7e8f1ab
|
||||
F test/with3.test a261f0ea225c4af0ce6447f1157bb603959b2a665f14a03951c2883d2ef1c0f0
|
||||
F test/with3.test 85e059bf4c2ef5626411ee59f399b4bb4b4a0f009bcb7db86f254e570ed11831
|
||||
F test/with4.test 257be66c0c67fee1defbbac0f685c3465e2cad037f21ce65f23f86084f198205
|
||||
F test/with5.test 6248213c41fab36290b5b73aa3f937309dfba337004d9d8434c3fabc8c7d4be8
|
||||
F test/with6.test 3001b59179cbdc26a8c67ff8f46944e3141fdece9ab064c49bbf08459b67b207
|
||||
F test/withM.test 693b61765f2b387b5e3e24a4536e2e82de15ff64
|
||||
F test/without_rowid1.test e4034c0849ccc2e8bb749c69f15bd69bb9fcf8fe77e8d17ce02369604242fe83
|
||||
F test/without_rowid2.test af260339f79d13cb220288b67cd287fbcf81ad99
|
||||
@@ -1827,7 +1838,7 @@ F tool/max-limits.c cbb635fbb37ae4d05f240bfb5b5270bb63c54439
|
||||
F tool/mkautoconfamal.sh f62353eb6c06ab264da027fd4507d09914433dbdcab9cb011cdc18016f1ab3b8
|
||||
F tool/mkccode.tcl 86463e68ce9c15d3041610fedd285ce32a5cf7a58fc88b3202b8b76837650dbe x
|
||||
F tool/mkctimec.tcl dd183b73ae1c28249669741c250525f0407e579a70482371668fd5f130d9feb3
|
||||
F tool/mkkeywordhash.c 750f25aef0e23f8e3367af6d824fbf5ed7d3e285f27cea91aa2dd72c367630eb
|
||||
F tool/mkkeywordhash.c 08b6e4d7a482a7f37a9a0032e7ba968e26624a027b6b2e9ba589be6f5e3d8c2c
|
||||
F tool/mkmsvcmin.tcl 6ecab9fe22c2c8de4d82d4c46797bda3d2deac8e763885f5a38d0c44a895ab33
|
||||
F tool/mkopcodec.tcl d1b6362bd3aa80d5520d4d6f3765badf01f6c43c
|
||||
F tool/mkopcodeh.tcl 352a4319c0ad869eb26442bf7c3b015aa15594c21f1cce5a6420dbe999367c21
|
||||
@@ -1864,7 +1875,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
|
||||
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
|
||||
F tool/speedtest8inst1.c 7ce07da76b5e745783e703a834417d725b7d45fd
|
||||
F tool/split-sqlite3c.tcl 3efcd4240b738f6bb2b5af0aea7e1e0ef9bc1c61654f645076cec883030b710c
|
||||
F tool/sqldiff.c 4151108387cb56c08906e5ac8d6a353dcfe8fc6014eeded0f0910e2230ea0f5b
|
||||
F tool/sqldiff.c 21226ef092ec1e543b237c5d3d2d32d344a60f2437eadfea04f65b348fbd00e4
|
||||
F tool/sqlite3_analyzer.c.in 7eeaae8b0d7577662acaabbb11107af0659d1b41bc1dfdd4d91422de27127968
|
||||
F tool/sqltclsh.c.in 1bcc2e9da58fadf17b0bf6a50e68c1159e602ce057210b655d50bad5aaaef898
|
||||
F tool/sqltclsh.tcl 862f4cf1418df5e1315b5db3b5ebe88969e2a784525af5fbf9596592f14ed848
|
||||
@@ -1899,7 +1910,9 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||
P b84c7f60c2e1e7debf9f50622087f87d60c6870061d61e14e59cc1ba0775ee92
|
||||
R 02daf4bf169cb22bac4b88e2c2565d05
|
||||
P 0ed7eb9115510511f13dca715bb2b178580648517d8d30436a992d70a2e85ac1
|
||||
R 6b9cbc5338ab96ec85af6f269ca8689c
|
||||
T +sym-release *
|
||||
T +sym-version-3.35.2 *
|
||||
U drh
|
||||
Z cfd272038413f78f81e2c24e00e99d6f
|
||||
Z df8a52cb5f4a5da779c9bf4ff3cf1b0f
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
a10c5a2503ff2998f6ee40f721aab8c9579052e535dc141bd57d10551eaea387
|
||||
ea80f3002f4120f5dcee76e8779dfdc88e1e096c5cdd06904c20fd26d50c3827
|
||||
+270
-51
@@ -49,15 +49,22 @@ static int isAlterableTable(Parse *pParse, Table *pTab){
|
||||
** statement to ensure that the operation has not rendered any schema
|
||||
** objects unusable.
|
||||
*/
|
||||
static void renameTestSchema(Parse *pParse, const char *zDb, int bTemp){
|
||||
static void renameTestSchema(
|
||||
Parse *pParse, /* Parse context */
|
||||
const char *zDb, /* Name of db to verify schema of */
|
||||
int bTemp, /* True if this is the temp db */
|
||||
const char *zWhen, /* "when" part of error message */
|
||||
const char *zDropColumn /* Name of column being dropped */
|
||||
){
|
||||
pParse->colNamesSet = 1;
|
||||
sqlite3NestedParse(pParse,
|
||||
"SELECT 1 "
|
||||
"FROM \"%w\"." DFLT_SCHEMA_TABLE " "
|
||||
"WHERE name NOT LIKE 'sqliteX_%%' ESCAPE 'X'"
|
||||
" AND sql NOT LIKE 'create virtual%%'"
|
||||
" AND sqlite_rename_test(%Q, sql, type, name, %d)=NULL ",
|
||||
" AND sqlite_rename_test(%Q, sql, type, name, %d, %Q, %Q)=NULL ",
|
||||
zDb,
|
||||
zDb, bTemp
|
||||
zDb, bTemp, zWhen, zDropColumn
|
||||
);
|
||||
|
||||
if( bTemp==0 ){
|
||||
@@ -66,8 +73,8 @@ static void renameTestSchema(Parse *pParse, const char *zDb, int bTemp){
|
||||
"FROM temp." DFLT_SCHEMA_TABLE " "
|
||||
"WHERE name NOT LIKE 'sqliteX_%%' ESCAPE 'X'"
|
||||
" AND sql NOT LIKE 'create virtual%%'"
|
||||
" AND sqlite_rename_test(%Q, sql, type, name, 1)=NULL ",
|
||||
zDb
|
||||
" AND sqlite_rename_test(%Q, sql, type, name, 1, %Q, %Q)=NULL ",
|
||||
zDb, zWhen, zDropColumn
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -76,12 +83,12 @@ static void renameTestSchema(Parse *pParse, const char *zDb, int bTemp){
|
||||
** Generate code to reload the schema for database iDb. And, if iDb!=1, for
|
||||
** the temp database as well.
|
||||
*/
|
||||
static void renameReloadSchema(Parse *pParse, int iDb){
|
||||
static void renameReloadSchema(Parse *pParse, int iDb, u16 p5){
|
||||
Vdbe *v = pParse->pVdbe;
|
||||
if( v ){
|
||||
sqlite3ChangeCookie(pParse, iDb);
|
||||
sqlite3VdbeAddParseSchemaOp(pParse->pVdbe, iDb, 0);
|
||||
if( iDb!=1 ) sqlite3VdbeAddParseSchemaOp(pParse->pVdbe, 1, 0);
|
||||
sqlite3VdbeAddParseSchemaOp(pParse->pVdbe, iDb, 0, p5);
|
||||
if( iDb!=1 ) sqlite3VdbeAddParseSchemaOp(pParse->pVdbe, 1, 0, p5);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -230,7 +237,7 @@ void sqlite3AlterRenameTable(
|
||||
"sql = sqlite_rename_table(%Q, type, name, sql, %Q, %Q, 1), "
|
||||
"tbl_name = "
|
||||
"CASE WHEN tbl_name=%Q COLLATE nocase AND "
|
||||
" sqlite_rename_test(%Q, sql, type, name, 1) "
|
||||
" sqlite_rename_test(%Q, sql, type, name, 1, 'after rename',0) "
|
||||
"THEN %Q ELSE tbl_name END "
|
||||
"WHERE type IN ('view', 'trigger')"
|
||||
, zDb, zTabName, zName, zTabName, zDb, zName);
|
||||
@@ -249,8 +256,8 @@ void sqlite3AlterRenameTable(
|
||||
}
|
||||
#endif
|
||||
|
||||
renameReloadSchema(pParse, iDb);
|
||||
renameTestSchema(pParse, zDb, iDb==1);
|
||||
renameReloadSchema(pParse, iDb, INITFLAG_AlterRename);
|
||||
renameTestSchema(pParse, zDb, iDb==1, "after rename", 0);
|
||||
|
||||
exit_rename_table:
|
||||
sqlite3SrcListDelete(db, pSrc);
|
||||
@@ -412,7 +419,7 @@ void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
|
||||
}
|
||||
|
||||
/* Reload the table definition */
|
||||
renameReloadSchema(pParse, iDb);
|
||||
renameReloadSchema(pParse, iDb, INITFLAG_AlterRename);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -512,7 +519,7 @@ exit_begin_add_column:
|
||||
** Or, if pTab is not a view or virtual table, zero is returned.
|
||||
*/
|
||||
#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE)
|
||||
static int isRealTable(Parse *pParse, Table *pTab){
|
||||
static int isRealTable(Parse *pParse, Table *pTab, int bDrop){
|
||||
const char *zType = 0;
|
||||
#ifndef SQLITE_OMIT_VIEW
|
||||
if( pTab->pSelect ){
|
||||
@@ -525,15 +532,16 @@ static int isRealTable(Parse *pParse, Table *pTab){
|
||||
}
|
||||
#endif
|
||||
if( zType ){
|
||||
sqlite3ErrorMsg(
|
||||
pParse, "cannot rename columns of %s \"%s\"", zType, pTab->zName
|
||||
sqlite3ErrorMsg(pParse, "cannot %s %s \"%s\"",
|
||||
(bDrop ? "drop column from" : "rename columns of"),
|
||||
zType, pTab->zName
|
||||
);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#else /* !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE) */
|
||||
# define isRealTable(x,y) (0)
|
||||
# define isRealTable(x,y,z) (0)
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -562,7 +570,7 @@ void sqlite3AlterRenameColumn(
|
||||
|
||||
/* Cannot alter a system table */
|
||||
if( SQLITE_OK!=isAlterableTable(pParse, pTab) ) goto exit_rename_column;
|
||||
if( SQLITE_OK!=isRealTable(pParse, pTab) ) goto exit_rename_column;
|
||||
if( SQLITE_OK!=isRealTable(pParse, pTab, 0) ) goto exit_rename_column;
|
||||
|
||||
/* Which schema holds the table to be altered */
|
||||
iSchema = sqlite3SchemaToIndex(db, pTab->pSchema);
|
||||
@@ -616,8 +624,8 @@ void sqlite3AlterRenameColumn(
|
||||
);
|
||||
|
||||
/* Drop and reload the database schema. */
|
||||
renameReloadSchema(pParse, iSchema);
|
||||
renameTestSchema(pParse, zDb, iSchema==1);
|
||||
renameReloadSchema(pParse, iSchema, INITFLAG_AlterRename);
|
||||
renameTestSchema(pParse, zDb, iSchema==1, "after rename", 0);
|
||||
|
||||
exit_rename_column:
|
||||
sqlite3SrcListDelete(db, pSrc);
|
||||
@@ -869,23 +877,33 @@ static void renameTokenFree(sqlite3 *db, RenameToken *pToken){
|
||||
|
||||
/*
|
||||
** Search the Parse object passed as the first argument for a RenameToken
|
||||
** object associated with parse tree element pPtr. If found, remove it
|
||||
** from the Parse object and add it to the list maintained by the
|
||||
** RenameCtx object passed as the second argument.
|
||||
** object associated with parse tree element pPtr. If found, return a pointer
|
||||
** to it. Otherwise, return NULL.
|
||||
**
|
||||
** If the second argument passed to this function is not NULL and a matching
|
||||
** RenameToken object is found, remove it from the Parse object and add it to
|
||||
** the list maintained by the RenameCtx object.
|
||||
*/
|
||||
static void renameTokenFind(Parse *pParse, struct RenameCtx *pCtx, void *pPtr){
|
||||
static RenameToken *renameTokenFind(
|
||||
Parse *pParse,
|
||||
struct RenameCtx *pCtx,
|
||||
void *pPtr
|
||||
){
|
||||
RenameToken **pp;
|
||||
assert( pPtr!=0 );
|
||||
for(pp=&pParse->pRename; (*pp); pp=&(*pp)->pNext){
|
||||
if( (*pp)->p==pPtr ){
|
||||
RenameToken *pToken = *pp;
|
||||
*pp = pToken->pNext;
|
||||
pToken->pNext = pCtx->pList;
|
||||
pCtx->pList = pToken;
|
||||
pCtx->nList++;
|
||||
break;
|
||||
if( pCtx ){
|
||||
*pp = pToken->pNext;
|
||||
pToken->pNext = pCtx->pList;
|
||||
pCtx->pList = pToken;
|
||||
pCtx->nList++;
|
||||
}
|
||||
return pToken;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -956,7 +974,7 @@ static RenameToken *renameColumnTokenNext(RenameCtx *pCtx){
|
||||
*/
|
||||
static void renameColumnParseError(
|
||||
sqlite3_context *pCtx,
|
||||
int bPost,
|
||||
const char *zWhen,
|
||||
sqlite3_value *pType,
|
||||
sqlite3_value *pObject,
|
||||
Parse *pParse
|
||||
@@ -965,8 +983,8 @@ static void renameColumnParseError(
|
||||
const char *zN = (const char*)sqlite3_value_text(pObject);
|
||||
char *zErr;
|
||||
|
||||
zErr = sqlite3_mprintf("error in %s %s%s: %s",
|
||||
zT, zN, (bPost ? " after rename" : ""),
|
||||
zErr = sqlite3_mprintf("error in %s %s%s%s: %s",
|
||||
zT, zN, (zWhen[0] ? " " : ""), zWhen,
|
||||
pParse->zErrMsg
|
||||
);
|
||||
sqlite3_result_error(pCtx, zErr, -1);
|
||||
@@ -1031,12 +1049,17 @@ static int renameParseSql(
|
||||
const char *zDb, /* Name of schema SQL belongs to */
|
||||
sqlite3 *db, /* Database handle */
|
||||
const char *zSql, /* SQL to parse */
|
||||
int bTemp /* True if SQL is from temp schema */
|
||||
int bTemp, /* True if SQL is from temp schema */
|
||||
const char *zDropColumn /* Name of column being dropped */
|
||||
){
|
||||
int rc;
|
||||
char *zErr = 0;
|
||||
|
||||
db->init.iDb = bTemp ? 1 : sqlite3FindDbName(db, zDb);
|
||||
if( zDropColumn ){
|
||||
db->init.bDropColumn = 1;
|
||||
db->init.azInit = (char**)&zDropColumn;
|
||||
}
|
||||
|
||||
/* Parse the SQL statement passed as the first argument. If no error
|
||||
** occurs and the parse does not result in a new table, index or
|
||||
@@ -1045,7 +1068,7 @@ static int renameParseSql(
|
||||
p->eParseMode = PARSE_MODE_RENAME;
|
||||
p->db = db;
|
||||
p->nQueryLoop = 1;
|
||||
rc = sqlite3RunParser(p, zSql, &zErr);
|
||||
rc = zSql ? sqlite3RunParser(p, zSql, &zErr) : SQLITE_NOMEM;
|
||||
assert( p->zErrMsg==0 );
|
||||
assert( rc!=SQLITE_OK || zErr==0 );
|
||||
p->zErrMsg = zErr;
|
||||
@@ -1069,6 +1092,7 @@ static int renameParseSql(
|
||||
#endif
|
||||
|
||||
db->init.iDb = 0;
|
||||
db->init.bDropColumn = 0;
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -1198,7 +1222,7 @@ static int renameResolveTrigger(Parse *pParse){
|
||||
if( pSrc ){
|
||||
int i;
|
||||
for(i=0; i<pSrc->nSrc && rc==SQLITE_OK; i++){
|
||||
struct SrcList_item *p = &pSrc->a[i];
|
||||
SrcItem *p = &pSrc->a[i];
|
||||
p->iCursor = pParse->nTab++;
|
||||
if( p->pSelect ){
|
||||
sqlite3SelectPrep(pParse, p->pSelect, 0);
|
||||
@@ -1224,9 +1248,8 @@ static int renameResolveTrigger(Parse *pParse){
|
||||
rc = sqlite3ResolveExprListNames(&sNC, pStep->pExprList);
|
||||
}
|
||||
assert( !pStep->pUpsert || (!pStep->pWhere && !pStep->pExprList) );
|
||||
if( pStep->pUpsert ){
|
||||
if( pStep->pUpsert && rc==SQLITE_OK ){
|
||||
Upsert *pUpsert = pStep->pUpsert;
|
||||
assert( rc==SQLITE_OK );
|
||||
pUpsert->pUpsertSrc = pSrc;
|
||||
sNC.uNC.pUpsert = pUpsert;
|
||||
sNC.ncFlags = NC_UUpsert;
|
||||
@@ -1371,7 +1394,7 @@ static void renameColumnFunc(
|
||||
#ifndef SQLITE_OMIT_AUTHORIZATION
|
||||
db->xAuth = 0;
|
||||
#endif
|
||||
rc = renameParseSql(&sParse, zDb, db, zSql, bTemp);
|
||||
rc = renameParseSql(&sParse, zDb, db, zSql, bTemp, 0);
|
||||
|
||||
/* Find tokens that need to be replaced. */
|
||||
memset(&sWalker, 0, sizeof(Walker));
|
||||
@@ -1413,12 +1436,12 @@ static void renameColumnFunc(
|
||||
for(pIdx=sParse.pNewIndex; pIdx; pIdx=pIdx->pNext){
|
||||
sqlite3WalkExprList(&sWalker, pIdx->aColExpr);
|
||||
}
|
||||
}
|
||||
#ifndef SQLITE_OMIT_GENERATED_COLUMNS
|
||||
for(i=0; i<sParse.pNewTable->nCol; i++){
|
||||
sqlite3WalkExpr(&sWalker, sParse.pNewTable->aCol[i].pDflt);
|
||||
}
|
||||
for(i=0; i<sParse.pNewTable->nCol; i++){
|
||||
sqlite3WalkExpr(&sWalker, sParse.pNewTable->aCol[i].pDflt);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
for(pFKey=sParse.pNewTable->pFKey; pFKey; pFKey=pFKey->pNextFrom){
|
||||
for(i=0; i<pFKey->nCol; i++){
|
||||
@@ -1472,7 +1495,7 @@ static void renameColumnFunc(
|
||||
renameColumnFunc_done:
|
||||
if( rc!=SQLITE_OK ){
|
||||
if( sParse.zErrMsg ){
|
||||
renameColumnParseError(context, 0, argv[1], argv[2], &sParse);
|
||||
renameColumnParseError(context, "", argv[1], argv[2], &sParse);
|
||||
}else{
|
||||
sqlite3_result_error_code(context, rc);
|
||||
}
|
||||
@@ -1510,7 +1533,7 @@ static int renameTableSelectCb(Walker *pWalker, Select *pSelect){
|
||||
return WRC_Abort;
|
||||
}
|
||||
for(i=0; i<pSrc->nSrc; i++){
|
||||
struct SrcList_item *pItem = &pSrc->a[i];
|
||||
SrcItem *pItem = &pSrc->a[i];
|
||||
if( pItem->pTab==p->pTab ){
|
||||
renameTokenFind(pWalker->pParse, p, pItem->zName);
|
||||
}
|
||||
@@ -1575,7 +1598,7 @@ static void renameTableFunc(
|
||||
sWalker.xSelectCallback = renameTableSelectCb;
|
||||
sWalker.u.pRename = &sCtx;
|
||||
|
||||
rc = renameParseSql(&sParse, zDb, db, zInput, bTemp);
|
||||
rc = renameParseSql(&sParse, zDb, db, zInput, bTemp, 0);
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
int isLegacy = (db->flags & SQLITE_LegacyAlter);
|
||||
@@ -1661,7 +1684,7 @@ static void renameTableFunc(
|
||||
}
|
||||
if( rc!=SQLITE_OK ){
|
||||
if( sParse.zErrMsg ){
|
||||
renameColumnParseError(context, 0, argv[1], argv[2], &sParse);
|
||||
renameColumnParseError(context, "", argv[1], argv[2], &sParse);
|
||||
}else{
|
||||
sqlite3_result_error_code(context, rc);
|
||||
}
|
||||
@@ -1690,6 +1713,8 @@ static void renameTableFunc(
|
||||
** 2: Object type ("view", "table", "trigger" or "index").
|
||||
** 3: Object name.
|
||||
** 4: True if object is from temp schema.
|
||||
** 5: "when" part of error message.
|
||||
** 6: Name of column being dropped, or NULL.
|
||||
**
|
||||
** Unless it finds an error, this function normally returns NULL. However, it
|
||||
** returns integer value 1 if:
|
||||
@@ -1707,6 +1732,8 @@ static void renameTableTest(
|
||||
char const *zInput = (const char*)sqlite3_value_text(argv[1]);
|
||||
int bTemp = sqlite3_value_int(argv[4]);
|
||||
int isLegacy = (db->flags & SQLITE_LegacyAlter);
|
||||
char const *zWhen = (const char*)sqlite3_value_text(argv[5]);
|
||||
char const *zDropColumn = (const char*)sqlite3_value_text(argv[6]);
|
||||
|
||||
#ifndef SQLITE_OMIT_AUTHORIZATION
|
||||
sqlite3_xauth xAuth = db->xAuth;
|
||||
@@ -1717,7 +1744,7 @@ static void renameTableTest(
|
||||
if( zDb && zInput ){
|
||||
int rc;
|
||||
Parse sParse;
|
||||
rc = renameParseSql(&sParse, zDb, db, zInput, bTemp);
|
||||
rc = renameParseSql(&sParse, zDb, db, zInput, bTemp, zDropColumn);
|
||||
if( rc==SQLITE_OK ){
|
||||
if( isLegacy==0 && sParse.pNewTable && sParse.pNewTable->pSelect ){
|
||||
NameContext sNC;
|
||||
@@ -1739,8 +1766,8 @@ static void renameTableTest(
|
||||
}
|
||||
}
|
||||
|
||||
if( rc!=SQLITE_OK ){
|
||||
renameColumnParseError(context, 1, argv[2], argv[3], &sParse);
|
||||
if( rc!=SQLITE_OK && zWhen ){
|
||||
renameColumnParseError(context, zWhen, argv[2], argv[3],&sParse);
|
||||
}
|
||||
renameParseCleanup(&sParse);
|
||||
}
|
||||
@@ -1750,14 +1777,206 @@ static void renameTableTest(
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
** The implementation of internal UDF sqlite_drop_column().
|
||||
**
|
||||
** Arguments:
|
||||
**
|
||||
** argv[0]: An integer - the index of the schema containing the table
|
||||
** argv[1]: CREATE TABLE statement to modify.
|
||||
** argv[2]: An integer - the index of the column to remove.
|
||||
**
|
||||
** The value returned is a string containing the CREATE TABLE statement
|
||||
** with column argv[2] removed.
|
||||
*/
|
||||
static void dropColumnFunc(
|
||||
sqlite3_context *context,
|
||||
int NotUsed,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
sqlite3 *db = sqlite3_context_db_handle(context);
|
||||
int iSchema = sqlite3_value_int(argv[0]);
|
||||
const char *zSql = (const char*)sqlite3_value_text(argv[1]);
|
||||
int iCol = sqlite3_value_int(argv[2]);
|
||||
const char *zDb = db->aDb[iSchema].zDbSName;
|
||||
int rc;
|
||||
Parse sParse;
|
||||
RenameToken *pCol;
|
||||
Table *pTab;
|
||||
const char *zEnd;
|
||||
char *zNew = 0;
|
||||
|
||||
#ifndef SQLITE_OMIT_AUTHORIZATION
|
||||
sqlite3_xauth xAuth = db->xAuth;
|
||||
db->xAuth = 0;
|
||||
#endif
|
||||
|
||||
UNUSED_PARAMETER(NotUsed);
|
||||
rc = renameParseSql(&sParse, zDb, db, zSql, iSchema==1, 0);
|
||||
if( rc!=SQLITE_OK ) goto drop_column_done;
|
||||
pTab = sParse.pNewTable;
|
||||
if( pTab==0 || pTab->nCol==1 || iCol>=pTab->nCol ){
|
||||
/* This can happen if the sqlite_schema table is corrupt */
|
||||
rc = SQLITE_CORRUPT_BKPT;
|
||||
goto drop_column_done;
|
||||
}
|
||||
|
||||
pCol = renameTokenFind(&sParse, 0, (void*)pTab->aCol[iCol].zName);
|
||||
if( iCol<pTab->nCol-1 ){
|
||||
RenameToken *pEnd;
|
||||
pEnd = renameTokenFind(&sParse, 0, (void*)pTab->aCol[iCol+1].zName);
|
||||
zEnd = (const char*)pEnd->t.z;
|
||||
}else{
|
||||
zEnd = (const char*)&zSql[pTab->addColOffset];
|
||||
while( ALWAYS(pCol->t.z[0]!=0) && pCol->t.z[0]!=',' ) pCol->t.z--;
|
||||
}
|
||||
|
||||
zNew = sqlite3MPrintf(db, "%.*s%s", pCol->t.z-zSql, zSql, zEnd);
|
||||
sqlite3_result_text(context, zNew, -1, SQLITE_TRANSIENT);
|
||||
sqlite3_free(zNew);
|
||||
|
||||
drop_column_done:
|
||||
renameParseCleanup(&sParse);
|
||||
#ifndef SQLITE_OMIT_AUTHORIZATION
|
||||
db->xAuth = xAuth;
|
||||
#endif
|
||||
if( rc!=SQLITE_OK ){
|
||||
sqlite3_result_error_code(context, rc);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** This function is called by the parser upon parsing an
|
||||
**
|
||||
** ALTER TABLE pSrc DROP COLUMN pName
|
||||
**
|
||||
** statement. Argument pSrc contains the possibly qualified name of the
|
||||
** table being edited, and token pName the name of the column to drop.
|
||||
*/
|
||||
void sqlite3AlterDropColumn(Parse *pParse, SrcList *pSrc, Token *pName){
|
||||
sqlite3 *db = pParse->db; /* Database handle */
|
||||
Table *pTab; /* Table to modify */
|
||||
int iDb; /* Index of db containing pTab in aDb[] */
|
||||
const char *zDb; /* Database containing pTab ("main" etc.) */
|
||||
char *zCol = 0; /* Name of column to drop */
|
||||
int iCol; /* Index of column zCol in pTab->aCol[] */
|
||||
|
||||
/* Look up the table being altered. */
|
||||
assert( pParse->pNewTable==0 );
|
||||
assert( sqlite3BtreeHoldsAllMutexes(db) );
|
||||
if( NEVER(db->mallocFailed) ) goto exit_drop_column;
|
||||
pTab = sqlite3LocateTableItem(pParse, 0, &pSrc->a[0]);
|
||||
if( !pTab ) goto exit_drop_column;
|
||||
|
||||
/* Make sure this is not an attempt to ALTER a view, virtual table or
|
||||
** system table. */
|
||||
if( SQLITE_OK!=isAlterableTable(pParse, pTab) ) goto exit_drop_column;
|
||||
if( SQLITE_OK!=isRealTable(pParse, pTab, 1) ) goto exit_drop_column;
|
||||
|
||||
/* Find the index of the column being dropped. */
|
||||
zCol = sqlite3NameFromToken(db, pName);
|
||||
if( zCol==0 ){
|
||||
assert( db->mallocFailed );
|
||||
goto exit_drop_column;
|
||||
}
|
||||
iCol = sqlite3ColumnIndex(pTab, zCol);
|
||||
if( iCol<0 ){
|
||||
sqlite3ErrorMsg(pParse, "no such column: \"%s\"", zCol);
|
||||
goto exit_drop_column;
|
||||
}
|
||||
|
||||
/* Do not allow the user to drop a PRIMARY KEY column or a column
|
||||
** constrained by a UNIQUE constraint. */
|
||||
if( pTab->aCol[iCol].colFlags & (COLFLAG_PRIMKEY|COLFLAG_UNIQUE) ){
|
||||
sqlite3ErrorMsg(pParse, "cannot drop %s column: \"%s\"",
|
||||
(pTab->aCol[iCol].colFlags&COLFLAG_PRIMKEY) ? "PRIMARY KEY" : "UNIQUE",
|
||||
zCol
|
||||
);
|
||||
goto exit_drop_column;
|
||||
}
|
||||
|
||||
/* Do not allow the number of columns to go to zero */
|
||||
if( pTab->nCol<=1 ){
|
||||
sqlite3ErrorMsg(pParse, "cannot drop column \"%s\": no other columns exist",zCol);
|
||||
goto exit_drop_column;
|
||||
}
|
||||
|
||||
/* Edit the sqlite_schema table */
|
||||
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
|
||||
assert( iDb>=0 );
|
||||
zDb = db->aDb[iDb].zDbSName;
|
||||
renameTestSchema(pParse, zDb, iDb==1, "", 0);
|
||||
sqlite3NestedParse(pParse,
|
||||
"UPDATE \"%w\"." DFLT_SCHEMA_TABLE " SET "
|
||||
"sql = sqlite_drop_column(%d, sql, %d) "
|
||||
"WHERE (type=='table' AND tbl_name=%Q COLLATE nocase)"
|
||||
, zDb, iDb, iCol, pTab->zName
|
||||
);
|
||||
|
||||
/* Drop and reload the database schema. */
|
||||
renameReloadSchema(pParse, iDb, INITFLAG_AlterDrop);
|
||||
renameTestSchema(pParse, zDb, iDb==1, "after drop column", zCol);
|
||||
|
||||
/* Edit rows of table on disk */
|
||||
if( pParse->nErr==0 && (pTab->aCol[iCol].colFlags & COLFLAG_VIRTUAL)==0 ){
|
||||
int i;
|
||||
int addr;
|
||||
int reg;
|
||||
int regRec;
|
||||
Index *pPk = 0;
|
||||
int nField = 0; /* Number of non-virtual columns after drop */
|
||||
int iCur;
|
||||
Vdbe *v = sqlite3GetVdbe(pParse);
|
||||
iCur = pParse->nTab++;
|
||||
sqlite3OpenTable(pParse, iCur, iDb, pTab, OP_OpenWrite);
|
||||
addr = sqlite3VdbeAddOp1(v, OP_Rewind, iCur); VdbeCoverage(v);
|
||||
reg = ++pParse->nMem;
|
||||
pParse->nMem += pTab->nCol;
|
||||
if( HasRowid(pTab) ){
|
||||
sqlite3VdbeAddOp2(v, OP_Rowid, iCur, reg);
|
||||
}else{
|
||||
pPk = sqlite3PrimaryKeyIndex(pTab);
|
||||
}
|
||||
for(i=0; i<pTab->nCol; i++){
|
||||
if( i!=iCol && (pTab->aCol[i].colFlags & COLFLAG_VIRTUAL)==0 ){
|
||||
int regOut;
|
||||
if( pPk ){
|
||||
int iPos = sqlite3TableColumnToIndex(pPk, i);
|
||||
int iColPos = sqlite3TableColumnToIndex(pPk, iCol);
|
||||
regOut = reg+1+iPos-(iPos>iColPos);
|
||||
}else{
|
||||
regOut = reg+1+nField;
|
||||
}
|
||||
sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, i, regOut);
|
||||
nField++;
|
||||
}
|
||||
}
|
||||
regRec = reg + pTab->nCol;
|
||||
sqlite3VdbeAddOp3(v, OP_MakeRecord, reg+1, nField, regRec);
|
||||
if( pPk ){
|
||||
sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iCur, regRec, reg+1, pPk->nKeyCol);
|
||||
}else{
|
||||
sqlite3VdbeAddOp3(v, OP_Insert, iCur, regRec, reg);
|
||||
}
|
||||
|
||||
sqlite3VdbeAddOp2(v, OP_Next, iCur, addr+1); VdbeCoverage(v);
|
||||
sqlite3VdbeJumpHere(v, addr);
|
||||
}
|
||||
|
||||
exit_drop_column:
|
||||
sqlite3DbFree(db, zCol);
|
||||
sqlite3SrcListDelete(db, pSrc);
|
||||
}
|
||||
|
||||
/*
|
||||
** Register built-in functions used to help implement ALTER TABLE
|
||||
*/
|
||||
void sqlite3AlterFunctions(void){
|
||||
static FuncDef aAlterTableFuncs[] = {
|
||||
INTERNAL_FUNCTION(sqlite_rename_column, 9, renameColumnFunc),
|
||||
INTERNAL_FUNCTION(sqlite_rename_table, 7, renameTableFunc),
|
||||
INTERNAL_FUNCTION(sqlite_rename_test, 5, renameTableTest),
|
||||
INTERNAL_FUNCTION(sqlite_rename_column, 9, renameColumnFunc),
|
||||
INTERNAL_FUNCTION(sqlite_rename_table, 7, renameTableFunc),
|
||||
INTERNAL_FUNCTION(sqlite_rename_test, 7, renameTableTest),
|
||||
INTERNAL_FUNCTION(sqlite_drop_column, 3, dropColumnFunc),
|
||||
};
|
||||
sqlite3InsertBuiltinFuncs(aAlterTableFuncs, ArraySize(aAlterTableFuncs));
|
||||
}
|
||||
|
||||
+1
-2
@@ -456,7 +456,7 @@ static int fixExprCb(Walker *p, Expr *pExpr){
|
||||
static int fixSelectCb(Walker *p, Select *pSelect){
|
||||
DbFixer *pFix = p->u.pFix;
|
||||
int i;
|
||||
struct SrcList_item *pItem;
|
||||
SrcItem *pItem;
|
||||
sqlite3 *db = pFix->pParse->db;
|
||||
int iDb = sqlite3FindDbName(db, pFix->zDb);
|
||||
SrcList *pList = pSelect->pSrc;
|
||||
@@ -480,7 +480,6 @@ static int fixSelectCb(Walker *p, Select *pSelect){
|
||||
#endif
|
||||
}
|
||||
if( pSelect->pWith ){
|
||||
int i;
|
||||
for(i=0; i<pSelect->pWith->nCte; i++){
|
||||
if( sqlite3WalkSelect(p, pSelect->pWith->a[i].pSelect) ){
|
||||
return WRC_Abort;
|
||||
|
||||
+5
-6
@@ -143,7 +143,6 @@ void sqlite3AuthRead(
|
||||
Schema *pSchema, /* The schema of the expression */
|
||||
SrcList *pTabList /* All table that pExpr might refer to */
|
||||
){
|
||||
sqlite3 *db = pParse->db;
|
||||
Table *pTab = 0; /* The table being read */
|
||||
const char *zCol; /* Name of the column of the table */
|
||||
int iSrc; /* Index in pTabList->a[] of table being read */
|
||||
@@ -151,8 +150,8 @@ void sqlite3AuthRead(
|
||||
int iCol; /* Index of column in table */
|
||||
|
||||
assert( pExpr->op==TK_COLUMN || pExpr->op==TK_TRIGGER );
|
||||
assert( !IN_RENAME_OBJECT || db->xAuth==0 );
|
||||
if( db->xAuth==0 ) return;
|
||||
assert( !IN_RENAME_OBJECT );
|
||||
assert( pParse->db->xAuth!=0 );
|
||||
iDb = sqlite3SchemaToIndex(pParse->db, pSchema);
|
||||
if( iDb<0 ){
|
||||
/* An attempt to read a column out of a subquery or other
|
||||
@@ -164,7 +163,7 @@ void sqlite3AuthRead(
|
||||
pTab = pParse->pTriggerTab;
|
||||
}else{
|
||||
assert( pTabList );
|
||||
for(iSrc=0; ALWAYS(iSrc<pTabList->nSrc); iSrc++){
|
||||
for(iSrc=0; iSrc<pTabList->nSrc; iSrc++){
|
||||
if( pExpr->iTable==pTabList->a[iSrc].iCursor ){
|
||||
pTab = pTabList->a[iSrc].pTab;
|
||||
break;
|
||||
@@ -172,7 +171,7 @@ void sqlite3AuthRead(
|
||||
}
|
||||
}
|
||||
iCol = pExpr->iColumn;
|
||||
if( NEVER(pTab==0) ) return;
|
||||
if( pTab==0 ) return;
|
||||
|
||||
if( iCol>=0 ){
|
||||
assert( iCol<pTab->nCol );
|
||||
@@ -183,7 +182,7 @@ void sqlite3AuthRead(
|
||||
}else{
|
||||
zCol = "ROWID";
|
||||
}
|
||||
assert( iDb>=0 && iDb<db->nDb );
|
||||
assert( iDb>=0 && iDb<pParse->db->nDb );
|
||||
if( SQLITE_IGNORE==sqlite3AuthReadCol(pParse, pTab->zName, zCol, iDb) ){
|
||||
pExpr->op = TK_NULL;
|
||||
}
|
||||
|
||||
+7
-7
@@ -7637,7 +7637,9 @@ static int balance_nonroot(
|
||||
}
|
||||
pgno = get4byte(pRight);
|
||||
while( 1 ){
|
||||
rc = getAndInitPage(pBt, pgno, &apOld[i], 0, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = getAndInitPage(pBt, pgno, &apOld[i], 0, 0);
|
||||
}
|
||||
if( rc ){
|
||||
memset(apOld, 0, (i+1)*sizeof(MemPage*));
|
||||
goto balance_cleanup;
|
||||
@@ -7676,12 +7678,10 @@ static int balance_nonroot(
|
||||
if( pBt->btsFlags & BTS_FAST_SECURE ){
|
||||
int iOff;
|
||||
|
||||
/* If the following if() condition is not true, the db is corrupted.
|
||||
** The call to dropCell() below will detect this. */
|
||||
iOff = SQLITE_PTR_TO_INT(apDiv[i]) - SQLITE_PTR_TO_INT(pParent->aData);
|
||||
if( (iOff+szNew[i])>(int)pBt->usableSize ){
|
||||
rc = SQLITE_CORRUPT_BKPT;
|
||||
memset(apOld, 0, (i+1)*sizeof(MemPage*));
|
||||
goto balance_cleanup;
|
||||
}else{
|
||||
if( (iOff+szNew[i])<=(int)pBt->usableSize ){
|
||||
memcpy(&aOvflSpace[iOff], apDiv[i], szNew[i]);
|
||||
apDiv[i] = &aOvflSpace[apDiv[i]-pParent->aData];
|
||||
}
|
||||
@@ -8014,7 +8014,7 @@ static int balance_nonroot(
|
||||
aPgOrder[i] = aPgno[i] = apNew[i]->pgno;
|
||||
aPgFlags[i] = apNew[i]->pDbPage->flags;
|
||||
for(j=0; j<i; j++){
|
||||
if( aPgno[j]==aPgno[i] ){
|
||||
if( NEVER(aPgno[j]==aPgno[i]) ){
|
||||
/* This branch is taken if the set of sibling pages somehow contains
|
||||
** duplicate entries. This can happen if the database is corrupt.
|
||||
** It would be simpler to detect this as part of the loop below, but
|
||||
|
||||
+1
-1
@@ -262,7 +262,7 @@ int sqlite3BtreeDelete(BtCursor*, u8 flags);
|
||||
#define BTREE_SAVEPOSITION 0x02 /* Leave cursor pointing at NEXT or PREV */
|
||||
#define BTREE_AUXDELETE 0x04 /* not the primary delete operation */
|
||||
#define BTREE_APPEND 0x08 /* Insert is likely an append */
|
||||
#define BTREE_PREFORMAT 0x80 /* Insert is likely an append */
|
||||
#define BTREE_PREFORMAT 0x80 /* Inserted data is a preformated cell */
|
||||
|
||||
/* An instance of the BtreePayload object describes the content of a single
|
||||
** entry in either an index or table btree.
|
||||
|
||||
+126
-52
@@ -143,14 +143,36 @@ void sqlite3FinishCoding(Parse *pParse){
|
||||
/* Begin by generating some termination code at the end of the
|
||||
** vdbe program
|
||||
*/
|
||||
if( pParse->pVdbe==0 && db->init.busy ){
|
||||
pParse->rc = SQLITE_DONE;
|
||||
return;
|
||||
v = pParse->pVdbe;
|
||||
if( v==0 ){
|
||||
if( db->init.busy ){
|
||||
pParse->rc = SQLITE_DONE;
|
||||
return;
|
||||
}
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
if( v==0 ) pParse->rc = SQLITE_ERROR;
|
||||
}
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
assert( !pParse->isMultiWrite
|
||||
|| sqlite3VdbeAssertMayAbort(v, pParse->mayAbort));
|
||||
if( v ){
|
||||
if( pParse->bReturning ){
|
||||
Returning *pReturning = pParse->u1.pReturning;
|
||||
int addrRewind;
|
||||
int i;
|
||||
int reg;
|
||||
|
||||
addrRewind =
|
||||
sqlite3VdbeAddOp1(v, OP_Rewind, pReturning->iRetCur);
|
||||
VdbeCoverage(v);
|
||||
reg = pReturning->iRetReg;
|
||||
for(i=0; i<pReturning->nRetCol; i++){
|
||||
sqlite3VdbeAddOp3(v, OP_Column, pReturning->iRetCur, i, reg+i);
|
||||
}
|
||||
sqlite3VdbeAddOp2(v, OP_ResultRow, reg, i);
|
||||
sqlite3VdbeAddOp2(v, OP_Next, pReturning->iRetCur, addrRewind+1);
|
||||
VdbeCoverage(v);
|
||||
sqlite3VdbeJumpHere(v, addrRewind);
|
||||
}
|
||||
sqlite3VdbeAddOp0(v, OP_Halt);
|
||||
|
||||
#if SQLITE_USER_AUTHENTICATION
|
||||
@@ -228,12 +250,16 @@ void sqlite3FinishCoding(Parse *pParse){
|
||||
}
|
||||
}
|
||||
|
||||
if( pParse->bReturning ){
|
||||
Returning *pRet = pParse->u1.pReturning;
|
||||
sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pRet->iRetCur, pRet->nRetCol);
|
||||
}
|
||||
|
||||
/* Finally, jump back to the beginning of the executable code. */
|
||||
sqlite3VdbeGoto(v, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Get the VDBE program ready for execution
|
||||
*/
|
||||
if( v && pParse->nErr==0 && !db->mallocFailed ){
|
||||
@@ -452,7 +478,7 @@ Table *sqlite3LocateTable(
|
||||
Table *sqlite3LocateTableItem(
|
||||
Parse *pParse,
|
||||
u32 flags,
|
||||
struct SrcList_item *p
|
||||
SrcItem *p
|
||||
){
|
||||
const char *zDb;
|
||||
assert( p->pSchema==0 || p->zDatabase==0 );
|
||||
@@ -1210,7 +1236,8 @@ void sqlite3StartTable(
|
||||
}else
|
||||
#endif
|
||||
{
|
||||
pParse->addrCrTab =
|
||||
assert( !pParse->bReturning );
|
||||
pParse->u1.addrCrTab =
|
||||
sqlite3VdbeAddOp3(v, OP_CreateBtree, iDb, reg2, BTREE_INTKEY);
|
||||
}
|
||||
sqlite3OpenSchemaTable(pParse, iDb);
|
||||
@@ -1237,6 +1264,7 @@ begin_table_error:
|
||||
void sqlite3ColumnPropertiesFromName(Table *pTab, Column *pCol){
|
||||
if( sqlite3_strnicmp(pCol->zName, "__hidden__", 10)==0 ){
|
||||
pCol->colFlags |= COLFLAG_HIDDEN;
|
||||
if( pTab ) pTab->tabFlags |= TF_HasHidden;
|
||||
}else if( pTab && pCol!=pTab->aCol && (pCol[-1].colFlags & COLFLAG_HIDDEN) ){
|
||||
pTab->tabFlags |= TF_OOOHidden;
|
||||
}
|
||||
@@ -1281,17 +1309,23 @@ void sqlite3AddReturning(Parse *pParse, ExprList *pList){
|
||||
Returning *pRet;
|
||||
Hash *pHash;
|
||||
sqlite3 *db = pParse->db;
|
||||
assert( !pParse->bReturning );
|
||||
if( pParse->pNewTrigger ){
|
||||
sqlite3ErrorMsg(pParse, "cannot use RETURNING in a trigger");
|
||||
}else{
|
||||
assert( pParse->bReturning==0 );
|
||||
}
|
||||
pParse->bReturning = 1;
|
||||
pRet = sqlite3DbMallocZero(db, sizeof(*pRet));
|
||||
if( pRet==0 ){
|
||||
sqlite3ExprListDelete(db, pList);
|
||||
return;
|
||||
}
|
||||
pParse->u1.pReturning = pRet;
|
||||
pRet->pParse = pParse;
|
||||
pRet->pReturnEL = pList;
|
||||
sqlite3ParserAddCleanup(pParse,
|
||||
(void(*)(sqlite3*,void*))sqlite3DeleteReturning, pRet);
|
||||
testcase( pParse->earlyCleanup );
|
||||
if( db->mallocFailed ) return;
|
||||
pRet->retTrig.zName = RETURNING_TRIGGER_NAME;
|
||||
pRet->retTrig.op = TK_RETURNING;
|
||||
@@ -1301,12 +1335,9 @@ void sqlite3AddReturning(Parse *pParse, ExprList *pList){
|
||||
pRet->retTrig.step_list = &pRet->retTStep;
|
||||
pRet->retTStep.op = TK_RETURNING;
|
||||
pRet->retTStep.pTrig = &pRet->retTrig;
|
||||
pRet->retTStep.pSelect = &pRet->retSel;
|
||||
pRet->retSel.op = TK_ALL;
|
||||
pRet->retSel.pEList = pList;
|
||||
pRet->retSel.pSrc = (SrcList*)&pRet->retSrcList;
|
||||
pRet->retTStep.pExprList = pList;
|
||||
pHash = &(db->aDb[1].pSchema->trigHash);
|
||||
assert( sqlite3HashFind(pHash, RETURNING_TRIGGER_NAME)==0 );
|
||||
assert( sqlite3HashFind(pHash, RETURNING_TRIGGER_NAME)==0 || pParse->nErr );
|
||||
if( sqlite3HashInsert(pHash, RETURNING_TRIGGER_NAME, &pRet->retTrig)
|
||||
==&pRet->retTrig ){
|
||||
sqlite3OomFault(db);
|
||||
@@ -2144,9 +2175,10 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
|
||||
/* Convert the P3 operand of the OP_CreateBtree opcode from BTREE_INTKEY
|
||||
** into BTREE_BLOBKEY.
|
||||
*/
|
||||
if( pParse->addrCrTab ){
|
||||
assert( !pParse->bReturning );
|
||||
if( pParse->u1.addrCrTab ){
|
||||
assert( v );
|
||||
sqlite3VdbeChangeP3(v, pParse->addrCrTab, BTREE_BLOBKEY);
|
||||
sqlite3VdbeChangeP3(v, pParse->u1.addrCrTab, BTREE_BLOBKEY);
|
||||
}
|
||||
|
||||
/* Locate the PRIMARY KEY index. Or, if this table was originally
|
||||
@@ -2610,7 +2642,7 @@ void sqlite3EndTable(
|
||||
|
||||
/* Reparse everything to update our internal data structures */
|
||||
sqlite3VdbeAddParseSchemaOp(v, iDb,
|
||||
sqlite3MPrintf(db, "tbl_name='%q' AND type!='trigger'", p->zName));
|
||||
sqlite3MPrintf(db, "tbl_name='%q' AND type!='trigger'", p->zName),0);
|
||||
}
|
||||
|
||||
/* Add the table to the in-memory representation of the database.
|
||||
@@ -2627,20 +2659,17 @@ void sqlite3EndTable(
|
||||
}
|
||||
pParse->pNewTable = 0;
|
||||
db->mDbFlags |= DBFLAG_SchemaChange;
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_ALTERTABLE
|
||||
if( !p->pSelect ){
|
||||
const char *zName = (const char *)pParse->sNameToken.z;
|
||||
int nName;
|
||||
assert( !pSelect && pCons && pEnd );
|
||||
if( pCons->z==0 ){
|
||||
pCons = pEnd;
|
||||
}
|
||||
nName = (int)((const char *)pCons->z - zName);
|
||||
p->addColOffset = 13 + nName;
|
||||
if( !pSelect && !p->pSelect ){
|
||||
assert( pCons && pEnd );
|
||||
if( pCons->z==0 ){
|
||||
pCons = pEnd;
|
||||
}
|
||||
#endif
|
||||
p->addColOffset = 13 + (int)(pCons->z - pParse->sNameToken.z);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_VIEW
|
||||
@@ -2831,6 +2860,7 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
|
||||
assert( pTable->aCol==0 );
|
||||
pTable->nCol = pSelTab->nCol;
|
||||
pTable->aCol = pSelTab->aCol;
|
||||
pTable->tabFlags |= (pSelTab->tabFlags & COLFLAG_NOINSERT);
|
||||
pSelTab->nCol = 0;
|
||||
pSelTab->aCol = 0;
|
||||
assert( sqlite3SchemaMutexHeld(db, 0, pTable->pSchema) );
|
||||
@@ -4098,7 +4128,7 @@ void sqlite3CreateIndex(
|
||||
sqlite3RefillIndex(pParse, pIndex, iMem);
|
||||
sqlite3ChangeCookie(pParse, iDb);
|
||||
sqlite3VdbeAddParseSchemaOp(v, iDb,
|
||||
sqlite3MPrintf(db, "name='%q' AND type='index'", pIndex->zName));
|
||||
sqlite3MPrintf(db, "name='%q' AND type='index'", pIndex->zName), 0);
|
||||
sqlite3VdbeAddOp2(v, OP_Expire, 0, 1);
|
||||
}
|
||||
|
||||
@@ -4491,7 +4521,7 @@ SrcList *sqlite3SrcListAppend(
|
||||
Token *pTable, /* Table to append */
|
||||
Token *pDatabase /* Database of the table */
|
||||
){
|
||||
struct SrcList_item *pItem;
|
||||
SrcItem *pItem;
|
||||
sqlite3 *db;
|
||||
assert( pDatabase==0 || pTable!=0 ); /* Cannot have C without B */
|
||||
assert( pParse!=0 );
|
||||
@@ -4532,7 +4562,7 @@ SrcList *sqlite3SrcListAppend(
|
||||
*/
|
||||
void sqlite3SrcListAssignCursors(Parse *pParse, SrcList *pList){
|
||||
int i;
|
||||
struct SrcList_item *pItem;
|
||||
SrcItem *pItem;
|
||||
assert(pList || pParse->db->mallocFailed );
|
||||
if( pList ){
|
||||
for(i=0, pItem=pList->a; i<pList->nSrc; i++, pItem++){
|
||||
@@ -4550,7 +4580,7 @@ void sqlite3SrcListAssignCursors(Parse *pParse, SrcList *pList){
|
||||
*/
|
||||
void sqlite3SrcListDelete(sqlite3 *db, SrcList *pList){
|
||||
int i;
|
||||
struct SrcList_item *pItem;
|
||||
SrcItem *pItem;
|
||||
if( pList==0 ) return;
|
||||
for(pItem=pList->a, i=0; i<pList->nSrc; i++, pItem++){
|
||||
if( pItem->zDatabase ) sqlite3DbFreeNN(db, pItem->zDatabase);
|
||||
@@ -4592,7 +4622,7 @@ SrcList *sqlite3SrcListAppendFromTerm(
|
||||
Expr *pOn, /* The ON clause of a join */
|
||||
IdList *pUsing /* The USING clause of a join */
|
||||
){
|
||||
struct SrcList_item *pItem;
|
||||
SrcItem *pItem;
|
||||
sqlite3 *db = pParse->db;
|
||||
if( !p && (pOn || pUsing) ){
|
||||
sqlite3ErrorMsg(pParse, "a JOIN clause is required before %s",
|
||||
@@ -4636,7 +4666,7 @@ SrcList *sqlite3SrcListAppendFromTerm(
|
||||
void sqlite3SrcListIndexedBy(Parse *pParse, SrcList *p, Token *pIndexedBy){
|
||||
assert( pIndexedBy!=0 );
|
||||
if( p && pIndexedBy->n>0 ){
|
||||
struct SrcList_item *pItem;
|
||||
SrcItem *pItem;
|
||||
assert( p->nSrc>0 );
|
||||
pItem = &p->a[p->nSrc-1];
|
||||
assert( pItem->fg.notIndexed==0 );
|
||||
@@ -4666,7 +4696,7 @@ SrcList *sqlite3SrcListAppendList(Parse *pParse, SrcList *p1, SrcList *p2){
|
||||
sqlite3SrcListDelete(pParse->db, p2);
|
||||
}else{
|
||||
p1 = pNew;
|
||||
memcpy(&p1->a[1], p2->a, p2->nSrc*sizeof(struct SrcList_item));
|
||||
memcpy(&p1->a[1], p2->a, p2->nSrc*sizeof(SrcItem));
|
||||
sqlite3DbFree(pParse->db, p2);
|
||||
}
|
||||
}
|
||||
@@ -4679,7 +4709,7 @@ SrcList *sqlite3SrcListAppendList(Parse *pParse, SrcList *p1, SrcList *p2){
|
||||
*/
|
||||
void sqlite3SrcListFuncArgs(Parse *pParse, SrcList *p, ExprList *pList){
|
||||
if( p ){
|
||||
struct SrcList_item *pItem = &p->a[p->nSrc-1];
|
||||
SrcItem *pItem = &p->a[p->nSrc-1];
|
||||
assert( pItem->fg.notIndexed==0 );
|
||||
assert( pItem->fg.isIndexedBy==0 );
|
||||
assert( pItem->fg.isTabFunc==0 );
|
||||
@@ -4834,7 +4864,7 @@ int sqlite3OpenTempDatabase(Parse *pParse){
|
||||
static void sqlite3CodeVerifySchemaAtToplevel(Parse *pToplevel, int iDb){
|
||||
assert( iDb>=0 && iDb<pToplevel->db->nDb );
|
||||
assert( pToplevel->db->aDb[iDb].pBt!=0 || iDb==1 );
|
||||
assert( iDb<SQLITE_MAX_ATTACHED+2 );
|
||||
assert( iDb<SQLITE_MAX_DB );
|
||||
assert( sqlite3SchemaMutexHeld(pToplevel->db, iDb, 0) );
|
||||
if( DbMaskTest(pToplevel->cookieMask, iDb)==0 ){
|
||||
DbMaskSet(pToplevel->cookieMask, iDb);
|
||||
@@ -5176,24 +5206,76 @@ KeyInfo *sqlite3KeyInfoOfIndex(Parse *pParse, Index *pIdx){
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_CTE
|
||||
/*
|
||||
** Create a new CTE object
|
||||
*/
|
||||
Cte *sqlite3CteNew(
|
||||
Parse *pParse, /* Parsing context */
|
||||
Token *pName, /* Name of the common-table */
|
||||
ExprList *pArglist, /* Optional column name list for the table */
|
||||
Select *pQuery, /* Query used to initialize the table */
|
||||
u8 eM10d /* The MATERIALIZED flag */
|
||||
){
|
||||
Cte *pNew;
|
||||
sqlite3 *db = pParse->db;
|
||||
|
||||
pNew = sqlite3DbMallocZero(db, sizeof(*pNew));
|
||||
assert( pNew!=0 || db->mallocFailed );
|
||||
|
||||
if( db->mallocFailed ){
|
||||
sqlite3ExprListDelete(db, pArglist);
|
||||
sqlite3SelectDelete(db, pQuery);
|
||||
}else{
|
||||
pNew->pSelect = pQuery;
|
||||
pNew->pCols = pArglist;
|
||||
pNew->zName = sqlite3NameFromToken(pParse->db, pName);
|
||||
pNew->eM10d = eM10d;
|
||||
}
|
||||
return pNew;
|
||||
}
|
||||
|
||||
/*
|
||||
** Clear information from a Cte object, but do not deallocate storage
|
||||
** for the object itself.
|
||||
*/
|
||||
static void cteClear(sqlite3 *db, Cte *pCte){
|
||||
assert( pCte!=0 );
|
||||
sqlite3ExprListDelete(db, pCte->pCols);
|
||||
sqlite3SelectDelete(db, pCte->pSelect);
|
||||
sqlite3DbFree(db, pCte->zName);
|
||||
}
|
||||
|
||||
/*
|
||||
** Free the contents of the CTE object passed as the second argument.
|
||||
*/
|
||||
void sqlite3CteDelete(sqlite3 *db, Cte *pCte){
|
||||
assert( pCte!=0 );
|
||||
cteClear(db, pCte);
|
||||
sqlite3DbFree(db, pCte);
|
||||
}
|
||||
|
||||
/*
|
||||
** This routine is invoked once per CTE by the parser while parsing a
|
||||
** WITH clause.
|
||||
** WITH clause. The CTE described by teh third argument is added to
|
||||
** the WITH clause of the second argument. If the second argument is
|
||||
** NULL, then a new WITH argument is created.
|
||||
*/
|
||||
With *sqlite3WithAdd(
|
||||
Parse *pParse, /* Parsing context */
|
||||
With *pWith, /* Existing WITH clause, or NULL */
|
||||
Token *pName, /* Name of the common-table */
|
||||
ExprList *pArglist, /* Optional column name list for the table */
|
||||
Select *pQuery /* Query used to initialize the table */
|
||||
Cte *pCte /* CTE to add to the WITH clause */
|
||||
){
|
||||
sqlite3 *db = pParse->db;
|
||||
With *pNew;
|
||||
char *zName;
|
||||
|
||||
if( pCte==0 ){
|
||||
return pWith;
|
||||
}
|
||||
|
||||
/* Check that the CTE name is unique within this WITH clause. If
|
||||
** not, store an error in the Parse structure. */
|
||||
zName = sqlite3NameFromToken(pParse->db, pName);
|
||||
zName = pCte->zName;
|
||||
if( zName && pWith ){
|
||||
int i;
|
||||
for(i=0; i<pWith->nCte; i++){
|
||||
@@ -5212,16 +5294,11 @@ With *sqlite3WithAdd(
|
||||
assert( (pNew!=0 && zName!=0) || db->mallocFailed );
|
||||
|
||||
if( db->mallocFailed ){
|
||||
sqlite3ExprListDelete(db, pArglist);
|
||||
sqlite3SelectDelete(db, pQuery);
|
||||
sqlite3DbFree(db, zName);
|
||||
sqlite3CteDelete(db, pCte);
|
||||
pNew = pWith;
|
||||
}else{
|
||||
pNew->a[pNew->nCte].pSelect = pQuery;
|
||||
pNew->a[pNew->nCte].pCols = pArglist;
|
||||
pNew->a[pNew->nCte].zName = zName;
|
||||
pNew->a[pNew->nCte].zCteErr = 0;
|
||||
pNew->nCte++;
|
||||
pNew->a[pNew->nCte++] = *pCte;
|
||||
sqlite3DbFree(db, pCte);
|
||||
}
|
||||
|
||||
return pNew;
|
||||
@@ -5234,10 +5311,7 @@ void sqlite3WithDelete(sqlite3 *db, With *pWith){
|
||||
if( pWith ){
|
||||
int i;
|
||||
for(i=0; i<pWith->nCte; i++){
|
||||
struct Cte *pCte = &pWith->a[i];
|
||||
sqlite3ExprListDelete(db, pCte->pCols);
|
||||
sqlite3SelectDelete(db, pCte->pSelect);
|
||||
sqlite3DbFree(db, pCte->zName);
|
||||
cteClear(db, &pWith->a[i]);
|
||||
}
|
||||
sqlite3DbFree(db, pWith);
|
||||
}
|
||||
|
||||
@@ -881,6 +881,7 @@ static int isDate(
|
||||
int eType;
|
||||
memset(p, 0, sizeof(*p));
|
||||
if( argc==0 ){
|
||||
if( !sqlite3NotPureFunc(context) ) return 1;
|
||||
return setDateTimeToCurrent(context, p);
|
||||
}
|
||||
if( (eType = sqlite3_value_type(argv[0]))==SQLITE_FLOAT
|
||||
|
||||
+12
-6
@@ -29,7 +29,7 @@
|
||||
**
|
||||
*/
|
||||
Table *sqlite3SrcListLookup(Parse *pParse, SrcList *pSrc){
|
||||
struct SrcList_item *pItem = pSrc->a;
|
||||
SrcItem *pItem = pSrc->a;
|
||||
Table *pTab;
|
||||
assert( pItem && pSrc->nSrc>=1 );
|
||||
pTab = sqlite3LocateTableItem(pParse, 0, pItem);
|
||||
@@ -37,9 +37,9 @@ Table *sqlite3SrcListLookup(Parse *pParse, SrcList *pSrc){
|
||||
pItem->pTab = pTab;
|
||||
if( pTab ){
|
||||
pTab->nTabRef++;
|
||||
}
|
||||
if( sqlite3IndexedByLookup(pParse, pItem) ){
|
||||
pTab = 0;
|
||||
if( pItem->fg.isIndexedBy && sqlite3IndexedByLookup(pParse, pItem) ){
|
||||
pTab = 0;
|
||||
}
|
||||
}
|
||||
return pTab;
|
||||
}
|
||||
@@ -207,9 +207,15 @@ Expr *sqlite3LimitWhere(
|
||||
/* duplicate the FROM clause as it is needed by both the DELETE/UPDATE tree
|
||||
** and the SELECT subtree. */
|
||||
pSrc->a[0].pTab = 0;
|
||||
pSelectSrc = sqlite3SrcListDup(pParse->db, pSrc, 0);
|
||||
pSelectSrc = sqlite3SrcListDup(db, pSrc, 0);
|
||||
pSrc->a[0].pTab = pTab;
|
||||
pSrc->a[0].pIBIndex = 0;
|
||||
if( pSrc->a[0].fg.isIndexedBy ){
|
||||
pSrc->a[0].u2.pIBIndex = 0;
|
||||
pSrc->a[0].fg.isIndexedBy = 0;
|
||||
sqlite3DbFree(db, pSrc->a[0].u1.zIndexedBy);
|
||||
}else if( pSrc->a[0].fg.isCte ){
|
||||
pSrc->a[0].u2.pCteUse->nUse++;
|
||||
}
|
||||
|
||||
/* generate the SELECT expression tree. */
|
||||
pSelect = sqlite3SelectNew(pParse, pEList, pSelectSrc, pWhere, 0 ,0,
|
||||
|
||||
+8
-5
@@ -1530,8 +1530,8 @@ SrcList *sqlite3SrcListDup(sqlite3 *db, SrcList *p, int flags){
|
||||
if( pNew==0 ) return 0;
|
||||
pNew->nSrc = pNew->nAlloc = p->nSrc;
|
||||
for(i=0; i<p->nSrc; i++){
|
||||
struct SrcList_item *pNewItem = &pNew->a[i];
|
||||
struct SrcList_item *pOldItem = &p->a[i];
|
||||
SrcItem *pNewItem = &pNew->a[i];
|
||||
SrcItem *pOldItem = &p->a[i];
|
||||
Table *pTab;
|
||||
pNewItem->pSchema = pOldItem->pSchema;
|
||||
pNewItem->zDatabase = sqlite3DbStrDup(db, pOldItem->zDatabase);
|
||||
@@ -1544,7 +1544,10 @@ SrcList *sqlite3SrcListDup(sqlite3 *db, SrcList *p, int flags){
|
||||
if( pNewItem->fg.isIndexedBy ){
|
||||
pNewItem->u1.zIndexedBy = sqlite3DbStrDup(db, pOldItem->u1.zIndexedBy);
|
||||
}
|
||||
pNewItem->pIBIndex = pOldItem->pIBIndex;
|
||||
pNewItem->u2 = pOldItem->u2;
|
||||
if( pNewItem->fg.isCte ){
|
||||
pNewItem->u2.pCteUse->nUse++;
|
||||
}
|
||||
if( pNewItem->fg.isTabFunc ){
|
||||
pNewItem->u1.pFuncArg =
|
||||
sqlite3ExprListDup(db, pOldItem->u1.pFuncArg, flags);
|
||||
@@ -2582,7 +2585,7 @@ int sqlite3FindInIndex(
|
||||
|
||||
/* Code an OP_Transaction and OP_TableLock for <table>. */
|
||||
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
|
||||
assert( iDb>=0 && iDb<SQLITE_MAX_ATTACHED );
|
||||
assert( iDb>=0 && iDb<SQLITE_MAX_DB );
|
||||
sqlite3CodeVerifySchema(pParse, iDb);
|
||||
sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName);
|
||||
|
||||
@@ -5861,7 +5864,7 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){
|
||||
/* Check to see if the column is in one of the tables in the FROM
|
||||
** clause of the aggregate query */
|
||||
if( ALWAYS(pSrcList!=0) ){
|
||||
struct SrcList_item *pItem = pSrcList->a;
|
||||
SrcItem *pItem = pSrcList->a;
|
||||
for(i=0; i<pSrcList->nSrc; i++, pItem++){
|
||||
struct AggInfo_col *pCol;
|
||||
assert( !ExprHasProperty(pExpr, EP_TokenOnly|EP_Reduced) );
|
||||
|
||||
+11
-8
@@ -1024,7 +1024,7 @@ void sqlite3FkCheck(
|
||||
** child table as a SrcList for sqlite3WhereBegin() */
|
||||
pSrc = sqlite3SrcListAppend(pParse, 0, 0, 0);
|
||||
if( pSrc ){
|
||||
struct SrcList_item *pItem = pSrc->a;
|
||||
SrcItem *pItem = pSrc->a;
|
||||
pItem->pTab = pFKey->pFrom;
|
||||
pItem->zName = pFKey->pFrom->zName;
|
||||
pItem->pTab->nTabRef++;
|
||||
@@ -1112,7 +1112,9 @@ u32 sqlite3FkOldmask(
|
||||
**
|
||||
** For an UPDATE, this function returns 2 if:
|
||||
**
|
||||
** * There are any FKs for which pTab is the child and the parent table, or
|
||||
** * There are any FKs for which pTab is the child and the parent table
|
||||
** and any FK processing at all is required (even of a different FK), or
|
||||
**
|
||||
** * the UPDATE modifies one or more parent keys for which the action is
|
||||
** not "NO ACTION" (i.e. is CASCADE, SET DEFAULT or SET NULL).
|
||||
**
|
||||
@@ -1124,13 +1126,14 @@ int sqlite3FkRequired(
|
||||
int *aChange, /* Non-NULL for UPDATE operations */
|
||||
int chngRowid /* True for UPDATE that affects rowid */
|
||||
){
|
||||
int eRet = 0;
|
||||
int eRet = 1; /* Value to return if bHaveFK is true */
|
||||
int bHaveFK = 0; /* If FK processing is required */
|
||||
if( pParse->db->flags&SQLITE_ForeignKeys ){
|
||||
if( !aChange ){
|
||||
/* A DELETE operation. Foreign key processing is required if the
|
||||
** table in question is either the child or parent table for any
|
||||
** foreign key constraint. */
|
||||
eRet = (sqlite3FkReferences(pTab) || pTab->pFKey);
|
||||
bHaveFK = (sqlite3FkReferences(pTab) || pTab->pFKey);
|
||||
}else{
|
||||
/* This is an UPDATE. Foreign key processing is only required if the
|
||||
** operation modifies one or more child or parent key columns. */
|
||||
@@ -1138,9 +1141,9 @@ int sqlite3FkRequired(
|
||||
|
||||
/* Check if any child key columns are being modified. */
|
||||
for(p=pTab->pFKey; p; p=p->pNextFrom){
|
||||
if( 0==sqlite3_stricmp(pTab->zName, p->zTo) ) return 2;
|
||||
if( fkChildIsModified(pTab, p, aChange, chngRowid) ){
|
||||
eRet = 1;
|
||||
if( 0==sqlite3_stricmp(pTab->zName, p->zTo) ) eRet = 2;
|
||||
bHaveFK = 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1148,12 +1151,12 @@ int sqlite3FkRequired(
|
||||
for(p=sqlite3FkReferences(pTab); p; p=p->pNextTo){
|
||||
if( fkParentIsModified(pTab, p, aChange, chngRowid) ){
|
||||
if( p->aAction[1]!=OE_None ) return 2;
|
||||
eRet = 1;
|
||||
bHaveFK = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return eRet;
|
||||
return bHaveFK ? eRet : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
+2
-1
@@ -694,7 +694,8 @@ static int patternCompare(
|
||||
/* Skip over multiple "*" characters in the pattern. If there
|
||||
** are also "?" characters, skip those as well, but consume a
|
||||
** single character of the input string for each "?" skipped */
|
||||
while( (c=Utf8Read(zPattern)) == matchAll || c == matchOne ){
|
||||
while( (c=Utf8Read(zPattern)) == matchAll
|
||||
|| (c == matchOne && matchOne!=0) ){
|
||||
if( c==matchOne && sqlite3Utf8Read(&zString)==0 ){
|
||||
return SQLITE_NOWILDCARDMATCH;
|
||||
}
|
||||
|
||||
+56
-30
@@ -930,19 +930,24 @@ void sqlite3Insert(
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Make sure the number of columns in the source data matches the number
|
||||
** of columns to be inserted into the table.
|
||||
*/
|
||||
for(i=0; i<pTab->nCol; i++){
|
||||
if( pTab->aCol[i].colFlags & COLFLAG_NOINSERT ) nHidden++;
|
||||
}
|
||||
if( pColumn==0 && nColumn && nColumn!=(pTab->nCol-nHidden) ){
|
||||
sqlite3ErrorMsg(pParse,
|
||||
"table %S has %d columns but %d values were supplied",
|
||||
pTabList, 0, pTab->nCol-nHidden, nColumn);
|
||||
goto insert_cleanup;
|
||||
/* Make sure the number of columns in the source data matches the number
|
||||
** of columns to be inserted into the table.
|
||||
*/
|
||||
assert( TF_HasHidden==COLFLAG_HIDDEN );
|
||||
assert( TF_HasGenerated==COLFLAG_GENERATED );
|
||||
assert( COLFLAG_NOINSERT==(COLFLAG_GENERATED|COLFLAG_HIDDEN) );
|
||||
if( (pTab->tabFlags & (TF_HasGenerated|TF_HasHidden))!=0 ){
|
||||
for(i=0; i<pTab->nCol; i++){
|
||||
if( pTab->aCol[i].colFlags & COLFLAG_NOINSERT ) nHidden++;
|
||||
}
|
||||
}
|
||||
if( nColumn!=(pTab->nCol-nHidden) ){
|
||||
sqlite3ErrorMsg(pParse,
|
||||
"table %S has %d columns but %d values were supplied",
|
||||
pTabList, 0, pTab->nCol-nHidden, nColumn);
|
||||
goto insert_cleanup;
|
||||
}
|
||||
}
|
||||
if( pColumn!=0 && nColumn!=pColumn->nId ){
|
||||
sqlite3ErrorMsg(pParse, "%d values for %d columns", nColumn, pColumn->nId);
|
||||
@@ -1143,11 +1148,6 @@ void sqlite3Insert(
|
||||
sqlite3VdbeAddOp1(v, OP_MustBeInt, regCols); VdbeCoverage(v);
|
||||
}
|
||||
|
||||
/* Cannot have triggers on a virtual table. If it were possible,
|
||||
** this block would have to account for hidden column.
|
||||
*/
|
||||
assert( !IsVirtual(pTab) );
|
||||
|
||||
/* Copy the new data already generated. */
|
||||
assert( pTab->nNVCol>0 );
|
||||
sqlite3VdbeAddOp3(v, OP_Copy, regRowid+1, regCols+1, pTab->nNVCol-1);
|
||||
@@ -2410,6 +2410,32 @@ void sqlite3SetMakeRecordP5(Vdbe *v, Table *pTab){
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Table pTab is a WITHOUT ROWID table that is being written to. The cursor
|
||||
** number is iCur, and register regData contains the new record for the
|
||||
** PK index. This function adds code to invoke the pre-update hook,
|
||||
** if one is registered.
|
||||
*/
|
||||
#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
|
||||
static void codeWithoutRowidPreupdate(
|
||||
Parse *pParse, /* Parse context */
|
||||
Table *pTab, /* Table being updated */
|
||||
int iCur, /* Cursor number for table */
|
||||
int regData /* Data containing new record */
|
||||
){
|
||||
Vdbe *v = pParse->pVdbe;
|
||||
int r = sqlite3GetTempReg(pParse);
|
||||
assert( !HasRowid(pTab) );
|
||||
assert( 0==(pParse->db->mDbFlags & DBFLAG_Vacuum) );
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, 0, r);
|
||||
sqlite3VdbeAddOp4(v, OP_Insert, iCur, regData, r, (char*)pTab, P4_TABLE);
|
||||
sqlite3VdbeChangeP5(v, OPFLAG_ISNOOP);
|
||||
sqlite3ReleaseTempReg(pParse, r);
|
||||
}
|
||||
#else
|
||||
# define codeWithoutRowidPreupdate(a,b,c,d)
|
||||
#endif
|
||||
|
||||
/*
|
||||
** This routine generates code to finish the INSERT or UPDATE operation
|
||||
** that was started by a prior call to sqlite3GenerateConstraintChecks.
|
||||
@@ -2458,17 +2484,9 @@ void sqlite3CompleteInsertion(
|
||||
assert( pParse->nested==0 );
|
||||
pik_flags |= OPFLAG_NCHANGE;
|
||||
pik_flags |= (update_flags & OPFLAG_SAVEPOSITION);
|
||||
#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
|
||||
if( update_flags==0 ){
|
||||
int r = sqlite3GetTempReg(pParse);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, 0, r);
|
||||
sqlite3VdbeAddOp4(v, OP_Insert,
|
||||
iIdxCur+i, aRegIdx[i], r, (char*)pTab, P4_TABLE
|
||||
);
|
||||
sqlite3VdbeChangeP5(v, OPFLAG_ISNOOP);
|
||||
sqlite3ReleaseTempReg(pParse, r);
|
||||
codeWithoutRowidPreupdate(pParse, pTab, iIdxCur+i, aRegIdx[i]);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iIdxCur+i, aRegIdx[i],
|
||||
aRegIdx[i]+1,
|
||||
@@ -2666,7 +2684,7 @@ static int xferOptimization(
|
||||
ExprList *pEList; /* The result set of the SELECT */
|
||||
Table *pSrc; /* The table in the FROM clause of SELECT */
|
||||
Index *pSrcIdx, *pDestIdx; /* Source and destination indices */
|
||||
struct SrcList_item *pItem; /* An element of pSelect->pSrc */
|
||||
SrcItem *pItem; /* An element of pSelect->pSrc */
|
||||
int i; /* Loop counter */
|
||||
int iDbSrc; /* The database of pSrc */
|
||||
int iSrc, iDest; /* Cursors from source and destination */
|
||||
@@ -2941,7 +2959,7 @@ static int xferOptimization(
|
||||
insFlags = OPFLAG_NCHANGE|OPFLAG_LASTROWID|OPFLAG_APPEND|OPFLAG_PREFORMAT;
|
||||
}
|
||||
#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
|
||||
if( db->xPreUpdateCallback ){
|
||||
if( (db->mDbFlags & DBFLAG_Vacuum)==0 ){
|
||||
sqlite3VdbeAddOp3(v, OP_RowData, iSrc, regData, 1);
|
||||
insFlags &= ~OPFLAG_PREFORMAT;
|
||||
}else
|
||||
@@ -2949,8 +2967,10 @@ static int xferOptimization(
|
||||
{
|
||||
sqlite3VdbeAddOp3(v, OP_RowCell, iDest, iSrc, regRowid);
|
||||
}
|
||||
sqlite3VdbeAddOp4(v, OP_Insert, iDest, regData, regRowid,
|
||||
(char*)pDest, P4_TABLE);
|
||||
sqlite3VdbeAddOp3(v, OP_Insert, iDest, regData, regRowid);
|
||||
if( (db->mDbFlags & DBFLAG_Vacuum)==0 ){
|
||||
sqlite3VdbeChangeP4(v, -1, (char*)pDest, P4_TABLE);
|
||||
}
|
||||
sqlite3VdbeChangeP5(v, insFlags);
|
||||
|
||||
sqlite3VdbeAddOp2(v, OP_Next, iSrc, addr1); VdbeCoverage(v);
|
||||
@@ -3003,6 +3023,12 @@ static int xferOptimization(
|
||||
}
|
||||
if( idxInsFlags!=(OPFLAG_USESEEKRESULT|OPFLAG_PREFORMAT) ){
|
||||
sqlite3VdbeAddOp3(v, OP_RowData, iSrc, regData, 1);
|
||||
if( (db->mDbFlags & DBFLAG_Vacuum)==0
|
||||
&& !HasRowid(pDest)
|
||||
&& IsPrimaryKeyIndex(pDestIdx)
|
||||
){
|
||||
codeWithoutRowidPreupdate(pParse, pDest, iDest, regData);
|
||||
}
|
||||
}
|
||||
sqlite3VdbeAddOp2(v, OP_IdxInsert, iDest, regData);
|
||||
sqlite3VdbeChangeP5(v, idxInsFlags|OPFLAG_APPEND);
|
||||
|
||||
+7
-3
@@ -2374,7 +2374,7 @@ int sqlite3_wal_checkpoint_v2(
|
||||
return SQLITE_OK;
|
||||
#else
|
||||
int rc; /* Return code */
|
||||
int iDb = SQLITE_MAX_ATTACHED; /* sqlite3.aDb[] index of db to checkpoint */
|
||||
int iDb; /* Schema to checkpoint */
|
||||
|
||||
#ifdef SQLITE_ENABLE_API_ARMOR
|
||||
if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
|
||||
@@ -2397,6 +2397,8 @@ int sqlite3_wal_checkpoint_v2(
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
if( zDb && zDb[0] ){
|
||||
iDb = sqlite3FindDbName(db, zDb);
|
||||
}else{
|
||||
iDb = SQLITE_MAX_DB; /* This means process all schemas */
|
||||
}
|
||||
if( iDb<0 ){
|
||||
rc = SQLITE_ERROR;
|
||||
@@ -2445,7 +2447,7 @@ int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb){
|
||||
** associated with the specific b-tree being checkpointed is taken by
|
||||
** this function while the checkpoint is running.
|
||||
**
|
||||
** If iDb is passed SQLITE_MAX_ATTACHED, then all attached databases are
|
||||
** If iDb is passed SQLITE_MAX_DB then all attached databases are
|
||||
** checkpointed. If an error is encountered it is returned immediately -
|
||||
** no attempt is made to checkpoint any remaining databases.
|
||||
**
|
||||
@@ -2460,9 +2462,11 @@ int sqlite3Checkpoint(sqlite3 *db, int iDb, int eMode, int *pnLog, int *pnCkpt){
|
||||
assert( sqlite3_mutex_held(db->mutex) );
|
||||
assert( !pnLog || *pnLog==-1 );
|
||||
assert( !pnCkpt || *pnCkpt==-1 );
|
||||
testcase( iDb==SQLITE_MAX_ATTACHED ); /* See forum post a006d86f72 */
|
||||
testcase( iDb==SQLITE_MAX_DB );
|
||||
|
||||
for(i=0; i<db->nDb && rc==SQLITE_OK; i++){
|
||||
if( i==iDb || iDb==SQLITE_MAX_ATTACHED ){
|
||||
if( i==iDb || iDb==SQLITE_MAX_DB ){
|
||||
rc = sqlite3BtreeCheckpoint(db->aDb[i].pBt, eMode, pnLog, pnCkpt);
|
||||
pnLog = 0;
|
||||
pnCkpt = 0;
|
||||
|
||||
+24
-19
@@ -70,7 +70,6 @@ struct MemJournal {
|
||||
int nChunkSize; /* In-memory chunk-size */
|
||||
|
||||
int nSpill; /* Bytes of data before flushing */
|
||||
int nSize; /* Bytes of data currently in memory */
|
||||
FileChunk *pFirst; /* Head of in-memory chunk-list */
|
||||
FilePoint endpoint; /* Pointer to the end of the file */
|
||||
FilePoint readpoint; /* Pointer to the end of the last xRead() */
|
||||
@@ -131,14 +130,13 @@ static int memjrnlRead(
|
||||
/*
|
||||
** Free the list of FileChunk structures headed at MemJournal.pFirst.
|
||||
*/
|
||||
static void memjrnlFreeChunks(MemJournal *p){
|
||||
static void memjrnlFreeChunks(FileChunk *pFirst){
|
||||
FileChunk *pIter;
|
||||
FileChunk *pNext;
|
||||
for(pIter=p->pFirst; pIter; pIter=pNext){
|
||||
for(pIter=pFirst; pIter; pIter=pNext){
|
||||
pNext = pIter->pNext;
|
||||
sqlite3_free(pIter);
|
||||
}
|
||||
p->pFirst = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -165,7 +163,7 @@ static int memjrnlCreateFile(MemJournal *p){
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
/* No error has occurred. Free the in-memory buffers. */
|
||||
memjrnlFreeChunks(©);
|
||||
memjrnlFreeChunks(copy.pFirst);
|
||||
}
|
||||
}
|
||||
if( rc!=SQLITE_OK ){
|
||||
@@ -248,7 +246,6 @@ static int memjrnlWrite(
|
||||
nWrite -= iSpace;
|
||||
p->endpoint.iOffset += iSpace;
|
||||
}
|
||||
p->nSize = iAmt + iOfst;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -256,22 +253,30 @@ static int memjrnlWrite(
|
||||
}
|
||||
|
||||
/*
|
||||
** Truncate the file.
|
||||
**
|
||||
** If the journal file is already on disk, truncate it there. Or, if it
|
||||
** is still in main memory but is being truncated to zero bytes in size,
|
||||
** ignore
|
||||
** Truncate the in-memory file.
|
||||
*/
|
||||
static int memjrnlTruncate(sqlite3_file *pJfd, sqlite_int64 size){
|
||||
MemJournal *p = (MemJournal *)pJfd;
|
||||
if( ALWAYS(size==0) ){
|
||||
memjrnlFreeChunks(p);
|
||||
p->nSize = 0;
|
||||
p->endpoint.pChunk = 0;
|
||||
p->endpoint.iOffset = 0;
|
||||
p->readpoint.pChunk = 0;
|
||||
p->readpoint.iOffset = 0;
|
||||
FileChunk *pIter = 0;
|
||||
|
||||
if( size==0 ){
|
||||
memjrnlFreeChunks(p->pFirst);
|
||||
p->pFirst = 0;
|
||||
}else{
|
||||
i64 iOff = p->nChunkSize;
|
||||
for(pIter=p->pFirst; ALWAYS(pIter) && iOff<=size; pIter=pIter->pNext){
|
||||
iOff += p->nChunkSize;
|
||||
}
|
||||
if( ALWAYS(pIter) ){
|
||||
memjrnlFreeChunks(pIter->pNext);
|
||||
pIter->pNext = 0;
|
||||
}
|
||||
}
|
||||
|
||||
p->endpoint.pChunk = pIter;
|
||||
p->endpoint.iOffset = size;
|
||||
p->readpoint.pChunk = 0;
|
||||
p->readpoint.iOffset = 0;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
@@ -280,7 +285,7 @@ static int memjrnlTruncate(sqlite3_file *pJfd, sqlite_int64 size){
|
||||
*/
|
||||
static int memjrnlClose(sqlite3_file *pJfd){
|
||||
MemJournal *p = (MemJournal *)pJfd;
|
||||
memjrnlFreeChunks(p);
|
||||
memjrnlFreeChunks(p->pFirst);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
|
||||
+10
-3
@@ -435,6 +435,7 @@ struct PagerSavepoint {
|
||||
Bitvec *pInSavepoint; /* Set of pages in this savepoint */
|
||||
Pgno nOrig; /* Original number of pages in file */
|
||||
Pgno iSubRec; /* Index of first record in sub-journal */
|
||||
int bTruncateOnRelease; /* If stmt journal may be truncated on RELEASE */
|
||||
#ifndef SQLITE_OMIT_WAL
|
||||
u32 aWalData[WAL_SAVEPOINT_NDATA]; /* WAL savepoint context */
|
||||
#endif
|
||||
@@ -1070,6 +1071,9 @@ static int subjRequiresPage(PgHdr *pPg){
|
||||
for(i=0; i<pPager->nSavepoint; i++){
|
||||
p = &pPager->aSavepoint[i];
|
||||
if( p->nOrig>=pgno && 0==sqlite3BitvecTestNotNull(p->pInSavepoint, pgno) ){
|
||||
for(i=i+1; i<pPager->nSavepoint; i++){
|
||||
pPager->aSavepoint[i].bTruncateOnRelease = 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@@ -6848,6 +6852,7 @@ static SQLITE_NOINLINE int pagerOpenSavepoint(Pager *pPager, int nSavepoint){
|
||||
}
|
||||
aNew[ii].iSubRec = pPager->nSubRec;
|
||||
aNew[ii].pInSavepoint = sqlite3BitvecCreate(pPager->dbSize);
|
||||
aNew[ii].bTruncateOnRelease = 1;
|
||||
if( !aNew[ii].pInSavepoint ){
|
||||
return SQLITE_NOMEM_BKPT;
|
||||
}
|
||||
@@ -6929,13 +6934,15 @@ int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint){
|
||||
/* If this is a release of the outermost savepoint, truncate
|
||||
** the sub-journal to zero bytes in size. */
|
||||
if( op==SAVEPOINT_RELEASE ){
|
||||
if( nNew==0 && isOpen(pPager->sjfd) ){
|
||||
PagerSavepoint *pRel = &pPager->aSavepoint[nNew];
|
||||
if( pRel->bTruncateOnRelease && isOpen(pPager->sjfd) ){
|
||||
/* Only truncate if it is an in-memory sub-journal. */
|
||||
if( sqlite3JournalIsInMemory(pPager->sjfd) ){
|
||||
rc = sqlite3OsTruncate(pPager->sjfd, 0);
|
||||
i64 sz = (pPager->pageSize+4)*pRel->iSubRec;
|
||||
rc = sqlite3OsTruncate(pPager->sjfd, sz);
|
||||
assert( rc==SQLITE_OK );
|
||||
}
|
||||
pPager->nSubRec = 0;
|
||||
pPager->nSubRec = pRel->iSubRec;
|
||||
}
|
||||
}
|
||||
/* Else this is a rollback operation, playback the specified savepoint.
|
||||
|
||||
+49
-29
@@ -250,6 +250,7 @@ columnname(A) ::= nm(A) typetoken(Y). {sqlite3AddColumn(pParse,&A,&Y);}
|
||||
%ifndef SQLITE_OMIT_GENERATED_COLUMNS
|
||||
GENERATED ALWAYS
|
||||
%endif
|
||||
MATERIALIZED
|
||||
REINDEX RENAME CTIME_KW IF
|
||||
.
|
||||
%wildcard ANY.
|
||||
@@ -496,11 +497,21 @@ cmd ::= select(X). {
|
||||
static void parserDoubleLinkSelect(Parse *pParse, Select *p){
|
||||
assert( p!=0 );
|
||||
if( p->pPrior ){
|
||||
Select *pNext = 0, *pLoop;
|
||||
int mxSelect, cnt = 0;
|
||||
for(pLoop=p; pLoop; pNext=pLoop, pLoop=pLoop->pPrior, cnt++){
|
||||
Select *pNext = 0, *pLoop = p;
|
||||
int mxSelect, cnt = 1;
|
||||
while(1){
|
||||
pLoop->pNext = pNext;
|
||||
pLoop->selFlags |= SF_Compound;
|
||||
pNext = pLoop;
|
||||
pLoop = pLoop->pPrior;
|
||||
if( pLoop==0 ) break;
|
||||
cnt++;
|
||||
if( pLoop->pOrderBy || pLoop->pLimit ){
|
||||
sqlite3ErrorMsg(pParse,"%s clause should come after %s not before",
|
||||
pLoop->pOrderBy!=0 ? "ORDER BY" : "LIMIT",
|
||||
sqlite3SelectOpName(pNext->op));
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( (p->selFlags & SF_MultiValue)==0 &&
|
||||
(mxSelect = pParse->db->aLimit[SQLITE_LIMIT_COMPOUND_SELECT])>0 &&
|
||||
@@ -510,29 +521,25 @@ cmd ::= select(X). {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Attach a With object describing the WITH clause to a Select
|
||||
** object describing the query for which the WITH clause is a prefix.
|
||||
*/
|
||||
static Select *attachWithToSelect(Parse *pParse, Select *pSelect, With *pWith){
|
||||
if( pSelect ){
|
||||
pSelect->pWith = pWith;
|
||||
parserDoubleLinkSelect(pParse, pSelect);
|
||||
}else{
|
||||
sqlite3WithDelete(pParse->db, pWith);
|
||||
}
|
||||
return pSelect;
|
||||
}
|
||||
}
|
||||
|
||||
%ifndef SQLITE_OMIT_CTE
|
||||
select(A) ::= WITH wqlist(W) selectnowith(X). {
|
||||
Select *p = X;
|
||||
if( p ){
|
||||
p->pWith = W;
|
||||
parserDoubleLinkSelect(pParse, p);
|
||||
}else{
|
||||
sqlite3WithDelete(pParse->db, W);
|
||||
}
|
||||
A = p;
|
||||
}
|
||||
select(A) ::= WITH RECURSIVE wqlist(W) selectnowith(X). {
|
||||
Select *p = X;
|
||||
if( p ){
|
||||
p->pWith = W;
|
||||
parserDoubleLinkSelect(pParse, p);
|
||||
}else{
|
||||
sqlite3WithDelete(pParse->db, W);
|
||||
}
|
||||
A = p;
|
||||
}
|
||||
select(A) ::= WITH wqlist(W) selectnowith(X). {A = attachWithToSelect(pParse,X,W);}
|
||||
select(A) ::= WITH RECURSIVE wqlist(W) selectnowith(X).
|
||||
{A = attachWithToSelect(pParse,X,W);}
|
||||
%endif /* SQLITE_OMIT_CTE */
|
||||
select(A) ::= selectnowith(X). {
|
||||
Select *p = X;
|
||||
@@ -699,8 +706,8 @@ seltablist(A) ::= stl_prefix(A) nm(Y) dbnm(D) LP exprlist(E) RP as(Z)
|
||||
}else if( F->nSrc==1 ){
|
||||
A = sqlite3SrcListAppendFromTerm(pParse,A,0,0,&Z,0,N,U);
|
||||
if( A ){
|
||||
struct SrcList_item *pNew = &A->a[A->nSrc-1];
|
||||
struct SrcList_item *pOld = F->a;
|
||||
SrcItem *pNew = &A->a[A->nSrc-1];
|
||||
SrcItem *pOld = F->a;
|
||||
pNew->zName = pOld->zName;
|
||||
pNew->zDatabase = pOld->zDatabase;
|
||||
pNew->pSelect = pOld->pSelect;
|
||||
@@ -1621,6 +1628,10 @@ cmd ::= ALTER TABLE add_column_fullname
|
||||
Y.n = (int)(pParse->sLastToken.z-Y.z) + pParse->sLastToken.n;
|
||||
sqlite3AlterFinishAddColumn(pParse, &Y);
|
||||
}
|
||||
cmd ::= ALTER TABLE fullname(X) DROP kwcolumn_opt nm(Y). {
|
||||
sqlite3AlterDropColumn(pParse, X, &Y);
|
||||
}
|
||||
|
||||
add_column_fullname ::= fullname(X). {
|
||||
disableLookaside(pParse);
|
||||
sqlite3AlterBeginAddColumn(pParse, X);
|
||||
@@ -1658,17 +1669,26 @@ anylist ::= anylist ANY.
|
||||
//////////////////////// COMMON TABLE EXPRESSIONS ////////////////////////////
|
||||
%type wqlist {With*}
|
||||
%destructor wqlist {sqlite3WithDelete(pParse->db, $$);}
|
||||
%type wqitem {Cte*}
|
||||
// %destructor wqitem {sqlite3CteDelete(pParse->db, $$);} // not reachable
|
||||
|
||||
with ::= .
|
||||
%ifndef SQLITE_OMIT_CTE
|
||||
with ::= WITH wqlist(W). { sqlite3WithPush(pParse, W, 1); }
|
||||
with ::= WITH RECURSIVE wqlist(W). { sqlite3WithPush(pParse, W, 1); }
|
||||
|
||||
wqlist(A) ::= nm(X) eidlist_opt(Y) AS LP select(Z) RP. {
|
||||
A = sqlite3WithAdd(pParse, 0, &X, Y, Z); /*A-overwrites-X*/
|
||||
%type wqas {u8}
|
||||
wqas(A) ::= AS. {A = M10d_Any;}
|
||||
wqas(A) ::= AS MATERIALIZED. {A = M10d_Yes;}
|
||||
wqas(A) ::= AS NOT MATERIALIZED. {A = M10d_No;}
|
||||
wqitem(A) ::= nm(X) eidlist_opt(Y) wqas(M) LP select(Z) RP. {
|
||||
A = sqlite3CteNew(pParse, &X, Y, Z, M); /*A-overwrites-X*/
|
||||
}
|
||||
wqlist(A) ::= wqlist(A) COMMA nm(X) eidlist_opt(Y) AS LP select(Z) RP. {
|
||||
A = sqlite3WithAdd(pParse, A, &X, Y, Z);
|
||||
wqlist(A) ::= wqitem(X). {
|
||||
A = sqlite3WithAdd(pParse, 0, X); /*A-overwrites-X*/
|
||||
}
|
||||
wqlist(A) ::= wqlist(A) COMMA wqitem(X). {
|
||||
A = sqlite3WithAdd(pParse, A, X);
|
||||
}
|
||||
%endif SQLITE_OMIT_CTE
|
||||
|
||||
|
||||
@@ -461,6 +461,7 @@ static PgHdr1 *pcache1AllocPage(PCache1 *pCache, int benignMalloc){
|
||||
p->page.pExtra = &p[1];
|
||||
p->isBulkLocal = 0;
|
||||
p->isAnchor = 0;
|
||||
p->pLruPrev = 0; /* Initializing this saves a valgrind error */
|
||||
}
|
||||
(*pCache->pnPurgeable)++;
|
||||
return p;
|
||||
|
||||
+1
-1
@@ -1969,7 +1969,7 @@ void sqlite3Pragma(
|
||||
** Checkpoint the database.
|
||||
*/
|
||||
case PragTyp_WAL_CHECKPOINT: {
|
||||
int iBt = (pId2->z?iDb:SQLITE_MAX_ATTACHED);
|
||||
int iBt = (pId2->z?iDb:SQLITE_MAX_DB);
|
||||
int eMode = SQLITE_CHECKPOINT_PASSIVE;
|
||||
if( zRight ){
|
||||
if( sqlite3StrICmp(zRight, "full")==0 ){
|
||||
|
||||
+28
-29
@@ -21,7 +21,7 @@
|
||||
*/
|
||||
static void corruptSchema(
|
||||
InitData *pData, /* Initialization context */
|
||||
const char *zObj, /* Object being parsed at the point of error */
|
||||
char **azObj, /* Type and name of object being parsed */
|
||||
const char *zExtra /* Error information */
|
||||
){
|
||||
sqlite3 *db = pData->db;
|
||||
@@ -29,14 +29,18 @@ static void corruptSchema(
|
||||
pData->rc = SQLITE_NOMEM_BKPT;
|
||||
}else if( pData->pzErrMsg[0]!=0 ){
|
||||
/* A error message has already been generated. Do not overwrite it */
|
||||
}else if( pData->mInitFlags & INITFLAG_AlterTable ){
|
||||
*pData->pzErrMsg = sqlite3DbStrDup(db, zExtra);
|
||||
}else if( pData->mInitFlags & (INITFLAG_AlterRename|INITFLAG_AlterDrop) ){
|
||||
*pData->pzErrMsg = sqlite3MPrintf(db,
|
||||
"error in %s %s after %s: %s", azObj[0], azObj[1],
|
||||
(pData->mInitFlags & INITFLAG_AlterRename) ? "rename" : "drop column",
|
||||
zExtra
|
||||
);
|
||||
pData->rc = SQLITE_ERROR;
|
||||
}else if( db->flags & SQLITE_WriteSchema ){
|
||||
pData->rc = SQLITE_CORRUPT_BKPT;
|
||||
}else{
|
||||
char *z;
|
||||
if( zObj==0 ) zObj = "?";
|
||||
const char *zObj = azObj[1] ? azObj[1] : "?";
|
||||
z = sqlite3MPrintf(db, "malformed database schema (%s)", zObj);
|
||||
if( zExtra && zExtra[0] ) z = sqlite3MPrintf(db, "%z - %s", z, zExtra);
|
||||
*pData->pzErrMsg = z;
|
||||
@@ -94,14 +98,14 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){
|
||||
db->mDbFlags |= DBFLAG_EncodingFixed;
|
||||
pData->nInitRow++;
|
||||
if( db->mallocFailed ){
|
||||
corruptSchema(pData, argv[1], 0);
|
||||
corruptSchema(pData, argv, 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
assert( iDb>=0 && iDb<db->nDb );
|
||||
if( argv==0 ) return 0; /* Might happen if EMPTY_RESULT_CALLBACKS are on */
|
||||
if( argv[3]==0 ){
|
||||
corruptSchema(pData, argv[1], 0);
|
||||
corruptSchema(pData, argv, 0);
|
||||
}else if( argv[4]
|
||||
&& 'c'==sqlite3UpperToLower[(unsigned char)argv[4][0]]
|
||||
&& 'r'==sqlite3UpperToLower[(unsigned char)argv[4][1]] ){
|
||||
@@ -126,7 +130,7 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){
|
||||
|| (db->init.newTnum>pData->mxPage && pData->mxPage>0)
|
||||
){
|
||||
if( sqlite3Config.bExtraSchemaChecks ){
|
||||
corruptSchema(pData, argv[1], "invalid rootpage");
|
||||
corruptSchema(pData, argv, "invalid rootpage");
|
||||
}
|
||||
}
|
||||
db->init.orphanTrigger = 0;
|
||||
@@ -145,13 +149,13 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){
|
||||
if( rc==SQLITE_NOMEM ){
|
||||
sqlite3OomFault(db);
|
||||
}else if( rc!=SQLITE_INTERRUPT && (rc&0xFF)!=SQLITE_LOCKED ){
|
||||
corruptSchema(pData, argv[1], sqlite3_errmsg(db));
|
||||
corruptSchema(pData, argv, sqlite3_errmsg(db));
|
||||
}
|
||||
}
|
||||
}
|
||||
sqlite3_finalize(pStmt);
|
||||
}else if( argv[1]==0 || (argv[4]!=0 && argv[4][0]!=0) ){
|
||||
corruptSchema(pData, argv[1], 0);
|
||||
corruptSchema(pData, argv, 0);
|
||||
}else{
|
||||
/* If the SQL column is blank it means this is an index that
|
||||
** was created to be the PRIMARY KEY or to fulfill a UNIQUE
|
||||
@@ -162,7 +166,7 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){
|
||||
Index *pIndex;
|
||||
pIndex = sqlite3FindIndex(db, argv[1], db->aDb[iDb].zDbSName);
|
||||
if( pIndex==0 ){
|
||||
corruptSchema(pData, argv[1], "orphan index");
|
||||
corruptSchema(pData, argv, "orphan index");
|
||||
}else
|
||||
if( sqlite3GetUInt32(argv[3],&pIndex->tnum)==0
|
||||
|| pIndex->tnum<2
|
||||
@@ -170,7 +174,7 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){
|
||||
|| sqlite3IndexHasDuplicateRootPage(pIndex)
|
||||
){
|
||||
if( sqlite3Config.bExtraSchemaChecks ){
|
||||
corruptSchema(pData, argv[1], "invalid rootpage");
|
||||
corruptSchema(pData, argv, "invalid rootpage");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -550,31 +554,16 @@ int sqlite3SchemaToIndex(sqlite3 *db, Schema *pSchema){
|
||||
return i;
|
||||
}
|
||||
|
||||
/*
|
||||
** Deallocate a single AggInfo object
|
||||
*/
|
||||
static void agginfoFree(sqlite3 *db, AggInfo *p){
|
||||
sqlite3DbFree(db, p->aCol);
|
||||
sqlite3DbFree(db, p->aFunc);
|
||||
sqlite3DbFree(db, p);
|
||||
}
|
||||
|
||||
/*
|
||||
** Free all memory allocations in the pParse object
|
||||
*/
|
||||
void sqlite3ParserReset(Parse *pParse){
|
||||
sqlite3 *db = pParse->db;
|
||||
AggInfo *pThis = pParse->pAggList;
|
||||
while( pThis ){
|
||||
AggInfo *pNext = pThis->pNext;
|
||||
agginfoFree(db, pThis);
|
||||
pThis = pNext;
|
||||
}
|
||||
while( pParse->pCleanup ){
|
||||
ParseCleanup *pCleanup = pParse->pCleanup;
|
||||
pParse->pCleanup = pCleanup->pNext;
|
||||
pCleanup->xCleanup(db, pCleanup->pPtr);
|
||||
sqlite3DbFree(db, pCleanup);
|
||||
sqlite3DbFreeNN(db, pCleanup);
|
||||
}
|
||||
sqlite3DbFree(db, pParse->aLabel);
|
||||
if( pParse->pConstExpr ){
|
||||
@@ -600,15 +589,23 @@ void sqlite3ParserReset(Parse *pParse){
|
||||
** sqlite3ParserReset(), which reduces the total CPU cycle count.
|
||||
**
|
||||
** If a memory allocation error occurs, then the cleanup happens immediately.
|
||||
** When eithr SQLITE_DEBUG or SQLITE_COVERAGE_TEST are defined, the
|
||||
** When either SQLITE_DEBUG or SQLITE_COVERAGE_TEST are defined, the
|
||||
** pParse->earlyCleanup flag is set in that case. Calling code show verify
|
||||
** that test cases exist for which this happens, to guard against possible
|
||||
** use-after-free errors following an OOM. The preferred way to do this is
|
||||
** to immediately follow the call to this routine with:
|
||||
**
|
||||
** testcase( pParse->earlyCleanup );
|
||||
**
|
||||
** This routine returns a copy of its pPtr input (the third parameter)
|
||||
** except if an early cleanup occurs, in which case it returns NULL. So
|
||||
** another way to check for early cleanup is to check the return value.
|
||||
** Or, stop using the pPtr parameter with this call and use only its
|
||||
** return value thereafter. Something like this:
|
||||
**
|
||||
** pObj = sqlite3ParserAddCleanup(pParse, destructor, pObj);
|
||||
*/
|
||||
void sqlite3ParserAddCleanup(
|
||||
void *sqlite3ParserAddCleanup(
|
||||
Parse *pParse, /* Destroy when this Parser finishes */
|
||||
void (*xCleanup)(sqlite3*,void*), /* The cleanup routine */
|
||||
void *pPtr /* Pointer to object to be cleaned up */
|
||||
@@ -621,10 +618,12 @@ void sqlite3ParserAddCleanup(
|
||||
pCleanup->xCleanup = xCleanup;
|
||||
}else{
|
||||
xCleanup(pParse->db, pPtr);
|
||||
pPtr = 0;
|
||||
#if defined(SQLITE_DEBUG) || defined(SQLITE_COVERAGE_TEST)
|
||||
pParse->earlyCleanup = 1;
|
||||
#endif
|
||||
}
|
||||
return pPtr;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
+2
-2
@@ -856,7 +856,7 @@ void sqlite3_str_vappendf(
|
||||
case etSRCLIST: {
|
||||
SrcList *pSrc;
|
||||
int k;
|
||||
struct SrcList_item *pItem;
|
||||
SrcItem *pItem;
|
||||
if( (pAccum->printfFlags & SQLITE_PRINTF_INTERNAL)==0 ) return;
|
||||
pSrc = va_arg(ap, SrcList*);
|
||||
k = va_arg(ap, int);
|
||||
@@ -921,7 +921,7 @@ static int sqlite3StrAccumEnlarge(StrAccum *p, int N){
|
||||
}else{
|
||||
char *zOld = isMalloced(p) ? p->zText : 0;
|
||||
i64 szNew = p->nChar;
|
||||
szNew += N + 1;
|
||||
szNew += (sqlite3_int64)N + 1;
|
||||
if( szNew+p->nChar<=p->mxAlloc ){
|
||||
/* Force exponential buffer size growth as long as it does not overflow,
|
||||
** to avoid having to call this routine too often */
|
||||
|
||||
+107
-50
@@ -70,7 +70,6 @@ static void resolveAlias(
|
||||
ExprList *pEList, /* A result set */
|
||||
int iCol, /* A column in the result set. 0..pEList->nExpr-1 */
|
||||
Expr *pExpr, /* Transform this into an alias to the result set */
|
||||
const char *zType, /* "GROUP" or "ORDER" or "" */
|
||||
int nSubquery /* Number of subqueries that the label is moving */
|
||||
){
|
||||
Expr *pOrig; /* The iCol-th column of the result set */
|
||||
@@ -83,7 +82,7 @@ static void resolveAlias(
|
||||
db = pParse->db;
|
||||
pDup = sqlite3ExprDup(db, pOrig, 0);
|
||||
if( pDup!=0 ){
|
||||
if( zType[0]!='G' ) incrAggFunctionDepth(pDup, nSubquery);
|
||||
incrAggFunctionDepth(pDup, nSubquery);
|
||||
if( pExpr->op==TK_COLLATE ){
|
||||
pDup = sqlite3ExprAddCollateString(pParse, pDup, pExpr->u.zToken);
|
||||
}
|
||||
@@ -112,7 +111,6 @@ static void resolveAlias(
|
||||
}
|
||||
sqlite3DbFree(db, pDup);
|
||||
}
|
||||
ExprSetProperty(pExpr, EP_Alias);
|
||||
}
|
||||
|
||||
|
||||
@@ -247,8 +245,8 @@ static int lookupName(
|
||||
int cntTab = 0; /* Number of matching table names */
|
||||
int nSubquery = 0; /* How many levels of subquery */
|
||||
sqlite3 *db = pParse->db; /* The database connection */
|
||||
struct SrcList_item *pItem; /* Use for looping over pSrcList items */
|
||||
struct SrcList_item *pMatch = 0; /* The matching pSrcList item */
|
||||
SrcItem *pItem; /* Use for looping over pSrcList items */
|
||||
SrcItem *pMatch = 0; /* The matching pSrcList item */
|
||||
NameContext *pTopNC = pNC; /* First namecontext in the list */
|
||||
Schema *pSchema = 0; /* Schema of the expression */
|
||||
int eNewExprOp = TK_COLUMN; /* New value for pExpr->op on success */
|
||||
@@ -369,9 +367,10 @@ static int lookupName(
|
||||
#if !defined(SQLITE_OMIT_TRIGGER) || !defined(SQLITE_OMIT_UPSERT)
|
||||
/* If we have not already resolved the name, then maybe
|
||||
** it is a new.* or old.* trigger argument reference. Or
|
||||
** maybe it is an excluded.* from an upsert.
|
||||
** maybe it is an excluded.* from an upsert. Or maybe it is
|
||||
** a reference in the RETURNING clause to a table being modified.
|
||||
*/
|
||||
if( zDb==0 && cntTab==0 ){
|
||||
if( cnt==0 && zDb==0 ){
|
||||
pTab = 0;
|
||||
#ifndef SQLITE_OMIT_TRIGGER
|
||||
if( pParse->pTriggerTab!=0 ){
|
||||
@@ -383,14 +382,14 @@ static int lookupName(
|
||||
}else if( op!=TK_INSERT && zTab && sqlite3StrICmp("old",zTab)==0 ){
|
||||
pExpr->iTable = 0;
|
||||
pTab = pParse->pTriggerTab;
|
||||
}else if( pParse->bReturning ){
|
||||
}else if( pParse->bReturning && (pNC->ncFlags & NC_UBaseReg)!=0 ){
|
||||
pExpr->iTable = op!=TK_DELETE;
|
||||
pTab = pParse->pTriggerTab;
|
||||
}
|
||||
}
|
||||
#endif /* SQLITE_OMIT_TRIGGER */
|
||||
#ifndef SQLITE_OMIT_UPSERT
|
||||
if( (pNC->ncFlags & NC_UUpsert)!=0 && ALWAYS(zTab) ){
|
||||
if( (pNC->ncFlags & NC_UUpsert)!=0 && zTab!=0 ){
|
||||
Upsert *pUpsert = pNC->uNC.pUpsert;
|
||||
if( pUpsert && sqlite3StrICmp("excluded",zTab)==0 ){
|
||||
pTab = pUpsert->pUpsertSrc->a[0].pTab;
|
||||
@@ -418,6 +417,7 @@ static int lookupName(
|
||||
}
|
||||
if( iCol<pTab->nCol ){
|
||||
cnt++;
|
||||
pMatch = 0;
|
||||
#ifndef SQLITE_OMIT_UPSERT
|
||||
if( pExpr->iTable==EXCLUDED_TABLE_NUMBER ){
|
||||
testcase( iCol==(-1) );
|
||||
@@ -429,27 +429,32 @@ static int lookupName(
|
||||
pExpr->iTable = pNC->uNC.pUpsert->regData +
|
||||
sqlite3TableColumnToStorage(pTab, iCol);
|
||||
eNewExprOp = TK_REGISTER;
|
||||
ExprSetProperty(pExpr, EP_Alias);
|
||||
}
|
||||
}else
|
||||
#endif /* SQLITE_OMIT_UPSERT */
|
||||
{
|
||||
#ifndef SQLITE_OMIT_TRIGGER
|
||||
if( iCol<0 ){
|
||||
pExpr->affExpr = SQLITE_AFF_INTEGER;
|
||||
}else if( pExpr->iTable==0 ){
|
||||
testcase( iCol==31 );
|
||||
testcase( iCol==32 );
|
||||
pParse->oldmask |= (iCol>=32 ? 0xffffffff : (((u32)1)<<iCol));
|
||||
}else{
|
||||
testcase( iCol==31 );
|
||||
testcase( iCol==32 );
|
||||
pParse->newmask |= (iCol>=32 ? 0xffffffff : (((u32)1)<<iCol));
|
||||
}
|
||||
pExpr->y.pTab = pTab;
|
||||
pExpr->iColumn = (i16)iCol;
|
||||
eNewExprOp = TK_TRIGGER;
|
||||
if( pParse->bReturning ){
|
||||
eNewExprOp = TK_REGISTER;
|
||||
pExpr->iTable = pNC->uNC.iBaseReg + (pTab->nCol+1)*pExpr->iTable +
|
||||
sqlite3TableColumnToStorage(pTab, iCol) + 1;
|
||||
}else{
|
||||
pExpr->iColumn = (i16)iCol;
|
||||
eNewExprOp = TK_TRIGGER;
|
||||
#ifndef SQLITE_OMIT_TRIGGER
|
||||
if( iCol<0 ){
|
||||
pExpr->affExpr = SQLITE_AFF_INTEGER;
|
||||
}else if( pExpr->iTable==0 ){
|
||||
testcase( iCol==31 );
|
||||
testcase( iCol==32 );
|
||||
pParse->oldmask |= (iCol>=32 ? 0xffffffff : (((u32)1)<<iCol));
|
||||
}else{
|
||||
testcase( iCol==31 );
|
||||
testcase( iCol==32 );
|
||||
pParse->newmask |= (iCol>=32 ? 0xffffffff : (((u32)1)<<iCol));
|
||||
}
|
||||
#endif /* SQLITE_OMIT_TRIGGER */
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -519,7 +524,7 @@ static int lookupName(
|
||||
sqlite3ErrorMsg(pParse, "row value misused");
|
||||
return WRC_Abort;
|
||||
}
|
||||
resolveAlias(pParse, pEList, j, pExpr, "", nSubquery);
|
||||
resolveAlias(pParse, pEList, j, pExpr, nSubquery);
|
||||
cnt = 1;
|
||||
pMatch = 0;
|
||||
assert( zTab==0 && zDb==0 );
|
||||
@@ -554,6 +559,7 @@ static int lookupName(
|
||||
assert( pExpr->op==TK_ID );
|
||||
if( ExprHasProperty(pExpr,EP_DblQuoted)
|
||||
&& areDoubleQuotedStringsEnabled(db, pTopNC)
|
||||
&& (db->init.bDropColumn==0 || sqlite3StrICmp(zCol, db->init.azInit[0])!=0)
|
||||
){
|
||||
/* If a double-quoted identifier does not match any known column name,
|
||||
** then treat it as a string.
|
||||
@@ -568,6 +574,11 @@ static int lookupName(
|
||||
** Someday, I hope to get rid of this hack. Unfortunately there is
|
||||
** a huge amount of legacy SQL that uses it. So for now, we just
|
||||
** issue a warning.
|
||||
**
|
||||
** 2021-03-15: ticket 1c24a659e6d7f3a1
|
||||
** Do not do the ID-to-STRING conversion when doing the schema
|
||||
** sanity check following a DROP COLUMN if the identifer name matches
|
||||
** the name of the column being dropped.
|
||||
*/
|
||||
sqlite3_log(SQLITE_WARNING,
|
||||
"double-quoted string literal: \"%w\"", zCol);
|
||||
@@ -621,18 +632,24 @@ static int lookupName(
|
||||
|
||||
/* Clean up and return
|
||||
*/
|
||||
sqlite3ExprDelete(db, pExpr->pLeft);
|
||||
pExpr->pLeft = 0;
|
||||
sqlite3ExprDelete(db, pExpr->pRight);
|
||||
pExpr->pRight = 0;
|
||||
if( !ExprHasProperty(pExpr,(EP_TokenOnly|EP_Leaf)) ){
|
||||
sqlite3ExprDelete(db, pExpr->pLeft);
|
||||
pExpr->pLeft = 0;
|
||||
sqlite3ExprDelete(db, pExpr->pRight);
|
||||
pExpr->pRight = 0;
|
||||
}
|
||||
pExpr->op = eNewExprOp;
|
||||
ExprSetProperty(pExpr, EP_Leaf);
|
||||
lookupname_end:
|
||||
if( cnt==1 ){
|
||||
assert( pNC!=0 );
|
||||
if( !ExprHasProperty(pExpr, EP_Alias) ){
|
||||
#ifndef SQLITE_OMIT_AUTHORIZATION
|
||||
if( pParse->db->xAuth
|
||||
&& (pExpr->op==TK_COLUMN || pExpr->op==TK_TRIGGER)
|
||||
){
|
||||
sqlite3AuthRead(pParse, pExpr, pSchema, pNC->pSrcList);
|
||||
}
|
||||
#endif
|
||||
/* Increment the nRef value on all name contexts from TopNC up to
|
||||
** the point where the name matched. */
|
||||
for(;;){
|
||||
@@ -654,7 +671,7 @@ lookupname_end:
|
||||
Expr *sqlite3CreateColumnExpr(sqlite3 *db, SrcList *pSrc, int iSrc, int iCol){
|
||||
Expr *p = sqlite3ExprAlloc(db, TK_COLUMN, 0, 0);
|
||||
if( p ){
|
||||
struct SrcList_item *pItem = &pSrc->a[iSrc];
|
||||
SrcItem *pItem = &pSrc->a[iSrc];
|
||||
Table *pTab = p->y.pTab = pItem->pTab;
|
||||
p->iTable = pItem->iCursor;
|
||||
if( p->y.pTab->iPKey==iCol ){
|
||||
@@ -766,7 +783,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
|
||||
*/
|
||||
case TK_ROW: {
|
||||
SrcList *pSrcList = pNC->pSrcList;
|
||||
struct SrcList_item *pItem;
|
||||
SrcItem *pItem;
|
||||
assert( pSrcList && pSrcList->nSrc>=1 );
|
||||
pItem = pSrcList->a;
|
||||
pExpr->op = TK_COLUMN;
|
||||
@@ -777,6 +794,47 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
|
||||
break;
|
||||
}
|
||||
|
||||
/* An optimization: Attempt to convert
|
||||
**
|
||||
** "expr IS NOT NULL" --> "TRUE"
|
||||
** "expr IS NULL" --> "FALSE"
|
||||
**
|
||||
** if we can prove that "expr" is never NULL. Call this the
|
||||
** "NOT NULL strength reduction optimization".
|
||||
**
|
||||
** If this optimization occurs, also restore the NameContext ref-counts
|
||||
** to the state they where in before the "column" LHS expression was
|
||||
** resolved. This prevents "column" from being counted as having been
|
||||
** referenced, which might prevent a SELECT from being erroneously
|
||||
** marked as correlated.
|
||||
*/
|
||||
case TK_NOTNULL:
|
||||
case TK_ISNULL: {
|
||||
int anRef[8];
|
||||
NameContext *p;
|
||||
int i;
|
||||
for(i=0, p=pNC; p && i<ArraySize(anRef); p=p->pNext, i++){
|
||||
anRef[i] = p->nRef;
|
||||
}
|
||||
sqlite3WalkExpr(pWalker, pExpr->pLeft);
|
||||
if( 0==sqlite3ExprCanBeNull(pExpr->pLeft) && !IN_RENAME_OBJECT ){
|
||||
if( pExpr->op==TK_NOTNULL ){
|
||||
pExpr->u.zToken = "true";
|
||||
ExprSetProperty(pExpr, EP_IsTrue);
|
||||
}else{
|
||||
pExpr->u.zToken = "false";
|
||||
ExprSetProperty(pExpr, EP_IsFalse);
|
||||
}
|
||||
pExpr->op = TK_TRUEFALSE;
|
||||
for(i=0, p=pNC; p && i<ArraySize(anRef); p=p->pNext, i++){
|
||||
p->nRef = anRef[i];
|
||||
}
|
||||
sqlite3ExprDelete(pParse->db, pExpr->pLeft);
|
||||
pExpr->pLeft = 0;
|
||||
}
|
||||
return WRC_Prune;
|
||||
}
|
||||
|
||||
/* A column name: ID
|
||||
** Or table name and column name: ID.ID
|
||||
** Or a database, table and column: ID.ID.ID
|
||||
@@ -1004,6 +1062,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
|
||||
assert( pWin==pExpr->y.pWin );
|
||||
if( IN_RENAME_OBJECT==0 ){
|
||||
sqlite3WindowUpdate(pParse, pSel ? pSel->pWinDefn : 0, pWin, pDef);
|
||||
if( pParse->db->mallocFailed ) break;
|
||||
}
|
||||
sqlite3WalkExprList(pWalker, pWin->pPartition);
|
||||
sqlite3WalkExprList(pWalker, pWin->pOrderBy);
|
||||
@@ -1078,7 +1137,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
|
||||
assert( !ExprHasProperty(pExpr, EP_Reduced) );
|
||||
/* Handle special cases of "x IS TRUE", "x IS FALSE", "x IS NOT TRUE",
|
||||
** and "x IS NOT FALSE". */
|
||||
if( pRight && (pRight->op==TK_ID || pRight->op==TK_TRUEFALSE) ){
|
||||
if( ALWAYS(pRight) && (pRight->op==TK_ID || pRight->op==TK_TRUEFALSE) ){
|
||||
int rc = resolveExprStep(pWalker, pRight);
|
||||
if( rc==WRC_Abort ) return WRC_Abort;
|
||||
if( pRight->op==TK_TRUEFALSE ){
|
||||
@@ -1394,8 +1453,7 @@ int sqlite3ResolveOrderGroupBy(
|
||||
resolveOutOfRangeError(pParse, zType, i+1, pEList->nExpr);
|
||||
return 1;
|
||||
}
|
||||
resolveAlias(pParse, pEList, pItem->u.x.iOrderByCol-1, pItem->pExpr,
|
||||
zType,0);
|
||||
resolveAlias(pParse, pEList, pItem->u.x.iOrderByCol-1, pItem->pExpr,0);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
@@ -1580,27 +1638,26 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
|
||||
/* Recursively resolve names in all subqueries
|
||||
*/
|
||||
for(i=0; i<p->pSrc->nSrc; i++){
|
||||
struct SrcList_item *pItem = &p->pSrc->a[i];
|
||||
SrcItem *pItem = &p->pSrc->a[i];
|
||||
if( pItem->pSelect && (pItem->pSelect->selFlags & SF_Resolved)==0 ){
|
||||
NameContext *pNC; /* Used to iterate name contexts */
|
||||
int nRef = 0; /* Refcount for pOuterNC and outer contexts */
|
||||
int nRef = pOuterNC ? pOuterNC->nRef : 0;
|
||||
const char *zSavedContext = pParse->zAuthContext;
|
||||
|
||||
/* Count the total number of references to pOuterNC and all of its
|
||||
** parent contexts. After resolving references to expressions in
|
||||
** pItem->pSelect, check if this value has changed. If so, then
|
||||
** SELECT statement pItem->pSelect must be correlated. Set the
|
||||
** pItem->fg.isCorrelated flag if this is the case. */
|
||||
for(pNC=pOuterNC; pNC; pNC=pNC->pNext) nRef += pNC->nRef;
|
||||
|
||||
if( pItem->zName ) pParse->zAuthContext = pItem->zName;
|
||||
sqlite3ResolveSelectNames(pParse, pItem->pSelect, pOuterNC);
|
||||
pParse->zAuthContext = zSavedContext;
|
||||
if( pParse->nErr || db->mallocFailed ) return WRC_Abort;
|
||||
|
||||
for(pNC=pOuterNC; pNC; pNC=pNC->pNext) nRef -= pNC->nRef;
|
||||
assert( pItem->fg.isCorrelated==0 && nRef<=0 );
|
||||
pItem->fg.isCorrelated = (nRef!=0);
|
||||
/* If the number of references to the outer context changed when
|
||||
** expressions in the sub-select were resolved, the sub-select
|
||||
** is correlated. It is not required to check the refcount on any
|
||||
** but the innermost outer context object, as lookupName() increments
|
||||
** the refcount on all contexts between the current one and the
|
||||
** context containing the column when it resolves a name. */
|
||||
if( pOuterNC ){
|
||||
assert( pItem->fg.isCorrelated==0 && pOuterNC->nRef>=nRef );
|
||||
pItem->fg.isCorrelated = (pOuterNC->nRef>nRef);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1642,7 +1699,7 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
|
||||
** Minor point: If this is the case, then the expression will be
|
||||
** re-evaluated for each reference to it.
|
||||
*/
|
||||
assert( (sNC.ncFlags & (NC_UAggInfo|NC_UUpsert))==0 );
|
||||
assert( (sNC.ncFlags & (NC_UAggInfo|NC_UUpsert|NC_UBaseReg))==0 );
|
||||
sNC.uNC.pEList = p->pEList;
|
||||
sNC.ncFlags |= NC_UEList;
|
||||
if( sqlite3ResolveExprNames(&sNC, p->pHaving) ) return WRC_Abort;
|
||||
@@ -1650,7 +1707,7 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
|
||||
|
||||
/* Resolve names in table-valued-function arguments */
|
||||
for(i=0; i<p->pSrc->nSrc; i++){
|
||||
struct SrcList_item *pItem = &p->pSrc->a[i];
|
||||
SrcItem *pItem = &p->pSrc->a[i];
|
||||
if( pItem->fg.isTabFunc
|
||||
&& sqlite3ResolveExprListNames(&sNC, pItem->u1.pFuncArg)
|
||||
){
|
||||
|
||||
+281
-139
@@ -85,12 +85,16 @@ static void clearSelect(sqlite3 *db, Select *p, int bFree){
|
||||
sqlite3ExprDelete(db, p->pHaving);
|
||||
sqlite3ExprListDelete(db, p->pOrderBy);
|
||||
sqlite3ExprDelete(db, p->pLimit);
|
||||
if( OK_IF_ALWAYS_TRUE(p->pWith) ) sqlite3WithDelete(db, p->pWith);
|
||||
#ifndef SQLITE_OMIT_WINDOWFUNC
|
||||
if( OK_IF_ALWAYS_TRUE(p->pWinDefn) ){
|
||||
sqlite3WindowListDelete(db, p->pWinDefn);
|
||||
}
|
||||
while( p->pWin ){
|
||||
assert( p->pWin->ppThis==&p->pWin );
|
||||
sqlite3WindowUnlinkFromSelect(p->pWin);
|
||||
}
|
||||
#endif
|
||||
if( OK_IF_ALWAYS_TRUE(p->pWith) ) sqlite3WithDelete(db, p->pWith);
|
||||
if( bFree ) sqlite3DbFreeNN(db, p);
|
||||
p = pPrior;
|
||||
bFree = 1;
|
||||
@@ -262,7 +266,7 @@ int sqlite3JoinType(Parse *pParse, Token *pA, Token *pB, Token *pC){
|
||||
** Return the index of a column in a table. Return -1 if the column
|
||||
** is not contained in the table.
|
||||
*/
|
||||
static int columnIndex(Table *pTab, const char *zCol){
|
||||
int sqlite3ColumnIndex(Table *pTab, const char *zCol){
|
||||
int i;
|
||||
u8 h = sqlite3StrIHash(zCol);
|
||||
Column *pCol;
|
||||
@@ -294,7 +298,7 @@ static int tableAndColumnIndex(
|
||||
|
||||
assert( (piTab==0)==(piCol==0) ); /* Both or neither are NULL */
|
||||
for(i=0; i<N; i++){
|
||||
iCol = columnIndex(pSrc->a[i].pTab, zCol);
|
||||
iCol = sqlite3ColumnIndex(pSrc->a[i].pTab, zCol);
|
||||
if( iCol>=0
|
||||
&& (bIgnoreHidden==0 || IsHiddenColumn(&pSrc->a[i].pTab->aCol[iCol])==0)
|
||||
){
|
||||
@@ -407,6 +411,9 @@ static void unsetJoinExpr(Expr *p, int iTable){
|
||||
&& (iTable<0 || p->iRightJoinTable==iTable) ){
|
||||
ExprClearProperty(p, EP_FromJoin);
|
||||
}
|
||||
if( p->op==TK_COLUMN && p->iTable==iTable ){
|
||||
ExprClearProperty(p, EP_CanBeNull);
|
||||
}
|
||||
if( p->op==TK_FUNCTION && p->x.pList ){
|
||||
int i;
|
||||
for(i=0; i<p->x.pList->nExpr; i++){
|
||||
@@ -435,8 +442,8 @@ static void unsetJoinExpr(Expr *p, int iTable){
|
||||
static int sqliteProcessJoin(Parse *pParse, Select *p){
|
||||
SrcList *pSrc; /* All tables in the FROM clause */
|
||||
int i, j; /* Loop counters */
|
||||
struct SrcList_item *pLeft; /* Left table being joined */
|
||||
struct SrcList_item *pRight; /* Right table being joined */
|
||||
SrcItem *pLeft; /* Left table being joined */
|
||||
SrcItem *pRight; /* Right table being joined */
|
||||
|
||||
pSrc = p->pSrc;
|
||||
pLeft = &pSrc->a[0];
|
||||
@@ -504,7 +511,7 @@ static int sqliteProcessJoin(Parse *pParse, Select *p){
|
||||
int iRightCol; /* Column number of matching column on the right */
|
||||
|
||||
zName = pList->a[j].zName;
|
||||
iRightCol = columnIndex(pRightTab, zName);
|
||||
iRightCol = sqlite3ColumnIndex(pRightTab, zName);
|
||||
if( iRightCol<0
|
||||
|| !tableAndColumnIndex(pSrc, i+1, zName, &iLeft, &iLeftCol, 0)
|
||||
){
|
||||
@@ -1383,7 +1390,7 @@ KeyInfo *sqlite3KeyInfoFromExprList(
|
||||
/*
|
||||
** Name of the connection operator, used for error messages.
|
||||
*/
|
||||
static const char *selectOpName(int id){
|
||||
const char *sqlite3SelectOpName(int id){
|
||||
char *z;
|
||||
switch( id ){
|
||||
case TK_ALL: z = "UNION ALL"; break;
|
||||
@@ -2086,6 +2093,7 @@ void sqlite3SelectAddColumnTypeAndCollation(
|
||||
for(i=0, pCol=pTab->aCol; i<pTab->nCol; i++, pCol++){
|
||||
const char *zType;
|
||||
int n, m;
|
||||
pTab->tabFlags |= (pCol->colFlags & COLFLAG_NOINSERT);
|
||||
p = a[i].pExpr;
|
||||
zType = columnType(&sNC, p, 0, 0, 0);
|
||||
/* pCol->szEst = ... // Column size est for SELECT tables never used */
|
||||
@@ -2601,12 +2609,8 @@ static int multiSelect(
|
||||
db = pParse->db;
|
||||
pPrior = p->pPrior;
|
||||
dest = *pDest;
|
||||
if( pPrior->pOrderBy || pPrior->pLimit ){
|
||||
sqlite3ErrorMsg(pParse,"%s clause should come after %s not before",
|
||||
pPrior->pOrderBy!=0 ? "ORDER BY" : "LIMIT", selectOpName(p->op));
|
||||
rc = 1;
|
||||
goto multi_select_end;
|
||||
}
|
||||
assert( pPrior->pOrderBy==0 );
|
||||
assert( pPrior->pLimit==0 );
|
||||
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
assert( v!=0 ); /* The VDBE already created by calling function */
|
||||
@@ -2663,7 +2667,7 @@ static int multiSelect(
|
||||
pPrior->iOffset = p->iOffset;
|
||||
pPrior->pLimit = p->pLimit;
|
||||
rc = sqlite3Select(pParse, pPrior, &dest);
|
||||
p->pLimit = 0;
|
||||
pPrior->pLimit = 0;
|
||||
if( rc ){
|
||||
goto multi_select_end;
|
||||
}
|
||||
@@ -2684,8 +2688,8 @@ static int multiSelect(
|
||||
pDelete = p->pPrior;
|
||||
p->pPrior = pPrior;
|
||||
p->nSelectRow = sqlite3LogEstAdd(p->nSelectRow, pPrior->nSelectRow);
|
||||
if( pPrior->pLimit
|
||||
&& sqlite3ExprIsInteger(pPrior->pLimit->pLeft, &nLimit)
|
||||
if( p->pLimit
|
||||
&& sqlite3ExprIsInteger(p->pLimit->pLeft, &nLimit)
|
||||
&& nLimit>0 && p->nSelectRow > sqlite3LogEst((u64)nLimit)
|
||||
){
|
||||
p->nSelectRow = sqlite3LogEst((u64)nLimit);
|
||||
@@ -2749,7 +2753,7 @@ static int multiSelect(
|
||||
p->pLimit = 0;
|
||||
uniondest.eDest = op;
|
||||
ExplainQueryPlan((pParse, 1, "%s USING TEMP B-TREE",
|
||||
selectOpName(p->op)));
|
||||
sqlite3SelectOpName(p->op)));
|
||||
rc = sqlite3Select(pParse, p, &uniondest);
|
||||
testcase( rc!=SQLITE_OK );
|
||||
assert( p->pOrderBy==0 );
|
||||
@@ -2825,7 +2829,7 @@ static int multiSelect(
|
||||
p->pLimit = 0;
|
||||
intersectdest.iSDParm = tab2;
|
||||
ExplainQueryPlan((pParse, 1, "%s USING TEMP B-TREE",
|
||||
selectOpName(p->op)));
|
||||
sqlite3SelectOpName(p->op)));
|
||||
rc = sqlite3Select(pParse, p, &intersectdest);
|
||||
testcase( rc!=SQLITE_OK );
|
||||
pDelete = p->pPrior;
|
||||
@@ -2934,7 +2938,8 @@ void sqlite3SelectWrongNumTermsError(Parse *pParse, Select *p){
|
||||
sqlite3ErrorMsg(pParse, "all VALUES must have the same number of terms");
|
||||
}else{
|
||||
sqlite3ErrorMsg(pParse, "SELECTs to the left and right of %s"
|
||||
" do not have the same number of result columns", selectOpName(p->op));
|
||||
" do not have the same number of result columns",
|
||||
sqlite3SelectOpName(p->op));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3031,10 +3036,8 @@ static int generateOutputSubroutine(
|
||||
** if it is the RHS of a row-value IN operator.
|
||||
*/
|
||||
case SRT_Mem: {
|
||||
if( pParse->nErr==0 ){
|
||||
testcase( pIn->nSdst>1 );
|
||||
sqlite3ExprCodeMove(pParse, pIn->iSdst, pDest->iSDParm, pIn->nSdst);
|
||||
}
|
||||
testcase( pIn->nSdst>1 );
|
||||
sqlite3ExprCodeMove(pParse, pIn->iSdst, pDest->iSDParm, pIn->nSdst);
|
||||
/* The LIMIT clause will jump out of the loop for us */
|
||||
break;
|
||||
}
|
||||
@@ -3326,7 +3329,7 @@ static int multiSelectOrderBy(
|
||||
sqlite3SelectDestInit(&destA, SRT_Coroutine, regAddrA);
|
||||
sqlite3SelectDestInit(&destB, SRT_Coroutine, regAddrB);
|
||||
|
||||
ExplainQueryPlan((pParse, 1, "MERGE (%s)", selectOpName(p->op)));
|
||||
ExplainQueryPlan((pParse, 1, "MERGE (%s)", sqlite3SelectOpName(p->op)));
|
||||
|
||||
/* Generate a coroutine to evaluate the SELECT statement to the
|
||||
** left of the compound operator - the "A" select.
|
||||
@@ -3596,7 +3599,7 @@ static void substSelect(
|
||||
int doPrior /* Do substitutes on p->pPrior too */
|
||||
){
|
||||
SrcList *pSrc;
|
||||
struct SrcList_item *pItem;
|
||||
SrcItem *pItem;
|
||||
int i;
|
||||
if( !p ) return;
|
||||
do{
|
||||
@@ -3626,7 +3629,7 @@ static void substSelect(
|
||||
** pSrcItem->colUsed mask.
|
||||
*/
|
||||
static int recomputeColumnsUsedExpr(Walker *pWalker, Expr *pExpr){
|
||||
struct SrcList_item *pItem;
|
||||
SrcItem *pItem;
|
||||
if( pExpr->op!=TK_COLUMN ) return WRC_Continue;
|
||||
pItem = pWalker->u.pSrcItem;
|
||||
if( pItem->iCursor!=pExpr->iTable ) return WRC_Continue;
|
||||
@@ -3636,7 +3639,7 @@ static int recomputeColumnsUsedExpr(Walker *pWalker, Expr *pExpr){
|
||||
}
|
||||
static void recomputeColumnsUsed(
|
||||
Select *pSelect, /* The complete SELECT statement */
|
||||
struct SrcList_item *pSrcItem /* Which FROM clause item to recompute */
|
||||
SrcItem *pSrcItem /* Which FROM clause item to recompute */
|
||||
){
|
||||
Walker w;
|
||||
if( NEVER(pSrcItem->pTab==0) ) return;
|
||||
@@ -3670,7 +3673,7 @@ static void srclistRenumberCursors(
|
||||
int iExcept /* FROM clause item to skip */
|
||||
){
|
||||
int i;
|
||||
struct SrcList_item *pItem;
|
||||
SrcItem *pItem;
|
||||
for(i=0, pItem=pSrc->a; i<pSrc->nSrc; i++, pItem++){
|
||||
if( i!=iExcept ){
|
||||
Select *p;
|
||||
@@ -3688,7 +3691,8 @@ static void srclistRenumberCursors(
|
||||
*/
|
||||
static int renumberCursorsCb(Walker *pWalker, Expr *pExpr){
|
||||
int *aCsrMap = pWalker->u.aiCol;
|
||||
if( pExpr->op==TK_COLUMN && aCsrMap[pExpr->iTable] ){
|
||||
int op = pExpr->op;
|
||||
if( (op==TK_COLUMN || op==TK_IF_NULL_ROW) && aCsrMap[pExpr->iTable] ){
|
||||
pExpr->iTable = aCsrMap[pExpr->iTable];
|
||||
}
|
||||
if( ExprHasProperty(pExpr, EP_FromJoin) && aCsrMap[pExpr->iRightJoinTable] ){
|
||||
@@ -3903,7 +3907,7 @@ static int flattenSubquery(
|
||||
int isLeftJoin = 0; /* True if pSub is the right side of a LEFT JOIN */
|
||||
int i; /* Loop counter */
|
||||
Expr *pWhere; /* The WHERE clause */
|
||||
struct SrcList_item *pSubitem; /* The subquery */
|
||||
SrcItem *pSubitem; /* The subquery */
|
||||
sqlite3 *db = pParse->db;
|
||||
Walker w; /* Walker to persist agginfo data */
|
||||
int *aCsrMap = 0;
|
||||
@@ -4035,6 +4039,7 @@ static int flattenSubquery(
|
||||
if( (p->selFlags & SF_Recursive) ) return 0;
|
||||
|
||||
if( pSrc->nSrc>1 ){
|
||||
if( pParse->nSelect>500 ) return 0;
|
||||
aCsrMap = sqlite3DbMallocZero(db, pParse->nTab*sizeof(int));
|
||||
}
|
||||
}
|
||||
@@ -4111,6 +4116,7 @@ static int flattenSubquery(
|
||||
if( pNew==0 ){
|
||||
p->pPrior = pPrior;
|
||||
}else{
|
||||
pNew->selId = ++pParse->nSelect;
|
||||
if( aCsrMap && db->mallocFailed==0 ){
|
||||
renumberCursors(pParse, pNew, iFrom, aCsrMap);
|
||||
}
|
||||
@@ -4487,6 +4493,35 @@ static int propagateConstants(
|
||||
return nChng;
|
||||
}
|
||||
|
||||
#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
|
||||
# if !defined(SQLITE_OMIT_WINDOWFUNC)
|
||||
/*
|
||||
** This function is called to determine whether or not it is safe to
|
||||
** push WHERE clause expression pExpr down to FROM clause sub-query
|
||||
** pSubq, which contains at least one window function. Return 1
|
||||
** if it is safe and the expression should be pushed down, or 0
|
||||
** otherwise.
|
||||
**
|
||||
** It is only safe to push the expression down if it consists only
|
||||
** of constants and copies of expressions that appear in the PARTITION
|
||||
** BY clause of all window function used by the sub-query. It is safe
|
||||
** to filter out entire partitions, but not rows within partitions, as
|
||||
** this may change the results of the window functions.
|
||||
**
|
||||
** At the time this function is called it is guaranteed that
|
||||
**
|
||||
** * the sub-query uses only one distinct window frame, and
|
||||
** * that the window frame has a PARTITION BY clase.
|
||||
*/
|
||||
static int pushDownWindowCheck(Parse *pParse, Select *pSubq, Expr *pExpr){
|
||||
assert( pSubq->pWin->pPartition );
|
||||
assert( (pSubq->selFlags & SF_MultiPart)==0 );
|
||||
assert( pSubq->pPrior==0 );
|
||||
return sqlite3ExprIsConstantOrGroupBy(pParse, pExpr, pSubq->pWin->pPartition);
|
||||
}
|
||||
# endif /* SQLITE_OMIT_WINDOWFUNC */
|
||||
#endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */
|
||||
|
||||
#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
|
||||
/*
|
||||
** Make copies of relevant WHERE clause terms of the outer query into
|
||||
@@ -4534,9 +4569,24 @@ static int propagateConstants(
|
||||
** But if the (b2=2) term were to be pushed down into the bb subquery,
|
||||
** then the (1,1,NULL) row would be suppressed.
|
||||
**
|
||||
** (6) The inner query features one or more window-functions (since
|
||||
** changes to the WHERE clause of the inner query could change the
|
||||
** window over which window functions are calculated).
|
||||
** (6) Window functions make things tricky as changes to the WHERE clause
|
||||
** of the inner query could change the window over which window
|
||||
** functions are calculated. Therefore, do not attempt the optimization
|
||||
** if:
|
||||
**
|
||||
** (6a) The inner query uses multiple incompatible window partitions.
|
||||
**
|
||||
** (6b) The inner query is a compound and uses window-functions.
|
||||
**
|
||||
** (6c) The WHERE clause does not consist entirely of constants and
|
||||
** copies of expressions found in the PARTITION BY clause of
|
||||
** all window-functions used by the sub-query. It is safe to
|
||||
** filter out entire partitions, as this does not change the
|
||||
** window over which any window-function is calculated.
|
||||
**
|
||||
** (7) The inner query is a Common Table Expression (CTE) that should
|
||||
** be materialized. (This restriction is implemented in the calling
|
||||
** routine.)
|
||||
**
|
||||
** Return 0 if no changes are made and non-zero if one or more WHERE clause
|
||||
** terms are duplicated into the subquery.
|
||||
@@ -4550,13 +4600,17 @@ static int pushDownWhereTerms(
|
||||
){
|
||||
Expr *pNew;
|
||||
int nChng = 0;
|
||||
Select *pSel;
|
||||
if( pWhere==0 ) return 0;
|
||||
if( pSubq->selFlags & SF_Recursive ) return 0; /* restriction (2) */
|
||||
if( pSubq->selFlags & (SF_Recursive|SF_MultiPart) ) return 0;
|
||||
|
||||
#ifndef SQLITE_OMIT_WINDOWFUNC
|
||||
for(pSel=pSubq; pSel; pSel=pSel->pPrior){
|
||||
if( pSel->pWin ) return 0; /* restriction (6) */
|
||||
if( pSubq->pPrior ){
|
||||
Select *pSel;
|
||||
for(pSel=pSubq; pSel; pSel=pSel->pPrior){
|
||||
if( pSel->pWin ) return 0; /* restriction (6b) */
|
||||
}
|
||||
}else{
|
||||
if( pSubq->pWin && pSubq->pWin->pPartition==0 ) return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -4592,6 +4646,7 @@ static int pushDownWhereTerms(
|
||||
}
|
||||
if( sqlite3ExprIsTableConstant(pWhere, iCursor) ){
|
||||
nChng++;
|
||||
pSubq->selFlags |= SF_PushDown;
|
||||
while( pSubq ){
|
||||
SubstContext x;
|
||||
pNew = sqlite3ExprDup(pParse->db, pWhere, 0);
|
||||
@@ -4602,6 +4657,14 @@ static int pushDownWhereTerms(
|
||||
x.isLeftJoin = 0;
|
||||
x.pEList = pSubq->pEList;
|
||||
pNew = substExpr(&x, pNew);
|
||||
#ifndef SQLITE_OMIT_WINDOWFUNC
|
||||
if( pSubq->pWin && 0==pushDownWindowCheck(pParse, pSubq, pNew) ){
|
||||
/* Restriction 6c has prevented push-down in this case */
|
||||
sqlite3ExprDelete(pParse->db, pNew);
|
||||
nChng--;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
if( pSubq->selFlags & SF_Aggregate ){
|
||||
pSubq->pHaving = sqlite3ExprAnd(pParse, pSubq->pHaving, pNew);
|
||||
}else{
|
||||
@@ -4707,24 +4770,26 @@ static Table *isSimpleCount(Select *p, AggInfo *pAggInfo){
|
||||
** SQLITE_ERROR and leave an error in pParse. Otherwise, populate
|
||||
** pFrom->pIndex and return SQLITE_OK.
|
||||
*/
|
||||
int sqlite3IndexedByLookup(Parse *pParse, struct SrcList_item *pFrom){
|
||||
if( pFrom->pTab && pFrom->fg.isIndexedBy ){
|
||||
Table *pTab = pFrom->pTab;
|
||||
char *zIndexedBy = pFrom->u1.zIndexedBy;
|
||||
Index *pIdx;
|
||||
for(pIdx=pTab->pIndex;
|
||||
pIdx && sqlite3StrICmp(pIdx->zName, zIndexedBy);
|
||||
pIdx=pIdx->pNext
|
||||
);
|
||||
if( !pIdx ){
|
||||
sqlite3ErrorMsg(pParse, "no such index: %s", zIndexedBy, 0);
|
||||
pParse->checkSchema = 1;
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
pFrom->pIBIndex = pIdx;
|
||||
int sqlite3IndexedByLookup(Parse *pParse, SrcItem *pFrom){
|
||||
Table *pTab = pFrom->pTab;
|
||||
char *zIndexedBy = pFrom->u1.zIndexedBy;
|
||||
Index *pIdx;
|
||||
assert( pTab!=0 );
|
||||
assert( pFrom->fg.isIndexedBy!=0 );
|
||||
|
||||
for(pIdx=pTab->pIndex;
|
||||
pIdx && sqlite3StrICmp(pIdx->zName, zIndexedBy);
|
||||
pIdx=pIdx->pNext
|
||||
);
|
||||
if( !pIdx ){
|
||||
sqlite3ErrorMsg(pParse, "no such index: %s", zIndexedBy, 0);
|
||||
pParse->checkSchema = 1;
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
pFrom->u2.pIBIndex = pIdx;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Detect compound SELECT statements that use an ORDER BY clause with
|
||||
** an alternative collating sequence.
|
||||
@@ -4811,7 +4876,7 @@ static int convertCompoundSelectToSubquery(Walker *pWalker, Select *p){
|
||||
** arguments. If it does, leave an error message in pParse and return
|
||||
** non-zero, since pFrom is not allowed to be a table-valued function.
|
||||
*/
|
||||
static int cannotBeFunction(Parse *pParse, struct SrcList_item *pFrom){
|
||||
static int cannotBeFunction(Parse *pParse, SrcItem *pFrom){
|
||||
if( pFrom->fg.isTabFunc ){
|
||||
sqlite3ErrorMsg(pParse, "'%s' is not a function", pFrom->zName);
|
||||
return 1;
|
||||
@@ -4832,19 +4897,19 @@ static int cannotBeFunction(Parse *pParse, struct SrcList_item *pFrom){
|
||||
*/
|
||||
static struct Cte *searchWith(
|
||||
With *pWith, /* Current innermost WITH clause */
|
||||
struct SrcList_item *pItem, /* FROM clause element to resolve */
|
||||
SrcItem *pItem, /* FROM clause element to resolve */
|
||||
With **ppContext /* OUT: WITH clause return value belongs to */
|
||||
){
|
||||
const char *zName;
|
||||
if( pItem->zDatabase==0 && (zName = pItem->zName)!=0 ){
|
||||
With *p;
|
||||
for(p=pWith; p; p=p->pOuter){
|
||||
int i;
|
||||
for(i=0; i<p->nCte; i++){
|
||||
if( sqlite3StrICmp(zName, p->a[i].zName)==0 ){
|
||||
*ppContext = p;
|
||||
return &p->a[i];
|
||||
}
|
||||
const char *zName = pItem->zName;
|
||||
With *p;
|
||||
assert( pItem->zDatabase==0 );
|
||||
assert( zName!=0 );
|
||||
for(p=pWith; p; p=p->pOuter){
|
||||
int i;
|
||||
for(i=0; i<p->nCte; i++){
|
||||
if( sqlite3StrICmp(zName, p->a[i].zName)==0 ){
|
||||
*ppContext = p;
|
||||
return &p->a[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4877,35 +4942,39 @@ void sqlite3WithPush(Parse *pParse, With *pWith, u8 bFree){
|
||||
|
||||
/*
|
||||
** This function checks if argument pFrom refers to a CTE declared by
|
||||
** a WITH clause on the stack currently maintained by the parser. And,
|
||||
** if currently processing a CTE expression, if it is a recursive
|
||||
** reference to the current CTE.
|
||||
** a WITH clause on the stack currently maintained by the parser (on the
|
||||
** pParse->pWith linked list). And if currently processing a CTE
|
||||
** CTE expression, through routine checks to see if the reference is
|
||||
** a recursive reference to the CTE.
|
||||
**
|
||||
** If pFrom falls into either of the two categories above, pFrom->pTab
|
||||
** and other fields are populated accordingly. The caller should check
|
||||
** (pFrom->pTab!=0) to determine whether or not a successful match
|
||||
** was found.
|
||||
** If pFrom matches a CTE according to either of these two above, pFrom->pTab
|
||||
** and other fields are populated accordingly.
|
||||
**
|
||||
** Whether or not a match is found, SQLITE_OK is returned if no error
|
||||
** occurs. If an error does occur, an error message is stored in the
|
||||
** parser and some error code other than SQLITE_OK returned.
|
||||
** Return 0 if no match is found.
|
||||
** Return 1 if a match is found.
|
||||
** Return 2 if an error condition is detected.
|
||||
*/
|
||||
static int withExpand(
|
||||
Walker *pWalker,
|
||||
struct SrcList_item *pFrom
|
||||
static int resolveFromTermToCte(
|
||||
Parse *pParse, /* The parsing context */
|
||||
Walker *pWalker, /* Current tree walker */
|
||||
SrcItem *pFrom /* The FROM clause term to check */
|
||||
){
|
||||
Parse *pParse = pWalker->pParse;
|
||||
sqlite3 *db = pParse->db;
|
||||
struct Cte *pCte; /* Matched CTE (or NULL if no match) */
|
||||
With *pWith; /* WITH clause that pCte belongs to */
|
||||
Cte *pCte; /* Matched CTE (or NULL if no match) */
|
||||
With *pWith; /* The matching WITH */
|
||||
|
||||
assert( pFrom->pTab==0 );
|
||||
if( pParse->nErr ){
|
||||
return SQLITE_ERROR;
|
||||
if( pParse->pWith==0 ){
|
||||
/* There are no WITH clauses in the stack. No match is possible */
|
||||
return 0;
|
||||
}
|
||||
if( pFrom->zDatabase!=0 ){
|
||||
/* The FROM term contains a schema qualifier (ex: main.t1) and so
|
||||
** it cannot possibly be a CTE reference. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
pCte = searchWith(pParse->pWith, pFrom, &pWith);
|
||||
if( pCte ){
|
||||
sqlite3 *db = pParse->db;
|
||||
Table *pTab;
|
||||
ExprList *pEList;
|
||||
Select *pSel;
|
||||
@@ -4914,6 +4983,7 @@ static int withExpand(
|
||||
int bMayRecursive; /* True if compound joined by UNION [ALL] */
|
||||
With *pSavedWith; /* Initial value of pParse->pWith */
|
||||
int iRecTab = -1; /* Cursor for recursive table */
|
||||
CteUse *pCteUse;
|
||||
|
||||
/* If pCte->zCteErr is non-NULL at this point, then this is an illegal
|
||||
** recursive reference to CTE pCte. Leave an error in pParse and return
|
||||
@@ -4921,21 +4991,39 @@ static int withExpand(
|
||||
** In this case, proceed. */
|
||||
if( pCte->zCteErr ){
|
||||
sqlite3ErrorMsg(pParse, pCte->zCteErr, pCte->zName);
|
||||
return SQLITE_ERROR;
|
||||
return 2;
|
||||
}
|
||||
if( cannotBeFunction(pParse, pFrom) ) return SQLITE_ERROR;
|
||||
if( cannotBeFunction(pParse, pFrom) ) return 2;
|
||||
|
||||
assert( pFrom->pTab==0 );
|
||||
pFrom->pTab = pTab = sqlite3DbMallocZero(db, sizeof(Table));
|
||||
if( pTab==0 ) return WRC_Abort;
|
||||
pTab = sqlite3DbMallocZero(db, sizeof(Table));
|
||||
if( pTab==0 ) return 2;
|
||||
pCteUse = pCte->pUse;
|
||||
if( pCteUse==0 ){
|
||||
pCte->pUse = pCteUse = sqlite3DbMallocZero(db, sizeof(pCteUse[0]));
|
||||
if( pCteUse==0
|
||||
|| sqlite3ParserAddCleanup(pParse,sqlite3DbFree,pCteUse)==0
|
||||
){
|
||||
sqlite3DbFree(db, pTab);
|
||||
return 2;
|
||||
}
|
||||
pCteUse->eM10d = pCte->eM10d;
|
||||
}
|
||||
pFrom->pTab = pTab;
|
||||
pTab->nTabRef = 1;
|
||||
pTab->zName = sqlite3DbStrDup(db, pCte->zName);
|
||||
pTab->iPKey = -1;
|
||||
pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) );
|
||||
pTab->tabFlags |= TF_Ephemeral | TF_NoVisibleRowid;
|
||||
pFrom->pSelect = sqlite3SelectDup(db, pCte->pSelect, 0);
|
||||
if( db->mallocFailed ) return SQLITE_NOMEM_BKPT;
|
||||
if( db->mallocFailed ) return 2;
|
||||
assert( pFrom->pSelect );
|
||||
pFrom->fg.isCte = 1;
|
||||
pFrom->u2.pCteUse = pCteUse;
|
||||
pCteUse->nUse++;
|
||||
if( pCteUse->nUse>=2 && pCteUse->eM10d==M10d_Any ){
|
||||
pCteUse->eM10d = M10d_Yes;
|
||||
}
|
||||
|
||||
/* Check if this is a recursive CTE. */
|
||||
pRecTerm = pSel = pFrom->pSelect;
|
||||
@@ -4945,7 +5033,7 @@ static int withExpand(
|
||||
SrcList *pSrc = pRecTerm->pSrc;
|
||||
assert( pRecTerm->pPrior!=0 );
|
||||
for(i=0; i<pSrc->nSrc; i++){
|
||||
struct SrcList_item *pItem = &pSrc->a[i];
|
||||
SrcItem *pItem = &pSrc->a[i];
|
||||
if( pItem->zDatabase==0
|
||||
&& pItem->zName!=0
|
||||
&& 0==sqlite3StrICmp(pItem->zName, pCte->zName)
|
||||
@@ -4957,7 +5045,7 @@ static int withExpand(
|
||||
sqlite3ErrorMsg(pParse,
|
||||
"multiple references to recursive table: %s", pCte->zName
|
||||
);
|
||||
return SQLITE_ERROR;
|
||||
return 2;
|
||||
}
|
||||
pRecTerm->selFlags |= SF_Recursive;
|
||||
if( iRecTab<0 ) iRecTab = pParse->nTab++;
|
||||
@@ -4993,7 +5081,7 @@ static int withExpand(
|
||||
pCte->zName, pEList->nExpr, pCte->pCols->nExpr
|
||||
);
|
||||
pParse->pWith = pSavedWith;
|
||||
return SQLITE_ERROR;
|
||||
return 2;
|
||||
}
|
||||
pEList = pCte->pCols;
|
||||
}
|
||||
@@ -5009,9 +5097,9 @@ static int withExpand(
|
||||
}
|
||||
pCte->zCteErr = 0;
|
||||
pParse->pWith = pSavedWith;
|
||||
return 1; /* Success */
|
||||
}
|
||||
|
||||
return SQLITE_OK;
|
||||
return 0; /* No match */
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -5045,7 +5133,7 @@ static void selectPopWith(Walker *pWalker, Select *p){
|
||||
** SQLITE_OK is returned. Otherwise, if an OOM error is encountered,
|
||||
** SQLITE_NOMEM.
|
||||
*/
|
||||
int sqlite3ExpandSubquery(Parse *pParse, struct SrcList_item *pFrom){
|
||||
int sqlite3ExpandSubquery(Parse *pParse, SrcItem *pFrom){
|
||||
Select *pSel = pFrom->pSelect;
|
||||
Table *pTab;
|
||||
|
||||
@@ -5093,10 +5181,10 @@ int sqlite3ExpandSubquery(Parse *pParse, struct SrcList_item *pFrom){
|
||||
*/
|
||||
static int selectExpander(Walker *pWalker, Select *p){
|
||||
Parse *pParse = pWalker->pParse;
|
||||
int i, j, k;
|
||||
int i, j, k, rc;
|
||||
SrcList *pTabList;
|
||||
ExprList *pEList;
|
||||
struct SrcList_item *pFrom;
|
||||
SrcItem *pFrom;
|
||||
sqlite3 *db = pParse->db;
|
||||
Expr *pE, *pRight, *pExpr;
|
||||
u16 selFlags = p->selFlags;
|
||||
@@ -5132,10 +5220,6 @@ static int selectExpander(Walker *pWalker, Select *p){
|
||||
assert( pFrom->fg.isRecursive==0 || pFrom->pTab!=0 );
|
||||
if( pFrom->pTab ) continue;
|
||||
assert( pFrom->fg.isRecursive==0 );
|
||||
#ifndef SQLITE_OMIT_CTE
|
||||
if( withExpand(pWalker, pFrom) ) return WRC_Abort;
|
||||
if( pFrom->pTab ) {} else
|
||||
#endif
|
||||
if( pFrom->zName==0 ){
|
||||
#ifndef SQLITE_OMIT_SUBQUERY
|
||||
Select *pSel = pFrom->pSelect;
|
||||
@@ -5144,6 +5228,12 @@ static int selectExpander(Walker *pWalker, Select *p){
|
||||
assert( pFrom->pTab==0 );
|
||||
if( sqlite3WalkSelect(pWalker, pSel) ) return WRC_Abort;
|
||||
if( sqlite3ExpandSubquery(pParse, pFrom) ) return WRC_Abort;
|
||||
#endif
|
||||
#ifndef SQLITE_OMIT_CTE
|
||||
}else if( (rc = resolveFromTermToCte(pParse, pWalker, pFrom))!=0 ){
|
||||
if( rc>1 ) return WRC_Abort;
|
||||
pTab = pFrom->pTab;
|
||||
assert( pTab!=0 );
|
||||
#endif
|
||||
}else{
|
||||
/* An ordinary table or view name in the FROM clause */
|
||||
@@ -5166,7 +5256,10 @@ static int selectExpander(Walker *pWalker, Select *p){
|
||||
u8 eCodeOrig = pWalker->eCode;
|
||||
if( sqlite3ViewGetColumnNames(pParse, pTab) ) return WRC_Abort;
|
||||
assert( pFrom->pSelect==0 );
|
||||
if( pTab->pSelect && (db->flags & SQLITE_EnableView)==0 ){
|
||||
if( pTab->pSelect
|
||||
&& (db->flags & SQLITE_EnableView)==0
|
||||
&& pTab->pSchema!=db->aDb[1].pSchema
|
||||
){
|
||||
sqlite3ErrorMsg(pParse, "access to view \"%s\" prohibited",
|
||||
pTab->zName);
|
||||
}
|
||||
@@ -5192,7 +5285,7 @@ static int selectExpander(Walker *pWalker, Select *p){
|
||||
}
|
||||
|
||||
/* Locate the index named by the INDEXED BY clause, if any. */
|
||||
if( sqlite3IndexedByLookup(pParse, pFrom) ){
|
||||
if( pFrom->fg.isIndexedBy && sqlite3IndexedByLookup(pParse, pFrom) ){
|
||||
return WRC_Abort;
|
||||
}
|
||||
}
|
||||
@@ -5435,7 +5528,7 @@ static void selectAddSubqueryTypeInfo(Walker *pWalker, Select *p){
|
||||
Parse *pParse;
|
||||
int i;
|
||||
SrcList *pTabList;
|
||||
struct SrcList_item *pFrom;
|
||||
SrcItem *pFrom;
|
||||
|
||||
assert( p->selFlags & SF_Resolved );
|
||||
if( p->selFlags & SF_HasTypeInfo ) return;
|
||||
@@ -5759,11 +5852,13 @@ static void havingToWhere(Parse *pParse, Select *p){
|
||||
** If it is, then return the SrcList_item for the prior view. If it is not,
|
||||
** then return 0.
|
||||
*/
|
||||
static struct SrcList_item *isSelfJoinView(
|
||||
static SrcItem *isSelfJoinView(
|
||||
SrcList *pTabList, /* Search for self-joins in this FROM clause */
|
||||
struct SrcList_item *pThis /* Search for prior reference to this subquery */
|
||||
SrcItem *pThis /* Search for prior reference to this subquery */
|
||||
){
|
||||
struct SrcList_item *pItem;
|
||||
SrcItem *pItem;
|
||||
assert( pThis->pSelect!=0 );
|
||||
if( pThis->pSelect->selFlags & SF_PushDown ) return 0;
|
||||
for(pItem = pTabList->a; pItem<pThis; pItem++){
|
||||
Select *pS1;
|
||||
if( pItem->pSelect==0 ) continue;
|
||||
@@ -5779,9 +5874,7 @@ static struct SrcList_item *isSelfJoinView(
|
||||
** names in the same FROM clause. */
|
||||
continue;
|
||||
}
|
||||
if( sqlite3ExprCompare(0, pThis->pSelect->pWhere, pS1->pWhere, -1)
|
||||
|| sqlite3ExprCompare(0, pThis->pSelect->pHaving, pS1->pHaving, -1)
|
||||
){
|
||||
if( pItem->pSelect->selFlags & SF_PushDown ){
|
||||
/* The view was modified by some other optimization such as
|
||||
** pushDownWhereTerms() */
|
||||
continue;
|
||||
@@ -5791,6 +5884,15 @@ static struct SrcList_item *isSelfJoinView(
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Deallocate a single AggInfo object
|
||||
*/
|
||||
static void agginfoFree(sqlite3 *db, AggInfo *p){
|
||||
sqlite3DbFree(db, p->aCol);
|
||||
sqlite3DbFree(db, p->aFunc);
|
||||
sqlite3DbFreeNN(db, p);
|
||||
}
|
||||
|
||||
#ifdef SQLITE_COUNTOFVIEW_OPTIMIZATION
|
||||
/*
|
||||
** Attempt to transform a query of the form
|
||||
@@ -5936,8 +6038,19 @@ int sqlite3Select(
|
||||
pDest->eDest==SRT_Except || pDest->eDest==SRT_Discard ||
|
||||
pDest->eDest==SRT_DistQueue || pDest->eDest==SRT_DistFifo );
|
||||
/* All of these destinations are also able to ignore the ORDER BY clause */
|
||||
sqlite3ExprListDelete(db, p->pOrderBy);
|
||||
p->pOrderBy = 0;
|
||||
if( p->pOrderBy ){
|
||||
#if SELECTTRACE_ENABLED
|
||||
SELECTTRACE(1,pParse,p, ("dropping superfluous ORDER BY:\n"));
|
||||
if( sqlite3SelectTrace & 0x100 ){
|
||||
sqlite3TreeViewExprList(0, p->pOrderBy, 0, "ORDERBY");
|
||||
}
|
||||
#endif
|
||||
sqlite3ParserAddCleanup(pParse,
|
||||
(void(*)(sqlite3*,void*))sqlite3ExprListDelete,
|
||||
p->pOrderBy);
|
||||
testcase( pParse->earlyCleanup );
|
||||
p->pOrderBy = 0;
|
||||
}
|
||||
p->selFlags &= ~SF_Distinct;
|
||||
p->selFlags |= SF_NoopOrderBy;
|
||||
}
|
||||
@@ -5958,9 +6071,9 @@ int sqlite3Select(
|
||||
** In this case, it is an error if the target object (pSrc->a[0]) name
|
||||
** or alias is duplicated within FROM clause (pSrc->a[1..n]). */
|
||||
if( p->selFlags & SF_UpdateFrom ){
|
||||
struct SrcList_item *p0 = &p->pSrc->a[0];
|
||||
SrcItem *p0 = &p->pSrc->a[0];
|
||||
for(i=1; i<p->pSrc->nSrc; i++){
|
||||
struct SrcList_item *p1 = &p->pSrc->a[i];
|
||||
SrcItem *p1 = &p->pSrc->a[i];
|
||||
if( p0->pTab==p1->pTab && 0==sqlite3_stricmp(p0->zAlias, p1->zAlias) ){
|
||||
sqlite3ErrorMsg(pParse,
|
||||
"target object/alias may not appear in FROM clause: %s",
|
||||
@@ -5998,7 +6111,7 @@ int sqlite3Select(
|
||||
*/
|
||||
#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
|
||||
for(i=0; !p->pPrior && i<pTabList->nSrc; i++){
|
||||
struct SrcList_item *pItem = &pTabList->a[i];
|
||||
SrcItem *pItem = &pTabList->a[i];
|
||||
Select *pSub = pItem->pSelect;
|
||||
Table *pTab = pItem->pTab;
|
||||
|
||||
@@ -6132,7 +6245,8 @@ int sqlite3Select(
|
||||
** (2) Generate code for all sub-queries
|
||||
*/
|
||||
for(i=0; i<pTabList->nSrc; i++){
|
||||
struct SrcList_item *pItem = &pTabList->a[i];
|
||||
SrcItem *pItem = &pTabList->a[i];
|
||||
SrcItem *pPrior;
|
||||
SelectDest dest;
|
||||
Select *pSub;
|
||||
#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
|
||||
@@ -6192,6 +6306,7 @@ int sqlite3Select(
|
||||
** inside the subquery. This can help the subquery to run more efficiently.
|
||||
*/
|
||||
if( OptimizationEnabled(db, SQLITE_PushDown)
|
||||
&& (pItem->fg.isCte==0 || pItem->u2.pCteUse->eM10d!=M10d_Yes)
|
||||
&& pushDownWhereTerms(pParse, pSub, p->pWhere, pItem->iCursor,
|
||||
(pItem->fg.jointype & JT_OUTER)!=0)
|
||||
){
|
||||
@@ -6202,6 +6317,7 @@ int sqlite3Select(
|
||||
sqlite3TreeViewSelect(0, p, 0);
|
||||
}
|
||||
#endif
|
||||
assert( pItem->pSelect && (pItem->pSelect->selFlags & SF_PushDown)!=0 );
|
||||
}else{
|
||||
SELECTTRACE(0x100,pParse,p,("Push-down not possible\n"));
|
||||
}
|
||||
@@ -6211,16 +6327,18 @@ int sqlite3Select(
|
||||
|
||||
/* Generate code to implement the subquery
|
||||
**
|
||||
** The subquery is implemented as a co-routine if the subquery is
|
||||
** guaranteed to be the outer loop (so that it does not need to be
|
||||
** computed more than once)
|
||||
** The subquery is implemented as a co-routine if:
|
||||
** (1) the subquery is guaranteed to be the outer loop (so that
|
||||
** it does not need to be computed more than once), and
|
||||
** (2) the subquery is not a CTE that should be materialized
|
||||
**
|
||||
** TODO: Are there other reasons beside (1) to use a co-routine
|
||||
** TODO: Are there other reasons beside (1) and (2) to use a co-routine
|
||||
** implementation?
|
||||
*/
|
||||
if( i==0
|
||||
&& (pTabList->nSrc==1
|
||||
|| (pTabList->a[1].fg.jointype&(JT_LEFT|JT_CROSS))!=0) /* (1) */
|
||||
&& (pItem->fg.isCte==0 || pItem->u2.pCteUse->eM10d!=M10d_Yes) /* (2) */
|
||||
){
|
||||
/* Implement a co-routine that will return a single row of the result
|
||||
** set on each invocation.
|
||||
@@ -6240,16 +6358,30 @@ int sqlite3Select(
|
||||
sqlite3VdbeEndCoroutine(v, pItem->regReturn);
|
||||
sqlite3VdbeJumpHere(v, addrTop-1);
|
||||
sqlite3ClearTempRegCache(pParse);
|
||||
}else if( pItem->fg.isCte && pItem->u2.pCteUse->addrM9e>0 ){
|
||||
/* This is a CTE for which materialization code has already been
|
||||
** generated. Invoke the subroutine to compute the materialization,
|
||||
** the make the pItem->iCursor be a copy of the ephemerial table that
|
||||
** holds the result of the materialization. */
|
||||
CteUse *pCteUse = pItem->u2.pCteUse;
|
||||
sqlite3VdbeAddOp2(v, OP_Gosub, pCteUse->regRtn, pCteUse->addrM9e);
|
||||
if( pItem->iCursor!=pCteUse->iCur ){
|
||||
sqlite3VdbeAddOp2(v, OP_OpenDup, pItem->iCursor, pCteUse->iCur);
|
||||
}
|
||||
pSub->nSelectRow = pCteUse->nRowEst;
|
||||
}else if( (pPrior = isSelfJoinView(pTabList, pItem))!=0 ){
|
||||
/* This view has already been materialized by a prior entry in
|
||||
** this same FROM clause. Reuse it. */
|
||||
if( pPrior->addrFillSub ){
|
||||
sqlite3VdbeAddOp2(v, OP_Gosub, pPrior->regReturn, pPrior->addrFillSub);
|
||||
}
|
||||
sqlite3VdbeAddOp2(v, OP_OpenDup, pItem->iCursor, pPrior->iCursor);
|
||||
pSub->nSelectRow = pPrior->pSelect->nSelectRow;
|
||||
}else{
|
||||
/* Generate a subroutine that will fill an ephemeral table with
|
||||
** the content of this subquery. pItem->addrFillSub will point
|
||||
** to the address of the generated subroutine. pItem->regReturn
|
||||
** is a register allocated to hold the subroutine return address
|
||||
*/
|
||||
/* Generate a subroutine that will materialize the view. */
|
||||
int topAddr;
|
||||
int onceAddr = 0;
|
||||
int retAddr;
|
||||
struct SrcList_item *pPrior;
|
||||
|
||||
testcase( pItem->addrFillSub==0 ); /* Ticket c52b09c7f38903b1311 */
|
||||
pItem->regReturn = ++pParse->nMem;
|
||||
@@ -6264,22 +6396,22 @@ int sqlite3Select(
|
||||
}else{
|
||||
VdbeNoopComment((v, "materialize \"%s\"", pItem->pTab->zName));
|
||||
}
|
||||
pPrior = isSelfJoinView(pTabList, pItem);
|
||||
if( pPrior ){
|
||||
sqlite3VdbeAddOp2(v, OP_OpenDup, pItem->iCursor, pPrior->iCursor);
|
||||
assert( pPrior->pSelect!=0 );
|
||||
pSub->nSelectRow = pPrior->pSelect->nSelectRow;
|
||||
}else{
|
||||
sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor);
|
||||
ExplainQueryPlan((pParse, 1, "MATERIALIZE %u", pSub->selId));
|
||||
sqlite3Select(pParse, pSub, &dest);
|
||||
}
|
||||
sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor);
|
||||
ExplainQueryPlan((pParse, 1, "MATERIALIZE %u", pSub->selId));
|
||||
sqlite3Select(pParse, pSub, &dest);
|
||||
pItem->pTab->nRowLogEst = pSub->nSelectRow;
|
||||
if( onceAddr ) sqlite3VdbeJumpHere(v, onceAddr);
|
||||
retAddr = sqlite3VdbeAddOp1(v, OP_Return, pItem->regReturn);
|
||||
VdbeComment((v, "end %s", pItem->pTab->zName));
|
||||
sqlite3VdbeChangeP1(v, topAddr, retAddr);
|
||||
sqlite3ClearTempRegCache(pParse);
|
||||
if( pItem->fg.isCte ){
|
||||
CteUse *pCteUse = pItem->u2.pCteUse;
|
||||
pCteUse->addrM9e = pItem->addrFillSub;
|
||||
pCteUse->regRtn = pItem->regReturn;
|
||||
pCteUse->iCur = pItem->iCursor;
|
||||
pCteUse->nRowEst = pSub->nSelectRow;
|
||||
}
|
||||
}
|
||||
if( db->mallocFailed ) goto select_end;
|
||||
pParse->nHeight -= sqlite3SelectExprHeight(p);
|
||||
@@ -6424,6 +6556,7 @@ int sqlite3Select(
|
||||
sSort.pOrderBy = 0;
|
||||
}
|
||||
}
|
||||
SELECTTRACE(1,pParse,p,("WhereBegin returns\n"));
|
||||
|
||||
/* If sorting index that was created by a prior OP_OpenEphemeral
|
||||
** instruction ended up not being needed, then change the OP_OpenEphemeral
|
||||
@@ -6462,6 +6595,7 @@ int sqlite3Select(
|
||||
|
||||
/* End the database scan loop.
|
||||
*/
|
||||
SELECTTRACE(1,pParse,p,("WhereEnd\n"));
|
||||
sqlite3WhereEnd(pWInfo);
|
||||
}
|
||||
}else{
|
||||
@@ -6532,11 +6666,14 @@ int sqlite3Select(
|
||||
** SELECT statement.
|
||||
*/
|
||||
pAggInfo = sqlite3DbMallocZero(db, sizeof(*pAggInfo) );
|
||||
if( pAggInfo==0 ){
|
||||
if( pAggInfo ){
|
||||
sqlite3ParserAddCleanup(pParse,
|
||||
(void(*)(sqlite3*,void*))agginfoFree, pAggInfo);
|
||||
testcase( pParse->earlyCleanup );
|
||||
}
|
||||
if( db->mallocFailed ){
|
||||
goto select_end;
|
||||
}
|
||||
pAggInfo->pNext = pParse->pAggList;
|
||||
pParse->pAggList = pAggInfo;
|
||||
pAggInfo->selId = p->selId;
|
||||
memset(&sNC, 0, sizeof(sNC));
|
||||
sNC.pParse = pParse;
|
||||
@@ -6655,6 +6792,7 @@ int sqlite3Select(
|
||||
WHERE_GROUPBY | (orderByGrp ? WHERE_SORTBYGROUP : 0), 0
|
||||
);
|
||||
if( pWInfo==0 ) goto select_end;
|
||||
SELECTTRACE(1,pParse,p,("WhereBegin returns\n"));
|
||||
if( sqlite3WhereIsOrdered(pWInfo)==pGroupBy->nExpr ){
|
||||
/* The optimizer is able to deliver rows in group by order so
|
||||
** we do not have to sort. The OP_OpenEphemeral table will be
|
||||
@@ -6703,6 +6841,7 @@ int sqlite3Select(
|
||||
sqlite3VdbeAddOp2(v, OP_SorterInsert, pAggInfo->sortingIdx, regRecord);
|
||||
sqlite3ReleaseTempReg(pParse, regRecord);
|
||||
sqlite3ReleaseTempRange(pParse, regBase, nCol);
|
||||
SELECTTRACE(1,pParse,p,("WhereEnd\n"));
|
||||
sqlite3WhereEnd(pWInfo);
|
||||
pAggInfo->sortingIdxPTab = sortPTab = pParse->nTab++;
|
||||
sortOut = sqlite3GetTempReg(pParse);
|
||||
@@ -6780,6 +6919,7 @@ int sqlite3Select(
|
||||
sqlite3VdbeAddOp2(v, OP_SorterNext, pAggInfo->sortingIdx,addrTopOfLoop);
|
||||
VdbeCoverage(v);
|
||||
}else{
|
||||
SELECTTRACE(1,pParse,p,("WhereEnd\n"));
|
||||
sqlite3WhereEnd(pWInfo);
|
||||
sqlite3VdbeChangeToNoop(v, addrSortingIdx);
|
||||
}
|
||||
@@ -6935,11 +7075,13 @@ int sqlite3Select(
|
||||
if( pWInfo==0 ){
|
||||
goto select_end;
|
||||
}
|
||||
SELECTTRACE(1,pParse,p,("WhereBegin returns\n"));
|
||||
updateAccumulator(pParse, regAcc, pAggInfo);
|
||||
if( regAcc ) sqlite3VdbeAddOp2(v, OP_Integer, 1, regAcc);
|
||||
if( minMaxFlag ){
|
||||
sqlite3WhereMinMaxOptEarlyOut(v, pWInfo);
|
||||
}
|
||||
SELECTTRACE(1,pParse,p,("WhereEnd\n"));
|
||||
sqlite3WhereEnd(pWInfo);
|
||||
finalizeAggFunctions(pParse, pAggInfo);
|
||||
}
|
||||
|
||||
+22
-8
@@ -3891,13 +3891,13 @@ static const char *(azHelp[]) = {
|
||||
".databases List names and files of attached databases",
|
||||
".dbconfig ?op? ?val? List or change sqlite3_db_config() options",
|
||||
".dbinfo ?DB? Show status information about the database",
|
||||
".dump ?TABLE? Render database content as SQL",
|
||||
".dump ?OBJECTS? Render database content as SQL",
|
||||
" Options:",
|
||||
" --data-only Output only INSERT statements",
|
||||
" --newlines Allow unescaped newline characters in output",
|
||||
" --nosys Omit system tables (ex: \"sqlite_stat1\")",
|
||||
" --preserve-rowids Include ROWID values in the output",
|
||||
" TABLE is a LIKE pattern for the tables to dump",
|
||||
" OBJECTS is a LIKE pattern for tables, indexes, triggers or views to dump",
|
||||
" Additional LIKE patterns can be given in subsequent arguments",
|
||||
".echo on|off Turn command echo on or off",
|
||||
".eqp on|off|full|... Enable or disable automatic EXPLAIN QUERY PLAN",
|
||||
@@ -8753,7 +8753,7 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
&& (strncmp(azArg[0], "output", n)==0||strncmp(azArg[0], "once", n)==0))
|
||||
|| (c=='e' && n==5 && strcmp(azArg[0],"excel")==0)
|
||||
){
|
||||
const char *zFile = 0;
|
||||
char *zFile = 0;
|
||||
int bTxtMode = 0;
|
||||
int i;
|
||||
int eMode = 0;
|
||||
@@ -8783,17 +8783,22 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
rc = 1;
|
||||
goto meta_command_exit;
|
||||
}
|
||||
}else if( zFile==0 ){
|
||||
zFile = z;
|
||||
}else if( zFile==0 && eMode!='e' && eMode!='x' ){
|
||||
zFile = sqlite3_mprintf("%s", z);
|
||||
if( zFile[0]=='|' ){
|
||||
while( i+1<nArg ) zFile = sqlite3_mprintf("%z %s", zFile, azArg[++i]);
|
||||
break;
|
||||
}
|
||||
}else{
|
||||
utf8_printf(p->out,"ERROR: extra parameter: \"%s\". Usage:\n",
|
||||
azArg[i]);
|
||||
showHelp(p->out, azArg[0]);
|
||||
rc = 1;
|
||||
sqlite3_free(zFile);
|
||||
goto meta_command_exit;
|
||||
}
|
||||
}
|
||||
if( zFile==0 ) zFile = "stdout";
|
||||
if( zFile==0 ) zFile = sqlite3_mprintf("stdout");
|
||||
if( bOnce ){
|
||||
p->outCount = 2;
|
||||
}else{
|
||||
@@ -8816,7 +8821,8 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
newTempFile(p, "txt");
|
||||
bTxtMode = 1;
|
||||
}
|
||||
zFile = p->zTempFile;
|
||||
sqlite3_free(zFile);
|
||||
zFile = sqlite3_mprintf("%s", p->zTempFile);
|
||||
}
|
||||
#endif /* SQLITE_NOHAVE_SYSTEM */
|
||||
if( zFile[0]=='|' ){
|
||||
@@ -8848,6 +8854,7 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", zFile);
|
||||
}
|
||||
}
|
||||
sqlite3_free(zFile);
|
||||
}else
|
||||
|
||||
if( c=='p' && n>=3 && strncmp(azArg[0], "parameter", n)==0 ){
|
||||
@@ -9031,6 +9038,11 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
goto meta_command_exit;
|
||||
}
|
||||
if( azArg[1][0]=='|' ){
|
||||
#ifdef SQLITE_OMIT_POPEN
|
||||
raw_printf(stderr, "Error: pipes are not supported in this OS\n");
|
||||
rc = 1;
|
||||
p->out = stdout;
|
||||
#else
|
||||
p->in = popen(azArg[1]+1, "r");
|
||||
if( p->in==0 ){
|
||||
utf8_printf(stderr, "Error: cannot open \"%s\"\n", azArg[1]);
|
||||
@@ -9039,6 +9051,7 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
rc = process_input(p);
|
||||
pclose(p->in);
|
||||
}
|
||||
#endif
|
||||
}else if( notNormalFile(azArg[1]) || (p->in = fopen(azArg[1], "rb"))==0 ){
|
||||
utf8_printf(stderr,"Error: cannot open \"%s\"\n", azArg[1]);
|
||||
rc = 1;
|
||||
@@ -10816,7 +10829,8 @@ static char *cmdline_option_value(int argc, char **argv, int i){
|
||||
}
|
||||
|
||||
#ifndef SQLITE_SHELL_IS_UTF8
|
||||
# if (defined(_WIN32) || defined(WIN32)) && defined(_MSC_VER)
|
||||
# if (defined(_WIN32) || defined(WIN32)) \
|
||||
&& (defined(_MSC_VER) || (defined(UNICODE) && defined(__GNUC__)))
|
||||
# define SQLITE_SHELL_IS_UTF8 (0)
|
||||
# else
|
||||
# define SQLITE_SHELL_IS_UTF8 (1)
|
||||
|
||||
+7
-1
@@ -2132,7 +2132,13 @@ struct sqlite3_mem_methods {
|
||||
** The second parameter is a pointer to an integer into which
|
||||
** is written 0 or 1 to indicate whether views are disabled or enabled
|
||||
** following this call. The second parameter may be a NULL pointer, in
|
||||
** which case the view setting is not reported back. </dd>
|
||||
** which case the view setting is not reported back.
|
||||
**
|
||||
** <p>Originally this option disabled all views. ^(However, since
|
||||
** SQLite version 3.35.0, TEMP views are still allowed even if
|
||||
** this option is off. So, in other words, this option now only disables
|
||||
** views in the main database schema or in the schemas of ATTACH-ed
|
||||
** databases.)^ </dd>
|
||||
**
|
||||
** [[SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER]]
|
||||
** <dt>SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER</dt>
|
||||
|
||||
+138
-60
@@ -1136,6 +1136,8 @@ typedef struct AutoincInfo AutoincInfo;
|
||||
typedef struct Bitvec Bitvec;
|
||||
typedef struct CollSeq CollSeq;
|
||||
typedef struct Column Column;
|
||||
typedef struct Cte Cte;
|
||||
typedef struct CteUse CteUse;
|
||||
typedef struct Db Db;
|
||||
typedef struct DbFixer DbFixer;
|
||||
typedef struct Schema Schema;
|
||||
@@ -1165,6 +1167,7 @@ typedef struct Savepoint Savepoint;
|
||||
typedef struct Select Select;
|
||||
typedef struct SQLiteThread SQLiteThread;
|
||||
typedef struct SelectDest SelectDest;
|
||||
typedef struct SrcItem SrcItem;
|
||||
typedef struct SrcList SrcList;
|
||||
typedef struct sqlite3_str StrAccum; /* Internal alias for sqlite3_str */
|
||||
typedef struct Table Table;
|
||||
@@ -1478,6 +1481,11 @@ void sqlite3CryptFunc(sqlite3_context*,int,sqlite3_value**);
|
||||
#endif /* SQLITE_OMIT_DEPRECATED */
|
||||
#define SQLITE_TRACE_NONLEGACY_MASK 0x0f /* Normal flags */
|
||||
|
||||
/*
|
||||
** Maximum number of sqlite3.aDb[] entries. This is the number of attached
|
||||
** databases plus 2 for "main" and "temp".
|
||||
*/
|
||||
#define SQLITE_MAX_DB (SQLITE_MAX_ATTACHED+2)
|
||||
|
||||
/*
|
||||
** Each database connection is an instance of the following structure.
|
||||
@@ -1525,7 +1533,10 @@ struct sqlite3 {
|
||||
unsigned orphanTrigger : 1; /* Last statement is orphaned TEMP trigger */
|
||||
unsigned imposterTable : 1; /* Building an imposter table */
|
||||
unsigned reopenMemdb : 1; /* ATTACH is really a reopen using MemDB */
|
||||
unsigned bDropColumn : 1; /* Doing schema check after DROP COLUMN */
|
||||
char **azInit; /* "type", "name", and "tbl_name" columns */
|
||||
/* or if bDropColumn, then azInit[0] is the */
|
||||
/* name of the column being dropped */
|
||||
} init;
|
||||
int nVdbeActive; /* Number of VDBEs currently running */
|
||||
int nVdbeRead; /* Number of active VDBEs that read or write */
|
||||
@@ -2015,7 +2026,12 @@ struct Column {
|
||||
u16 colFlags; /* Boolean properties. See COLFLAG_ defines below */
|
||||
};
|
||||
|
||||
/* Allowed values for Column.colFlags:
|
||||
/* Allowed values for Column.colFlags.
|
||||
**
|
||||
** Constraints:
|
||||
** TF_HasVirtual == COLFLAG_VIRTUAL
|
||||
** TF_HasStored == COLFLAG_STORED
|
||||
** TF_HasHidden == COLFLAG_HIDDEN
|
||||
*/
|
||||
#define COLFLAG_PRIMKEY 0x0001 /* Column is part of the primary key */
|
||||
#define COLFLAG_HIDDEN 0x0002 /* A hidden column in a virtual table */
|
||||
@@ -2204,11 +2220,12 @@ struct Table {
|
||||
**
|
||||
** Constraints:
|
||||
**
|
||||
** TF_HasVirtual == COLFLAG_Virtual
|
||||
** TF_HasStored == COLFLAG_Stored
|
||||
** TF_HasVirtual == COLFLAG_VIRTUAL
|
||||
** TF_HasStored == COLFLAG_STORED
|
||||
** TF_HasHidden == COLFLAG_HIDDEN
|
||||
*/
|
||||
#define TF_Readonly 0x0001 /* Read-only system table */
|
||||
#define TF_Ephemeral 0x0002 /* An ephemeral table */
|
||||
#define TF_HasHidden 0x0002 /* Has one or more hidden columns */
|
||||
#define TF_HasPrimaryKey 0x0004 /* Table has a primary key */
|
||||
#define TF_Autoincrement 0x0008 /* Integer primary key is autoincrement */
|
||||
#define TF_HasStat1 0x0010 /* nRowLogEst set from sqlite_stat1 */
|
||||
@@ -2223,6 +2240,7 @@ struct Table {
|
||||
#define TF_HasNotNull 0x0800 /* Contains NOT NULL constraints */
|
||||
#define TF_Shadow 0x1000 /* True for a shadow table */
|
||||
#define TF_HasStat4 0x2000 /* STAT4 info available for this table */
|
||||
#define TF_Ephemeral 0x4000 /* An ephemeral table */
|
||||
|
||||
/*
|
||||
** Test to see whether or not a table is a virtual table. This is
|
||||
@@ -2591,7 +2609,6 @@ struct AggInfo {
|
||||
} *aFunc;
|
||||
int nFunc; /* Number of entries in aFunc[] */
|
||||
u32 selId; /* Select to which this AggInfo belongs */
|
||||
AggInfo *pNext; /* Next in list of them all */
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -2762,7 +2779,7 @@ struct Expr {
|
||||
#define EP_ConstFunc 0x080000 /* A SQLITE_FUNC_CONSTANT or _SLOCHNG function */
|
||||
#define EP_CanBeNull 0x100000 /* Can be null despite NOT NULL constraint */
|
||||
#define EP_Subquery 0x200000 /* Tree contains a TK_SELECT operator */
|
||||
#define EP_Alias 0x400000 /* Is an alias for a result set column */
|
||||
/* 0x400000 // Available */
|
||||
#define EP_Leaf 0x800000 /* Expr.pLeft, .pRight, .u.pSelect all NULL */
|
||||
#define EP_WinFunc 0x1000000 /* TK_FUNCTION with Expr.y.pWin set */
|
||||
#define EP_Subrtn 0x2000000 /* Uses Expr.y.sub. TK_IN, _SELECT, or _EXISTS */
|
||||
@@ -2910,6 +2927,45 @@ struct IdList {
|
||||
int nId; /* Number of identifiers on the list */
|
||||
};
|
||||
|
||||
/*
|
||||
** The SrcItem object represents a single term in the FROM clause of a query.
|
||||
** The SrcList object is mostly an array of SrcItems.
|
||||
*/
|
||||
struct SrcItem {
|
||||
Schema *pSchema; /* Schema to which this item is fixed */
|
||||
char *zDatabase; /* Name of database holding this table */
|
||||
char *zName; /* Name of the table */
|
||||
char *zAlias; /* The "B" part of a "A AS B" phrase. zName is the "A" */
|
||||
Table *pTab; /* An SQL table corresponding to zName */
|
||||
Select *pSelect; /* A SELECT statement used in place of a table name */
|
||||
int addrFillSub; /* Address of subroutine to manifest a subquery */
|
||||
int regReturn; /* Register holding return address of addrFillSub */
|
||||
int regResult; /* Registers holding results of a co-routine */
|
||||
struct {
|
||||
u8 jointype; /* Type of join between this table and the previous */
|
||||
unsigned notIndexed :1; /* True if there is a NOT INDEXED clause */
|
||||
unsigned isIndexedBy :1; /* True if there is an INDEXED BY clause */
|
||||
unsigned isTabFunc :1; /* True if table-valued-function syntax */
|
||||
unsigned isCorrelated :1; /* True if sub-query is correlated */
|
||||
unsigned viaCoroutine :1; /* Implemented as a co-routine */
|
||||
unsigned isRecursive :1; /* True for recursive reference in WITH */
|
||||
unsigned fromDDL :1; /* Comes from sqlite_schema */
|
||||
unsigned isCte :1; /* This is a CTE */
|
||||
} fg;
|
||||
int iCursor; /* The VDBE cursor number used to access this table */
|
||||
Expr *pOn; /* The ON clause of a join */
|
||||
IdList *pUsing; /* The USING clause of a join */
|
||||
Bitmask colUsed; /* Bit N (1<<N) set if column N of pTab is used */
|
||||
union {
|
||||
char *zIndexedBy; /* Identifier from "INDEXED BY <zIndex>" clause */
|
||||
ExprList *pFuncArg; /* Arguments to table-valued-function */
|
||||
} u1;
|
||||
union {
|
||||
Index *pIBIndex; /* Index structure corresponding to u1.zIndexedBy */
|
||||
CteUse *pCteUse; /* CTE Usage info info fg.isCte is true */
|
||||
} u2;
|
||||
};
|
||||
|
||||
/*
|
||||
** The following structure describes the FROM clause of a SELECT statement.
|
||||
** Each table or subquery in the FROM clause is a separate element of
|
||||
@@ -2932,36 +2988,7 @@ struct IdList {
|
||||
struct SrcList {
|
||||
int nSrc; /* Number of tables or subqueries in the FROM clause */
|
||||
u32 nAlloc; /* Number of entries allocated in a[] below */
|
||||
struct SrcList_item {
|
||||
Schema *pSchema; /* Schema to which this item is fixed */
|
||||
char *zDatabase; /* Name of database holding this table */
|
||||
char *zName; /* Name of the table */
|
||||
char *zAlias; /* The "B" part of a "A AS B" phrase. zName is the "A" */
|
||||
Table *pTab; /* An SQL table corresponding to zName */
|
||||
Select *pSelect; /* A SELECT statement used in place of a table name */
|
||||
int addrFillSub; /* Address of subroutine to manifest a subquery */
|
||||
int regReturn; /* Register holding return address of addrFillSub */
|
||||
int regResult; /* Registers holding results of a co-routine */
|
||||
struct {
|
||||
u8 jointype; /* Type of join between this table and the previous */
|
||||
unsigned notIndexed :1; /* True if there is a NOT INDEXED clause */
|
||||
unsigned isIndexedBy :1; /* True if there is an INDEXED BY clause */
|
||||
unsigned isTabFunc :1; /* True if table-valued-function syntax */
|
||||
unsigned isCorrelated :1; /* True if sub-query is correlated */
|
||||
unsigned viaCoroutine :1; /* Implemented as a co-routine */
|
||||
unsigned isRecursive :1; /* True for recursive reference in WITH */
|
||||
unsigned fromDDL :1; /* Comes from sqlite_schema */
|
||||
} fg;
|
||||
int iCursor; /* The VDBE cursor number used to access this table */
|
||||
Expr *pOn; /* The ON clause of a join */
|
||||
IdList *pUsing; /* The USING clause of a join */
|
||||
Bitmask colUsed; /* Bit N (1<<N) set if column N of pTab is used */
|
||||
union {
|
||||
char *zIndexedBy; /* Identifier from "INDEXED BY <zIndex>" clause */
|
||||
ExprList *pFuncArg; /* Arguments to table-valued-function */
|
||||
} u1;
|
||||
Index *pIBIndex; /* Index structure corresponding to u1.zIndexedBy */
|
||||
} a[1]; /* One entry for each identifier on the list */
|
||||
SrcItem a[1]; /* One entry for each identifier on the list */
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -3037,6 +3064,7 @@ struct NameContext {
|
||||
ExprList *pEList; /* Optional list of result-set columns */
|
||||
AggInfo *pAggInfo; /* Information about aggregates at this level */
|
||||
Upsert *pUpsert; /* ON CONFLICT clause information from an upsert */
|
||||
int iBaseReg; /* For TK_REGISTER when parsing RETURNING */
|
||||
} uNC;
|
||||
NameContext *pNext; /* Next outer name context. NULL for outermost */
|
||||
int nRef; /* Number of names resolved by this context */
|
||||
@@ -3065,6 +3093,7 @@ struct NameContext {
|
||||
#define NC_UEList 0x00080 /* True if uNC.pEList is used */
|
||||
#define NC_UAggInfo 0x00100 /* True if uNC.pAggInfo is used */
|
||||
#define NC_UUpsert 0x00200 /* True if uNC.pUpsert is used */
|
||||
#define NC_UBaseReg 0x00400 /* True if uNC.iBaseReg is used */
|
||||
#define NC_MinMaxAgg 0x01000 /* min/max aggregates seen. See note above */
|
||||
#define NC_Complex 0x02000 /* True if a function or subquery seen */
|
||||
#define NC_AllowWin 0x04000 /* Window functions are allowed here */
|
||||
@@ -3182,6 +3211,8 @@ struct Select {
|
||||
#define SF_View 0x0200000 /* SELECT statement is a view */
|
||||
#define SF_NoopOrderBy 0x0400000 /* ORDER BY is ignored for this query */
|
||||
#define SF_UpdateFrom 0x0800000 /* Statement is an UPDATE...FROM */
|
||||
#define SF_PushDown 0x1000000 /* SELECT has be modified by push-down opt */
|
||||
#define SF_MultiPart 0x2000000 /* Has multiple incompatible PARTITIONs */
|
||||
|
||||
/*
|
||||
** The results of a SELECT can be distributed in several ways, as defined
|
||||
@@ -3424,8 +3455,10 @@ struct Parse {
|
||||
Parse *pToplevel; /* Parse structure for main program (or NULL) */
|
||||
Table *pTriggerTab; /* Table triggers are being coded for */
|
||||
Parse *pParentParse; /* Parent parser if this parser is nested */
|
||||
AggInfo *pAggList; /* List of all AggInfo objects */
|
||||
int addrCrTab; /* Address of OP_CreateBtree opcode on CREATE TABLE */
|
||||
union {
|
||||
int addrCrTab; /* Address of OP_CreateBtree on CREATE TABLE */
|
||||
Returning *pReturning; /* The RETURNING clause */
|
||||
} u1;
|
||||
u32 nQueryLoop; /* Est number of iterations of a query (10*log2(N)) */
|
||||
u32 oldmask; /* Mask of old.* columns referenced */
|
||||
u32 newmask; /* Mask of new.* columns referenced */
|
||||
@@ -3647,7 +3680,7 @@ struct TriggerStep {
|
||||
char *zTarget; /* Target table for DELETE, UPDATE, INSERT */
|
||||
SrcList *pFrom; /* FROM clause for UPDATE statement (if any) */
|
||||
Expr *pWhere; /* The WHERE clause for DELETE or UPDATE steps */
|
||||
ExprList *pExprList; /* SET clause for UPDATE */
|
||||
ExprList *pExprList; /* SET clause for UPDATE, or RETURNING clause */
|
||||
IdList *pIdList; /* Column names for INSERT */
|
||||
Upsert *pUpsert; /* Upsert clauses on an INSERT */
|
||||
char *zSpan; /* Original SQL text of this command */
|
||||
@@ -3663,8 +3696,9 @@ struct Returning {
|
||||
ExprList *pReturnEL; /* List of expressions to return */
|
||||
Trigger retTrig; /* The transient trigger that implements RETURNING */
|
||||
TriggerStep retTStep; /* The trigger step */
|
||||
Select retSel; /* The SELECT statement that implements RETURNING */
|
||||
u64 retSrcList; /* The empty FROM clause of the SELECT */
|
||||
int iRetCur; /* Transient table holding RETURNING results */
|
||||
int nRetCol; /* Number of in pReturnEL after expansion */
|
||||
int iRetReg; /* Register array for holding a row of RETURNING */
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -3704,7 +3738,8 @@ typedef struct {
|
||||
/*
|
||||
** Allowed values for mInitFlags
|
||||
*/
|
||||
#define INITFLAG_AlterTable 0x0001 /* This is a reparse after ALTER TABLE */
|
||||
#define INITFLAG_AlterRename 0x0001 /* Reparse after a RENAME */
|
||||
#define INITFLAG_AlterDrop 0x0002 /* Reparse after a DROP COLUMN */
|
||||
|
||||
/*
|
||||
** Structure containing global configuration data for the SQLite library.
|
||||
@@ -3816,7 +3851,7 @@ struct Walker {
|
||||
struct WhereConst *pConst; /* WHERE clause constants */
|
||||
struct RenameCtx *pRename; /* RENAME COLUMN context */
|
||||
struct Table *pTab; /* Table of generated column */
|
||||
struct SrcList_item *pSrcItem; /* A single FROM clause item */
|
||||
SrcItem *pSrcItem; /* A single FROM clause item */
|
||||
DbFixer *pFix;
|
||||
} u;
|
||||
};
|
||||
@@ -3861,20 +3896,55 @@ void sqlite3SelectWalkAssert2(Walker*, Select*);
|
||||
#define WRC_Abort 2 /* Abandon the tree walk */
|
||||
|
||||
/*
|
||||
** An instance of this structure represents a set of one or more CTEs
|
||||
** (common table expressions) created by a single WITH clause.
|
||||
** A single common table expression
|
||||
*/
|
||||
struct Cte {
|
||||
char *zName; /* Name of this CTE */
|
||||
ExprList *pCols; /* List of explicit column names, or NULL */
|
||||
Select *pSelect; /* The definition of this CTE */
|
||||
const char *zCteErr; /* Error message for circular references */
|
||||
CteUse *pUse; /* Usage information for this CTE */
|
||||
u8 eM10d; /* The MATERIALIZED flag */
|
||||
};
|
||||
|
||||
/*
|
||||
** Allowed values for the materialized flag (eM10d):
|
||||
*/
|
||||
#define M10d_Yes 0 /* AS MATERIALIZED */
|
||||
#define M10d_Any 1 /* Not specified. Query planner's choice */
|
||||
#define M10d_No 2 /* AS NOT MATERIALIZED */
|
||||
|
||||
/*
|
||||
** An instance of the With object represents a WITH clause containing
|
||||
** one or more CTEs (common table expressions).
|
||||
*/
|
||||
struct With {
|
||||
int nCte; /* Number of CTEs in the WITH clause */
|
||||
With *pOuter; /* Containing WITH clause, or NULL */
|
||||
struct Cte { /* For each CTE in the WITH clause.... */
|
||||
char *zName; /* Name of this CTE */
|
||||
ExprList *pCols; /* List of explicit column names, or NULL */
|
||||
Select *pSelect; /* The definition of this CTE */
|
||||
const char *zCteErr; /* Error message for circular references */
|
||||
} a[1];
|
||||
int nCte; /* Number of CTEs in the WITH clause */
|
||||
With *pOuter; /* Containing WITH clause, or NULL */
|
||||
Cte a[1]; /* For each CTE in the WITH clause.... */
|
||||
};
|
||||
|
||||
/*
|
||||
** The Cte object is not guaranteed to persist for the entire duration
|
||||
** of code generation. (The query flattener or other parser tree
|
||||
** edits might delete it.) The following object records information
|
||||
** about each Common Table Expression that must be preserved for the
|
||||
** duration of the parse.
|
||||
**
|
||||
** The CteUse objects are freed using sqlite3ParserAddCleanup() rather
|
||||
** than sqlite3SelectDelete(), which is what enables them to persist
|
||||
** until the end of code generation.
|
||||
*/
|
||||
struct CteUse {
|
||||
int nUse; /* Number of users of this CTE */
|
||||
int addrM9e; /* Start of subroutine to compute materialization */
|
||||
int regRtn; /* Return address register for addrM9e subroutine */
|
||||
int iCur; /* Ephemeral table holding the materialization */
|
||||
LogEst nRowEst; /* Estimated number of rows in the table */
|
||||
u8 eM10d; /* The MATERIALIZED flag */
|
||||
};
|
||||
|
||||
|
||||
#ifdef SQLITE_DEBUG
|
||||
/*
|
||||
** An instance of the TreeView object is used for printing the content of
|
||||
@@ -4334,7 +4404,7 @@ SrcList *sqlite3SrcListAppendFromTerm(Parse*, SrcList*, Token*, Token*,
|
||||
Token*, Select*, Expr*, IdList*);
|
||||
void sqlite3SrcListIndexedBy(Parse *, SrcList *, Token *);
|
||||
void sqlite3SrcListFuncArgs(Parse*, SrcList*, ExprList*);
|
||||
int sqlite3IndexedByLookup(Parse *, struct SrcList_item *);
|
||||
int sqlite3IndexedByLookup(Parse *, SrcItem *);
|
||||
void sqlite3SrcListShiftJoinType(SrcList*);
|
||||
void sqlite3SrcListAssignCursors(Parse*, SrcList*);
|
||||
void sqlite3IdListDelete(sqlite3*, IdList*);
|
||||
@@ -4396,7 +4466,7 @@ Table *sqlite3FindTable(sqlite3*,const char*, const char*);
|
||||
#define LOCATE_VIEW 0x01
|
||||
#define LOCATE_NOERR 0x02
|
||||
Table *sqlite3LocateTable(Parse*,u32 flags,const char*, const char*);
|
||||
Table *sqlite3LocateTableItem(Parse*,u32 flags,struct SrcList_item *);
|
||||
Table *sqlite3LocateTableItem(Parse*,u32 flags,SrcItem *);
|
||||
Index *sqlite3FindIndex(sqlite3*,const char*, const char*);
|
||||
void sqlite3UnlinkAndDeleteTable(sqlite3*,int,const char*);
|
||||
void sqlite3UnlinkAndDeleteIndex(sqlite3*,int,const char*);
|
||||
@@ -4524,6 +4594,7 @@ void sqlite3MaterializeView(Parse*, Table*, Expr*, ExprList*,Expr*,int);
|
||||
#endif
|
||||
|
||||
int sqlite3JoinType(Parse*, Token*, Token*, Token*);
|
||||
int sqlite3ColumnIndex(Table *pTab, const char *zCol);
|
||||
void sqlite3SetJoinExpr(Expr*,int);
|
||||
void sqlite3CreateForeignKey(Parse*, ExprList*, Token*, ExprList*, int);
|
||||
void sqlite3DeferForeignKey(Parse*, int);
|
||||
@@ -4690,7 +4761,7 @@ void sqlite3ExpirePreparedStatements(sqlite3*, int);
|
||||
void sqlite3CodeRhsOfIN(Parse*, Expr*, int);
|
||||
int sqlite3CodeSubselect(Parse*, Expr*);
|
||||
void sqlite3SelectPrep(Parse*, Select*, NameContext*);
|
||||
int sqlite3ExpandSubquery(Parse*, struct SrcList_item*);
|
||||
int sqlite3ExpandSubquery(Parse*, SrcItem*);
|
||||
void sqlite3SelectWrongNumTermsError(Parse *pParse, Select *p);
|
||||
int sqlite3MatchEName(
|
||||
const struct ExprList_item*,
|
||||
@@ -4708,6 +4779,7 @@ int sqlite3ResolveOrderGroupBy(Parse*, Select*, ExprList*, const char*);
|
||||
void sqlite3ColumnDefault(Vdbe *, Table *, int, int);
|
||||
void sqlite3AlterFinishAddColumn(Parse *, Token *);
|
||||
void sqlite3AlterBeginAddColumn(Parse *, SrcList *);
|
||||
void sqlite3AlterDropColumn(Parse*, SrcList*, Token*);
|
||||
void *sqlite3RenameTokenMap(Parse*, void*, Token*);
|
||||
void sqlite3RenameTokenRemap(Parse*, void *pTo, void *pFrom);
|
||||
void sqlite3RenameExprUnmap(Parse*, Expr*);
|
||||
@@ -4731,6 +4803,7 @@ void sqlite3KeyInfoUnref(KeyInfo*);
|
||||
KeyInfo *sqlite3KeyInfoRef(KeyInfo*);
|
||||
KeyInfo *sqlite3KeyInfoOfIndex(Parse*, Index*);
|
||||
KeyInfo *sqlite3KeyInfoFromExprList(Parse*, ExprList*, int, int);
|
||||
const char *sqlite3SelectOpName(int);
|
||||
int sqlite3HasExplicitNulls(Parse*, ExprList*);
|
||||
|
||||
#ifdef SQLITE_DEBUG
|
||||
@@ -4861,7 +4934,7 @@ sqlite3_int64 sqlite3StmtCurrentTime(sqlite3_context*);
|
||||
int sqlite3VdbeParameterIndex(Vdbe*, const char*, int);
|
||||
int sqlite3TransferBindings(sqlite3_stmt *, sqlite3_stmt *);
|
||||
void sqlite3ParserReset(Parse*);
|
||||
void sqlite3ParserAddCleanup(Parse*,void(*)(sqlite3*,void*),void*);
|
||||
void *sqlite3ParserAddCleanup(Parse*,void(*)(sqlite3*,void*),void*);
|
||||
#ifdef SQLITE_ENABLE_NORMALIZE
|
||||
char *sqlite3Normalize(Vdbe*, const char*);
|
||||
#endif
|
||||
@@ -4876,12 +4949,17 @@ const char *sqlite3JournalModename(int);
|
||||
int sqlite3WalDefaultHook(void*,sqlite3*,const char*,int);
|
||||
#endif
|
||||
#ifndef SQLITE_OMIT_CTE
|
||||
With *sqlite3WithAdd(Parse*,With*,Token*,ExprList*,Select*);
|
||||
Cte *sqlite3CteNew(Parse*,Token*,ExprList*,Select*,u8);
|
||||
void sqlite3CteDelete(sqlite3*,Cte*);
|
||||
With *sqlite3WithAdd(Parse*,With*,Cte*);
|
||||
void sqlite3WithDelete(sqlite3*,With*);
|
||||
void sqlite3WithPush(Parse*, With*, u8);
|
||||
#else
|
||||
#define sqlite3WithPush(x,y,z)
|
||||
#define sqlite3WithDelete(x,y)
|
||||
# define sqlite3CteNew(P,T,E,S) ((void*)0)
|
||||
# define sqlite3CteDelete(D,C)
|
||||
# define sqlite3CteWithAdd(P,W,C) ((void*)0)
|
||||
# define sqlite3WithDelete(x,y)
|
||||
# define sqlite3WithPush(x,y,z)
|
||||
#endif
|
||||
#ifndef SQLITE_OMIT_UPSERT
|
||||
Upsert *sqlite3UpsertNew(sqlite3*,ExprList*,Expr*,ExprList*,Expr*,Upsert*);
|
||||
|
||||
+4
-2
@@ -6648,7 +6648,7 @@ static int SQLITE_TCLAPI prng_seed(
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "SEED ?DB?");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( Tcl_GetIntFromObj(interp,objv[0],&i) ) return TCL_ERROR;
|
||||
if( Tcl_GetIntFromObj(interp,objv[1],&i) ) return TCL_ERROR;
|
||||
if( objc==3 && getDbPointer(interp, Tcl_GetString(objv[2]), &db) ){
|
||||
return TCL_ERROR;
|
||||
}
|
||||
@@ -7494,6 +7494,7 @@ static int SQLITE_TCLAPI tclLoadStaticExtensionCmd(
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
extern int sqlite3_amatch_init(sqlite3*,char**,const sqlite3_api_routines*);
|
||||
extern int sqlite3_appendvfs_init(sqlite3*,char**,const sqlite3_api_routines*);
|
||||
extern int sqlite3_carray_init(sqlite3*,char**,const sqlite3_api_routines*);
|
||||
extern int sqlite3_closure_init(sqlite3*,char**,const sqlite3_api_routines*);
|
||||
extern int sqlite3_csv_init(sqlite3*,char**,const sqlite3_api_routines*);
|
||||
@@ -7523,6 +7524,7 @@ static int SQLITE_TCLAPI tclLoadStaticExtensionCmd(
|
||||
int (*pInit)(sqlite3*,char**,const sqlite3_api_routines*);
|
||||
} aExtension[] = {
|
||||
{ "amatch", sqlite3_amatch_init },
|
||||
{ "appendvfs", sqlite3_appendvfs_init },
|
||||
{ "carray", sqlite3_carray_init },
|
||||
{ "closure", sqlite3_closure_init },
|
||||
{ "csv", sqlite3_csv_init },
|
||||
@@ -7571,7 +7573,7 @@ static int SQLITE_TCLAPI tclLoadStaticExtensionCmd(
|
||||
}else{
|
||||
rc = SQLITE_OK;
|
||||
}
|
||||
if( rc!=SQLITE_OK || zErrMsg ){
|
||||
if( (rc!=SQLITE_OK && rc!=SQLITE_OK_LOAD_PERMANENTLY) || zErrMsg ){
|
||||
Tcl_AppendResult(interp, "initialization of ", zName, " failed: ", zErrMsg,
|
||||
(char*)0);
|
||||
sqlite3_free(zErrMsg);
|
||||
|
||||
+8
-2
@@ -111,7 +111,10 @@ void sqlite3TreeViewWith(TreeView *pView, const With *pWith, u8 moreToFollow){
|
||||
}
|
||||
sqlite3_str_appendf(&x, ")");
|
||||
}
|
||||
sqlite3_str_appendf(&x, " AS");
|
||||
if( pCte->pUse ){
|
||||
sqlite3_str_appendf(&x, " (pUse=0x%p, nUse=%d)", pCte->pUse,
|
||||
pCte->pUse->nUse);
|
||||
}
|
||||
sqlite3StrAccumFinish(&x);
|
||||
sqlite3TreeViewItem(pView, zLine, i<pWith->nCte-1);
|
||||
sqlite3TreeViewSelect(pView, pCte->pSelect, 0);
|
||||
@@ -127,7 +130,7 @@ void sqlite3TreeViewWith(TreeView *pView, const With *pWith, u8 moreToFollow){
|
||||
void sqlite3TreeViewSrcList(TreeView *pView, const SrcList *pSrc){
|
||||
int i;
|
||||
for(i=0; i<pSrc->nSrc; i++){
|
||||
const struct SrcList_item *pItem = &pSrc->a[i];
|
||||
const SrcItem *pItem = &pSrc->a[i];
|
||||
StrAccum x;
|
||||
char zLine[100];
|
||||
sqlite3StrAccumInit(&x, 0, zLine, sizeof(zLine), 0);
|
||||
@@ -150,6 +153,9 @@ void sqlite3TreeViewSrcList(TreeView *pView, const SrcList *pSrc){
|
||||
if( pItem->fg.fromDDL ){
|
||||
sqlite3_str_appendf(&x, " DDL");
|
||||
}
|
||||
if( pItem->fg.isCte ){
|
||||
sqlite3_str_appendf(&x, " CteUse=0x%p", pItem->u2.pCteUse);
|
||||
}
|
||||
sqlite3StrAccumFinish(&x);
|
||||
sqlite3TreeViewItem(pView, zLine, i<pSrc->nSrc-1);
|
||||
if( pItem->pSelect ){
|
||||
|
||||
+96
-44
@@ -70,6 +70,8 @@ Trigger *sqlite3TriggerList(Parse *pParse, Table *pTab){
|
||||
pTrig->pNext = pList;
|
||||
pList = pTrig;
|
||||
}else if( pTrig->op==TK_RETURNING ){
|
||||
assert( pParse->bReturning );
|
||||
assert( &(pParse->u1.pReturning->retTrig) == pTrig );
|
||||
pTrig->table = pTab->zName;
|
||||
pTrig->pTabSchema = pTab->pSchema;
|
||||
pTrig->pNext = pList;
|
||||
@@ -354,7 +356,7 @@ void sqlite3FinishTrigger(
|
||||
sqlite3DbFree(db, z);
|
||||
sqlite3ChangeCookie(pParse, iDb);
|
||||
sqlite3VdbeAddParseSchemaOp(v, iDb,
|
||||
sqlite3MPrintf(db, "type='trigger' AND name='%q'", zName));
|
||||
sqlite3MPrintf(db, "type='trigger' AND name='%q'", zName), 0);
|
||||
}
|
||||
|
||||
if( db->init.busy ){
|
||||
@@ -759,16 +761,21 @@ Trigger *sqlite3TriggersExist(
|
||||
** us what time of trigger it should be. */
|
||||
assert( sqlite3IsToplevel(pParse) );
|
||||
p->op = op;
|
||||
mask |= TRIGGER_AFTER;
|
||||
if( IsVirtual(pTab) && op!=TK_INSERT ){
|
||||
sqlite3ErrorMsg(pParse,
|
||||
"%s RETURNING is not available on virtual tables",
|
||||
op==TK_DELETE ? "DELETE" : "UPDATE");
|
||||
if( IsVirtual(pTab) ){
|
||||
if( op!=TK_INSERT ){
|
||||
sqlite3ErrorMsg(pParse,
|
||||
"%s RETURNING is not available on virtual tables",
|
||||
op==TK_DELETE ? "DELETE" : "UPDATE");
|
||||
}
|
||||
p->tr_tm = TRIGGER_BEFORE;
|
||||
}else{
|
||||
p->tr_tm = TRIGGER_AFTER;
|
||||
}
|
||||
mask |= p->tr_tm;
|
||||
}else if( p->bReturning && p->op==TK_INSERT && op==TK_UPDATE
|
||||
&& sqlite3IsToplevel(pParse) ){
|
||||
/* Also fire a RETURNING trigger for an UPSERT */
|
||||
mask |= TRIGGER_AFTER;
|
||||
mask |= p->tr_tm;
|
||||
}
|
||||
p = p->pNext;
|
||||
}while( p );
|
||||
@@ -830,13 +837,15 @@ static ExprList *sqlite3ExpandReturning(
|
||||
ExprList *pNew = 0;
|
||||
sqlite3 *db = pParse->db;
|
||||
int i;
|
||||
|
||||
for(i=0; i<pList->nExpr; i++){
|
||||
Expr *pOldExpr = pList->a[i].pExpr;
|
||||
if( ALWAYS(pOldExpr!=0) && pOldExpr->op==TK_ASTERISK ){
|
||||
int jj;
|
||||
for(jj=0; jj<pTab->nCol; jj++){
|
||||
Expr *pNewExpr;
|
||||
if( IsHiddenColumn(pTab->aCol+jj) ) continue;
|
||||
Expr *pNewExpr = sqlite3Expr(db, TK_ID, pTab->aCol[jj].zName);
|
||||
pNewExpr = sqlite3Expr(db, TK_ID, pTab->aCol[jj].zName);
|
||||
pNew = sqlite3ExprListAppend(pParse, pNew, pNewExpr);
|
||||
if( !db->mallocFailed ){
|
||||
struct ExprList_item *pItem = &pNew->a[pNew->nExpr-1];
|
||||
@@ -854,9 +863,71 @@ static ExprList *sqlite3ExpandReturning(
|
||||
}
|
||||
}
|
||||
}
|
||||
if( !db->mallocFailed ){
|
||||
Vdbe *v = pParse->pVdbe;
|
||||
assert( v!=0 );
|
||||
sqlite3VdbeSetNumCols(v, pNew->nExpr);
|
||||
for(i=0; i<pNew->nExpr; i++){
|
||||
sqlite3VdbeSetColName(v, i, COLNAME_NAME, pNew->a[i].zEName,
|
||||
SQLITE_TRANSIENT);
|
||||
}
|
||||
}
|
||||
return pNew;
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate code for the RETURNING trigger. Unlike other triggers
|
||||
** that invoke a subprogram in the bytecode, the code for RETURNING
|
||||
** is generated in-line.
|
||||
*/
|
||||
static void codeReturningTrigger(
|
||||
Parse *pParse, /* Parse context */
|
||||
Trigger *pTrigger, /* The trigger step that defines the RETURNING */
|
||||
Table *pTab, /* The table to code triggers from */
|
||||
int regIn /* The first in an array of registers */
|
||||
){
|
||||
Vdbe *v = pParse->pVdbe;
|
||||
ExprList *pNew;
|
||||
Returning *pReturning;
|
||||
|
||||
assert( v!=0 );
|
||||
assert( pParse->bReturning );
|
||||
pReturning = pParse->u1.pReturning;
|
||||
assert( pTrigger == &(pReturning->retTrig) );
|
||||
pNew = sqlite3ExpandReturning(pParse, pReturning->pReturnEL, pTab);
|
||||
if( pNew ){
|
||||
NameContext sNC;
|
||||
memset(&sNC, 0, sizeof(sNC));
|
||||
if( pReturning->nRetCol==0 ){
|
||||
pReturning->nRetCol = pNew->nExpr;
|
||||
pReturning->iRetCur = pParse->nTab++;
|
||||
}
|
||||
sNC.pParse = pParse;
|
||||
sNC.uNC.iBaseReg = regIn;
|
||||
sNC.ncFlags = NC_UBaseReg;
|
||||
pParse->eTriggerOp = pTrigger->op;
|
||||
pParse->pTriggerTab = pTab;
|
||||
if( sqlite3ResolveExprListNames(&sNC, pNew)==SQLITE_OK ){
|
||||
int i;
|
||||
int nCol = pNew->nExpr;
|
||||
int reg = pParse->nMem+1;
|
||||
pParse->nMem += nCol+2;
|
||||
pReturning->iRetReg = reg;
|
||||
for(i=0; i<nCol; i++){
|
||||
sqlite3ExprCodeFactorable(pParse, pNew->a[i].pExpr, reg+i);
|
||||
}
|
||||
sqlite3VdbeAddOp3(v, OP_MakeRecord, reg, i, reg+i);
|
||||
sqlite3VdbeAddOp2(v, OP_NewRowid, pReturning->iRetCur, reg+i+1);
|
||||
sqlite3VdbeAddOp3(v, OP_Insert, pReturning->iRetCur, reg+i, reg+i+1);
|
||||
}
|
||||
sqlite3ExprListDelete(pParse->db, pNew);
|
||||
pParse->eTriggerOp = 0;
|
||||
pParse->pTriggerTab = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
** Generate VDBE code for the statements inside the body of a single
|
||||
** trigger.
|
||||
@@ -928,7 +999,7 @@ static int codeTriggerProgram(
|
||||
sqlite3VdbeAddOp0(v, OP_ResetCount);
|
||||
break;
|
||||
}
|
||||
case TK_SELECT: {
|
||||
default: assert( pStep->op==TK_SELECT ); {
|
||||
SelectDest sDest;
|
||||
Select *pSelect = sqlite3SelectDup(db, pStep->pSelect, 0);
|
||||
sqlite3SelectDestInit(&sDest, SRT_Discard, 0);
|
||||
@@ -936,26 +1007,6 @@ static int codeTriggerProgram(
|
||||
sqlite3SelectDelete(db, pSelect);
|
||||
break;
|
||||
}
|
||||
default: assert( pStep->op==TK_RETURNING ); {
|
||||
Select *pSelect = pStep->pSelect;
|
||||
ExprList *pList = pSelect->pEList;
|
||||
SelectDest sDest;
|
||||
Select *pNew;
|
||||
pSelect->pEList =
|
||||
sqlite3ExpandReturning(pParse, pList, pParse->pTriggerTab);
|
||||
sqlite3SelectDestInit(&sDest, SRT_Output, 0);
|
||||
pNew = sqlite3SelectDup(db, pSelect, 0);
|
||||
if( pNew ){
|
||||
sqlite3Select(pParse, pNew, &sDest);
|
||||
if( pNew->selFlags & (SF_Aggregate|SF_HasAgg|SF_WinRewrite) ){
|
||||
sqlite3ErrorMsg(pParse, "aggregates not allowed in RETURNING");
|
||||
}
|
||||
sqlite3SelectDelete(db, pNew);
|
||||
}
|
||||
sqlite3ExprListDelete(db, pSelect->pEList);
|
||||
pStep->pSelect->pEList = pList;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1046,7 +1097,6 @@ static TriggerPrg *codeRowTrigger(
|
||||
pSubParse->pToplevel = pTop;
|
||||
pSubParse->zAuthContext = pTrigger->zName;
|
||||
pSubParse->eTriggerOp = pTrigger->op;
|
||||
pSubParse->bReturning = pTrigger->bReturning;
|
||||
pSubParse->nQueryLoop = pParse->nQueryLoop;
|
||||
pSubParse->disableVtab = pParse->disableVtab;
|
||||
|
||||
@@ -1096,9 +1146,6 @@ static TriggerPrg *codeRowTrigger(
|
||||
if( db->mallocFailed==0 && pParse->nErr==0 ){
|
||||
pProgram->aOp = sqlite3VdbeTakeOpArray(v, &pProgram->nOp, &pTop->nMaxArg);
|
||||
}
|
||||
if( pTrigger->bReturning ){
|
||||
sqlite3VdbeColumnInfoXfer(sqlite3ParseToplevel(pParse)->pVdbe, v);
|
||||
}
|
||||
pProgram->nMem = pSubParse->nMem;
|
||||
pProgram->nCsr = pSubParse->nTab;
|
||||
pProgram->token = (void *)pTrigger;
|
||||
@@ -1208,7 +1255,7 @@ void sqlite3CodeRowTriggerDirect(
|
||||
** ... ...
|
||||
** reg+N OLD.* value of right-most column of pTab
|
||||
** reg+N+1 NEW.rowid
|
||||
** reg+N+2 OLD.* value of left-most column of pTab
|
||||
** reg+N+2 NEW.* value of left-most column of pTab
|
||||
** ... ...
|
||||
** reg+N+N+1 NEW.* value of right-most column of pTab
|
||||
**
|
||||
@@ -1261,12 +1308,12 @@ void sqlite3CodeRowTrigger(
|
||||
if( (p->op==op || (p->bReturning && p->op==TK_INSERT && op==TK_UPDATE))
|
||||
&& p->tr_tm==tr_tm
|
||||
&& checkColumnOverlap(p->pColumns, pChanges)
|
||||
&& (sqlite3IsToplevel(pParse) || !p->bReturning)
|
||||
){
|
||||
u8 origOp = p->op;
|
||||
p->op = op;
|
||||
sqlite3CodeRowTriggerDirect(pParse, p, pTab, reg, orconf, ignoreJump);
|
||||
p->op = origOp;
|
||||
if( !p->bReturning ){
|
||||
sqlite3CodeRowTriggerDirect(pParse, p, pTab, reg, orconf, ignoreJump);
|
||||
}else if( sqlite3IsToplevel(pParse) ){
|
||||
codeReturningTrigger(pParse, p, pTab, reg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1311,13 +1358,18 @@ u32 sqlite3TriggerColmask(
|
||||
|
||||
assert( isNew==1 || isNew==0 );
|
||||
for(p=pTrigger; p; p=p->pNext){
|
||||
if( p->op==op && (tr_tm&p->tr_tm)
|
||||
if( p->op==op
|
||||
&& (tr_tm&p->tr_tm)
|
||||
&& checkColumnOverlap(p->pColumns,pChanges)
|
||||
){
|
||||
TriggerPrg *pPrg;
|
||||
pPrg = getRowTrigger(pParse, p, pTab, orconf);
|
||||
if( pPrg ){
|
||||
mask |= pPrg->aColmask[isNew];
|
||||
if( p->bReturning ){
|
||||
mask = 0xffffffff;
|
||||
}else{
|
||||
TriggerPrg *pPrg;
|
||||
pPrg = getRowTrigger(pParse, p, pTab, orconf);
|
||||
if( pPrg ){
|
||||
mask |= pPrg->aColmask[isNew];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+4
-4
@@ -685,7 +685,7 @@ int sqlite3VdbeExec(
|
||||
#endif
|
||||
/*** INSERT STACK UNION HERE ***/
|
||||
|
||||
assert( p->magic==VDBE_MAGIC_RUN ); /* sqlite3_step() verifies this */
|
||||
assert( p->iVdbeMagic==VDBE_MAGIC_RUN ); /* sqlite3_step() verifies this */
|
||||
sqlite3VdbeEnter(p);
|
||||
#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
|
||||
if( db->xProgress ){
|
||||
@@ -1461,7 +1461,7 @@ case OP_ChngCntRow: {
|
||||
if( (rc = sqlite3VdbeCheckFk(p,0))!=SQLITE_OK ){
|
||||
goto abort_due_to_error;
|
||||
}
|
||||
/* Fall through to the next case, OP_String */
|
||||
/* Fall through to the next case, OP_ResultRow */
|
||||
/* no break */ deliberate_fall_through
|
||||
}
|
||||
|
||||
@@ -3949,7 +3949,7 @@ case OP_OpenEphemeral: {
|
||||
aMem[pOp->p3].z = "";
|
||||
}
|
||||
pCx = p->apCsr[pOp->p1];
|
||||
if( pCx && pCx->pBtx ){
|
||||
if( pCx && ALWAYS(pCx->pBtx) ){
|
||||
/* If the ephermeral table is already open, erase all existing content
|
||||
** so that the table is empty again, rather than creating a new table. */
|
||||
assert( pCx->isEphemeral );
|
||||
@@ -6330,7 +6330,7 @@ case OP_ParseSchema: {
|
||||
if( pOp->p4.z==0 ){
|
||||
sqlite3SchemaClear(db->aDb[iDb].pSchema);
|
||||
db->mDbFlags &= ~DBFLAG_SchemaKnownOk;
|
||||
rc = sqlite3InitOne(db, iDb, &p->zErrMsg, INITFLAG_AlterTable);
|
||||
rc = sqlite3InitOne(db, iDb, &p->zErrMsg, pOp->p5);
|
||||
db->mDbFlags |= DBFLAG_SchemaChange;
|
||||
p->expired = 0;
|
||||
}else
|
||||
|
||||
+1
-2
@@ -223,7 +223,7 @@ VdbeOp *sqlite3VdbeAddOpList(Vdbe*, int nOp, VdbeOpList const *aOp,int iLineno);
|
||||
#else
|
||||
# define sqlite3ExplainBreakpoint(A,B) /*no-op*/
|
||||
#endif
|
||||
void sqlite3VdbeAddParseSchemaOp(Vdbe*,int,char*);
|
||||
void sqlite3VdbeAddParseSchemaOp(Vdbe*, int, char*, u16);
|
||||
void sqlite3VdbeChangeOpcode(Vdbe*, int addr, u8);
|
||||
void sqlite3VdbeChangeP1(Vdbe*, int addr, int P1);
|
||||
void sqlite3VdbeChangeP2(Vdbe*, int addr, int P2);
|
||||
@@ -259,7 +259,6 @@ void sqlite3VdbeResetStepResult(Vdbe*);
|
||||
void sqlite3VdbeRewind(Vdbe*);
|
||||
int sqlite3VdbeReset(Vdbe*);
|
||||
void sqlite3VdbeSetNumCols(Vdbe*,int);
|
||||
void sqlite3VdbeColumnInfoXfer(Vdbe*,Vdbe*);
|
||||
int sqlite3VdbeSetColName(Vdbe*, int, int, const char *, void(*)(void*));
|
||||
void sqlite3VdbeCountChanges(Vdbe*);
|
||||
sqlite3 *sqlite3VdbeDb(Vdbe*);
|
||||
|
||||
+1
-1
@@ -381,7 +381,7 @@ struct Vdbe {
|
||||
Vdbe *pPrev,*pNext; /* Linked list of VDBEs with the same Vdbe.db */
|
||||
Parse *pParse; /* Parsing context used to create this Vdbe */
|
||||
ynVar nVar; /* Number of entries in aVar[] */
|
||||
u32 magic; /* Magic number for sanity checking */
|
||||
u32 iVdbeMagic; /* Magic number defining state of the SQL statement */
|
||||
int nMem; /* Number of memory locations currently allocated */
|
||||
int nCursor; /* Number of slots in apCsr[] */
|
||||
u32 cacheCtr; /* VdbeCursor row cache generation counter */
|
||||
|
||||
+3
-3
@@ -617,7 +617,7 @@ static int sqlite3Step(Vdbe *p){
|
||||
int rc;
|
||||
|
||||
assert(p);
|
||||
if( p->magic!=VDBE_MAGIC_RUN ){
|
||||
if( p->iVdbeMagic!=VDBE_MAGIC_RUN ){
|
||||
/* We used to require that sqlite3_reset() be called before retrying
|
||||
** sqlite3_step() after any error or after SQLITE_DONE. But beginning
|
||||
** with version 3.7.0, we changed this so that sqlite3_reset() would
|
||||
@@ -1333,7 +1333,7 @@ static int vdbeUnbind(Vdbe *p, int i){
|
||||
return SQLITE_MISUSE_BKPT;
|
||||
}
|
||||
sqlite3_mutex_enter(p->db->mutex);
|
||||
if( p->magic!=VDBE_MAGIC_RUN || p->pc>=0 ){
|
||||
if( p->iVdbeMagic!=VDBE_MAGIC_RUN || p->pc>=0 ){
|
||||
sqlite3Error(p->db, SQLITE_MISUSE);
|
||||
sqlite3_mutex_leave(p->db->mutex);
|
||||
sqlite3_log(SQLITE_MISUSE,
|
||||
@@ -1687,7 +1687,7 @@ int sqlite3_stmt_isexplain(sqlite3_stmt *pStmt){
|
||||
*/
|
||||
int sqlite3_stmt_busy(sqlite3_stmt *pStmt){
|
||||
Vdbe *v = (Vdbe*)pStmt;
|
||||
return v!=0 && v->magic==VDBE_MAGIC_RUN && v->pc>=0;
|
||||
return v!=0 && v->iVdbeMagic==VDBE_MAGIC_RUN && v->pc>=0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
+19
-35
@@ -35,7 +35,7 @@ Vdbe *sqlite3VdbeCreate(Parse *pParse){
|
||||
p->pNext = db->pVdbe;
|
||||
p->pPrev = 0;
|
||||
db->pVdbe = p;
|
||||
p->magic = VDBE_MAGIC_INIT;
|
||||
p->iVdbeMagic = VDBE_MAGIC_INIT;
|
||||
p->pParse = pParse;
|
||||
pParse->pVdbe = p;
|
||||
assert( pParse->aLabel==0 );
|
||||
@@ -236,7 +236,7 @@ int sqlite3VdbeAddOp3(Vdbe *p, int op, int p1, int p2, int p3){
|
||||
VdbeOp *pOp;
|
||||
|
||||
i = p->nOp;
|
||||
assert( p->magic==VDBE_MAGIC_INIT );
|
||||
assert( p->iVdbeMagic==VDBE_MAGIC_INIT );
|
||||
assert( op>=0 && op<0xff );
|
||||
if( p->nOpAlloc<=i ){
|
||||
return growOp3(p, op, p1, p2, p3);
|
||||
@@ -471,9 +471,10 @@ void sqlite3VdbeExplainPop(Parse *pParse){
|
||||
** The zWhere string must have been obtained from sqlite3_malloc().
|
||||
** This routine will take ownership of the allocated memory.
|
||||
*/
|
||||
void sqlite3VdbeAddParseSchemaOp(Vdbe *p, int iDb, char *zWhere){
|
||||
void sqlite3VdbeAddParseSchemaOp(Vdbe *p, int iDb, char *zWhere, u16 p5){
|
||||
int j;
|
||||
sqlite3VdbeAddOp4(p, OP_ParseSchema, iDb, 0, 0, zWhere, P4_DYNAMIC);
|
||||
sqlite3VdbeChangeP5(p, p5);
|
||||
for(j=0; j<p->db->nDb; j++) sqlite3VdbeUsesBtree(p, j);
|
||||
sqlite3MayAbort(p->pParse);
|
||||
}
|
||||
@@ -565,7 +566,7 @@ static SQLITE_NOINLINE void resizeResolveLabel(Parse *p, Vdbe *v, int j){
|
||||
void sqlite3VdbeResolveLabel(Vdbe *v, int x){
|
||||
Parse *p = v->pParse;
|
||||
int j = ADDR(x);
|
||||
assert( v->magic==VDBE_MAGIC_INIT );
|
||||
assert( v->iVdbeMagic==VDBE_MAGIC_INIT );
|
||||
assert( j<-p->nLabel );
|
||||
assert( j>=0 );
|
||||
#ifdef SQLITE_DEBUG
|
||||
@@ -890,7 +891,7 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){
|
||||
** Return the address of the next instruction to be inserted.
|
||||
*/
|
||||
int sqlite3VdbeCurrentAddr(Vdbe *p){
|
||||
assert( p->magic==VDBE_MAGIC_INIT );
|
||||
assert( p->iVdbeMagic==VDBE_MAGIC_INIT );
|
||||
return p->nOp;
|
||||
}
|
||||
|
||||
@@ -975,7 +976,7 @@ VdbeOp *sqlite3VdbeAddOpList(
|
||||
int i;
|
||||
VdbeOp *pOut, *pFirst;
|
||||
assert( nOp>0 );
|
||||
assert( p->magic==VDBE_MAGIC_INIT );
|
||||
assert( p->iVdbeMagic==VDBE_MAGIC_INIT );
|
||||
if( p->nOp + nOp > p->nOpAlloc && growOpArray(p, nOp) ){
|
||||
return 0;
|
||||
}
|
||||
@@ -1299,7 +1300,7 @@ void sqlite3VdbeChangeP4(Vdbe *p, int addr, const char *zP4, int n){
|
||||
sqlite3 *db;
|
||||
assert( p!=0 );
|
||||
db = p->db;
|
||||
assert( p->magic==VDBE_MAGIC_INIT );
|
||||
assert( p->iVdbeMagic==VDBE_MAGIC_INIT );
|
||||
assert( p->aOp!=0 || db->mallocFailed );
|
||||
if( db->mallocFailed ){
|
||||
if( n!=P4_VTAB ) freeP4(db, n, (void*)*(char**)&zP4);
|
||||
@@ -1428,7 +1429,7 @@ VdbeOp *sqlite3VdbeGetOp(Vdbe *p, int addr){
|
||||
/* C89 specifies that the constant "dummy" will be initialized to all
|
||||
** zeros, which is correct. MSVC generates a warning, nevertheless. */
|
||||
static VdbeOp dummy; /* Ignore the MSVC warning about no initializer */
|
||||
assert( p->magic==VDBE_MAGIC_INIT );
|
||||
assert( p->iVdbeMagic==VDBE_MAGIC_INIT );
|
||||
if( addr<0 ){
|
||||
addr = p->nOp - 1;
|
||||
}
|
||||
@@ -2113,7 +2114,7 @@ int sqlite3VdbeList(
|
||||
Op *pOp; /* Current opcode */
|
||||
|
||||
assert( p->explain );
|
||||
assert( p->magic==VDBE_MAGIC_RUN );
|
||||
assert( p->iVdbeMagic==VDBE_MAGIC_RUN );
|
||||
assert( p->rc==SQLITE_OK || p->rc==SQLITE_BUSY || p->rc==SQLITE_NOMEM );
|
||||
|
||||
/* Even though this opcode does not use dynamic strings for
|
||||
@@ -2293,14 +2294,14 @@ void sqlite3VdbeRewind(Vdbe *p){
|
||||
int i;
|
||||
#endif
|
||||
assert( p!=0 );
|
||||
assert( p->magic==VDBE_MAGIC_INIT || p->magic==VDBE_MAGIC_RESET );
|
||||
assert( p->iVdbeMagic==VDBE_MAGIC_INIT || p->iVdbeMagic==VDBE_MAGIC_RESET );
|
||||
|
||||
/* There should be at least one opcode.
|
||||
*/
|
||||
assert( p->nOp>0 );
|
||||
|
||||
/* Set the magic to VDBE_MAGIC_RUN sooner rather than later. */
|
||||
p->magic = VDBE_MAGIC_RUN;
|
||||
p->iVdbeMagic = VDBE_MAGIC_RUN;
|
||||
|
||||
#ifdef SQLITE_DEBUG
|
||||
for(i=0; i<p->nMem; i++){
|
||||
@@ -2356,7 +2357,7 @@ void sqlite3VdbeMakeReady(
|
||||
assert( p!=0 );
|
||||
assert( p->nOp>0 );
|
||||
assert( pParse!=0 );
|
||||
assert( p->magic==VDBE_MAGIC_INIT );
|
||||
assert( p->iVdbeMagic==VDBE_MAGIC_INIT );
|
||||
assert( pParse==p->pParse );
|
||||
p->pVList = pParse->pVList;
|
||||
pParse->pVList = 0;
|
||||
@@ -2595,23 +2596,6 @@ void sqlite3VdbeSetNumCols(Vdbe *p, int nResColumn){
|
||||
initMemArray(p->aColName, n, db, MEM_Null);
|
||||
}
|
||||
|
||||
/*
|
||||
** Transfer the column count and name information from one Vdbe to
|
||||
** another.
|
||||
*/
|
||||
void sqlite3VdbeColumnInfoXfer(Vdbe *pTo, Vdbe *pFrom){
|
||||
sqlite3 *db = pTo->db;
|
||||
assert( db==pFrom->db );
|
||||
if( pTo->nResColumn ){
|
||||
releaseMemArray(pTo->aColName, pTo->nResColumn*COLNAME_N);
|
||||
sqlite3DbFree(db, pTo->aColName);
|
||||
}
|
||||
pTo->aColName = pFrom->aColName;
|
||||
pFrom->aColName = 0;
|
||||
pTo->nResColumn = pFrom->nResColumn;
|
||||
pFrom->nResColumn = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Set the name of the idx'th column to be returned by the SQL statement.
|
||||
** zName must be a pointer to a nul terminated string.
|
||||
@@ -3058,7 +3042,7 @@ int sqlite3VdbeHalt(Vdbe *p){
|
||||
** one, or the complete transaction if there is no statement transaction.
|
||||
*/
|
||||
|
||||
if( p->magic!=VDBE_MAGIC_RUN ){
|
||||
if( p->iVdbeMagic!=VDBE_MAGIC_RUN ){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
if( db->mallocFailed ){
|
||||
@@ -3216,7 +3200,7 @@ int sqlite3VdbeHalt(Vdbe *p){
|
||||
assert( db->nVdbeRead>=db->nVdbeWrite );
|
||||
assert( db->nVdbeWrite>=0 );
|
||||
}
|
||||
p->magic = VDBE_MAGIC_HALT;
|
||||
p->iVdbeMagic = VDBE_MAGIC_HALT;
|
||||
checkActiveVdbeCnt(db);
|
||||
if( db->mallocFailed ){
|
||||
p->rc = SQLITE_NOMEM_BKPT;
|
||||
@@ -3389,7 +3373,7 @@ int sqlite3VdbeReset(Vdbe *p){
|
||||
}
|
||||
}
|
||||
#endif
|
||||
p->magic = VDBE_MAGIC_RESET;
|
||||
p->iVdbeMagic = VDBE_MAGIC_RESET;
|
||||
return p->rc & db->errMask;
|
||||
}
|
||||
|
||||
@@ -3399,7 +3383,7 @@ int sqlite3VdbeReset(Vdbe *p){
|
||||
*/
|
||||
int sqlite3VdbeFinalize(Vdbe *p){
|
||||
int rc = SQLITE_OK;
|
||||
if( p->magic==VDBE_MAGIC_RUN || p->magic==VDBE_MAGIC_HALT ){
|
||||
if( p->iVdbeMagic==VDBE_MAGIC_RUN || p->iVdbeMagic==VDBE_MAGIC_HALT ){
|
||||
rc = sqlite3VdbeReset(p);
|
||||
assert( (rc & p->db->errMask)==rc );
|
||||
}
|
||||
@@ -3460,7 +3444,7 @@ void sqlite3VdbeClearObject(sqlite3 *db, Vdbe *p){
|
||||
vdbeFreeOpArray(db, pSub->aOp, pSub->nOp);
|
||||
sqlite3DbFree(db, pSub);
|
||||
}
|
||||
if( p->magic!=VDBE_MAGIC_INIT ){
|
||||
if( p->iVdbeMagic!=VDBE_MAGIC_INIT ){
|
||||
releaseMemArray(p->aVar, p->nVar);
|
||||
sqlite3DbFree(db, p->pVList);
|
||||
sqlite3DbFree(db, p->pFree);
|
||||
@@ -3508,7 +3492,7 @@ void sqlite3VdbeDelete(Vdbe *p){
|
||||
if( p->pNext ){
|
||||
p->pNext->pPrev = p->pPrev;
|
||||
}
|
||||
p->magic = VDBE_MAGIC_DEAD;
|
||||
p->iVdbeMagic = VDBE_MAGIC_DEAD;
|
||||
p->db = 0;
|
||||
sqlite3DbFreeNN(db, p);
|
||||
}
|
||||
|
||||
+3
-2
@@ -489,7 +489,7 @@ void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){
|
||||
|
||||
sqlite3VdbeAddOp0(v, OP_Expire);
|
||||
zWhere = sqlite3MPrintf(db, "name=%Q AND sql=%Q", pTab->zName, zStmt);
|
||||
sqlite3VdbeAddParseSchemaOp(v, iDb, zWhere);
|
||||
sqlite3VdbeAddParseSchemaOp(v, iDb, zWhere, 0);
|
||||
sqlite3DbFree(db, zStmt);
|
||||
|
||||
iReg = ++pParse->nMem;
|
||||
@@ -660,6 +660,7 @@ static int vtabCallConstructor(
|
||||
zType[i-1] = '\0';
|
||||
}
|
||||
pTab->aCol[iCol].colFlags |= COLFLAG_HIDDEN;
|
||||
pTab->tabFlags |= TF_HasHidden;
|
||||
oooHidden = TF_OOOHidden;
|
||||
}else{
|
||||
pTab->tabFlags |= oooHidden;
|
||||
@@ -828,7 +829,7 @@ int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
|
||||
Table *pNew = sParse.pNewTable;
|
||||
Index *pIdx;
|
||||
pTab->aCol = pNew->aCol;
|
||||
pTab->nCol = pNew->nCol;
|
||||
pTab->nNVCol = pTab->nCol = pNew->nCol;
|
||||
pTab->tabFlags |= pNew->tabFlags & (TF_WithoutRowid|TF_NoVisibleRowid);
|
||||
pNew->nCol = 0;
|
||||
pNew->aCol = 0;
|
||||
|
||||
+1
-1
@@ -154,7 +154,7 @@ int sqlite3WalkSelectExpr(Walker *pWalker, Select *p){
|
||||
int sqlite3WalkSelectFrom(Walker *pWalker, Select *p){
|
||||
SrcList *pSrc;
|
||||
int i;
|
||||
struct SrcList_item *pItem;
|
||||
SrcItem *pItem;
|
||||
|
||||
pSrc = p->pSrc;
|
||||
if( pSrc ){
|
||||
|
||||
+23
-23
@@ -694,7 +694,7 @@ static void whereTraceIndexInfoOutputs(sqlite3_index_info *p){
|
||||
*/
|
||||
static int termCanDriveIndex(
|
||||
WhereTerm *pTerm, /* WHERE clause term to check */
|
||||
struct SrcList_item *pSrc, /* Table we are trying to access */
|
||||
SrcItem *pSrc, /* Table we are trying to access */
|
||||
Bitmask notReady /* Tables in outer loops of the join */
|
||||
){
|
||||
char aff;
|
||||
@@ -728,7 +728,7 @@ static int termCanDriveIndex(
|
||||
static void constructAutomaticIndex(
|
||||
Parse *pParse, /* The parsing context */
|
||||
WhereClause *pWC, /* The WHERE clause */
|
||||
struct SrcList_item *pSrc, /* The FROM clause term to get the next index */
|
||||
SrcItem *pSrc, /* The FROM clause term to get the next index */
|
||||
Bitmask notReady, /* Mask of cursors that are not available */
|
||||
WhereLevel *pLevel /* Write new index here */
|
||||
){
|
||||
@@ -752,7 +752,7 @@ static void constructAutomaticIndex(
|
||||
u8 sentWarning = 0; /* True if a warnning has been issued */
|
||||
Expr *pPartial = 0; /* Partial Index Expression */
|
||||
int iContinue = 0; /* Jump here to skip excluded rows */
|
||||
struct SrcList_item *pTabItem; /* FROM clause term being indexed */
|
||||
SrcItem *pTabItem; /* FROM clause term being indexed */
|
||||
int addrCounter = 0; /* Address where integer counter is initialized */
|
||||
int regBase; /* Array of registers where record is assembled */
|
||||
|
||||
@@ -936,7 +936,7 @@ static sqlite3_index_info *allocateIndexInfo(
|
||||
Parse *pParse, /* The parsing context */
|
||||
WhereClause *pWC, /* The WHERE clause being analyzed */
|
||||
Bitmask mUnusable, /* Ignore terms with these prereqs */
|
||||
struct SrcList_item *pSrc, /* The FROM clause term that is the vtab */
|
||||
SrcItem *pSrc, /* The FROM clause term that is the vtab */
|
||||
ExprList *pOrderBy, /* The ORDER BY clause */
|
||||
u16 *pmNoOmit /* Mask of terms not to omit */
|
||||
){
|
||||
@@ -1834,7 +1834,7 @@ void sqlite3WhereClausePrint(WhereClause *pWC){
|
||||
void sqlite3WhereLoopPrint(WhereLoop *p, WhereClause *pWC){
|
||||
WhereInfo *pWInfo = pWC->pWInfo;
|
||||
int nb = 1+(pWInfo->pTabList->nSrc+3)/4;
|
||||
struct SrcList_item *pItem = pWInfo->pTabList->a + p->iTab;
|
||||
SrcItem *pItem = pWInfo->pTabList->a + p->iTab;
|
||||
Table *pTab = pItem->pTab;
|
||||
Bitmask mAll = (((Bitmask)1)<<(nb*4)) - 1;
|
||||
sqlite3DebugPrintf("%c%2d.%0*llx.%0*llx", p->cId,
|
||||
@@ -2445,7 +2445,7 @@ static int whereRangeVectorLen(
|
||||
*/
|
||||
static int whereLoopAddBtreeIndex(
|
||||
WhereLoopBuilder *pBuilder, /* The WhereLoop factory */
|
||||
struct SrcList_item *pSrc, /* FROM clause term being analyzed */
|
||||
SrcItem *pSrc, /* FROM clause term being analyzed */
|
||||
Index *pProbe, /* An index on pSrc */
|
||||
LogEst nInMul /* log(Number of iterations due to IN) */
|
||||
){
|
||||
@@ -2936,7 +2936,7 @@ static int whereLoopAddBtree(
|
||||
LogEst aiRowEstPk[2]; /* The aiRowLogEst[] value for the sPk index */
|
||||
i16 aiColumnPk = -1; /* The aColumn[] value for the sPk index */
|
||||
SrcList *pTabList; /* The FROM clause */
|
||||
struct SrcList_item *pSrc; /* The FROM clause btree term to add */
|
||||
SrcItem *pSrc; /* The FROM clause btree term to add */
|
||||
WhereLoop *pNew; /* Template WhereLoop object */
|
||||
int rc = SQLITE_OK; /* Return code */
|
||||
int iSortIdx = 1; /* Index number */
|
||||
@@ -2954,9 +2954,9 @@ static int whereLoopAddBtree(
|
||||
pWC = pBuilder->pWC;
|
||||
assert( !IsVirtual(pSrc->pTab) );
|
||||
|
||||
if( pSrc->pIBIndex ){
|
||||
if( pSrc->fg.isIndexedBy ){
|
||||
/* An INDEXED BY clause specifies a particular index to use */
|
||||
pProbe = pSrc->pIBIndex;
|
||||
pProbe = pSrc->u2.pIBIndex;
|
||||
}else if( !HasRowid(pTab) ){
|
||||
pProbe = pTab->pIndex;
|
||||
}else{
|
||||
@@ -2992,7 +2992,7 @@ static int whereLoopAddBtree(
|
||||
if( !pBuilder->pOrSet /* Not part of an OR optimization */
|
||||
&& (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)==0
|
||||
&& (pWInfo->pParse->db->flags & SQLITE_AutoIndex)!=0
|
||||
&& pSrc->pIBIndex==0 /* Has no INDEXED BY clause */
|
||||
&& !pSrc->fg.isIndexedBy /* Has no INDEXED BY clause */
|
||||
&& !pSrc->fg.notIndexed /* Has no NOT INDEXED clause */
|
||||
&& HasRowid(pTab) /* Not WITHOUT ROWID table. (FIXME: Why not?) */
|
||||
&& !pSrc->fg.isCorrelated /* Not a correlated subquery */
|
||||
@@ -3042,7 +3042,7 @@ static int whereLoopAddBtree(
|
||||
/* Loop over all indices. If there was an INDEXED BY clause, then only
|
||||
** consider index pProbe. */
|
||||
for(; rc==SQLITE_OK && pProbe;
|
||||
pProbe=(pSrc->pIBIndex ? 0 : pProbe->pNext), iSortIdx++
|
||||
pProbe=(pSrc->fg.isIndexedBy ? 0 : pProbe->pNext), iSortIdx++
|
||||
){
|
||||
int isLeft = (pSrc->fg.jointype & JT_OUTER)!=0;
|
||||
if( pProbe->pPartIdxWhere!=0
|
||||
@@ -3217,7 +3217,7 @@ static int whereLoopAddVirtualOne(
|
||||
int rc = SQLITE_OK;
|
||||
WhereLoop *pNew = pBuilder->pNew;
|
||||
Parse *pParse = pBuilder->pWInfo->pParse;
|
||||
struct SrcList_item *pSrc = &pBuilder->pWInfo->pTabList->a[pNew->iTab];
|
||||
SrcItem *pSrc = &pBuilder->pWInfo->pTabList->a[pNew->iTab];
|
||||
int nConstraint = pIdxInfo->nConstraint;
|
||||
|
||||
assert( (mUsable & mPrereq)==mPrereq );
|
||||
@@ -3409,7 +3409,7 @@ static int whereLoopAddVirtual(
|
||||
WhereInfo *pWInfo; /* WHERE analysis context */
|
||||
Parse *pParse; /* The parsing context */
|
||||
WhereClause *pWC; /* The WHERE clause */
|
||||
struct SrcList_item *pSrc; /* The FROM clause term to search */
|
||||
SrcItem *pSrc; /* The FROM clause term to search */
|
||||
sqlite3_index_info *p; /* Object to pass to xBestIndex() */
|
||||
int nConstraint; /* Number of constraints in p */
|
||||
int bIn; /* True if plan uses IN(...) operator */
|
||||
@@ -3537,7 +3537,7 @@ static int whereLoopAddOr(
|
||||
WhereClause tempWC;
|
||||
WhereLoopBuilder sSubBuild;
|
||||
WhereOrSet sSum, sCur;
|
||||
struct SrcList_item *pItem;
|
||||
SrcItem *pItem;
|
||||
|
||||
pWC = pBuilder->pWC;
|
||||
pWCEnd = pWC->a + pWC->nTerm;
|
||||
@@ -3653,8 +3653,8 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){
|
||||
Bitmask mPrior = 0;
|
||||
int iTab;
|
||||
SrcList *pTabList = pWInfo->pTabList;
|
||||
struct SrcList_item *pItem;
|
||||
struct SrcList_item *pEnd = &pTabList->a[pWInfo->nLevel];
|
||||
SrcItem *pItem;
|
||||
SrcItem *pEnd = &pTabList->a[pWInfo->nLevel];
|
||||
sqlite3 *db = pWInfo->pParse->db;
|
||||
int rc = SQLITE_OK;
|
||||
WhereLoop *pNew;
|
||||
@@ -3677,7 +3677,7 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){
|
||||
}
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
if( IsVirtual(pItem->pTab) ){
|
||||
struct SrcList_item *p;
|
||||
SrcItem *p;
|
||||
for(p=&pItem[1]; p<pEnd; p++){
|
||||
if( mUnusable || (p->fg.jointype & (JT_LEFT|JT_CROSS)) ){
|
||||
mUnusable |= sqlite3WhereGetMask(&pWInfo->sMaskSet, p->iCursor);
|
||||
@@ -4532,7 +4532,7 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
|
||||
*/
|
||||
static int whereShortCut(WhereLoopBuilder *pBuilder){
|
||||
WhereInfo *pWInfo;
|
||||
struct SrcList_item *pItem;
|
||||
SrcItem *pItem;
|
||||
WhereClause *pWC;
|
||||
WhereTerm *pTerm;
|
||||
WhereLoop *pLoop;
|
||||
@@ -4991,7 +4991,7 @@ WhereInfo *sqlite3WhereBegin(
|
||||
if( pWInfo->pOrderBy==0 && (db->flags & SQLITE_ReverseOrder)!=0 ){
|
||||
pWInfo->revMask = ALLBITS;
|
||||
}
|
||||
if( pParse->nErr || NEVER(db->mallocFailed) ){
|
||||
if( pParse->nErr || db->mallocFailed ){
|
||||
goto whereBeginError;
|
||||
}
|
||||
#ifdef WHERETRACE_ENABLED
|
||||
@@ -5062,7 +5062,7 @@ WhereInfo *sqlite3WhereBegin(
|
||||
}
|
||||
for(i=pWInfo->nLevel-1; i>=1; i--){
|
||||
WhereTerm *pTerm, *pEnd;
|
||||
struct SrcList_item *pItem;
|
||||
SrcItem *pItem;
|
||||
pLoop = pWInfo->a[i].pWLoop;
|
||||
pItem = &pWInfo->pTabList->a[pLoop->iTab];
|
||||
if( (pItem->fg.jointype & JT_LEFT)==0 ) continue;
|
||||
@@ -5152,7 +5152,7 @@ WhereInfo *sqlite3WhereBegin(
|
||||
for(ii=0, pLevel=pWInfo->a; ii<nTabList; ii++, pLevel++){
|
||||
Table *pTab; /* Table to open */
|
||||
int iDb; /* Index of database containing table/index */
|
||||
struct SrcList_item *pTabItem;
|
||||
SrcItem *pTabItem;
|
||||
|
||||
pTabItem = &pTabList->a[pLevel->iFrom];
|
||||
pTab = pTabItem->pTab;
|
||||
@@ -5489,7 +5489,7 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
|
||||
int k, last;
|
||||
VdbeOp *pOp, *pLastOp;
|
||||
Index *pIdx = 0;
|
||||
struct SrcList_item *pTabItem = &pTabList->a[pLevel->iFrom];
|
||||
SrcItem *pTabItem = &pTabList->a[pLevel->iFrom];
|
||||
Table *pTab = pTabItem->pTab;
|
||||
assert( pTab!=0 );
|
||||
pLoop = pLevel->pWLoop;
|
||||
@@ -5565,7 +5565,7 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
|
||||
#endif
|
||||
pOp = sqlite3VdbeGetOp(v, k);
|
||||
pLastOp = pOp + (last - k);
|
||||
assert( pOp<pLastOp );
|
||||
assert( pOp<pLastOp || (pParse->nErr>0 && pOp==pLastOp) );
|
||||
do{
|
||||
if( pOp->p1!=pLevel->iTabCur ){
|
||||
/* no-op */
|
||||
|
||||
+1
-1
@@ -540,7 +540,7 @@ Bitmask sqlite3WhereExprUsage(WhereMaskSet*, Expr*);
|
||||
Bitmask sqlite3WhereExprUsageNN(WhereMaskSet*, Expr*);
|
||||
Bitmask sqlite3WhereExprListUsage(WhereMaskSet*, ExprList*);
|
||||
void sqlite3WhereExprAnalyze(SrcList*, WhereClause*);
|
||||
void sqlite3WhereTabFuncArgs(Parse*, struct SrcList_item*, WhereClause*);
|
||||
void sqlite3WhereTabFuncArgs(Parse*, SrcItem*, WhereClause*);
|
||||
|
||||
|
||||
|
||||
|
||||
+4
-4
@@ -129,7 +129,7 @@ int sqlite3WhereExplainOneScan(
|
||||
if( sqlite3ParseToplevel(pParse)->explain==2 )
|
||||
#endif
|
||||
{
|
||||
struct SrcList_item *pItem = &pTabList->a[pLevel->iFrom];
|
||||
SrcItem *pItem = &pTabList->a[pLevel->iFrom];
|
||||
Vdbe *v = pParse->pVdbe; /* VM being constructed */
|
||||
sqlite3 *db = pParse->db; /* Database handle */
|
||||
int isSearch; /* True for a SEARCH. False for SCAN. */
|
||||
@@ -922,7 +922,7 @@ static int codeCursorHintFixExpr(Walker *pWalker, Expr *pExpr){
|
||||
** Insert an OP_CursorHint instruction if it is appropriate to do so.
|
||||
*/
|
||||
static void codeCursorHint(
|
||||
struct SrcList_item *pTabItem, /* FROM clause item */
|
||||
SrcItem *pTabItem, /* FROM clause item */
|
||||
WhereInfo *pWInfo, /* The where clause */
|
||||
WhereLevel *pLevel, /* Which loop to provide hints for */
|
||||
WhereTerm *pEndRange /* Hint this end-of-scan boundary term if not NULL */
|
||||
@@ -1297,7 +1297,7 @@ Bitmask sqlite3WhereCodeOneLoopStart(
|
||||
WhereClause *pWC; /* Decomposition of the entire WHERE clause */
|
||||
WhereTerm *pTerm; /* A WHERE clause term */
|
||||
sqlite3 *db; /* Database connection */
|
||||
struct SrcList_item *pTabItem; /* FROM clause term being coded */
|
||||
SrcItem *pTabItem; /* FROM clause term being coded */
|
||||
int addrBrk; /* Jump here to break out of the loop */
|
||||
int addrHalt; /* addrBrk for the outermost loop */
|
||||
int addrCont; /* Jump here to continue with next cycle */
|
||||
@@ -2085,7 +2085,7 @@ Bitmask sqlite3WhereCodeOneLoopStart(
|
||||
*/
|
||||
if( pWInfo->nLevel>1 ){
|
||||
int nNotReady; /* The number of notReady tables */
|
||||
struct SrcList_item *origSrc; /* Original list of tables */
|
||||
SrcItem *origSrc; /* Original list of tables */
|
||||
nNotReady = pWInfo->nLevel - iLevel - 1;
|
||||
pOrTab = sqlite3StackAllocRaw(db,
|
||||
sizeof(*pOrTab)+ nNotReady*sizeof(pOrTab->a[0]));
|
||||
|
||||
+14
-3
@@ -1028,7 +1028,9 @@ static int exprUsesSrclistCb(Walker *p, Expr *pExpr){
|
||||
/*
|
||||
** Select callback for exprUsesSrclist().
|
||||
*/
|
||||
static int exprUsesSrclistSelectCb(Walker *p, Select *pSelect){
|
||||
static int exprUsesSrclistSelectCb(Walker *NotUsed1, Select *NotUsed2){
|
||||
UNUSED_PARAMETER(NotUsed1);
|
||||
UNUSED_PARAMETER(NotUsed2);
|
||||
return WRC_Abort;
|
||||
}
|
||||
|
||||
@@ -1208,7 +1210,10 @@ static void exprAnalyzeExists(
|
||||
assert( pExpr->op==TK_EXISTS );
|
||||
assert( (pExpr->flags & EP_VarSelect) && (pExpr->flags & EP_xIsSelect) );
|
||||
|
||||
if( (pSel->selFlags & SF_Aggregate) || pSel->pWin ) return;
|
||||
if( pSel->selFlags & SF_Aggregate ) return;
|
||||
#ifndef SQLITE_OMIT_WINDOWFUNC
|
||||
if( pSel->pWin ) return;
|
||||
#endif
|
||||
if( pSel->pPrior ) return;
|
||||
if( pSel->pWhere==0 ) return;
|
||||
if( 0==exprAnalyzeExistsFindEq(pSel, 0, 0) ) return;
|
||||
@@ -1405,6 +1410,12 @@ static void exprAnalyze(
|
||||
pNew->prereqRight = prereqLeft | extraRight;
|
||||
pNew->prereqAll = prereqAll;
|
||||
pNew->eOperator = (operatorMask(pDup->op) + eExtraOp) & opMask;
|
||||
}else if( op==TK_ISNULL && 0==sqlite3ExprCanBeNull(pLeft) ){
|
||||
pExpr->op = TK_TRUEFALSE;
|
||||
pExpr->u.zToken = "false";
|
||||
ExprSetProperty(pExpr, EP_IsFalse);
|
||||
pTerm->prereqAll = 0;
|
||||
pTerm->eOperator = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1851,7 +1862,7 @@ void sqlite3WhereExprAnalyze(
|
||||
*/
|
||||
void sqlite3WhereTabFuncArgs(
|
||||
Parse *pParse, /* Parsing context */
|
||||
struct SrcList_item *pItem, /* The FROM clause term to process */
|
||||
SrcItem *pItem, /* The FROM clause term to process */
|
||||
WhereClause *pWC /* Xfer function arguments to here */
|
||||
){
|
||||
Table *pTab;
|
||||
|
||||
+15
-8
@@ -1304,15 +1304,19 @@ void sqlite3WindowAttach(Parse *pParse, Expr *p, Window *pWin){
|
||||
** SELECT, or (b) the windows already linked use a compatible window frame.
|
||||
*/
|
||||
void sqlite3WindowLink(Select *pSel, Window *pWin){
|
||||
if( pSel!=0
|
||||
&& (0==pSel->pWin || 0==sqlite3WindowCompare(0, pSel->pWin, pWin, 0))
|
||||
){
|
||||
pWin->pNextWin = pSel->pWin;
|
||||
if( pSel->pWin ){
|
||||
pSel->pWin->ppThis = &pWin->pNextWin;
|
||||
if( pSel ){
|
||||
if( 0==pSel->pWin || 0==sqlite3WindowCompare(0, pSel->pWin, pWin, 0) ){
|
||||
pWin->pNextWin = pSel->pWin;
|
||||
if( pSel->pWin ){
|
||||
pSel->pWin->ppThis = &pWin->pNextWin;
|
||||
}
|
||||
pSel->pWin = pWin;
|
||||
pWin->ppThis = &pSel->pWin;
|
||||
}else{
|
||||
if( sqlite3ExprListCompare(pWin->pPartition, pSel->pWin->pPartition,-1) ){
|
||||
pSel->selFlags |= SF_MultiPart;
|
||||
}
|
||||
}
|
||||
pSel->pWin = pWin;
|
||||
pWin->ppThis = &pSel->pWin;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2061,6 +2065,7 @@ static void windowCodeRangeTest(
|
||||
int regString = ++pParse->nMem; /* Reg. for constant value '' */
|
||||
int arith = OP_Add; /* OP_Add or OP_Subtract */
|
||||
int addrGe; /* Jump destination */
|
||||
CollSeq *pColl;
|
||||
|
||||
assert( op==OP_Ge || op==OP_Gt || op==OP_Le );
|
||||
assert( pOrderBy && pOrderBy->nExpr==1 );
|
||||
@@ -2151,6 +2156,8 @@ static void windowCodeRangeTest(
|
||||
** control skips over this test if the BIGNULL flag is set and either
|
||||
** reg1 or reg2 contain a NULL value. */
|
||||
sqlite3VdbeAddOp3(v, op, reg2, lbl, reg1); VdbeCoverage(v);
|
||||
pColl = sqlite3ExprNNCollSeq(pParse, pOrderBy->a[0].pExpr);
|
||||
sqlite3VdbeAppendP4(v, (void*)pColl, P4_COLLSEQ);
|
||||
sqlite3VdbeChangeP5(v, SQLITE_NULLEQ);
|
||||
|
||||
assert( op==OP_Ge || op==OP_Gt || op==OP_Lt || op==OP_Le );
|
||||
|
||||
@@ -903,4 +903,16 @@ ifcapable rtree {
|
||||
} {1 1.0 2.0 3 1.5 3.5}
|
||||
}
|
||||
|
||||
# 2021-03-08 dbsqlfuzz 3f0a7245b69cd08617d7d7781ebaedb0fe765a93
|
||||
reset_db
|
||||
do_catchsql_test alter-18.1 {
|
||||
CREATE TABLE t1(a,b,c);
|
||||
CREATE TABLE log(a INTEGER PRIMARY KEY,b,c);
|
||||
CREATE TRIGGER tr1 AFTER INSERT ON t1 BEGIN
|
||||
INSERT INTO logx(a,b,c) VALUES(new.a,new.b,new.c)
|
||||
ON CONFLICT(a) DO UPDATE SET c=excluded.c, b=new.b;
|
||||
END;
|
||||
ALTER TABLE log RENAME COLUMN a TO x;
|
||||
} {1 {error in trigger tr1: no such table: main.logx}}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -95,4 +95,21 @@ do_auth_test 1.2 {
|
||||
{SQLITE_UPDATE sqlite_temp_master sql temp {}}
|
||||
}
|
||||
|
||||
do_auth_test 1.3 {
|
||||
ALTER TABLE t2 DROP COLUMN c;
|
||||
} {
|
||||
{SQLITE_FUNCTION {} like {} {}}
|
||||
{SQLITE_FUNCTION {} sqlite_drop_column {} {}}
|
||||
{SQLITE_FUNCTION {} sqlite_rename_test {} {}}
|
||||
{SQLITE_READ sqlite_master name main {}}
|
||||
{SQLITE_READ sqlite_master sql main {}}
|
||||
{SQLITE_READ sqlite_master tbl_name main {}}
|
||||
{SQLITE_READ sqlite_master type main {}}
|
||||
{SQLITE_READ sqlite_temp_master name temp {}}
|
||||
{SQLITE_READ sqlite_temp_master sql temp {}}
|
||||
{SQLITE_READ sqlite_temp_master type temp {}}
|
||||
{SQLITE_SELECT {} {} {} {}}
|
||||
{SQLITE_UPDATE sqlite_master sql main {}}
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
+32
-2
@@ -13,8 +13,6 @@
|
||||
# file format change that may be used in the future to implement
|
||||
# "ALTER TABLE ... RENAME COLUMN ... TO".
|
||||
#
|
||||
# $Id: alter4.test,v 1.1 2009/02/02 18:03:22 drh Exp $
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
@@ -804,6 +802,38 @@ do_execsql_test 20.110 {
|
||||
SELECT sql FROM sqlite_master WHERE name='t1';
|
||||
} {{CREATE TABLE t1(xx UNIQUE,yy UNIQUE,zz UNIQUE,UNIQUE(xx),PRIMARY KEY(yy),UNIQUE(zz))}}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_execsql_test 21.0 {
|
||||
CREATE TABLE t1(a, b, c NOT NULL);
|
||||
CREATE TRIGGER tr1 AFTER INSERT ON t1 WHEN new.c IS NOT NULL BEGIN
|
||||
SELECT c NOT NULL FROM t1;
|
||||
END;
|
||||
}
|
||||
|
||||
do_execsql_test 21.1 {
|
||||
ALTER TABLE t1 RENAME c TO d;
|
||||
}
|
||||
|
||||
do_execsql_test 21.2 {
|
||||
SELECT sql FROM sqlite_schema WHERE name IS 'tr1'
|
||||
} {{CREATE TRIGGER tr1 AFTER INSERT ON t1 WHEN new.d IS NOT NULL BEGIN
|
||||
SELECT d NOT NULL FROM t1;
|
||||
END}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 22.0 {
|
||||
CREATE TABLE t1(a, b);
|
||||
CREATE TABLE t2(c, othername, extra AS (c + 1));
|
||||
ALTER TABLE t1 RENAME a to othername;
|
||||
SELECT sql FROM sqlite_schema;
|
||||
} {
|
||||
{CREATE TABLE t1(othername, b)}
|
||||
{CREATE TABLE t2(c, othername, extra AS (c + 1))}
|
||||
}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -0,0 +1,175 @@
|
||||
# 2019-01-11
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix altercorrupt
|
||||
|
||||
database_may_be_corrupt
|
||||
|
||||
#--------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_test 1.0 {
|
||||
sqlite3 db {}
|
||||
db deserialize [decode_hexdb {
|
||||
.open --hexdb
|
||||
| size 24576 pagesize 4096 filename crash-685346d89b5e5f.db
|
||||
| page 1 offset 0
|
||||
| 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3.
|
||||
| 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 06 .....@ ........
|
||||
| 32: 00 00 63 00 00 05 f0 00 00 00 00 04 10 00 00 04 ..c.............
|
||||
| 48: 00 00 00 00 00 00 0f f0 00 00 00 01 00 00 00 00 ................
|
||||
| 64: 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
| 96: 00 00 00 00 0d 0f f8 00 05 0e cf 00 0f 79 0f d3 .............y..
|
||||
| 112: 0f 2e 0e f3 0e cf 00 00 00 00 00 00 00 00 00 00 ................
|
||||
| 3776: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 22 ................
|
||||
| 3792: 05 06 17 11 11 01 31 74 61 62 6c 65 74 34 74 34 ......1tablet4t4
|
||||
| 3808: 06 43 52 45 41 54 45 20 54 41 42 4c 45 20 74 34 .CREATE TABLE t4
|
||||
| 3824: 28 7a 29 39 04 06 17 11 11 01 5f 74 61 62 6c 65 (z)9......_table
|
||||
| 3840: 74 33 74 33 05 43 52 45 41 54 45 20 54 41 42 4c t3t3.CREATE TABL
|
||||
| 3856: 45 20 74 33 28 78 20 49 4e 54 45 47 45 52 20 50 E t3(x INTEGER P
|
||||
| 3872: 52 49 4d 41 52 59 20 4b 45 59 2c 20 79 29 49 03 RIMARY KEY, y)I.
|
||||
| 3888: 06 17 11 11 01 7f 74 61 62 6c 65 74 32 74 32 04 ......tablet2t2.
|
||||
| 3904: 43 52 45 41 54 45 20 54 41 42 4c 45 20 74 32 28 CREATE TABLE t2(
|
||||
| 3920: 61 2c 62 2c 63 20 50 52 49 4d 41 52 59 20 4b 45 a,b,c PRIMARY KE
|
||||
| 3936: 59 2c 20 64 2c 20 65 2c 20 66 29 20 57 49 54 48 Y, d, e, f) WITH
|
||||
| 3952: 4f 55 54 20 52 4f 57 49 44 58 03 07 17 11 11 01 OUT ROWIDX......
|
||||
| 3968: 81 1b 74 61 62 6c 65 74 31 74 31 02 43 52 45 41 ..tablet1t1.CREA
|
||||
| 3984: 54 45 20 54 41 42 4c 45 20 74 31 28 61 2c 62 2c TE TABLE t1(a,b,
|
||||
| 4000: 63 20 41 53 20 28 2d 62 29 20 56 49 52 54 55 41 c AS (-b) VIRTUA
|
||||
| 4016: 4c 2c 64 20 43 48 45 43 4b 28 64 3e 35 29 2c 65 L,d CHECK(d>5),e
|
||||
| 4032: 20 55 4e 49 51 55 45 2c 20 66 20 41 53 20 28 2b UNIQUE, f AS (+
|
||||
| 4048: 62 29 29 23 02 06 17 37 11 01 00 69 6e 64 65 78 b))#...7...index
|
||||
| 4064: 73 71 6c 69 74 65 5f 61 75 74 6f 69 6e 64 65 78 sqlite_autoindex
|
||||
| 4080: 5f 74 31 5f 31 74 31 03 00 00 00 08 00 00 00 00 _t1_1t1.........
|
||||
| page 2 offset 4096
|
||||
| 0: 0d 00 00 00 0a 0f 93 00 0f f6 0f eb 0f e0 0f d5 ................
|
||||
| 16: 0f ca 0f 8f 0f b4 0f a9 0f 9e 0f 93 00 00 00 00 ................
|
||||
| 3984: 00 00 00 09 0a 05 01 01 01 01 0a 64 6e 14 09 09 ...........dn...
|
||||
| 4000: 05 01 01 01 01 09 5a 6d 12 09 08 05 01 01 01 01 ......Zm........
|
||||
| 4016: 08 50 6c 10 09 07 05 01 01 01 01 07 46 6b 0e 09 .Pl.........Fk..
|
||||
| 4032: 06 05 01 01 01 01 06 3c 6a 0c 09 05 05 01 01 01 .......<j.......
|
||||
| 4048: 01 05 32 69 0a 09 04 05 01 01 01 01 04 28 68 08 ..2i.........(h.
|
||||
| 4064: 09 03 05 01 01 01 01 03 1e 67 06 09 02 05 01 01 .........g......
|
||||
| 4080: 01 01 02 14 66 04 08 01 05 09 01 01 01 0a 65 02 ....f.........e.
|
||||
| page 3 offset 8192
|
||||
| 0: 0a 00 00 00 0a 0f c5 00 0f fb 0f f5 0f ef 0f e9 ................
|
||||
| 16: 0f e3 0f dd 0f d7 0f d1 0f cb 0f c5 00 00 00 00 ................
|
||||
| 4032: 00 00 00 00 00 05 03 01 01 14 0a 05 03 01 01 12 ................
|
||||
| 4048: 09 05 03 01 01 10 08 05 03 01 01 0e 07 05 03 01 ................
|
||||
| 4064: 01 0c 06 05 03 01 01 0a 05 05 03 01 01 08 04 05 ................
|
||||
| 4080: 03 01 01 06 03 05 03 01 01 04 02 04 03 01 09 02 ................
|
||||
| page 4 offset 12288
|
||||
| 0: 0a 00 00 00 0a 0f 75 00 0f 75 0f 83 0f 91 0f 9f ......u..u......
|
||||
| 16: 0f ad 0f bb 0f 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
| 3952: 00 00 00 00 00 0d 07 01 01 01 01 01 01 9c 0a 64 ...............d
|
||||
| 3968: 6e 14 64 0d 07 02 01 01 01 01 01 a6 09 5a 6d 12 n.d..........Zm.
|
||||
| 3984: 5a 0d 07 01 01 01 01 01 01 b0 08 50 6c 10 50 0d Z..........Pl.P.
|
||||
| 4000: 07 01 01 01 01 01 01 ba 07 46 6b 0e 46 0d 07 01 .........Fk.F...
|
||||
| 4016: 01 01 01 01 01 c4 06 3c 6a 0c 3c 0d 07 01 01 01 .......<j.<.....
|
||||
| 4032: 01 01 01 ce 05 32 69 0a 32 0d 07 01 01 01 01 01 .....2i.2.......
|
||||
| 4048: 01 d8 04 28 68 08 28 0d 07 01 01 01 01 01 01 e2 ...(h.(.........
|
||||
| 4064: 03 1e 67 06 1e 0d 07 01 01 01 01 01 01 ec 02 14 ..g.............
|
||||
| 4080: 66 04 14 0c 07 01 09 01 01 01 01 f6 0a 65 02 0a f............e..
|
||||
| page 5 offset 16384
|
||||
| 0: 0d 00 00 00 03 0f e9 00 0f e9 0f fb 0f f6 00 00 ................
|
||||
| 16: 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
| 4064: 00 00 00 00 00 00 00 00 00 03 ff ff ff ff ff ff ................
|
||||
| 4080: ff ff 9c 03 00 00 03 64 03 00 00 03 01 03 00 00 .......d........
|
||||
| page 6 offset 20480
|
||||
| 0: 0d 00 00 00 00 10 00 00 00 00 00 00 00 00 00 00 ................
|
||||
| end crash-685346d89b5e5f.db
|
||||
}]} {}
|
||||
|
||||
do_catchsql_test 1.1 {
|
||||
ALTER TABLE t2 DROP COLUMN e;
|
||||
ALTER TABLE t1 DROP COLUMN f;
|
||||
} {1 {database disk image is malformed}}
|
||||
|
||||
|
||||
#--------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_test 2.0 {
|
||||
sqlite3 db {}
|
||||
db deserialize [decode_hexdb {
|
||||
.open --hexdb
|
||||
| size 24576 pagesize 4096 filename crash-0572db8f391431.db
|
||||
| page 1 offset 0
|
||||
| 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3.
|
||||
| 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 06 .....@ ........
|
||||
| 32: 00 00 63 00 10 05 f0 00 00 00 00 04 10 00 00 04 ..c.............
|
||||
| 48: 00 00 00 00 00 00 0f f0 00 00 00 00 00 00 00 00 ................
|
||||
| 96: 00 00 00 00 0d 0f f8 00 05 0e cf 00 0f 79 0f d3 .............y..
|
||||
| 112: 0f 2e 0e f3 0e cf 00 00 00 00 00 00 00 00 00 00 ................
|
||||
| 3776: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 22 ................
|
||||
| 3792: 05 06 17 11 11 01 31 74 61 62 6c 65 74 34 74 34 ......1tablet4t4
|
||||
| 3808: 06 43 52 45 41 54 45 20 54 41 42 4c 45 20 74 34 .CREATE TABLE t4
|
||||
| 3824: 28 7a 29 39 04 06 17 11 11 01 5f 74 61 62 6c 65 (z)9......_table
|
||||
| 3840: 74 33 74 33 05 43 52 45 41 54 45 20 54 41 42 4c t3t3.CREATE TABL
|
||||
| 3856: 45 20 74 33 28 78 20 49 4e 54 55 47 45 52 20 50 E t3(x INTUGER P
|
||||
| 3872: 52 49 4d 41 52 59 20 4b 45 59 2c 20 79 29 49 03 RIMARY KEY, y)I.
|
||||
| 3888: 06 17 11 11 01 7f 74 61 62 6c 65 74 32 74 32 04 ......tablet2t2.
|
||||
| 3904: 43 52 45 41 54 45 20 54 41 42 4c 45 20 74 32 28 CREATE TABLE t2(
|
||||
| 3920: 61 2c 62 2c 63 20 50 52 49 4d 41 52 59 20 4b 45 a,b,c PRIMARY KE
|
||||
| 3936: 59 2c 20 64 2c 20 65 2c 20 66 29 20 57 49 54 48 Y, d, e, f) WITH
|
||||
| 3952: 4f 55 54 20 52 4f 57 49 44 58 05 07 17 11 11 01 OUT ROWIDX......
|
||||
| 3968: 81 1b 74 61 62 6c 65 74 31 74 31 02 43 52 45 41 ..tablet1t1.CREA
|
||||
| 3984: 54 45 20 54 41 42 4c 45 20 74 31 28 61 2c 62 2c TE TABLE t1(a,b,
|
||||
| 4000: 63 20 41 53 20 28 2d 62 29 20 56 49 52 54 55 41 c AS (-b) VIRTUA
|
||||
| 4016: 4c 2c 64 20 43 48 45 43 4b 28 64 3e 35 29 2c 65 L,d CHECK(d>5),e
|
||||
| 4032: 20 55 4e 49 51 55 45 2c 20 66 20 41 53 20 28 2b UNIQUE, f AS (+
|
||||
| 4048: 62 29 29 23 02 06 17 37 11 01 00 69 6e 64 65 78 b))#...7...index
|
||||
| 4064: 73 71 6c 69 74 65 5f 61 75 74 6f 69 6e 64 65 78 sqlite_autoindex
|
||||
| 4080: 5f 74 31 5f 31 84 31 03 01 00 00 08 00 00 00 00 _t1_1.1.........
|
||||
| page 2 offset 4096
|
||||
| 0: 0d 00 00 00 0a 0f 93 00 0f f6 0f eb 0f e0 0f d5 ................
|
||||
| 16: 0f ca 0f 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
| 3984: 00 00 00 09 0a 05 01 01 01 01 0a 64 6e 14 09 09 ...........dn...
|
||||
| 4000: 05 01 01 01 01 09 5a 6d 12 09 08 05 01 00 f1 01 ......Zm........
|
||||
| 4016: 08 50 6c 10 09 07 05 01 01 01 01 07 46 6b 0e 09 .Pl.........Fk..
|
||||
| 4032: 06 05 01 00 f1 01 06 3c 6a 0c 09 05 05 01 01 01 .......<j.......
|
||||
| 4048: 01 05 32 69 0a 09 04 05 01 01 01 01 04 28 68 08 ..2i.........(h.
|
||||
| 4064: 57 03 05 01 01 01 01 03 1e 67 06 09 02 05 01 01 W........g......
|
||||
| 4080: 01 01 02 14 66 04 08 01 05 09 01 01 01 0a 65 02 ....f.........e.
|
||||
| page 3 offset 8192
|
||||
| 0: 09 ff ff ff fa 0f c5 00 0f fb 0f f5 0f ef 0f e9 ................
|
||||
| 16: 0f e3 0f dd 0f d7 00 00 00 00 00 00 00 00 00 00 ................
|
||||
| 4032: 00 00 00 00 00 05 03 01 01 14 0a 05 03 01 01 12 ................
|
||||
| 4048: 09 05 03 01 01 10 08 05 03 01 01 0e 07 05 03 01 ................
|
||||
| 4064: 01 0c 06 05 03 01 01 0a 05 05 03 01 01 08 04 05 ................
|
||||
| 4080: 03 01 01 06 03 05 03 01 01 04 02 04 03 01 09 02 ................
|
||||
| page 4 offset 12288
|
||||
| 0: 0a 00 00 00 0a 0f 75 00 0f 75 0f 83 0f 91 0f 9f ......u..u......
|
||||
| 16: 0f ad 0f bb 0f 00 00 00 00 00 01 00 00 00 00 00 ................
|
||||
| 3952: 00 00 00 00 00 0d 07 01 01 01 01 01 01 9c 0a 64 ...............d
|
||||
| 3968: 6e 14 64 0d 07 02 01 01 01 01 01 a6 09 5a 6d 12 n.d..........Zm.
|
||||
| 3984: 5a 0d 07 01 01 01 01 d4 01 b0 08 50 6c 10 50 0d Z..........Pl.P.
|
||||
| 4000: 07 01 01 01 01 01 01 ba 07 46 6b 0e 46 0d 07 00 .........Fk.F...
|
||||
| 4016: 01 01 01 01 01 c4 06 3c 6a 0c 3c 0d 07 01 01 01 .......<j.<.....
|
||||
| 4032: 01 01 01 ce 05 32 69 0a 32 0d 07 01 01 01 01 01 .....2i.2.......
|
||||
| 4048: 01 d8 04 28 68 08 28 0d 07 01 01 01 01 01 01 e2 ...(h.(.........
|
||||
| 4064: 03 1e 67 06 1e 0d 07 01 01 01 01 01 01 ec 02 14 ..g.............
|
||||
| 4080: 66 04 14 0c 07 01 09 01 01 00 f1 f6 0a 65 02 0a f............e..
|
||||
| page 5 offset 16384
|
||||
| 0: 0d 00 00 00 03 0f e9 00 0f e9 0f fb 0f f6 00 00 ................
|
||||
| 4064: 00 00 00 00 00 00 00 00 00 03 ff ff ff ff ff ff ................
|
||||
| 4080: ff ff 9c 03 00 00 03 64 03 00 01 03 01 03 00 00 .......d........
|
||||
| page 6 offset 20480
|
||||
| 0: 0d 00 10 00 00 10 01 00 00 00 00 00 00 00 00 00 ................
|
||||
| end crash-0572db8f391431.db
|
||||
}]} {}
|
||||
|
||||
do_catchsql_test 2.1 {
|
||||
ALTER TABLE t1 DROP COLUMN a;
|
||||
} {1 {database disk image is malformed}}
|
||||
|
||||
finish_test
|
||||
@@ -0,0 +1,279 @@
|
||||
# 2021 February 16
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#*************************************************************************
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix alterdropcol
|
||||
|
||||
# If SQLITE_OMIT_ALTERTABLE is defined, omit this file.
|
||||
ifcapable !altertable {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE TABLE t1(a, b, c);
|
||||
CREATE VIEW v1 AS SELECT * FROM t1;
|
||||
|
||||
CREATE TABLE t2(x INTEGER PRIMARY KEY, y, z UNIQUE);
|
||||
CREATE INDEX t2y ON t2(y);
|
||||
|
||||
CREATE TABLE t3(q, r, s);
|
||||
CREATE INDEX t3rs ON t3(r+s);
|
||||
}
|
||||
|
||||
do_catchsql_test 1.1 {
|
||||
ALTER TABLE nosuch DROP COLUMN z;
|
||||
} {1 {no such table: nosuch}}
|
||||
|
||||
do_catchsql_test 1.2 {
|
||||
ALTER TABLE v1 DROP COLUMN c;
|
||||
} {1 {cannot drop column from view "v1"}}
|
||||
|
||||
ifcapable fts5 {
|
||||
do_execsql_test 1.3.1 {
|
||||
CREATE VIRTUAL TABLE ft1 USING fts5(one, two);
|
||||
}
|
||||
do_catchsql_test 1.3.2 {
|
||||
ALTER TABLE ft1 DROP COLUMN two;
|
||||
} {1 {cannot drop column from virtual table "ft1"}}
|
||||
}
|
||||
|
||||
do_catchsql_test 1.4 {
|
||||
ALTER TABLE sqlite_schema DROP COLUMN sql;
|
||||
} {1 {table sqlite_master may not be altered}}
|
||||
|
||||
do_catchsql_test 1.5 {
|
||||
ALTER TABLE t1 DROP COLUMN d;
|
||||
} {1 {no such column: "d"}}
|
||||
|
||||
do_execsql_test 1.6.1 {
|
||||
ALTER TABLE t1 DROP COLUMN b;
|
||||
}
|
||||
do_execsql_test 1.6.2 {
|
||||
SELECT sql FROM sqlite_schema WHERE name = 't1'
|
||||
} {{CREATE TABLE t1(a, c)}}
|
||||
|
||||
do_execsql_test 1.7.1 {
|
||||
ALTER TABLE t1 DROP COLUMN c;
|
||||
}
|
||||
do_execsql_test 1.7.2 {
|
||||
SELECT sql FROM sqlite_schema WHERE name = 't1'
|
||||
} {{CREATE TABLE t1(a)}}
|
||||
|
||||
do_catchsql_test 1.7.3 {
|
||||
ALTER TABLE t1 DROP COLUMN a;
|
||||
} {1 {cannot drop column "a": no other columns exist}}
|
||||
|
||||
|
||||
do_catchsql_test 1.8 {
|
||||
ALTER TABLE t2 DROP COLUMN z
|
||||
} {1 {cannot drop UNIQUE column: "z"}}
|
||||
|
||||
do_catchsql_test 1.9 {
|
||||
ALTER TABLE t2 DROP COLUMN x
|
||||
} {1 {cannot drop PRIMARY KEY column: "x"}}
|
||||
|
||||
do_catchsql_test 1.10 {
|
||||
ALTER TABLE t2 DROP COLUMN y
|
||||
} {1 {error in index t2y after drop column: no such column: y}}
|
||||
|
||||
do_catchsql_test 1.11 {
|
||||
ALTER TABLE t3 DROP COLUMN s
|
||||
} {1 {error in index t3rs after drop column: no such column: s}}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
foreach {tn wo} {
|
||||
1 {}
|
||||
2 {WITHOUT ROWID}
|
||||
} { eval [string map [list %TN% $tn %WO% $wo] {
|
||||
|
||||
reset_db
|
||||
do_execsql_test 2.%TN%.0 {
|
||||
CREATE TABLE t1(x, y INTEGER PRIMARY KEY, z) %WO% ;
|
||||
INSERT INTO t1 VALUES(1, 2, 3);
|
||||
INSERT INTO t1 VALUES(4, 5, 6);
|
||||
INSERT INTO t1 VALUES(7, 8, 9);
|
||||
}
|
||||
|
||||
do_execsql_test 2.%TN%.1 {
|
||||
ALTER TABLE t1 DROP COLUMN x;
|
||||
SELECT * FROM t1;
|
||||
} {
|
||||
2 3 5 6 8 9
|
||||
}
|
||||
do_execsql_test 2.%TN%.2 {
|
||||
ALTER TABLE t1 DROP COLUMN z;
|
||||
SELECT * FROM t1;
|
||||
} {
|
||||
2 5 8
|
||||
}
|
||||
}]}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
|
||||
do_execsql_test 3.0 {
|
||||
CREATE TABLE t12(a, b, c, CHECK(c>10));
|
||||
CREATE TABLE t13(a, b, c CHECK(c>10));
|
||||
}
|
||||
do_catchsql_test 3.1 {
|
||||
ALTER TABLE t12 DROP COLUMN c;
|
||||
} {1 {error in table t12 after drop column: no such column: c}}
|
||||
|
||||
do_catchsql_test 3.2 {
|
||||
ALTER TABLE t13 DROP COLUMN c;
|
||||
} {0 {}}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test that generated columns can be dropped. And that other columns from
|
||||
# tables that contain generated columns can be dropped.
|
||||
#
|
||||
foreach {tn wo vs} {
|
||||
1 "" ""
|
||||
2 "" VIRTUAL
|
||||
3 "" STORED
|
||||
4 "WITHOUT ROWID" STORED
|
||||
5 "WITHOUT ROWID" VIRTUAL
|
||||
} {
|
||||
reset_db
|
||||
|
||||
do_execsql_test 4.$tn.0 "
|
||||
CREATE TABLE 'my table'(a, b PRIMARY KEY, c AS (a+b) $vs, d) $wo
|
||||
"
|
||||
do_execsql_test 4.$tn.1 {
|
||||
INSERT INTO "my table"(a, b, d) VALUES(1, 2, 'hello');
|
||||
INSERT INTO "my table"(a, b, d) VALUES(3, 4, 'world');
|
||||
|
||||
SELECT * FROM "my table"
|
||||
} {
|
||||
1 2 3 hello
|
||||
3 4 7 world
|
||||
}
|
||||
|
||||
do_execsql_test 4.$tn.2 {
|
||||
ALTER TABLE "my table" DROP COLUMN c;
|
||||
}
|
||||
do_execsql_test 4.$tn.3 {
|
||||
SELECT * FROM "my table"
|
||||
} {
|
||||
1 2 hello
|
||||
3 4 world
|
||||
}
|
||||
|
||||
do_execsql_test 4.$tn.4 "
|
||||
CREATE TABLE x1(a, b, c PRIMARY KEY, d AS (b+c) $vs, e) $wo
|
||||
"
|
||||
do_execsql_test 4.$tn.5 {
|
||||
INSERT INTO x1(a, b, c, e) VALUES(1, 2, 3, 4);
|
||||
INSERT INTO x1(a, b, c, e) VALUES(5, 6, 7, 8);
|
||||
INSERT INTO x1(a, b, c, e) VALUES(9, 10, 11, 12);
|
||||
SELECT * FROM x1;
|
||||
} {
|
||||
1 2 3 5 4
|
||||
5 6 7 13 8
|
||||
9 10 11 21 12
|
||||
}
|
||||
|
||||
do_execsql_test 4.$tn.6 {
|
||||
ALTER TABLE x1 DROP COLUMN a
|
||||
}
|
||||
do_execsql_test 4.$tn.7 {
|
||||
SELECT * FROM x1
|
||||
} {
|
||||
2 3 5 4
|
||||
6 7 13 8
|
||||
10 11 21 12
|
||||
}
|
||||
do_execsql_test 4.$tn.8 {
|
||||
ALTER TABLE x1 DROP COLUMN e
|
||||
}
|
||||
do_execsql_test 4.$tn.9 {
|
||||
SELECT * FROM x1
|
||||
} {
|
||||
2 3 5
|
||||
6 7 13
|
||||
10 11 21
|
||||
}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_execsql_test 5.0 {
|
||||
CREATE TABLE p1(a PRIMARY KEY, b UNIQUE);
|
||||
CREATE TABLE c1(x, y, z REFERENCES p1(c));
|
||||
CREATE TABLE c2(x, y, z, w REFERENCES p1(b));
|
||||
}
|
||||
do_execsql_test 5.1 {
|
||||
ALTER TABLE c1 DROP COLUMN z;
|
||||
ALTER TABLE c2 DROP COLUMN z;
|
||||
SELECT sql FROM sqlite_schema WHERE name IN ('c1', 'c2');
|
||||
} {
|
||||
{CREATE TABLE c1(x, y)}
|
||||
{CREATE TABLE c2(x, y, w REFERENCES p1(b))}
|
||||
}
|
||||
|
||||
do_execsql_test 5.2.1 {
|
||||
CREATE VIEW v1 AS SELECT d, e FROM p1
|
||||
}
|
||||
do_catchsql_test 5.2.2 {
|
||||
ALTER TABLE c1 DROP COLUMN x
|
||||
} {1 {error in view v1: no such column: d}}
|
||||
do_execsql_test 5.3.1 {
|
||||
DROP VIEW v1;
|
||||
CREATE VIEW v1 AS SELECT x, y FROM c1;
|
||||
}
|
||||
do_catchsql_test 5.3.2 {
|
||||
ALTER TABLE c1 DROP COLUMN x
|
||||
} {1 {error in view v1 after drop column: no such column: x}}
|
||||
|
||||
do_execsql_test 5.4.1 {
|
||||
CREATE TRIGGER tr AFTER INSERT ON c1 BEGIN
|
||||
INSERT INTO p1 VALUES(new.y, new.xyz);
|
||||
END;
|
||||
}
|
||||
do_catchsql_test 5.4.2 {
|
||||
ALTER TABLE c1 DROP COLUMN y
|
||||
} {1 {error in trigger tr: no such column: new.xyz}}
|
||||
do_execsql_test 5.5.1 {
|
||||
DROP TRIGGER tr;
|
||||
CREATE TRIGGER tr AFTER INSERT ON c1 BEGIN
|
||||
INSERT INTO p1 VALUES(new.y, new.z);
|
||||
END;
|
||||
}
|
||||
do_catchsql_test 5.5.2 {
|
||||
ALTER TABLE c1 DROP COLUMN y
|
||||
} {1 {error in trigger tr: no such column: new.z}}
|
||||
|
||||
# 2021-03-06 dbsqlfuzz crash-419aa525df93db6e463772c686ac6da27b46da9e
|
||||
reset_db
|
||||
do_catchsql_test 6.0 {
|
||||
CREATE TABLE t1(a,b,c);
|
||||
CREATE TABLE t2(x,y,z);
|
||||
PRAGMA writable_schema=ON;
|
||||
UPDATE sqlite_schema SET sql='CREATE INDEX t1b ON t1(b)' WHERE name='t2';
|
||||
PRAGMA writable_schema=OFF;
|
||||
ALTER TABLE t2 DROP COLUMN z;
|
||||
} {1 {database disk image is malformed}}
|
||||
reset_db
|
||||
do_catchsql_test 6.1 {
|
||||
CREATE TABLE t1(a,b,c);
|
||||
CREATE TABLE t2(x,y,z);
|
||||
PRAGMA writable_schema=ON;
|
||||
UPDATE sqlite_schema SET sql='CREATE VIEW t2(x,y,z) AS SELECT b,a,c FROM t1'
|
||||
WHERE name='t2';
|
||||
PRAGMA writable_schema=OFF;
|
||||
ALTER TABLE t2 DROP COLUMN z;
|
||||
} {1 {database disk image is malformed}}
|
||||
|
||||
finish_test
|
||||
@@ -0,0 +1,222 @@
|
||||
# 2021 February 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.
|
||||
#
|
||||
#*************************************************************************
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix alterdropcol2
|
||||
|
||||
# If SQLITE_OMIT_ALTERTABLE is defined, omit this file.
|
||||
ifcapable !altertable {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
# EVIDENCE-OF: R-58318-35349 The DROP COLUMN syntax is used to remove an
|
||||
# existing column from a table.
|
||||
do_execsql_test 1.0 {
|
||||
CREATE TABLE t1(c, b, a, PRIMARY KEY(b, a)) WITHOUT ROWID;
|
||||
INSERT INTO t1 VALUES(1, 2, 3), (4, 5, 6);
|
||||
}
|
||||
do_execsql_test 1.1 {
|
||||
ALTER TABLE t1 DROP c;
|
||||
}
|
||||
|
||||
# EVIDENCE-OF: The DROP COLUMN command removes the named column from the table,
|
||||
# and also rewrites the entire table to purge the data associated with that
|
||||
# column.
|
||||
do_execsql_test 1.2.1 {
|
||||
SELECT * FROM t1;
|
||||
} {2 3 5 6}
|
||||
|
||||
do_execsql_test 1.2.2 {
|
||||
SELECT sql FROM sqlite_schema;
|
||||
} {
|
||||
{CREATE TABLE t1(b, a, PRIMARY KEY(b, a)) WITHOUT ROWID}
|
||||
}
|
||||
|
||||
proc do_atdc_error_test {tn schema atdc error} {
|
||||
reset_db
|
||||
execsql $schema
|
||||
uplevel [list do_catchsql_test $tn $atdc [list 1 [string trim $error]]]
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test cases 2.* attempt to verify the following:
|
||||
#
|
||||
# EVIDENCE-OF: R-24098-10282 The DROP COLUMN command only works if the column
|
||||
# is not referenced by any other parts of the schema and is not a PRIMARY KEY
|
||||
# and does not have a UNIQUE constraint.
|
||||
#
|
||||
|
||||
# EVIDENCE-OF: R-52436-31752 The column is a PRIMARY KEY or part of one.
|
||||
#
|
||||
do_atdc_error_test 2.1.1 {
|
||||
CREATE TABLE x1(a PRIMARY KEY, b, c);
|
||||
} {
|
||||
ALTER TABLE x1 DROP COLUMN a
|
||||
} {
|
||||
cannot drop PRIMARY KEY column: "a"
|
||||
}
|
||||
do_atdc_error_test 2.1.2 {
|
||||
CREATE TABLE x1(a,b,c,d,e, PRIMARY KEY(b,c,d));
|
||||
} {
|
||||
ALTER TABLE x1 DROP COLUMN c
|
||||
} {
|
||||
cannot drop PRIMARY KEY column: "c"
|
||||
}
|
||||
|
||||
# EVIDENCE-OF: R-43412-16016 The column has a UNIQUE constraint.
|
||||
#
|
||||
do_atdc_error_test 2.2.1 {
|
||||
CREATE TABLE x1(a PRIMARY KEY, b, c UNIQUE);
|
||||
} {
|
||||
ALTER TABLE x1 DROP COLUMN c
|
||||
} {
|
||||
cannot drop UNIQUE column: "c"
|
||||
}
|
||||
do_atdc_error_test 2.2.2 {
|
||||
CREATE TABLE x1(a PRIMARY KEY, b, c, UNIQUE(b, c));
|
||||
} {
|
||||
ALTER TABLE x1 DROP COLUMN c
|
||||
} {
|
||||
error in table x1 after drop column: no such column: c
|
||||
}
|
||||
|
||||
# EVIDENCE-OF: R-46731-08965 The column is indexed.
|
||||
#
|
||||
do_atdc_error_test 2.3.1 {
|
||||
CREATE TABLE 'one two'('x y', 'z 1', 'a b');
|
||||
CREATE INDEX idx ON 'one two'('z 1');
|
||||
} {
|
||||
ALTER TABLE 'one two' DROP COLUMN 'z 1'
|
||||
} {
|
||||
error in index idx after drop column: no such column: z 1
|
||||
}
|
||||
do_atdc_error_test 2.3.2 {
|
||||
CREATE TABLE x1(a, b, c);
|
||||
CREATE INDEX idx ON x1(a);
|
||||
} {
|
||||
ALTER TABLE x1 DROP COLUMN a;
|
||||
} {
|
||||
error in index idx after drop column: no such column: a
|
||||
}
|
||||
|
||||
# EVIDENCE-OF: R-46731-08965 The column is indexed.
|
||||
#
|
||||
do_atdc_error_test 2.4.1 {
|
||||
CREATE TABLE x1234(a, b, c PRIMARY KEY) WITHOUT ROWID;
|
||||
CREATE INDEX i1 ON x1234(b) WHERE ((a+5) % 10)==0;
|
||||
} {
|
||||
ALTER TABLE x1234 DROP a
|
||||
} {
|
||||
error in index i1 after drop column: no such column: a
|
||||
}
|
||||
|
||||
# EVIDENCE-OF: R-47838-03249 The column is named in a table or column
|
||||
# CHECK constraint not associated with the column being dropped.
|
||||
#
|
||||
do_atdc_error_test 2.5.1 {
|
||||
CREATE TABLE x1234(a, b, c PRIMARY KEY, CHECK(((a+5)%10)!=0)) WITHOUT ROWID;
|
||||
} {
|
||||
ALTER TABLE x1234 DROP a
|
||||
} {
|
||||
error in table x1234 after drop column: no such column: a
|
||||
}
|
||||
|
||||
# EVIDENCE-OF: R-55640-01652 The column is used in a foreign key constraint.
|
||||
#
|
||||
do_atdc_error_test 2.6.1 {
|
||||
CREATE TABLE p1(x, y UNIQUE);
|
||||
CREATE TABLE c1(u, v, FOREIGN KEY (v) REFERENCES p1(y))
|
||||
} {
|
||||
ALTER TABLE c1 DROP v
|
||||
} {
|
||||
error in table c1 after drop column: unknown column "v" in foreign key definition
|
||||
}
|
||||
|
||||
# EVIDENCE-OF: R-20795-39479 The column is used in the expression of a
|
||||
# generated column.
|
||||
do_atdc_error_test 2.7.1 {
|
||||
CREATE TABLE c1(u, v, w AS (u+v));
|
||||
} {
|
||||
ALTER TABLE c1 DROP v
|
||||
} {
|
||||
error in table c1 after drop column: no such column: v
|
||||
}
|
||||
do_atdc_error_test 2.7.2 {
|
||||
CREATE TABLE c1(u, v, w AS (u+v) STORED);
|
||||
} {
|
||||
ALTER TABLE c1 DROP u
|
||||
} {
|
||||
error in table c1 after drop column: no such column: u
|
||||
}
|
||||
|
||||
# EVIDENCE-OF: R-01515-49025 The column appears in a trigger or view.
|
||||
#
|
||||
do_atdc_error_test 2.8.1 {
|
||||
CREATE TABLE log(l);
|
||||
CREATE TABLE c1(u, v, w);
|
||||
CREATE TRIGGER tr1 AFTER INSERT ON c1 BEGIN
|
||||
INSERT INTO log VALUES(new.w);
|
||||
END;
|
||||
} {
|
||||
ALTER TABLE c1 DROP w
|
||||
} {
|
||||
error in trigger tr1 after drop column: no such column: new.w
|
||||
}
|
||||
do_atdc_error_test 2.8.2 {
|
||||
CREATE TABLE c1(u, v, w);
|
||||
CREATE VIEW v1 AS SELECT u, v, w FROM c1;
|
||||
} {
|
||||
ALTER TABLE c1 DROP w
|
||||
} {
|
||||
error in view v1 after drop column: no such column: w
|
||||
}
|
||||
do_atdc_error_test 2.8.3 {
|
||||
CREATE TABLE c1(u, v, w);
|
||||
CREATE VIEW v1 AS SELECT * FROM c1 WHERE w IS NOT NULL;
|
||||
} {
|
||||
ALTER TABLE c1 DROP w
|
||||
} {
|
||||
error in view v1 after drop column: no such column: w
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Verify that a column that is part of a CHECK constraint may be dropped
|
||||
# if the CHECK constraint was specified as part of the column definition.
|
||||
#
|
||||
|
||||
# STALE-EVIDENCE: R-60924-11170 However, the column being deleted can be used in a
|
||||
# column CHECK constraint because the column CHECK constraint is dropped
|
||||
# together with the column itself.
|
||||
do_execsql_test 3.0 {
|
||||
CREATE TABLE yyy(q, w, e CHECK (e > 0), r);
|
||||
INSERT INTO yyy VALUES(1,1,1,1), (2,2,2,2);
|
||||
|
||||
CREATE TABLE zzz(q, w, e, r, CHECK (e > 0));
|
||||
INSERT INTO zzz VALUES(1,1,1,1), (2,2,2,2);
|
||||
}
|
||||
do_catchsql_test 3.1.1 {
|
||||
INSERT INTO yyy VALUES(0,0,0,0);
|
||||
} {1 {CHECK constraint failed: e > 0}}
|
||||
do_catchsql_test 3.1.2 {
|
||||
INSERT INTO yyy VALUES(0,0,0,0);
|
||||
} {1 {CHECK constraint failed: e > 0}}
|
||||
|
||||
do_execsql_test 3.2.1 {
|
||||
ALTER TABLE yyy DROP e;
|
||||
}
|
||||
do_catchsql_test 3.2.2 {
|
||||
ALTER TABLE zzz DROP e;
|
||||
} {1 {error in table zzz after drop column: no such column: e}}
|
||||
|
||||
finish_test
|
||||
@@ -40,7 +40,7 @@ do_execsql_test 1.1 {
|
||||
# slightly different - it rejects the change and rolls back the transaction.
|
||||
do_catchsql_test 1.2 {
|
||||
ALTER TABLE t1 RENAME TO t1new;
|
||||
} {1 {no such column: t1.a}}
|
||||
} {1 {error in table t1new after rename: no such column: t1.a}}
|
||||
|
||||
do_execsql_test 1.3 {
|
||||
CREATE TABLE t3(c, d);
|
||||
@@ -59,7 +59,7 @@ do_execsql_test 1.4 {
|
||||
|
||||
do_catchsql_test 1.3 {
|
||||
ALTER TABLE t2 RENAME TO t2new;
|
||||
} {1 {no such column: t2.b}}
|
||||
} {1 {error in index t2expr after rename: no such column: t2.b}}
|
||||
do_execsql_test 1.4 {
|
||||
SELECT sql FROM sqlite_master
|
||||
} {
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
# 2021 February 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 altermalloc3
|
||||
|
||||
# If SQLITE_OMIT_ALTERTABLE is defined, omit this file.
|
||||
ifcapable !altertable {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE TABLE t1(a, b, c, d, PRIMARY KEY(d, b)) WITHOUT ROWID;
|
||||
INSERT INTO t1 VALUES(1, 2, 3, 4);
|
||||
}
|
||||
faultsim_save_and_close
|
||||
|
||||
do_faultsim_test 1 -prep {
|
||||
faultsim_restore_and_reopen
|
||||
} -body {
|
||||
execsql { ALTER TABLE t1 DROP COLUMN c }
|
||||
} -test {
|
||||
faultsim_test_result {0 {}}
|
||||
}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -711,5 +711,31 @@ do_execsql_test 23.4 {
|
||||
{CREATE VIEW v1 AS SELECT * FROM "idx2" WHERE y='abc'}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 24.1.0 {
|
||||
CREATE TABLE t1(a, b);
|
||||
CREATE TRIGGER AFTER INSERT ON t1 BEGIN
|
||||
INSERT INTO nosuchtable VALUES(new.a) ON CONFLICT(a) DO NOTHING;
|
||||
END;
|
||||
}
|
||||
do_catchsql_test 24.1.1 {
|
||||
ALTER TABLE t1 RENAME TO t2;
|
||||
} {1 {error in trigger AFTER: no such table: main.nosuchtable}}
|
||||
|
||||
reset_db
|
||||
do_execsql_test 24.2.0 {
|
||||
CREATE TABLE t1(a, b);
|
||||
CREATE TRIGGER AFTER INSERT ON t1 BEGIN
|
||||
INSERT INTO v1 VALUES(new.a) ON CONFLICT(a) DO NOTHING;
|
||||
END;
|
||||
CREATE VIEW v1 AS SELECT * FROM nosuchtable;
|
||||
}
|
||||
do_catchsql_test 24.2.1 {
|
||||
ALTER TABLE t1 RENAME TO t2;
|
||||
} {1 {error in trigger AFTER: no such table: main.nosuchtable}}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
@@ -910,4 +910,19 @@ do_execsql_test attach-12.1 {
|
||||
PRAGMA integrity_check;
|
||||
} {ok}
|
||||
|
||||
# 2021-03-10 Forum post https://sqlite.org/forum/forumpost/a006d86f72
|
||||
#
|
||||
reset_db
|
||||
do_test attach-13.1 {
|
||||
sqlite3 db :memory:
|
||||
db eval {CREATE TABLE base(x);}
|
||||
for {set i 0} {$i<$SQLITE_MAX_ATTACHED} {incr i} {
|
||||
db eval "ATTACH ':memory:' AS a$i"
|
||||
}
|
||||
set m "a[expr {$SQLITE_MAX_ATTACHED-1}]"
|
||||
db eval "CREATE TABLE $m.t1(a INTEGER PRIMARY KEY, b);"
|
||||
db eval "CREATE TABLE $m.t2(a INTEGER PRIMARY KEY, b);"
|
||||
db eval {SELECT a FROM t1 WHERE b IN (SELECT a FROM t2);}
|
||||
} {}
|
||||
|
||||
finish_test
|
||||
|
||||
+395
@@ -0,0 +1,395 @@
|
||||
# 2021-03-06
|
||||
#
|
||||
# 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 tests for the appendvfs extension.
|
||||
#
|
||||
# Tests performed:
|
||||
# avfs-1.0. Test that an appendvfs DB can be added to an empty (ZLF) file.
|
||||
# avfs-1.1. Test that the DB can be read with correct content upon reopen.
|
||||
# avfs-1.2. Test that an appendvfs DB can be added to a simple text file.
|
||||
# avfs-1.3. Test that the DB can be read with correct content upon reopen.
|
||||
# avfs-1.4. Test that appended DB is aligned to default page boundary.
|
||||
# avfs-2.1. Test that the simple text file retains its initial text.
|
||||
# avfs-3.1. Test that the appendvfs can grow and shrink, remaining intact.
|
||||
# avfs-3.2. Test that appendvfs is intact after grow/shrink/close/reopen.
|
||||
# avfs-3.3. Test that appendvfs can grow by many pages and be written.
|
||||
# avfs-3.4. Test that grown appendvfs can be reopened and appear intact.
|
||||
# avfs-3.5. Test that much grown appendvfs can shrink and reopen intact.
|
||||
# avfs-4.1. Test shell's ability to append to a non-appendvfs file.
|
||||
# avfs-4.2. Test shell's ability to append to empty or nonexistent file.
|
||||
# avfs-4.3. Test shell's ability to reopen and alter an appendvfs file.
|
||||
# avfs-5.1. Test appendvfs refusal to open too-tiny DB appended onto ZLF.
|
||||
# avfs-5.2. Test appendvfs refusal to open too-tiny DB appended on other.
|
||||
# ...
|
||||
# (more to come)
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set ::testprefix avfs
|
||||
|
||||
# Do not attempt this test if SQLITE_OMIT_VIRTUALTABLE is defined.
|
||||
#
|
||||
ifcapable !vtab {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
set CLI [test_find_cli]
|
||||
db close
|
||||
# forcedelete test.db
|
||||
|
||||
load_static_extension db appendvfs
|
||||
|
||||
set ::fa avfs.adb
|
||||
set ::fza avfs.sdb
|
||||
forcedelete $::fa $::fza
|
||||
set ::result {}
|
||||
|
||||
proc shellDoesAr {} {
|
||||
set shdo "sh_app1.sql"
|
||||
forcedelete $shdo
|
||||
set fd [open $shdo w]
|
||||
puts $fd ".help\n.q"
|
||||
close $fd
|
||||
set res [catchcmd "-batch -cmd \".read $shdo\""]
|
||||
return [regexp {^.archive} [lindex $res 1]]
|
||||
}
|
||||
|
||||
set ::vf "&vfs=apndvfs"
|
||||
|
||||
# Return file offset of appendvfs portion of a file, or {} if none such.
|
||||
proc fosAvfs {fname} {
|
||||
if {[file size $fname] < 25} {
|
||||
return {}
|
||||
}
|
||||
if {[catch {set fd [open $fname rb]}]} {
|
||||
return {}
|
||||
}
|
||||
seek $fd -25 end
|
||||
set am [read $fd 17]
|
||||
set ao [read $fd 8]
|
||||
close $fd
|
||||
if {$am ne "Start-Of-SQLite3-"} {
|
||||
return {}
|
||||
}
|
||||
binary scan $ao "W" rvo
|
||||
return $rvo
|
||||
}
|
||||
|
||||
do_test 1.0 {
|
||||
set results {}
|
||||
set out [open $::fza wb]
|
||||
close $out
|
||||
sqlite3 adb "file:$::fza?mode=rwc$::vf" -uri 1
|
||||
adb eval {
|
||||
PRAGMA page_size=1024;
|
||||
PRAGMA cache_size=10;
|
||||
CREATE TABLE t1(a TEXT);
|
||||
INSERT INTO t1 VALUES ('dog'),('cat');
|
||||
SELECT group_concat(a) as pets FROM (SELECT a FROM t1 ORDER BY a);
|
||||
} { lappend results $pets }
|
||||
adb close
|
||||
lappend results [fosAvfs $fza]
|
||||
set ::result [join $results " | "]
|
||||
} {cat,dog | 0}
|
||||
|
||||
do_test 1.1 {
|
||||
set results {}
|
||||
sqlite3 adb "file:$::fza?mode=rw$::vf" -uri 1
|
||||
adb eval {
|
||||
SELECT group_concat(a) as pets FROM (SELECT a FROM t1 ORDER BY a DESC);
|
||||
} { lappend results $pets }
|
||||
adb close
|
||||
set ::result [join $results " | "]
|
||||
} {dog,cat}
|
||||
|
||||
do_test 1.2 {
|
||||
set results {}
|
||||
set out [open $::fa wb]
|
||||
set ::tlo { "Just some text," "and more text," "ending at 3 lines." }
|
||||
puts $out [join $::tlo "\n"]
|
||||
close $out
|
||||
set adbSz [file size $::fa]
|
||||
sqlite3 adb "file:$::fa?mode=rwc$::vf" -uri 1
|
||||
adb eval {
|
||||
PRAGMA auto_vacuum = 0;
|
||||
PRAGMA page_size=512;
|
||||
PRAGMA cache_size=0;
|
||||
CREATE TABLE t1(a TEXT);
|
||||
INSERT INTO t1 VALUES ('dog'),('cat'),('pig');
|
||||
SELECT group_concat(a) as pets FROM (SELECT a FROM t1 ORDER BY a);
|
||||
} { lappend results $pets }
|
||||
adb close
|
||||
set adaSz [file size $::fa]
|
||||
lappend results "Bytes before/after $adbSz/$adaSz"
|
||||
set ::result [join $results " | "]
|
||||
} {cat,dog,pig | Bytes before/after 50/5145}
|
||||
|
||||
do_test 1.3 {
|
||||
set results {}
|
||||
sqlite3 adb "file:$::fa?mode=rw$::vf" -uri 1
|
||||
adb eval {
|
||||
SELECT group_concat(a) as pets FROM (SELECT a FROM t1 ORDER BY a DESC);
|
||||
} { lappend results $pets }
|
||||
adb close
|
||||
set ::result [join $results " | "]
|
||||
} {pig,dog,cat}
|
||||
|
||||
do_test 1.4 {
|
||||
set ::result [fosAvfs $fa]
|
||||
} {4096}
|
||||
|
||||
do_test 2.1 {
|
||||
set in [open $::fa r]
|
||||
set tli {}
|
||||
for {set i [llength $::tlo]} {$i > 0} {incr i -1} {
|
||||
lappend tli [gets $in]
|
||||
}
|
||||
close $in
|
||||
if { [join $tli ":"] ne [join $::tlo ":"] } {
|
||||
set ::result "Appendee changed."
|
||||
} else {
|
||||
set ::result "Appendee intact."
|
||||
}
|
||||
} {Appendee intact.}
|
||||
|
||||
# Set of repeatable random integers for a couple tests.
|
||||
set ::nrint 50000
|
||||
proc rint {v} {
|
||||
return [::tcl::mathfunc::int [expr $v * 100000]]
|
||||
}
|
||||
array set ::randints [list 0 [rint [::tcl::mathfunc::srand 0]]]
|
||||
for {set i 1} {$i < $::nrint} {incr i} {
|
||||
set ::randints($i) [rint [::tcl::mathfunc::rand]]
|
||||
}
|
||||
|
||||
do_test 3.1 {
|
||||
set results {}
|
||||
sqlite3 adb "file:$::fa?mode=rw$::vf" -uri 1
|
||||
adb eval {
|
||||
DROP TABLE t1;
|
||||
PRAGMA cache_size=10;
|
||||
CREATE TABLE ri (i INTEGER);
|
||||
BEGIN;
|
||||
}
|
||||
for {set i 0} {$i < $::nrint} {incr i} {
|
||||
set r $::randints($i)
|
||||
set s $::randints([incr i])
|
||||
set t $::randints([incr i])
|
||||
set u $::randints([incr i])
|
||||
set v $::randints([incr i])
|
||||
adb eval {
|
||||
INSERT INTO ri VALUES ($r),($s),($t),($u),($v)
|
||||
}
|
||||
}
|
||||
adb eval {
|
||||
COMMIT;
|
||||
SELECT integrity_check as ic FROM pragma_integrity_check();
|
||||
} { lappend results $ic }
|
||||
set adbSz [file size $::fa]
|
||||
set qr {}
|
||||
adb eval {
|
||||
SELECT count(*) as ic FROM ri;
|
||||
DELETE FROM ri WHERE (i % 50) <> 25;
|
||||
SELECT integrity_check as ic FROM pragma_integrity_check();
|
||||
VACUUM;
|
||||
SELECT integrity_check as ic FROM pragma_integrity_check();
|
||||
SELECT count(*) as ic FROM ri;
|
||||
} { lappend qr $ic }
|
||||
adb close
|
||||
set adaSz [file size $::fa]
|
||||
set adba [expr ($adbSz + 0.1)/$adaSz]
|
||||
# lappend results $adba
|
||||
set results [concat $results [lrange $qr 0 2]]
|
||||
lappend results [expr {$adba > 10.0}]
|
||||
set ::result [join $results " | "]
|
||||
} "ok | $::nrint | ok | ok | 1"
|
||||
|
||||
do_test 3.2 {
|
||||
set results {}
|
||||
sqlite3 adb "file:$::fa?mode=rw$::vf" -uri 1
|
||||
adb eval {
|
||||
SELECT integrity_check as ic FROM pragma_integrity_check();
|
||||
} { lappend results $ic }
|
||||
adb close
|
||||
set ::result [join $results " | "]
|
||||
} {ok}
|
||||
|
||||
# avfs-3.3. Test that appendvfs can grow by many pages and be written.
|
||||
do_test 3.3 {
|
||||
set results {}
|
||||
sqlite3 adb "file:$::fa?mode=rw$::vf" -uri 1
|
||||
set npages 300
|
||||
adb eval { BEGIN }
|
||||
while {$npages > 0} {
|
||||
adb eval { INSERT INTO ri VALUES (randomblob(1500)) }
|
||||
incr npages -1
|
||||
}
|
||||
adb eval { COMMIT }
|
||||
adb eval {
|
||||
SELECT integrity_check as ic FROM pragma_integrity_check();
|
||||
} { lappend results $ic }
|
||||
adb close
|
||||
set adaSzr [expr [file size $::fa] / 300.0 / 1500 ]
|
||||
set okSzr [expr $adaSzr > 1.0 && $adaSzr < 1.3 ]
|
||||
lappend results $okSzr
|
||||
set ::result [join $results " | "]
|
||||
} {ok | 1}
|
||||
|
||||
# avfs-3.4. Test that grown appendvfs can be reopened and appear intact.
|
||||
do_test 3.4 {
|
||||
set results {}
|
||||
sqlite3 adb "file:$::fa?mode=rw$::vf" -uri 1
|
||||
adb eval {
|
||||
SELECT integrity_check as ic FROM pragma_integrity_check();
|
||||
} { lappend results $ic }
|
||||
adb close
|
||||
set ::result $ic
|
||||
} {ok}
|
||||
|
||||
# avfs-3.5. Test that much grown appendvfs can shrink and reopen intact.
|
||||
do_test 3.5 {
|
||||
set results {}
|
||||
set adbsz [file size $::fa]
|
||||
sqlite3 adb "file:$::fa?mode=rw$::vf" -uri 1
|
||||
adb eval {
|
||||
DELETE FROM ri WHERE rowid % 8 <> 0;
|
||||
SELECT integrity_check as ic FROM pragma_integrity_check();
|
||||
VACUUM;
|
||||
SELECT integrity_check as ic FROM pragma_integrity_check();
|
||||
} { lappend results $ic }
|
||||
adb close
|
||||
set adasz [file size $::fa]
|
||||
lappend results [expr {$adbsz/$adasz > 5}]
|
||||
sqlite3 adb "file:$::fa?mode=rw$::vf" -uri 1
|
||||
adb eval {
|
||||
SELECT integrity_check as ic FROM pragma_integrity_check();
|
||||
} { lappend results $ic }
|
||||
adb close
|
||||
set ::result [join $results " | "]
|
||||
} {ok | ok | 1 | ok}
|
||||
|
||||
set ::cliDoesAr [shellDoesAr]
|
||||
|
||||
do_test 4.1 {
|
||||
set shdo "sh_app1.sql"
|
||||
set shod "sh_app1.adb"
|
||||
forcedelete $shdo $shod
|
||||
set ofd [open $shdo w]
|
||||
if {$::cliDoesAr} {
|
||||
puts $ofd ".ar -c"
|
||||
} else {
|
||||
puts $ofd "pragma page_size=512;"
|
||||
puts $ofd "create table sqlar (a);"
|
||||
}
|
||||
puts $ofd ".tables"
|
||||
puts $ofd ".q"
|
||||
close $ofd
|
||||
set ofd [open $shod wb]
|
||||
puts $ofd "Some text."
|
||||
close $ofd
|
||||
set res [catchcmd "-append -batch -init $shdo $shod" ""]
|
||||
lappend res [fosAvfs $shod]
|
||||
forcedelete $shdo $shod
|
||||
set ::result [join $res " | "]
|
||||
} {0 | sqlar | 4096}
|
||||
|
||||
do_test 4.2 {
|
||||
set shdo "sh_app1.sql"
|
||||
set shod "sh_app1.adb"
|
||||
forcedelete $shdo $shod
|
||||
set ofd [open $shdo w]
|
||||
if {$::cliDoesAr} {
|
||||
puts $ofd ".ar -c"
|
||||
} else {
|
||||
puts $ofd "pragma page_size=512;"
|
||||
puts $ofd "create table sqlar (a);"
|
||||
}
|
||||
puts $ofd ".tables"
|
||||
puts $ofd ".q"
|
||||
close $ofd
|
||||
set ofd [open $shod wb]
|
||||
close $ofd
|
||||
set res [catchcmd "-append -batch -init $shdo $shod" ""]
|
||||
lappend res [fosAvfs $shod]
|
||||
forcedelete $shdo ; # Leave $shod for next test.
|
||||
set ::result [join $res " | "]
|
||||
} {0 | sqlar | 0}
|
||||
|
||||
do_test 4.3 {
|
||||
set shdo "sh_app1.sql"
|
||||
set shod "sh_app1.adb" ; # Same as test 4.2, reusing ADB.
|
||||
forcedelete $shdo
|
||||
set ofd [open $shdo w]
|
||||
if {$::cliDoesAr} {
|
||||
puts $ofd ".ar -u $shdo"
|
||||
puts $ofd "select count(*) from sqlar where name = '$shdo';"
|
||||
} else {
|
||||
puts $ofd "insert into sqlar values (1);"
|
||||
puts $ofd "select count(*) from sqlar;"
|
||||
}
|
||||
puts $ofd ".q"
|
||||
close $ofd
|
||||
set res [catchcmd "-append -batch -init $shdo $shod" ""]
|
||||
sqlite3 adb "file:$shod?mode=rw$::vf" -uri 1
|
||||
adb eval {
|
||||
SELECT count(*) as n FROM sqlar
|
||||
} { lappend res $n }
|
||||
adb close
|
||||
forcedelete $shdo $shod;
|
||||
set ::result [join $res " | "]
|
||||
} {0 | 1 | 1}
|
||||
|
||||
do_test 5.1 {
|
||||
set fake "faketiny.sdb"
|
||||
forcedelete $fake
|
||||
set ofd [open $fake wb]
|
||||
puts -nonewline $ofd "SQLite format 3"
|
||||
puts -nonewline $ofd [binary format "c" 0]
|
||||
puts -nonewline $ofd "Start-Of-SQLite3-"
|
||||
puts -nonewline $ofd [binary format "W" 0]
|
||||
close $ofd
|
||||
if {[catch {sqlite3 adb "file:$fake?mode=rw$::vf" -uri 1}]} {
|
||||
set res "Open failed."
|
||||
} else {
|
||||
adb close
|
||||
set res "Opened when should not."
|
||||
}
|
||||
forcedelete $fake
|
||||
set ::result $res
|
||||
} {Open failed.}
|
||||
|
||||
do_test 5.2 {
|
||||
set fake "faketiny.sdb"
|
||||
forcedelete $fake
|
||||
set ofd [open $fake wb]
|
||||
set fakeAppendee "Dog ate my homework.\n"
|
||||
puts -nonewline $ofd $fakeAppendee
|
||||
puts -nonewline $ofd "SQLite format 3"
|
||||
puts -nonewline $ofd [binary format "c" 0]
|
||||
puts -nonewline $ofd "Start-Of-SQLite3-"
|
||||
puts -nonewline $ofd [binary format "W" [string length $fakeAppendee]]
|
||||
close $ofd
|
||||
if {[catch {sqlite3 adb "file:$fake?mode=rw$::vf" -uri 1}]} {
|
||||
set res "Open failed."
|
||||
} else {
|
||||
adb close
|
||||
set res "Opened when should not."
|
||||
}
|
||||
forcedelete $fake
|
||||
set ::result $res
|
||||
} {Open failed.}
|
||||
|
||||
forcedelete $::fa $::fza
|
||||
|
||||
unset -nocomplain ::fa ::fza ::tlo ::result ::randints ::nrint ::cliDoesAr
|
||||
|
||||
finish_test
|
||||
+3
-2
@@ -144,7 +144,7 @@ do_test backup2-9 {
|
||||
if {$tcl_platform(platform)=="windows"} {
|
||||
set msg {cannot open source database: unable to open database file}
|
||||
} elseif {[string match *BSD $tcl_platform(os)]} {
|
||||
set msg {restore failed: file is not a database}
|
||||
set msg {}
|
||||
} else {
|
||||
set msg {cannot open source database: disk I/O error}
|
||||
}
|
||||
@@ -152,7 +152,8 @@ do_test backup2-10 {
|
||||
forcedelete bu3.db
|
||||
file mkdir bu3.db
|
||||
set rc [catch {db restore temp bu3.db} res]
|
||||
lappend rc $res
|
||||
if {[string match *BSD $tcl_platform(os)]} { set res "" }
|
||||
list $rc $res
|
||||
} [list 1 $msg]
|
||||
|
||||
# Try to restore from something that is not a database file.
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
# 2021 February 15
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
# This file implements regression tests for SQLite library. The
|
||||
# focus of this file is testing the sqlite3_column_count() API.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix columncount
|
||||
|
||||
proc do_ccsql_test {tn sql res} {
|
||||
|
||||
uplevel [list do_test $tn [subst -nocommands {
|
||||
set stmt [sqlite3_prepare_v2 db {$sql} -1 dummy]
|
||||
set res [sqlite3_column_count [set stmt]]
|
||||
while {[sqlite3_step [set stmt]]=="SQLITE_ROW"} {
|
||||
for {set i 0} {[set i] < [sqlite3_data_count [set stmt]]} {incr i} {
|
||||
lappend res [sqlite3_column_text [set stmt] [set i]]
|
||||
}
|
||||
}
|
||||
|
||||
set rc [sqlite3_finalize [set stmt]]
|
||||
if {[set rc]!="SQLITE_OK"} {
|
||||
error [sqlite3_errmsg db]
|
||||
}
|
||||
|
||||
set res
|
||||
}] [list {*}$res]]
|
||||
|
||||
}
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE TABLE t1(x, y, z);
|
||||
INSERT INTO t1 VALUES('a', 'b', 'c');
|
||||
}
|
||||
|
||||
do_ccsql_test 1.1 { SELECT * FROM t1 } {3 a b c}
|
||||
do_ccsql_test 1.2 { CREATE TABLE t2(a, b) } {0}
|
||||
|
||||
do_ccsql_test 1.3 { ALTER TABLE t2 RENAME TO t3 } {0}
|
||||
do_ccsql_test 1.4 { ALTER TABLE t3 RENAME b TO ccc } {0}
|
||||
do_ccsql_test 1.5 { ALTER TABLE t3 ADD COLUMN d } {0}
|
||||
|
||||
do_ccsql_test 1.6 { DROP TABLE t3 } {0}
|
||||
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -38,6 +38,13 @@ do_catchsql_test date2-130 {
|
||||
INSERT INTO t1(x,y) VALUES('2017-08-01','two');
|
||||
} {1 {CHECK constraint failed: date(x) BETWEEN '2017-07-01' AND '2017-07-31'}}
|
||||
|
||||
# 2021-03-16 Forum post https://sqlite.org/forum/forumpost/464afd4086
|
||||
do_catchsql_test date2-140 {
|
||||
DROP TABLE t1;
|
||||
CREATE TABLE t1(x, y, z AS (date()));
|
||||
INSERT INTO t1(x,y) VALUES(1,2);
|
||||
} {1 {non-deterministic use of date() in a generated column}}
|
||||
|
||||
do_execsql_test date2-200 {
|
||||
CREATE TABLE t2(x,y);
|
||||
INSERT INTO t2(x,y) VALUES(1, '2017-07-20'), (2, 'xyzzy');
|
||||
|
||||
+2
-2
@@ -2055,9 +2055,9 @@ do_test e_fkey-44.5 {
|
||||
#-------------------------------------------------------------------------
|
||||
# Test SET DEFAULT actions.
|
||||
#
|
||||
# EVIDENCE-OF: R-43054-54832 The "SET DEFAULT" actions are similar to
|
||||
# EVIDENCE-OF: R-55814-22637 The "SET DEFAULT" actions are similar to
|
||||
# "SET NULL", except that each of the child key columns is set to
|
||||
# contain the columns default value instead of NULL.
|
||||
# contain the column's default value instead of NULL.
|
||||
#
|
||||
drop_all_tables
|
||||
do_test e_fkey-45.1 {
|
||||
|
||||
@@ -6298,4 +6298,92 @@ do_catchsql_test 47.3 {
|
||||
SELECT matchinfo(t1) FROM t1 WHERE t1 MATCH '"json1 enable"';
|
||||
} {1 {database disk image is malformed}}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
reset_db
|
||||
do_test 48.0 {
|
||||
sqlite3 db {}
|
||||
db deserialize [decode_hexdb {
|
||||
.open --hexdb
|
||||
| size 20480 pagesize 4096 filename sql038051.txt.db
|
||||
| page 1 offset 0
|
||||
| 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3.
|
||||
| 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 00 .....@ ........
|
||||
| 96: 00 00 00 00 0d 0e fc 00 05 0e 13 00 0f ca 0f 6c ...............l
|
||||
| 112: 0f 04 0e 13 0e c9 00 00 00 00 00 00 00 00 00 00 ................
|
||||
| 3600: 00 00 00 81 33 04 07 17 1f 1f 01 82 35 74 61 62 ....3.......5tab
|
||||
| 3616: 6c 65 78 31 5f 73 65 67 64 69 72 78 31 5f 73 65 lex1_segdirx1_se
|
||||
| 3632: 67 64 69 72 04 43 52 45 41 54 45 20 54 41 42 4c gdir.CREATE TABL
|
||||
| 3648: 45 20 27 78 31 5f 73 65 67 64 69 72 27 28 6c 65 E 'x1_segdir'(le
|
||||
| 3664: 76 65 6c 20 49 4e 54 45 47 45 52 2c 69 64 78 20 vel INTEGER,idx
|
||||
| 3680: 49 4e 54 45 47 45 52 2c 73 74 61 72 74 5f 62 6c INTEGER,start_bl
|
||||
| 3696: 6f 63 6b 20 49 4e 54 45 47 45 52 2c 6c 65 61 76 ock INTEGER,leav
|
||||
| 3712: 65 73 5f 65 6e 64 5f 62 6c 6f 63 6b 20 49 4e 54 es_end_block INT
|
||||
| 3728: 45 47 45 52 2c 65 6e 64 5f 62 6c 6f 63 6b 20 49 EGER,end_block I
|
||||
| 3744: 4e 54 45 47 45 52 2c 72 6f 6f 74 20 42 4c 4f 42 NTEGER,root BLOB
|
||||
| 3760: 2c 50 52 49 4d 41 52 59 20 4b 45 59 28 6c 65 76 ,PRIMARY KEY(lev
|
||||
| 3776: 65 6c 2c 20 69 64 78 29 29 31 05 06 17 45 1f 01 el, idx))1...E..
|
||||
| 3792: 00 69 6e 64 65 78 73 71 6c 69 74 65 5f 61 75 74 .indexsqlite_aut
|
||||
| 3808: 6f 69 6e 64 65 78 5f 78 31 5f 73 65 67 64 69 72 oindex_x1_segdir
|
||||
| 3824: 5f 31 78 31 5f 73 65 67 64 69 72 05 00 00 00 08 _1x1_segdir.....
|
||||
| 3840: 00 00 00 00 66 03 07 17 23 23 01 81 13 74 61 62 ....f...##...tab
|
||||
| 3856: 6c 65 78 31 5f 73 65 67 6d 65 6e 74 73 78 31 5f lex1_segmentsx1_
|
||||
| 3872: 73 65 67 6d 65 6e 74 73 03 43 52 45 41 54 45 20 segments.CREATE
|
||||
| 3888: 54 41 42 4c 45 20 27 78 31 5f 73 65 67 6d 65 6e TABLE 'x1_segmen
|
||||
| 3904: 74 73 27 28 62 6c 6f 63 6b 69 64 20 49 4e 54 45 ts'(blockid INTE
|
||||
| 3920: 47 45 52 20 50 52 49 4d 41 52 59 20 4b 45 59 2c GER PRIMARY KEY,
|
||||
| 3936: 20 62 6c 6f 63 6b 20 42 4c 4f 42 29 5c 02 07 17 block BLOB)....
|
||||
| 3952: 21 21 01 81 03 74 61 62 6c 65 78 31 5f 63 6f 6e !!...tablex1_con
|
||||
| 3968: 74 65 6e 74 78 31 5f 63 6f 6e 74 65 6e 74 02 43 tentx1_content.C
|
||||
| 3984: 52 45 41 54 45 20 54 41 42 4c 45 20 27 78 31 5f REATE TABLE 'x1_
|
||||
| 4000: 63 6f 6e 74 65 6e 74 27 28 64 6f 63 69 64 20 49 content'(docid I
|
||||
| 4016: 4e 54 45 47 45 52 20 50 52 49 4d 41 52 59 20 4b NTEGER PRIMARY K
|
||||
| 4032: 45 59 2c 20 27 63 30 78 27 29 34 01 06 17 11 11 EY, 'c0x')4.....
|
||||
| 4048: 08 57 74 61 62 6c 65 78 31 78 31 43 52 45 41 54 .Wtablex1x1CREAT
|
||||
| 4064: 45 20 56 49 52 54 55 41 4c 20 54 41 42 4c 45 20 E VIRTUAL TABLE
|
||||
| 4080: 78 31 20 55 53 49 4e 47 20 66 74 73 33 28 78 29 x1 USING fts3(x)
|
||||
| page 2 offset 4096
|
||||
| 0: 0d 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
| 3920: 00 00 00 2e 04 03 00 63 62 72 61 69 6e 73 74 65 .......cbrainste
|
||||
| 3936: 6d 20 62 72 61 69 6e 73 74 65 6d 73 20 62 72 61 m brainstems bra
|
||||
| 3952: 69 6e 73 74 6f 72 6d 20 62 72 61 69 6e 73 74 6f instorm brainsto
|
||||
| 3968: 72 6d 73 2b 03 03 00 5d 62 72 61 69 6e 20 62 72 rms+...]brain br
|
||||
| 3984: 61 69 6e 63 68 69 6c 64 20 62 72 61 69 6e 65 64 ainchild brained
|
||||
| 4000: 20 62 72 61 69 6e 69 6e 67 20 62 72 61 69 6e 73 braining brains
|
||||
| 4016: 26 02 03 00 53 62 72 61 67 73 20 62 72 61 69 64 &...Sbrags braid
|
||||
| 4032: 20 62 72 61 69 64 65 64 20 62 72 61 69 64 69 6e braided braidin
|
||||
| 4048: 67 20 62 72 61 69 64 73 26 01 03 00 53 62 72 61 g braids&...Sbra
|
||||
| 4064: 65 73 20 62 72 61 67 20 62 72 61 67 67 65 64 20 es brag bragged
|
||||
| 4080: 62 72 61 c3 67 65 72 20 62 72 61 67 67 69 6e 67 bra.ger bragging
|
||||
| page 3 offset 8192
|
||||
| 0: 0d 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 ................
|
||||
| page 4 offset 12288
|
||||
| 0: 0d 00 00 00 04 0f 20 00 0f c8 0f 90 0f 54 0f 20 ...... ......T.
|
||||
| 3872: 32 04 07 08 01 08 08 15 58 03 30 20 33 38 00 09 2.......X.0 38..
|
||||
| 3888: 62 72 61 69 6e 73 74 65 6d 03 04 02 00 09 01 73 brainstem......s
|
||||
| 3904: 03 04 03 00 07 03 6f 72 6d 03 04 04 00 0a 01 73 ......orm......s
|
||||
| 3920: 03 04 05 00 3a 03 07 08 01 08 08 15 68 02 30 20 ....:.......h.0
|
||||
| 3936: 34 36 00 05 62 72 61 69 6e 03 03 02 00 05 05 63 46..brain......c
|
||||
| 3952: 68 69 6c 64 03 03 03 00 05 02 65 64 03 03 04 00 hild......ed....
|
||||
| 3968: 05 03 69 6e 67 03 03 05 00 05 01 73 03 03 06 00 ..ing......s....
|
||||
| 3984: 36 02 07 08 09 08 08 15 62 30 20 34 33 00 05 62 6.......b0 43..b
|
||||
| 4000: 72 61 67 73 03 02 02 00 03 02 69 64 03 02 03 00 rags......id....
|
||||
| 4016: 05 02 65 64 03 02 04 00 05 03 69 6e 67 03 02 05 ..ed......ing...
|
||||
| 4032: 00 05 01 73 03 02 06 00 36 01 07 08 08 08 08 15 ...s....6.......
|
||||
| 4048: 62 30 20 34 33 00 05 62 72 61 65 73 03 01 02 00 b0 43..braes....
|
||||
| 4064: 03 01 68 03 01 03 00 04 03 67 65 74 03 01 04 00 ..h......get....
|
||||
| 4080: 06 01 72 03 01 05 00 05 03 69 6e 67 03 01 06 00 ..r......ing....
|
||||
| page 5 offset 16384
|
||||
| 0: 0a 00 00 00 04 0f e7 00 0f fb 0f f5 0f ee 0f e7 ................
|
||||
| 4064: 00 00 00 00 00 00 00 06 04 08 01 01 03 04 06 04 ................
|
||||
| 4080: 08 01 01 02 03 05 04 08 09 01 02 04 04 08 08 09 ................
|
||||
| end sql038051.txt.db
|
||||
}]} {}
|
||||
|
||||
do_catchsql_test 48.1 {
|
||||
INSERT INTO x1(x1) VALUES('nodesize=24'),('merge=3,4');
|
||||
INSERT INTO x1(x1) VALUES( 'merge=3,4' ),('merge=3,4');
|
||||
} {1 {database disk image is malformed}}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
+10
-2
@@ -11,8 +11,6 @@
|
||||
# This file implements regression tests for SQLite library. The
|
||||
# focus of this script is testing the FTS3 module.
|
||||
#
|
||||
# $Id: fts3aa.test,v 1.1 2007/08/20 17:38:42 shess Exp $
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
@@ -54,6 +52,16 @@ do_execsql_test 1.3 {
|
||||
SELECT 42+matchinfo(t1,'yxyyxy') FROM t1 WHERE t1 MATCH x'2b0a312b0a312a312a2a0b5d0a0b0b0a312a0a0b0b0a312a0b310a392a0b0a27312a2a0b5d0a312a0b310a31315d0b310a312a316d2a0b313b15bceaa50a312a0b0a27312a2a0b5d0a312a0b310a312b0b2a310a312a0b2a0b2a0b2e5d0a0bff313336e34a2a312a0b0a3c310b0a0b4b4b0b4b2a4bec40322b2a0b310a0a312a0a0a0a0a0a0a0a0a0b310a312a2a2a0b5d0a0b0b0a312a0b310a312a0b0a4e4541530b310a5df5ced70a0a0a0a0a4f520a0a0a0a0a0a0a312a0b0a4e4541520b310a5d616161610a0a0a0a4f520a0a0a0a0a0a312b0a312a312a0a0a0a0a0a0a004a0b0a310b220a0b0a310a4a22310a0b0a7e6fe0e0e030e0e0e0e0e01176e02000e0e0e0e0e01131320226310a0b0a310a4a22310a0b0a310a766f8b8b4ee0e0300ae0090909090909090909090909090909090909090909090909090909090909090947aaaa540b09090909090909090909090909090909090909090909090909090909090909fae0e0f2f22164e0e0f273e07fefefef7d6dfafafafa6d6d6d6d';
|
||||
} {42}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_execsql_test 2.0 {
|
||||
CREATE VIRTUAL TABLE t0 USING fts3(a);
|
||||
INSERT INTO t0_segdir VALUES(0,0,0,0,'0 42',X'000131030782000103323334050100fff200010461616161050101020200000462626262050101030200');
|
||||
}
|
||||
do_execsql_test 2.1 {
|
||||
SELECT count(*) FROM t0 WHERE t0 MATCH '(1 NEAR 1) AND (aaaa OR 1)';
|
||||
} 1
|
||||
|
||||
set sqlite_fts3_enable_parentheses $saved_sqlite_fts3_enable_parentheses
|
||||
finish_test
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ do_execsql_test 1.0 {
|
||||
|
||||
do_catchsql_test 1.1 {
|
||||
ALTER TABLE t1_content RENAME c0a TO docid;
|
||||
} {1 {duplicate column name: docid}}
|
||||
} {1 {error in table t1_content after rename: duplicate column name: docid}}
|
||||
|
||||
do_catchsql_test 1.2 {
|
||||
UPDATE t1 SET Col0 = 1 ;
|
||||
|
||||
+6
-3
@@ -759,9 +759,10 @@ static int block_troublesome_sql(
|
||||
if( sqlite3_stricmp("oom",zArg1)==0 && zArg2!=0 && zArg2[0]!=0 ){
|
||||
oomCounter = atoi(zArg2);
|
||||
}
|
||||
}else if( (eCode==SQLITE_ATTACH || eCode==SQLITE_DETACH)
|
||||
&& zArg1 && zArg1[0] ){
|
||||
return SQLITE_DENY;
|
||||
}else if( eCode==SQLITE_ATTACH ){
|
||||
if( zArg1==0 || (zArg1[0]!=0 && strcmp(zArg1,":memory:")!=0) ){
|
||||
return SQLITE_DENY;
|
||||
}
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
@@ -1989,6 +1990,8 @@ int main(int argc, char **argv){
|
||||
sqlite3_limit(db, SQLITE_LIMIT_LIKE_PATTERN_LENGTH, 50);
|
||||
if( cellSzCkFlag ) runSql(db, "PRAGMA cell_size_check=ON", runFlags);
|
||||
setAlarm((iTimeout+999)/1000);
|
||||
/* Enable test functions */
|
||||
sqlite3_test_control(SQLITE_TESTCTRL_INTERNAL_FUNCTIONS, db);
|
||||
#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
|
||||
if( sqlFuzz || vdbeLimitFlag ){
|
||||
sqlite3_progress_handler(db, 100000, progressHandler,
|
||||
|
||||
Binary file not shown.
@@ -88,5 +88,24 @@ do_faultsim_test 3 -prep {
|
||||
faultsim_test_result {0 2} {1 {vtable constructor failed: x1}}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_execsql_test 4.0 {
|
||||
CREATE TABLE t1_a(a INTEFDR PRIMARY KEY, b TEXT);
|
||||
CREATE TABLE t3_a(k FnTEGER PRIMARY KEY, v TEXT);
|
||||
CREATE TABLE t3_b(k INTEÀ5R PRIMARY KEY, v TEXT);
|
||||
CREATE VIEW t3 AS SELECT * FROM t3_a UNION ALL SELECT * FROM t3_b;
|
||||
}
|
||||
faultsim_save_and_close
|
||||
|
||||
do_faultsim_test 4 -faults oom-t* -prep {
|
||||
faultsim_restore_and_reopen
|
||||
} -body {
|
||||
execsql {
|
||||
SELECT 1 FROM t1_a LEFT JOIN t3 ON ((1+1) AND k=1)
|
||||
}
|
||||
} -test {
|
||||
faultsim_test_result {0 {}}
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -956,5 +956,63 @@ ifcapable analyze {
|
||||
}]
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test that the pre-update hook is fired for INSERT statements that use
|
||||
# the xfer optimization on without rowid tables.
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 12.1 {
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
|
||||
CREATE TABLE t2(a INTEGER PRIMARY KEY, b) WITHOUT ROWID;
|
||||
|
||||
INSERT INTO t1 VALUES(1, 2);
|
||||
INSERT INTO t1 VALUES(3, 4);
|
||||
INSERT INTO t2 VALUES(5, 6);
|
||||
INSERT INTO t2 VALUES(7, 8);
|
||||
|
||||
CREATE TABLE t3 (a INTEGER PRIMARY KEY, b) WITHOUT ROWID;
|
||||
}
|
||||
|
||||
db preupdate hook preupdate_cb
|
||||
db update_hook update_cb
|
||||
|
||||
proc preupdate_cb {args} { lappend ::res "preupdate" $args }
|
||||
proc update_cb {args} { lappend ::res "update" $args }
|
||||
|
||||
set ::res [list]
|
||||
do_test 12.2 {
|
||||
execsql VACUUM
|
||||
set ::res
|
||||
} {}
|
||||
|
||||
do_test 12.3 {
|
||||
set ::res [list]
|
||||
execsql { INSERT INTO t3 SELECT a, b FROM t2 }
|
||||
set ::res
|
||||
} {preupdate {INSERT main t3 0 0} preupdate {INSERT main t3 0 0}}
|
||||
|
||||
do_test 12.4 {
|
||||
execsql { DELETE FROM t3 }
|
||||
set ::res [list]
|
||||
execsql { INSERT INTO t3 SELECT * FROM t2 }
|
||||
set ::res
|
||||
} {preupdate {INSERT main t3 0 0} preupdate {INSERT main t3 0 0}}
|
||||
|
||||
do_execsql_test 12.5 {
|
||||
CREATE TABLE t4(a COLLATE nocase PRIMARY KEY, b) WITHOUT ROWID;
|
||||
INSERT INTO t4 VALUES('abc', 1);
|
||||
INSERT INTO t4 VALUES('DEF', 2);
|
||||
}
|
||||
|
||||
set ::res [list]
|
||||
do_test 12.6 {
|
||||
execsql VACUUM
|
||||
set ::res
|
||||
} {}
|
||||
|
||||
do_catchsql_test 12.6 {
|
||||
INSERT INTO t4 VALUES('def', 3);
|
||||
} {1 {UNIQUE constraint failed: t4.a}}
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
+3
-3
@@ -90,9 +90,9 @@ do_test indexedby-2.4 {
|
||||
catchsql { SELECT * FROM t1 INDEXED BY i3 WHERE a = 'one' AND b = 'two'}
|
||||
} {1 {no such index: i3}}
|
||||
|
||||
# EVIDENCE-OF: R-62112-42456 If the query optimizer is unable to use the
|
||||
# index specified by the INDEX BY clause, then the query will fail with
|
||||
# an error.
|
||||
# EVIDENCE-OF: R-05301-32681 If the query optimizer is unable to use the
|
||||
# index specified by the INDEXED BY clause, then the query will fail
|
||||
# with an error.
|
||||
do_test indexedby-2.4.1 {
|
||||
catchsql { SELECT b FROM t1 INDEXED BY i1 WHERE b = 'two' }
|
||||
} {0 {}}
|
||||
|
||||
@@ -1131,4 +1131,11 @@ do_execsql_test 17.1 {
|
||||
SELECT id FROM t1 WHERE x LIKE 'abc__' ESCAPE '_';
|
||||
} {2}
|
||||
|
||||
# 2021-02-15 ticket c0aeea67d58ae0fd
|
||||
#
|
||||
do_execsql_test 17.1 {
|
||||
SELECT 'x' LIKE '%' ESCAPE '_';
|
||||
} {1}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -641,5 +641,28 @@ do_execsql_test limit-14.7 {
|
||||
SELECT 123 LIMIT -1 OFFSET 1
|
||||
} {}
|
||||
|
||||
# 2021-03-05 dbsqlfuzz crash-d811039c9f44f2d43199d5889fcf4085ef6221b9
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test limit-15.1 {
|
||||
CREATE TABLE t1(a PRIMARY KEY, b TEXT);
|
||||
CREATE TABLE t4(c PRIMARY KEY, d);
|
||||
CREATE TABLE t5(e PRIMARY KEY, f);
|
||||
CREATE TABLE t6(g, h);
|
||||
CREATE TABLE t3_a(k, v);
|
||||
CREATE TABLE t3_b(k, v);
|
||||
CREATE VIEW t3 AS SELECT * FROM t3_a UNION ALL SELECT * FROM t3_b;
|
||||
INSERT INTO t5(e,f) VALUES(500000,'orange');
|
||||
INSERT INTO t4(c,d) VALUES(300000,'blue'),(400,'green'),(8000,'grey');
|
||||
INSERT INTO t1(a,b) VALUES(300000,'purple');
|
||||
INSERT INTO t3_a VALUES(300000,'yellow'),(500,'pink'),(8000,'red');
|
||||
INSERT INTO t6 default values;
|
||||
SELECT (
|
||||
SELECT 100000 FROM
|
||||
(SELECT 200000 FROM t6 WHERE a = ( SELECT 300000 FROM t3 WHERE a ) ),
|
||||
(SELECT 400000 FROM t5 WHERE e=500000),
|
||||
(SELECT 600000 FROM t4 WHERE c=a)
|
||||
) FROM t1;
|
||||
} {100000}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
# 2021 February 15
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
# This file implements regression tests for SQLite library. The
|
||||
# focus of this file is testing optimizations associated with "IS NULL"
|
||||
# and "IS NOT NULL" operators on columns with NOT NULL constraints.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix notnull2
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE TABLE t1(a, b);
|
||||
CREATE TABLE t2(c, d NOT NULL);
|
||||
|
||||
WITH x(i) AS (
|
||||
SELECT 1 UNION ALL SELECT i+1 FROM x WHERE i<1000
|
||||
)
|
||||
INSERT INTO t1 SELECT i, i FROM x;
|
||||
INSERT INTO t2 SELECT * FROM t1;
|
||||
}
|
||||
|
||||
proc do_vmstep_test {tn sql nstep {res {}}} {
|
||||
uplevel [list do_execsql_test $tn.0 $sql $res]
|
||||
|
||||
set vmstep [db status vmstep]
|
||||
if {[string range $nstep 0 0]=="+"} {
|
||||
set body "if {$vmstep<$nstep} {
|
||||
error \"got $vmstep, expected more than [string range $nstep 1 end]\"
|
||||
}"
|
||||
} else {
|
||||
set body "if {$vmstep>$nstep} {
|
||||
error \"got $vmstep, expected less than $nstep\"
|
||||
}"
|
||||
}
|
||||
|
||||
# set name "$tn.vmstep=$vmstep,expect=$nstep"
|
||||
set name "$tn.1"
|
||||
uplevel [list do_test $name $body {}]
|
||||
}
|
||||
|
||||
do_vmstep_test 1.1.1 {
|
||||
SELECT * FROM t1 LEFT JOIN t2 WHERE a=c AND d IS NULL;
|
||||
} 100 {}
|
||||
do_vmstep_test 1.1.2 {
|
||||
SELECT * FROM t1 LEFT JOIN t2 WHERE a=c AND c IS NULL;
|
||||
} +1000 {}
|
||||
|
||||
do_vmstep_test 1.2.1 {
|
||||
SELECT * FROM ( SELECT * FROM t2 ) WHERE d IS NULL
|
||||
} 100 {}
|
||||
do_vmstep_test 1.2.2 {
|
||||
SELECT * FROM ( SELECT * FROM t2 ) WHERE c IS NULL
|
||||
} +1000 {}
|
||||
|
||||
do_vmstep_test 1.3.1 {
|
||||
SELECT * FROM t2 WHERE d IS NULL
|
||||
} 100 {}
|
||||
do_vmstep_test 1.3.2 {
|
||||
SELECT * FROM t2 WHERE c IS NULL
|
||||
} +1000 {}
|
||||
|
||||
do_vmstep_test 1.4.1 {
|
||||
SELECT (d IS NOT NULL) FROM t2 WHERE 0==( d IS NOT NULL )
|
||||
} 100 {}
|
||||
do_vmstep_test 1.4.2 {
|
||||
SELECT * FROM t2 WHERE 0==( c IS NOT NULL )
|
||||
} +1000 {}
|
||||
|
||||
do_vmstep_test 1.5.1 {
|
||||
SELECT count(*) FROM t2 WHERE EXISTS(
|
||||
SELECT t2.d IS NULL FROM t1 WHERE t1.a=450
|
||||
)
|
||||
} 10000 {1000}
|
||||
do_vmstep_test 1.5.2 {
|
||||
SELECT count(*) FROM t2 WHERE EXISTS(
|
||||
SELECT t2.c IS NULL FROM t1 WHERE t1.a=450
|
||||
)
|
||||
} +100000 {1000}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_execsql_test 2.0 {
|
||||
CREATE TABLE T1(a INTEGER PRIMARY KEY, b);
|
||||
CREATE TABLE T3(k, v);
|
||||
}
|
||||
|
||||
do_execsql_test 2.1 {
|
||||
SELECT * FROM (SELECT a, b FROM t1) LEFT JOIN t3 ON a IS NULL;
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
# 2021 February 15
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
# This file implements regression tests for SQLite library. The
|
||||
# focus of this file is testing optimizations associated with "IS NULL"
|
||||
# and "IS NOT NULL" operators on columns with NOT NULL constraints.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix notnullfault
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE TABLE t1(a, b);
|
||||
CREATE TABLE t2(c, d NOT NULL);
|
||||
}
|
||||
faultsim_save_and_close
|
||||
|
||||
do_faultsim_test 1 -prep {
|
||||
faultsim_restore_and_reopen
|
||||
} -body {
|
||||
execsql {
|
||||
SELECT * FROM t2 WHERE d NOT NULL
|
||||
}
|
||||
} -test {
|
||||
faultsim_test_result {0 {}}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_execsql_test 2.0 {
|
||||
CREATE TABLE t1(a, b, c);
|
||||
CREATE TABLE t2(a, b, c, PRIMARY KEY(a, b, c)) WITHOUT ROWID;
|
||||
}
|
||||
faultsim_save_and_close
|
||||
|
||||
do_faultsim_test 2.1 -faults oom-t* -prep {
|
||||
faultsim_restore_and_reopen
|
||||
} -body {
|
||||
execsql {
|
||||
SELECT dense_rank() OVER win FROM t2
|
||||
WINDOW win AS (ORDER BY c IS NULL)
|
||||
}
|
||||
} -test {
|
||||
faultsim_test_result {0 {}}
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
+14
-4
@@ -989,7 +989,7 @@ test_suite "journaltest" -description {
|
||||
pager1.test syscall.test tkt3457.test *malloc* mmap* multiplex* nolock*
|
||||
pager2.test *fault* rowal* snapshot* superlock* symlink.test
|
||||
delete_db.test shmlock.test chunksize.test
|
||||
busy2.test
|
||||
busy2.test avfs.test
|
||||
}]
|
||||
|
||||
if {[info commands register_demovfs] != ""} {
|
||||
@@ -1062,7 +1062,8 @@ test_suite "no_optimization" -description {
|
||||
where6.test where7.test where8.test where9.test \
|
||||
whereA.test whereB.test wherelimit.test \
|
||||
select1.test select2.test select3.test select4.test select5.test \
|
||||
select7.test select8.test selectA.test selectC.test
|
||||
select7.test select8.test selectA.test selectC.test \
|
||||
-exclude windowpushd.test
|
||||
] -dbconfig {
|
||||
optimization_control $::dbhandle all 0
|
||||
}
|
||||
@@ -1137,11 +1138,20 @@ proc run_tests {name args} {
|
||||
set ::G(perm:presql) $options(-presql)
|
||||
|
||||
foreach file [lsort $options(-files)] {
|
||||
uplevel $options(-initialize)
|
||||
if {[file tail $file] == $file} { set file [file join $::testdir $file] }
|
||||
|
||||
if {[info exists ::env(SQLITE_TEST_PATTERN_LIST)]} {
|
||||
set ok 0
|
||||
foreach p $::env(SQLITE_TEST_PATTERN_LIST) {
|
||||
set p [string map {% *} $p]
|
||||
if {[string match $p [file tail $file]]} {set ok 1 ; break}
|
||||
}
|
||||
if {!$ok} continue
|
||||
}
|
||||
|
||||
uplevel $options(-initialize)
|
||||
slave_test_file $file
|
||||
uplevel $options(-shutdown)
|
||||
|
||||
unset -nocomplain ::G(perm:sqlite3_args)
|
||||
}
|
||||
|
||||
|
||||
+42
-3
@@ -110,7 +110,7 @@ do_execsql_test 2.2 {
|
||||
PRAGMA writable_schema = 1;
|
||||
CREATE TABLE xyz(a, b, c CHECK (c!="null") );
|
||||
CREATE INDEX i2 ON t1(x, y, z||"abc");
|
||||
CREATE INDEX i3 ON t1("w");
|
||||
CREATE INDEX i3 ON t1("w"||"");
|
||||
CREATE INDEX i4 ON t1(x) WHERE z="w";
|
||||
}
|
||||
|
||||
@@ -135,10 +135,49 @@ do_execsql_test 2.5 {
|
||||
{CREATE TABLE t1(x, y, z)}
|
||||
{CREATE TABLE xyz(a, b, c CHECK (c!="null") )}
|
||||
{CREATE INDEX i2 ON t1(x, y, z||"abc")}
|
||||
{CREATE INDEX i3 ON t1("w")}
|
||||
{CREATE INDEX i3 ON t1("w"||"")}
|
||||
{CREATE INDEX i4 ON t1(x) WHERE z="w"}
|
||||
}
|
||||
|
||||
|
||||
# 2021-03-13
|
||||
# ticket 1c24a659e6d7f3a1
|
||||
reset_db
|
||||
do_catchsql_test 3.0 {
|
||||
CREATE TABLE t1(a,b);
|
||||
CREATE INDEX x1 on t1("b");
|
||||
ALTER TABLE t1 DROP COLUMN b;
|
||||
} {1 {error in index x1 after drop column: no such column: b}}
|
||||
do_catchsql_test 3.1 {
|
||||
DROP TABLE t1;
|
||||
CREATE TABLE t1(a,"b");
|
||||
CREATE INDEX x1 on t1("b");
|
||||
ALTER TABLE t1 DROP COLUMN b;
|
||||
} {1 {error in index x1 after drop column: no such column: b}}
|
||||
do_catchsql_test 3.2 {
|
||||
DROP TABLE t1;
|
||||
CREATE TABLE t1(a,'b');
|
||||
CREATE INDEX x1 on t1("b");
|
||||
ALTER TABLE t1 DROP COLUMN b;
|
||||
} {1 {error in index x1 after drop column: no such column: b}}
|
||||
do_catchsql_test 3.3 {
|
||||
DROP TABLE t1;
|
||||
CREATE TABLE t1(a,"b");
|
||||
CREATE INDEX x1 on t1('b');
|
||||
ALTER TABLE t1 DROP COLUMN b;
|
||||
} {1 {error in index x1 after drop column: no such column: b}}
|
||||
do_catchsql_test 3.4 {
|
||||
DROP TABLE t1;
|
||||
CREATE TABLE t1(a, b, c);
|
||||
CREATE INDEX x1 ON t1("a"||"b");
|
||||
INSERT INTO t1 VALUES(1,2,3),(1,4,5);
|
||||
ALTER TABLE t1 DROP COLUMN b;
|
||||
} {1 {error in index x1 after drop column: no such column: b}}
|
||||
do_catchsql_test 3.5 {
|
||||
DROP TABLE t1;
|
||||
CREATE TABLE t1(a, b, c);
|
||||
CREATE INDEX x1 ON t1("a"||"x");
|
||||
INSERT INTO t1 VALUES(1,2,3),(1,4,5);
|
||||
ALTER TABLE t1 DROP COLUMN b;
|
||||
} {0 {}}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -283,13 +283,13 @@ array set ::Configs [strip_comments {
|
||||
FuzzFail2 {-O0}
|
||||
}]
|
||||
if {$tcl_platform(os)=="Darwin"} {
|
||||
lappend Configs(Apple -DSQLITE_ENABLE_LOCKING_STYLE=1
|
||||
lappend Configs(Apple) -DSQLITE_ENABLE_LOCKING_STYLE=1
|
||||
}
|
||||
|
||||
array set ::Platforms [strip_comments {
|
||||
Linux-x86_64 {
|
||||
"Check-Symbols*" checksymbols
|
||||
"Fast-One" "fuzztest test"
|
||||
"Fast-One" "QUICKTEST_INCLUDE=rbu.test fuzztest test"
|
||||
"Debug-One" "mptest test"
|
||||
"Debug-Two" "test"
|
||||
"Have-Not" test
|
||||
@@ -302,7 +302,7 @@ array set ::Platforms [strip_comments {
|
||||
"No-lookaside" test
|
||||
"Devkit" test
|
||||
"Apple" test
|
||||
"Sanitize" {QUICKTEST_OMIT=crash*,shell*,sqldiff*,sessionB.test test}
|
||||
"Sanitize" test
|
||||
"Device-One" fulltest
|
||||
"Default" "threadtest fulltest"
|
||||
"Valgrind*" valgrindtest
|
||||
@@ -355,6 +355,14 @@ array set ::Platforms [strip_comments {
|
||||
}
|
||||
}]
|
||||
|
||||
#--------------------------------------------------------------------------
|
||||
#--------------------------------------------------------------------------
|
||||
#--------------------------------------------------------------------------
|
||||
# End of configuration section.
|
||||
#--------------------------------------------------------------------------
|
||||
#--------------------------------------------------------------------------
|
||||
#--------------------------------------------------------------------------
|
||||
|
||||
# Configuration verification: Check that each entry in the list of configs
|
||||
# specified for each platforms exists.
|
||||
#
|
||||
@@ -586,9 +594,15 @@ proc main_tests {args} {
|
||||
puts "$config \"$target\""
|
||||
if {$bNodebug==0 && $bNosynthetic==0} {
|
||||
set iHas [string first SQLITE_DEBUG $::Configs($config)]
|
||||
set dtarget test
|
||||
if {$target=="tcltest"} {
|
||||
set dtarget tcltest
|
||||
set dtarget [list]
|
||||
set iQTI [lsearch -glob $target QUICKTEST_*]
|
||||
if {$iQTI>=0} {
|
||||
lappend dtarget [lindex $target $iQTI]
|
||||
}
|
||||
if {[lsearch $target tcltest]>=0} {
|
||||
lappend dtarget tcltest
|
||||
} else {
|
||||
lappend dtarget test
|
||||
}
|
||||
if {$iHas>=0} {
|
||||
puts "$config-ndebug \"$dtarget\""
|
||||
|
||||
@@ -83,5 +83,37 @@ do_execsql_test 4.5 {
|
||||
RETURNING *, '|';
|
||||
} {2 3 4 | 4 100 6 | 5 6 7 |}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test RETURNING on a table with virtual columns.
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 5.0 {
|
||||
CREATE TABLE t1(xyz);
|
||||
CREATE TABLE t2(a as (1+1), b);
|
||||
}
|
||||
|
||||
do_execsql_test 5.1 {
|
||||
UPDATE t2 SET b='123' WHERE b='abc' RETURNING (SELECT b FROM t1);
|
||||
} {}
|
||||
|
||||
do_execsql_test 5.2 {
|
||||
INSERT INTO t2(b) VALUES('abc');
|
||||
}
|
||||
|
||||
do_execsql_test 5.3 {
|
||||
UPDATE t2 SET b='123' WHERE b='abc' RETURNING (SELECT b FROM t1);
|
||||
} {{}}
|
||||
|
||||
do_execsql_test 5.4 {
|
||||
INSERT INTO t2(b) VALUES('abc');
|
||||
INSERT INTO t1(xyz) VALUES(1);
|
||||
UPDATE t2 SET b='123' WHERE b='abc' RETURNING b;
|
||||
} {123}
|
||||
|
||||
do_execsql_test 5.5 {
|
||||
INSERT INTO t2(b) VALUES('abc');
|
||||
UPDATE t2 SET b='123' WHERE b='abc' RETURNING (SELECT b FROM t1);
|
||||
} {123}
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
@@ -644,4 +644,17 @@ do_catchsql_test 27.10 {
|
||||
INSERT INTO t0(c0) VALUES(0) ON CONFLICT(c0) DO UPDATE SET c0 = 3;
|
||||
} {1 {ON CONFLICT clause does not match any PRIMARY KEY or UNIQUE constraint}}
|
||||
|
||||
# 2021-02-03
|
||||
# https://bugs.chromium.org/p/chromium/issues/detail?id=1173511
|
||||
# Faulty assert() statement.
|
||||
#
|
||||
reset_db
|
||||
do_catchsql_test 28.10 {
|
||||
CREATE TABLE t0(c0 PRIMARY KEY, c1);
|
||||
CREATE TRIGGER trigger0 BEFORE DELETE ON t0 BEGIN
|
||||
SELECT (SELECT c0,c1 FROM t0) FROM t0;
|
||||
END ;
|
||||
DELETE FROM t0;
|
||||
} {1 {sub-select returns 2 columns - expected 1}}
|
||||
|
||||
finish_test
|
||||
|
||||
+6
-6
@@ -1167,17 +1167,17 @@ do_execsql_test select1-18.4 {
|
||||
|
||||
# 2019-12-17 gramfuzz find
|
||||
#
|
||||
do_execsql_test select-19.10 {
|
||||
do_execsql_test select1-19.10 {
|
||||
DROP TABLE IF EXISTS t1;
|
||||
CREATE TABLE t1(x);
|
||||
} {}
|
||||
do_catchsql_test select-19.20 {
|
||||
do_catchsql_test select1-19.20 {
|
||||
INSERT INTO t1
|
||||
SELECT 1,2,3,4,5,6,7
|
||||
UNION ALL SELECT 1,2,3,4,5,6,7
|
||||
ORDER BY 1;
|
||||
} {1 {table t1 has 1 columns but 7 values were supplied}}
|
||||
do_catchsql_test select-19.21 {
|
||||
do_catchsql_test select1-19.21 {
|
||||
INSERT INTO t1
|
||||
SELECT 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
|
||||
UNION ALL SELECT 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
|
||||
@@ -1187,7 +1187,7 @@ do_catchsql_test select-19.21 {
|
||||
# 2020-01-01 Found by Yongheng's fuzzer
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test select-20.10 {
|
||||
do_execsql_test select1-20.10 {
|
||||
CREATE TABLE t1 (
|
||||
a INTEGER PRIMARY KEY,
|
||||
b AS('Y') UNIQUE
|
||||
@@ -1197,13 +1197,13 @@ do_execsql_test select-20.10 {
|
||||
WHERE ((SELECT t1.a FROM t1 AS x GROUP BY b) AND b=0)
|
||||
OR a = 10;
|
||||
} {10 Y}
|
||||
do_execsql_test select-20.20 {
|
||||
do_execsql_test select1-20.20 {
|
||||
SELECT ifnull(a, max((SELECT 123))), count(a) FROM t1 ;
|
||||
} {10 1}
|
||||
|
||||
# 2020-10-02 dbsqlfuzz find
|
||||
reset_db
|
||||
do_execsql_test select-21.1 {
|
||||
do_execsql_test select1-21.1 {
|
||||
CREATE TABLE t1(a IMTEGES PRIMARY KEY,R);
|
||||
CREATE TABLE t2(x UNIQUE);
|
||||
CREATE VIEW v1a(z,y) AS SELECT x IS NULL, x FROM t2;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user